diff options
Diffstat (limited to 'src/yuzu')
-rw-r--r-- | src/yuzu/configuration/configure_audio.cpp | 3 | ||||
-rw-r--r-- | src/yuzu/configuration/shared_translation.cpp | 3 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 127 | ||||
-rw-r--r-- | src/yuzu/main.h | 9 | ||||
-rw-r--r-- | src/yuzu/main.ui | 39 | ||||
-rw-r--r-- | src/yuzu/uisettings.h | 2 |
6 files changed, 163 insertions, 20 deletions
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 9ccfb2435..81dd51ad3 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -42,6 +42,9 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) { for (auto* setting : Settings::values.linkage.by_category[category]) { settings.push_back(setting); } + for (auto* setting : UISettings::values.linkage.by_category[category]) { + settings.push_back(setting); + } }; push(Settings::Category::Audio); diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 276bdbaba..a4e8af1b4 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -29,9 +29,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { INSERT(Settings, sink_id, "Output Engine:", ""); INSERT(Settings, audio_output_device_id, "Output Device:", ""); INSERT(Settings, audio_input_device_id, "Input Device:", ""); - INSERT(Settings, audio_muted, "Mute audio when in background", ""); + INSERT(Settings, audio_muted, "Mute audio", ""); INSERT(Settings, volume, "Volume:", ""); INSERT(Settings, dump_audio_commands, "", ""); + INSERT(UISettings, mute_when_in_background, "Mute audio when in background", ""); // Core INSERT(Settings, use_multi_core, "Multicore CPU Emulation", ""); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d32aa9615..1753fec12 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -18,6 +18,8 @@ #include <sys/socket.h> #endif +#include <boost/container/flat_set.hpp> + // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. #include "applets/qt_amiibo_settings.h" #include "applets/qt_controller.h" @@ -1445,6 +1447,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { Settings::values.audio_muted = false; auto_muted = false; } + UpdateVolumeUI(); } } @@ -1551,6 +1554,15 @@ void GMainWindow::ConnectMenuEvents() { // Tools connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); + connect_menu(ui->action_Load_Cabinet_Nickname_Owner, + [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); }); + connect_menu(ui->action_Load_Cabinet_Eraser, + [this]() { OnCabinet(Service::NFP::CabinetMode::StartGameDataEraser); }); + connect_menu(ui->action_Load_Cabinet_Restorer, + [this]() { OnCabinet(Service::NFP::CabinetMode::StartRestorer); }); + connect_menu(ui->action_Load_Cabinet_Formatter, + [this]() { OnCabinet(Service::NFP::CabinetMode::StartFormatter); }); + connect_menu(ui->action_Load_Mii_Edit, &GMainWindow::OnMiiEdit); connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot); // TAS @@ -1567,6 +1579,7 @@ void GMainWindow::ConnectMenuEvents() { void GMainWindow::UpdateMenuState() { const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning(); + const bool is_firmware_available = CheckFirmwarePresence(); const std::array running_actions{ ui->action_Stop, @@ -1577,10 +1590,22 @@ void GMainWindow::UpdateMenuState() { ui->action_Pause, }; + const std::array applet_actions{ + ui->action_Load_Cabinet_Nickname_Owner, + ui->action_Load_Cabinet_Eraser, + ui->action_Load_Cabinet_Restorer, + ui->action_Load_Cabinet_Formatter, + ui->action_Load_Mii_Edit, + }; + for (QAction* action : running_actions) { action->setEnabled(emulation_running); } + for (QAction* action : applet_actions) { + action->setEnabled(is_firmware_available && !emulation_running); + } + ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused); if (emulation_running && is_paused) { @@ -2100,6 +2125,8 @@ void GMainWindow::OnEmulationStopped() { OnTasStateChanged(); render_window->FinalizeCamera(); + system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::None); + // Enable all controllers system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); @@ -3110,10 +3137,9 @@ void GMainWindow::OnMenuInstallToNAND() { QFuture<InstallResult> future; InstallResult result; - if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || - file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); }); + future = QtConcurrent::run([this, &file] { return InstallNSP(file); }); while (!future.isFinished()) { QCoreApplication::processEvents(); @@ -3172,7 +3198,7 @@ void GMainWindow::OnMenuInstallToNAND() { ui->action_Install_File_NAND->setEnabled(true); } -InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { +InstallResult GMainWindow::InstallNSP(const QString& filename) { const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, std::size_t block_size) { if (src == nullptr || dest == nullptr) { @@ -3206,9 +3232,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { return InstallResult::Failure; } } else { - const auto xci = std::make_shared<FileSys::XCI>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - nsp = xci->GetSecurePartitionNSP(); + return InstallResult::Failure; } if (nsp->GetStatus() != Loader::ResultStatus::Success) { @@ -4134,6 +4158,53 @@ void GMainWindow::OnToggleStatusBar() { statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); } +void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { + constexpr u64 CabinetId = 0x0100000000001002ull; + auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + QMessageBox::warning(this, tr("No firmware available"), + tr("Please install the firmware to use the Cabinet applet.")); + return; + } + + auto cabinet_nca = bis_system->GetEntry(CabinetId, FileSys::ContentRecordType::Program); + if (!cabinet_nca) { + QMessageBox::warning(this, tr("Cabinet Applet"), + tr("Cabinet applet is not available. Please reinstall firmware.")); + return; + } + + system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Cabinet); + system->GetAppletManager().SetCabinetMode(mode); + + const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); + UISettings::values.roms_path = QFileInfo(filename).path(); + BootGame(filename); +} + +void GMainWindow::OnMiiEdit() { + constexpr u64 MiiEditId = 0x0100000000001009ull; + auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + QMessageBox::warning(this, tr("No firmware available"), + tr("Please install the firmware to use the Mii editor.")); + return; + } + + auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program); + if (!mii_applet_nca) { + QMessageBox::warning(this, tr("Mii Edit Applet"), + tr("Mii editor is not available. Please reinstall firmware.")); + return; + } + + system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); + + const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); + UISettings::values.roms_path = QFileInfo(filename).path(); + BootGame(filename); +} + void GMainWindow::OnCaptureScreenshot() { if (emu_thread == nullptr || !emu_thread->IsRunning()) { return; @@ -4540,6 +4611,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { if (behavior == ReinitializeKeyBehavior::Warning) { game_list->PopulateAsync(UISettings::values.game_dirs); } + + UpdateMenuState(); } bool GMainWindow::CheckSystemArchiveDecryption() { @@ -4561,10 +4634,26 @@ bool GMainWindow::CheckSystemArchiveDecryption() { return mii_nca->GetRomFS().get() != nullptr; } +bool GMainWindow::CheckFirmwarePresence() { + constexpr u64 MiiEditId = 0x0100000000001009ull; + + auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + return false; + } + + auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program); + if (!mii_applet_nca) { + return false; + } + + return true; +} + bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id, u64* selected_title_id, u8* selected_content_record_type) { - using ContentInfo = std::pair<FileSys::TitleType, FileSys::ContentRecordType>; - boost::container::flat_map<u64, ContentInfo> available_title_ids; + using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>; + boost::container::flat_set<ContentInfo> available_title_ids; const auto RetrieveEntries = [&](FileSys::TitleType title_type, FileSys::ContentRecordType record_type) { @@ -4572,12 +4661,14 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe for (const auto& entry : entries) { if (FileSys::GetBaseTitleID(entry.title_id) == program_id && installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) { - available_title_ids[entry.title_id] = {title_type, record_type}; + available_title_ids.insert({entry.title_id, title_type, record_type}); } } }; RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program); + RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::HtmlDocument); + RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::LegalInformation); RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); if (available_title_ids.empty()) { @@ -4588,10 +4679,14 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe if (available_title_ids.size() > 1) { QStringList list; - for (auto& [title_id, content_info] : available_title_ids) { + for (auto& [title_id, title_type, record_type] : available_title_ids) { const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id)); - if (content_info.first == FileSys::TitleType::Application) { - list.push_back(QStringLiteral("Application [%1]").arg(hex_title_id)); + if (record_type == FileSys::ContentRecordType::Program) { + list.push_back(QStringLiteral("Program [%1]").arg(hex_title_id)); + } else if (record_type == FileSys::ContentRecordType::HtmlDocument) { + list.push_back(QStringLiteral("HTML document [%1]").arg(hex_title_id)); + } else if (record_type == FileSys::ContentRecordType::LegalInformation) { + list.push_back(QStringLiteral("Legal information [%1]").arg(hex_title_id)); } else { list.push_back( QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id)); @@ -4609,9 +4704,9 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe title_index = list.indexOf(res); } - const auto selected_info = available_title_ids.nth(title_index); - *selected_title_id = selected_info->first; - *selected_content_record_type = static_cast<u8>(selected_info->second.second); + const auto& [title_id, title_type, record_type] = *available_title_ids.nth(title_index); + *selected_title_id = title_id; + *selected_content_record_type = static_cast<u8>(record_type); return true; } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index cf191f698..52028234c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -102,6 +102,10 @@ namespace Service::NFC { class NfcDevice; } // namespace Service::NFC +namespace Service::NFP { +enum class CabinetMode : u8; +} // namespace Service::NFP + namespace Ui { class MainWindow; } @@ -365,6 +369,8 @@ private slots: void ResetWindowSize720(); void ResetWindowSize900(); void ResetWindowSize1080(); + void OnCabinet(Service::NFP::CabinetMode mode); + void OnMiiEdit(); void OnCaptureScreenshot(); void OnReinitializeKeys(ReinitializeKeyBehavior behavior); void OnLanguageChanged(const QString& locale); @@ -386,7 +392,7 @@ private: void RemoveCacheStorage(u64 program_id); bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); - InstallResult InstallNSPXCI(const QString& filename); + InstallResult InstallNSP(const QString& filename); InstallResult InstallNCA(const QString& filename); void MigrateConfigFiles(); void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, @@ -409,6 +415,7 @@ private: void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); bool CheckDarkMode(); bool CheckSystemArchiveDecryption(); + bool CheckFirmwarePresence(); void ConfigureFilesystemProvider(const std::string& filepath); QString GetTasStateDescription() const; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index e54d7d75d..31c3de9ef 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -137,6 +137,15 @@ <property name="title"> <string>&Tools</string> </property> + <widget class="QMenu" name="menu_cabinet_applet"> + <property name="title"> + <string>&Amiibo</string> + </property> + <addaction name="action_Load_Cabinet_Nickname_Owner"/> + <addaction name="action_Load_Cabinet_Eraser"/> + <addaction name="action_Load_Cabinet_Restorer"/> + <addaction name="action_Load_Cabinet_Formatter"/> + </widget> <widget class="QMenu" name="menuTAS"> <property name="title"> <string>&TAS</string> @@ -150,6 +159,9 @@ <addaction name="action_Rederive"/> <addaction name="action_Verify_installed_contents"/> <addaction name="separator"/> + <addaction name="menu_cabinet_applet"/> + <addaction name="action_Load_Mii_Edit"/> + <addaction name="separator"/> <addaction name="action_Capture_Screenshot"/> <addaction name="menuTAS"/> </widget> @@ -217,7 +229,7 @@ </action> <action name="action_Verify_installed_contents"> <property name="text"> - <string>Verify installed contents</string> + <string>&Verify Installed Contents</string> </property> </action> <action name="action_About"> @@ -368,6 +380,31 @@ <string>&Capture Screenshot</string> </property> </action> + <action name="action_Load_Cabinet_Nickname_Owner"> + <property name="text"> + <string>&Set Nickname and Owner</string> + </property> + </action> + <action name="action_Load_Cabinet_Eraser"> + <property name="text"> + <string>&Delete Game Data</string> + </property> + </action> + <action name="action_Load_Cabinet_Restorer"> + <property name="text"> + <string>&Restore Amiibo</string> + </property> + </action> + <action name="action_Load_Cabinet_Formatter"> + <property name="text"> + <string>&Format Amiibo</string> + </property> + </action> + <action name="action_Load_Mii_Edit"> + <property name="text"> + <string>Open &Mii Editor</string> + </property> + </action> <action name="action_Configure_Tas"> <property name="text"> <string>&Configure TAS...</string> diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 8efd63f31..8a2caa9dd 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -103,7 +103,7 @@ struct Values { true, true}; Setting<bool> mute_when_in_background{ - linkage, false, "muteWhenInBackground", Category::Ui, Settings::Specialization::Default, + linkage, false, "muteWhenInBackground", Category::Audio, Settings::Specialization::Default, true, true}; Setting<bool> hide_mouse{ linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, |