From d9cbb6f0a43b52d6539c1e0dc2b0d787f96722a0 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:48:13 -0400 Subject: [PATCH] [qt_common] reorg, move more stuff out of main Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 + src/qt_common/qt_common.cpp | 175 +------- src/qt_common/qt_common.h | 76 +--- src/qt_common/qt_content_util.cpp | 202 +++++++++ src/qt_common/qt_content_util.h | 48 +++ src/qt_common/qt_frontend_util.cpp | 73 +++- src/qt_common/qt_frontend_util.h | 44 +- src/qt_common/qt_game_util.cpp | 270 ++++++++++-- src/qt_common/qt_game_util.h | 40 +- src/qt_common/qt_meta.cpp | 72 ++++ src/qt_common/qt_meta.h | 12 + src/qt_common/qt_path_util.cpp | 9 +- src/qt_common/qt_path_util.h | 4 +- src/qt_common/qt_rom_util.cpp | 75 ++++ src/qt_common/qt_rom_util.h | 17 + .../configuration/configure_filesystem.cpp | 13 +- src/yuzu/game_list.cpp | 25 +- src/yuzu/game_list.h | 19 +- src/yuzu/main.cpp | 403 +++--------------- src/yuzu/main.h | 21 +- 20 files changed, 923 insertions(+), 680 deletions(-) create mode 100644 src/qt_common/qt_content_util.cpp create mode 100644 src/qt_common/qt_content_util.h create mode 100644 src/qt_common/qt_meta.cpp create mode 100644 src/qt_common/qt_meta.h create mode 100644 src/qt_common/qt_rom_util.cpp create mode 100644 src/qt_common/qt_rom_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 0c9bb54b11..da6c9b0481 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -18,11 +19,15 @@ add_library(qt_common STATIC qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp qt_frontend_util.h qt_frontend_util.cpp + qt_meta.h qt_meta.cpp + qt_content_util.h qt_content_util.cpp + qt_rom_util.h qt_rom_util.cpp ) create_target_directory_groups(qt_common) target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PRIVATE Qt6::Core) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index c7b75a196d..6f8808ca32 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,11 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "frontend_common/firmware_manager.h" -#include "uisettings.h" #include #include @@ -16,7 +11,6 @@ #include #include -#include "qt_frontend_util.h" #include @@ -27,19 +21,9 @@ #endif namespace QtCommon { -MetadataResult ResetMetadata() -{ - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) - / "game_list/")) { - return MetadataResult::Empty; - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return MetadataResult::Success; - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - return MetadataResult::Failure; - } -} + +QObject *rootObject = nullptr; +Core::System *system = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -86,157 +70,14 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs, - QWidget* parent) +const QString tr(const char* str) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; - - QMessageBox::Icon icon; - FirmwareInstallResult result; - - const auto ShowMessage = [&]() { - QtCommon::Frontend::ShowMessage(icon, - failedTitle, - GetFirmwareInstallResultString(result), - buttons, - parent); - }; - - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); - - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - result = FirmwareInstallResult::NoNCAs; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() - && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - result = FirmwareInstallResult::FailedDelete; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), - FileSys::OpenMode::Read); - auto firmware_dst_vfile = firmware_vdir - ->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, - "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), - firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback(100, - 20 - + static_cast(((i) / static_cast(out.size())) - * 70.0))) { - result = FirmwareInstallResult::FailedCorrupted; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - } - - if (!success) { - result = FirmwareInstallResult::FailedCopy; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - - const auto pair = FirmwareManager::GetFirmwareVersion(*system); - const auto firmware_data = pair.first; - const std::string display_version(firmware_data.display_version.data()); - - result = FirmwareInstallResult::Success; - QtCommon::Frontend::ShowMessage(QMessageBox::Information, - qApp->tr(successTitle), - qApp->tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons, - parent); - return result; + return QGuiApplication::tr(str); } -QString UnzipFirmwareToTmp(const QString& location) +const QString tr(const std::string& str) { - namespace fs = std::filesystem; - fs::path tmp{fs::temp_directory_path()}; - - if (!fs::create_directories(tmp / "eden" / "firmware")) { - return ""; - } - - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - return ""; - } - - return qCacheDir; + return QGuiApplication::tr(str.c_str()); } + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index ef9b5577f1..cf52cedc32 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,8 +4,6 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include - #include #include "core/core.h" #include @@ -13,68 +11,28 @@ #include namespace QtCommon { -static constexpr std::array METADATA_RESULTS = { - "The operation completed successfully.", - "The metadata cache couldn't be deleted. It might be in use or non-existent.", - "The metadata cache is already empty.", -}; -enum class MetadataResult { - Success, - Failure, - Empty, -}; -/** - * @brief ResetMetadata Reset game list metadata. - * @return A result code. - */ -MetadataResult ResetMetadata(); +extern QObject *rootObject; +extern Core::System *system; -/** - * \brief Get a string representation of a result from ResetMetadata. - * \param result The result code. - * \return A string representation of the passed result code. - */ -inline constexpr const char *GetResetMetadataResultString(MetadataResult result) -{ - return METADATA_RESULTS.at(static_cast(result)); -} - -static constexpr std::array FIRMWARE_RESULTS - = {"Successfully installed firmware version %1", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware."}; - -enum class FirmwareInstallResult { - Success, - NoOp, - NoNCAs, - FailedDelete, - FailedCopy, - FailedCorrupted, -}; - -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs, - QWidget *parent = nullptr); - -QString UnzipFirmwareToTmp(const QString &location); - -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +typedef std::function QtProgressCallback; Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); + +static inline void SetRootObject(QObject *parent) +{ + rootObject = parent; +} + +static inline void SetSystem(Core::System *newSystem) +{ + system = newSystem; +} + +const QString tr(const char *str); +const QString tr(const std::string &str); + } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp new file mode 100644 index 0000000000..81ec7c9cea --- /dev/null +++ b/src/qt_common/qt_content_util.cpp @@ -0,0 +1,202 @@ +#include "qt_content_util.h" +#include "common/fs/fs.h" +#include "frontend_common/content_manager.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_game_util.h" +#include "qt_frontend_util.h" + +#include + +namespace QtCommon::Content { + +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +{ + if (FirmwareManager::GameRequiresFirmware(program_id) + && !FirmwareManager::CheckFirmwarePresence(system)) { + auto result = QtCommon::Frontend::ShowMessage( + QMessageBox::Warning, + "Game Requires Firmware", + "The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways.", + QMessageBox::Ok | QMessageBox::Cancel, + parent); + + return result == QMessageBox::Ok; + } + + return true; +} + +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) +{ + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + rootObject); + }; + + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable dir_callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + callback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + callback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (callback(100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + } + + if (!success) { + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::Information(rootObject, + tr(successTitle), + tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons); + return result; +} + +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; +} + +// Content // +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); + + switch (result) { + case ContentManager::GameVerificationResult::Success: + QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + break; + case ContentManager::GameVerificationResult::Failed: + QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + tr("File contents may be corrupt or missing.")); + break; + case ContentManager::GameVerificationResult::NotImplemented: + QtCommon::Frontend::Warning( + rootObject, + tr("Integrity verification couldn't be performed"), + tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " + "File contents could not be checked for validity.")); + } +} + + +} diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h new file mode 100644 index 0000000000..9a1a4e5bc2 --- /dev/null +++ b/src/qt_common/qt_content_util.h @@ -0,0 +1,48 @@ +#ifndef QT_CONTENT_UTIL_H +#define QT_CONTENT_UTIL_H + +#include +#include "common/common_types.h" +#include "core/core.h" +#include "qt_common/qt_common.h" + +namespace QtCommon::Content { + +// +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); + +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem *vfs); + +QString UnzipFirmwareToTmp(const QString &location); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + +// Content // +void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +} +#endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index bcb662239b..6b96a26a21 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -4,27 +4,84 @@ #include "qt_frontend_util.h" namespace QtCommon::Frontend { + QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, - QWidget *parent) + QObject *parent) { #ifdef YUZU_QT_WIDGETS - QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); return static_cast(box->exec()); #endif // TODO(crueter): If Qt Widgets is disabled... // need a way to reference icon/buttons too } -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons, - QWidget *parent) +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) { - return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); + return ShowMessage(QMessageBox::Information, title, text, buttons, parent); } +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, title, text, buttons, parent); +} + +QMessageBox::StandardButton Information(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); +} + + } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8a38c033bf..a91a0db07b 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -17,16 +17,52 @@ namespace QtCommon::Frontend { Q_NAMESPACE +// TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QObject *parent = nullptr); -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Information(QObject *parent, const char *title, const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index a870c2ab27..488eb8c971 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -4,40 +4,50 @@ #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/file_sys/savedata_factory.h" +#include "frontend_common/content_manager.h" +#include "qt_common.h" +#include "qt_common/uisettings.h" +#include "qt_frontend_util.h" #include #include #ifdef _WIN32 - #include - #include - #include "common/scope_exit.h" - #include "common/string_util.h" +#include "common/scope_exit.h" +#include "common/string_util.h" +#include +#include #else - #include "fmt/ostream.h" - #include +#include "fmt/ostream.h" +#include #endif -namespace QtCommon { +namespace QtCommon::Game { bool CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name) +try { #ifdef _WIN32 // Windows HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { LOG_ERROR(Frontend, "CoInitialize failed"); return false; } - SCOPE_EXIT { + SCOPE_EXIT + { CoUninitialize(); }; IShellLinkW* ps1 = nullptr; IPersistFile* persist_file = nullptr; - SCOPE_EXIT { + SCOPE_EXIT + { if (persist_file != nullptr) { persist_file->Release(); } @@ -45,7 +55,10 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, ps1->Release(); } }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IShellLinkW, reinterpret_cast(&ps1)); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); @@ -115,17 +128,18 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Keywords={}\n", keywords); } return true; -#else // Unsupported platform +#else // Unsupported platform return false; #endif -} - catch (const std::exception& e) { +} catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); return false; } -bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path) +{ // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) @@ -146,12 +160,13 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(path)))); +void OpenEdenFolder(const Common::FS::EdenPath& path) +{ + QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } -void OpenRootDataFolder() { +void OpenRootDataFolder() +{ OpenEdenFolder(Common::FS::EdenPath::EdenDir); } @@ -175,4 +190,211 @@ void OpenLogFolder() OpenEdenFolder(Common::FS::EdenPath::LogDir); } +static QString GetGameListErrorRemoving(QtCommon::Game::InstalledEntryType type) +{ + switch (type) { + case QtCommon::Game::InstalledEntryType::Game: + return tr("Error Removing Contents"); + case QtCommon::Game::InstalledEntryType::Update: + return tr("Error Removing Update"); + case QtCommon::Game::InstalledEntryType::AddOnContent: + return tr("Error Removing DLC"); + default: + return QStringLiteral("Error Removing "); + } } + +// Game Content // +void RemoveBaseContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveBaseContent(system->GetFileSystemController(), + program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed base game."); + } else { + QtCommon::Frontend::Warning( + rootObject, + GetGameListErrorRemoving(type), + tr("The base game is not installed in the NAND and cannot be removed.")); + } +} + +void RemoveUpdateContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed update."); + } else { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There is no update installed for this title.")); + } +} + +void RemoveAddOnContent(u64 program_id, InstalledEntryType type) +{ + const size_t count = ContentManager::RemoveAllDLC(*system, program_id); + if (count == 0) { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There are no DLCs installed for this title.")); + return; + } + + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed %1 installed DLC.").arg(count)); +} + +// Global Content // + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) +{ + const auto target_file_name = [target] { + switch (target) { + case GameListRemoveTarget::GlShaderCache: + return "opengl.bin"; + case GameListRemoveTarget::VkShaderCache: + return "vulkan.bin"; + default: + return ""; + } + }(); + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader cache.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("Failed to remove the transferable shader cache.")); + } +} + +void RemoveVulkanDriverPipelineCache(u64 program_id) +{ + static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; + + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + return; + } + if (!Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Vulkan Driver Pipeline Cache"), + tr("Failed to remove the driver pipeline cache.")); + } +} + +void RemoveAllTransferableShaderCaches(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); + + if (!Common::FS::Exists(program_shader_cache_dir)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader caches.")); + } else { + QtCommon::Frontend::Warning( + rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("Failed to remove the transferable shader cache directory.")); + } +} + +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) +{ + const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); + const auto config_file_name = program_id == 0 + ? Common::FS::PathToUTF8String(file_path.filename()) + .append(".ini") + : fmt::format("{:016X}.ini", program_id); + const auto custom_config_file_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) + / "custom" / config_file_name; + + if (!Common::FS::Exists(custom_config_file_path)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("A custom configuration for this title does not exist.")); + return; + } + + if (Common::FS::RemoveFile(custom_config_file_path)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the custom game configuration.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("Failed to remove the custom game configuration.")); + } +} + +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +{ + const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); + auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), + FileSys::OpenMode::Read); + + const auto cache_storage_path + = FileSys::SaveDataFactory::GetFullPath({}, + vfs_nand_dir, + FileSys::SaveDataSpaceId::User, + FileSys::SaveDataType::Cache, + 0 /* program_id */, + {}, + 0); + + const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); + + // Not an error if it wasn't cleared. + Common::FS::RemoveDirRecursively(path); +} + +// Metadata // +void ResetMetadata() +{ + const QString title = tr("Reset Metadata Cache"); + + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + QtCommon::Frontend::Information(rootObject, + title, + tr("The operation completed successfully.")); + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + QtCommon::Frontend::Warning( + rootObject, + title, + tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + } +} + +} // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 12916d8a98..9861910833 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,23 +4,25 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include #include "common/fs/path_util.h" -#include "frontend_common/content_manager.h" -#include +#include -namespace QtCommon { +namespace QtCommon::Game { -static constexpr std::array GAME_VERIFICATION_RESULTS = { - "The operation completed successfully.", - "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "File contents could not be checked for validity." +enum class InstalledEntryType { + Game, + Update, + AddOnContent, }; -inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) -{ - return GAME_VERIFICATION_RESULTS.at(static_cast(result)); -} +enum class GameListRemoveTarget { + GlShaderCache, + VkShaderCache, + AllShaderCache, + CustomConfiguration, + CacheStorage, +}; bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, @@ -41,6 +43,20 @@ void OpenNANDFolder(); void OpenSDMCFolder(); void OpenModFolder(); void OpenLogFolder(); + +void RemoveBaseContent(u64 program_id, InstalledEntryType type); +void RemoveUpdateContent(u64 program_id, InstalledEntryType type); +void RemoveAddOnContent(u64 program_id, InstalledEntryType type); + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); +void RemoveVulkanDriverPipelineCache(u64 program_id); +void RemoveAllTransferableShaderCaches(u64 program_id); +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); + +// Metadata // +void ResetMetadata(); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp new file mode 100644 index 0000000000..c972c0fe45 --- /dev/null +++ b/src/qt_common/qt_meta.cpp @@ -0,0 +1,72 @@ +#include "qt_meta.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" + +namespace QtCommon::Meta { + +void RegisterMetaTypes() +{ + // Register integral and floating point types + qRegisterMetaType("u8"); + qRegisterMetaType("u16"); + qRegisterMetaType("u32"); + qRegisterMetaType("u64"); + qRegisterMetaType("u128"); + qRegisterMetaType("s8"); + qRegisterMetaType("s16"); + qRegisterMetaType("s32"); + qRegisterMetaType("s64"); + qRegisterMetaType("f32"); + qRegisterMetaType("f64"); + + // Register string types + qRegisterMetaType("std::string"); + qRegisterMetaType("std::wstring"); + qRegisterMetaType("std::u8string"); + qRegisterMetaType("std::u16string"); + qRegisterMetaType("std::u32string"); + qRegisterMetaType("std::string_view"); + qRegisterMetaType("std::wstring_view"); + qRegisterMetaType("std::u8string_view"); + qRegisterMetaType("std::u16string_view"); + qRegisterMetaType("std::u32string_view"); + + // Register applet types + + // Cabinet Applet + qRegisterMetaType("Core::Frontend::CabinetParameters"); + qRegisterMetaType>( + "std::shared_ptr"); + + // Controller Applet + qRegisterMetaType("Core::Frontend::ControllerParameters"); + + // Profile Select Applet + qRegisterMetaType( + "Core::Frontend::ProfileSelectParameters"); + + // Software Keyboard Applet + qRegisterMetaType( + "Core::Frontend::KeyboardInitializeParameters"); + qRegisterMetaType( + "Core::Frontend::InlineAppearParameters"); + qRegisterMetaType("Core::Frontend::InlineTextParameters"); + qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdReplyType"); + + // Web Browser Applet + qRegisterMetaType("Service::AM::Frontend::WebExitReason"); + + // Register loader types + qRegisterMetaType("Core::SystemResultStatus"); +} + +} diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h new file mode 100644 index 0000000000..36cafba2bf --- /dev/null +++ b/src/qt_common/qt_meta.h @@ -0,0 +1,12 @@ +#ifndef QT_META_H +#define QT_META_H + +#include + +namespace QtCommon::Meta { + +// +void RegisterMetaTypes(); + +} +#endif // QT_META_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 6875d01dea..761e6e8405 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -7,17 +7,22 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "qt_common/qt_frontend_util.h" #include -bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +namespace QtCommon::Path { + +bool OpenShaderCache(u64 program_id, QObject *parent) { const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - return false; + QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent); } const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } + +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 7f399c4bb4..855b06caa9 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -5,6 +5,8 @@ #define QT_PATH_UTIL_H #include "common/common_types.h" -namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } +#include + +namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); } #endif // QT_PATH_UTIL_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp new file mode 100644 index 0000000000..e707d1e471 --- /dev/null +++ b/src/qt_common/qt_rom_util.cpp @@ -0,0 +1,75 @@ +#include "qt_rom_util.h" + +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full) +{ + // TODO(crueter) + // if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + // return false; + // if (dialog.wasCanceled()) + // return false; + + // std::vector buffer(CopyBufferSize); + // auto last_timestamp = std::chrono::steady_clock::now(); + + // const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file, + // const FileSys::VirtualFile& dest_file) { + // if (src_file == nullptr || dest_file == nullptr) { + // return false; + // } + // if (!dest_file->Resize(src_file->GetSize())) { + // return false; + // } + + // for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) { + // if (dialog.wasCanceled()) { + // dest_file->Resize(0); + // return false; + // } + + // using namespace std::literals::chrono_literals; + // const auto new_timestamp = std::chrono::steady_clock::now(); + + // if ((new_timestamp - last_timestamp) > 33ms) { + // last_timestamp = new_timestamp; + // dialog.setValue( + // static_cast(std::min(read_size, total_size) * 100 / total_size)); + // QCoreApplication::processEvents(); + // } + + // const auto read = src_file->Read(buffer.data(), buffer.size(), i); + // dest_file->Write(buffer.data(), read, i); + + // read_size += read; + // } + + // return true; + // }; + + // if (full) { + // for (const auto& file : src->GetFiles()) { + // const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); + // if (!QtRawCopy(file, out)) + // return false; + // } + // } + + // for (const auto& dir : src->GetSubdirectories()) { + // const auto out = dest->CreateSubdirectory(dir->GetName()); + // if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full)) + // return false; + // } + + // return true; + return true; +} + +} diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h new file mode 100644 index 0000000000..52ebb1e8d0 --- /dev/null +++ b/src/qt_common/qt_rom_util.h @@ -0,0 +1,17 @@ +#ifndef QT_ROM_UTIL_H +#define QT_ROM_UTIL_H + +#include "qt_common/qt_common.h" +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full); + +} +#endif // QT_ROM_UTIL_H diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index d02e6dec2b..d461bd2cc9 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" #include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" @@ -130,17 +131,7 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - auto result = QtCommon::ResetMetadata(); - const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); - const QString title = tr("Reset Metadata Cache"); - - switch (result) { - case QtCommon::MetadataResult::Failure: - QMessageBox::warning(this, title, resultMessage); - break; - default: - QMessageBox::information(this, title, resultMessage); - } + QtCommon::Game::ResetMetadata(); } void ConfigureFilesystem::UpdateEnabledControls() { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index dceafa58de..48364af53b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include "yuzu/game_list.h" #include #include #include @@ -13,19 +13,20 @@ #include #include #include -#include #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" -#include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" +#include +#include GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) : QObject(parent), gamelist{gamelist_} {} @@ -608,30 +609,30 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(open_transferable_shader_cache, &QAction::triggered, [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); connect(remove_all_content, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Game); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game); }); connect(remove_update, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Update); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update); }); connect(remove_dlc, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent); }); connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path); }); connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path); }); connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path); }); connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path); }); connect(remove_play_time_data, &QAction::triggered, [this, program_id]() { emit RemovePlayTimeRequested(program_id); }); connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path); }); connect(dump_romfs, &QAction::triggered, [this, program_id, path]() { emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 328432138c..367d047c40 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -21,6 +21,7 @@ #include "common/common_types.h" #include "core/core.h" #include "qt_common/uisettings.h" +#include "qt_common/qt_game_util.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -46,14 +47,6 @@ enum class GameListOpenTarget { ModData, }; -enum class GameListRemoveTarget { - GlShaderCache, - VkShaderCache, - AllShaderCache, - CustomConfiguration, - CacheStorage, -}; - enum class DumpRomFSTarget { Normal, SDMC, @@ -64,12 +57,6 @@ enum class GameListShortcutTarget { Applications, }; -enum class InstalledEntryType { - Game, - Update, - AddOnContent, -}; - class GameList : public QWidget { Q_OBJECT @@ -118,8 +105,8 @@ signals: void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OpenTransferableShaderCacheRequested(u64 program_id); - void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); - void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, + void RemoveInstalledEntryRequested(u64 program_id, QtCommon::Game::InstalledEntryType type); + void RemoveFileRequested(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void RemovePlayTimeRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 50d9d7c730..0d8219d062 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -14,6 +14,8 @@ #include "qt_common/qt_common.h" #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -297,14 +299,6 @@ enum class CalloutFlag : uint32_t { DRDDeprecation = 0x2, }; -/** - * Some games perform worse or straight-up don't work with updates, - * so this tracks which games are bad in this regard. - */ -constexpr std::array bad_update_games{ - 0x0100F2C0115B6000 // Tears of the Kingdom -}; - const int GMainWindow::max_recent_files_item; static void RemoveCachedContents() { @@ -386,6 +380,7 @@ static void OverrideWindowsFont() { } #endif +// TODO(crueter): carboxyl does this, is it needed in qml? inline static bool isDarkMode() { #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) const auto scheme = QGuiApplication::styleHints()->colorScheme(); @@ -403,6 +398,9 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) input_subsystem{std::make_shared()}, user_data_migrator{this}, vfs{std::make_shared()}, provider{std::make_unique()} { + QtCommon::SetSystem(system.get()); + QtCommon::SetRootObject(this); + Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -459,7 +457,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) Network::Init(); - RegisterMetaTypes(); + QtCommon::Meta::RegisterMetaTypes(); InitializeWidgets(); InitializeDebugWidgets(); @@ -730,65 +728,6 @@ GMainWindow::~GMainWindow() { #endif } -void GMainWindow::RegisterMetaTypes() { - // Register integral and floating point types - qRegisterMetaType("u8"); - qRegisterMetaType("u16"); - qRegisterMetaType("u32"); - qRegisterMetaType("u64"); - qRegisterMetaType("u128"); - qRegisterMetaType("s8"); - qRegisterMetaType("s16"); - qRegisterMetaType("s32"); - qRegisterMetaType("s64"); - qRegisterMetaType("f32"); - qRegisterMetaType("f64"); - - // Register string types - qRegisterMetaType("std::string"); - qRegisterMetaType("std::wstring"); - qRegisterMetaType("std::u8string"); - qRegisterMetaType("std::u16string"); - qRegisterMetaType("std::u32string"); - qRegisterMetaType("std::string_view"); - qRegisterMetaType("std::wstring_view"); - qRegisterMetaType("std::u8string_view"); - qRegisterMetaType("std::u16string_view"); - qRegisterMetaType("std::u32string_view"); - - // Register applet types - - // Cabinet Applet - qRegisterMetaType("Core::Frontend::CabinetParameters"); - qRegisterMetaType>( - "std::shared_ptr"); - - // Controller Applet - qRegisterMetaType("Core::Frontend::ControllerParameters"); - - // Profile Select Applet - qRegisterMetaType( - "Core::Frontend::ProfileSelectParameters"); - - // Software Keyboard Applet - qRegisterMetaType( - "Core::Frontend::KeyboardInitializeParameters"); - qRegisterMetaType( - "Core::Frontend::InlineAppearParameters"); - qRegisterMetaType("Core::Frontend::InlineTextParameters"); - qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdTextCheckResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdReplyType"); - - // Web Browser Applet - qRegisterMetaType("Service::AM::Frontend::WebExitReason"); - - // Register loader types - qRegisterMetaType("Core::SystemResultStatus"); -} - void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr nfp_device) { cabinet_applet = @@ -1630,8 +1569,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); - connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, - &GMainWindow::OnTransferableShaderCacheOpenFile); + connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, [this](u64 program_id) { + QtCommon::Path::OpenShaderCache(program_id, this); + }); connect(game_list, &GameList::RemoveInstalledEntryRequested, this, &GMainWindow::OnGameListRemoveInstalledEntry); connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile); @@ -1966,74 +1906,10 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa nullptr, // Net Connect }); - /** Game Updates check */ + /** firmware check */ - // yuzu's configuration doesn't actually support lists so this is a bit hacky - QSettings settings; - QStringList currentIgnored = settings.value("ignoredBadUpdates", {}).toStringList(); - - if (std::find(bad_update_games.begin(), bad_update_games.end(), params.program_id) != - bad_update_games.end() && - !currentIgnored.contains(QString::number(params.program_id))) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Updates Warning")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch is known to have performance or booting " - "issues when updates are applied. Please try increasing the memory layout to " - "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " - "\"Cancel\" to cancel the launch.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - QCheckBox* dontShowAgain = new QCheckBox(msg); - dontShowAgain->setText(tr("Don't show again for this game")); - msg->setCheckBox(dontShowAgain); - - int result = msg->exec(); - - // wtf - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - if (dontShowAgain->isChecked()) { - currentIgnored << QString::number(params.program_id); - settings.setValue("ignoredBadUpdates", currentIgnored); - settings.sync(); - } - break; - } - } - - if (FirmwareManager::GameRequiresFirmware(params.program_id) && - !FirmwareManager::CheckFirmwarePresence(*system)) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Requires Firmware")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch requires firmware to boot or to get past the " - "opening menu. Please " - "dump and install firmware, or press \"OK\" to launch anyways.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - int exec_result = msg->exec(); - - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)exec_result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - break; - } + if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + return false; } /** Exec */ @@ -2451,6 +2327,7 @@ void GMainWindow::ShutdownGame() { return; } + // TODO(crueter): make this common as well (frontend_common?) play_time_manager->Stop(); OnShutdownBegin(); OnEmulationStopTimeExpired(); @@ -2495,6 +2372,7 @@ void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { BootGame(game_path, params); } +// TODO(crueter): Common profile selector void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path) { std::filesystem::path path; @@ -2603,13 +2481,6 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -// TODO(crueter): Transfer ts to showmessage -void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { - QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); - } -} - static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest, bool full) { @@ -2675,26 +2546,14 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& // TODO(crueter): All this can be transfered to qt_common // Aldoe I need to decide re: message boxes for QML // translations_common? strings_common? qt_strings? who knows -QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { - switch (type) { - case InstalledEntryType::Game: - return tr("Error Removing Contents"); - case InstalledEntryType::Update: - return tr("Error Removing Update"); - case InstalledEntryType::AddOnContent: - return tr("Error Removing DLC"); - default: - return QStringLiteral("Error Removing "); - } -} -void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { +void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type) { const QString entry_question = [type] { switch (type) { - case InstalledEntryType::Game: + case QtCommon::Game::InstalledEntryType::Game: return tr("Remove Installed Game Contents?"); - case InstalledEntryType::Update: + case QtCommon::Game::InstalledEntryType::Update: return tr("Remove Installed Game Update?"); - case InstalledEntryType::AddOnContent: + case QtCommon::Game::InstalledEntryType::AddOnContent: return tr("Remove Installed Game DLC?"); default: return QStringLiteral("Remove Installed Game ?"); @@ -2706,18 +2565,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT return; } + // TODO(crueter): move this to QtCommon (populate async?) switch (type) { - case InstalledEntryType::Game: - RemoveBaseContent(program_id, type); + case QtCommon::Game::InstalledEntryType::Game: + QtCommon::Game::RemoveBaseContent(program_id, type); [[fallthrough]]; - case InstalledEntryType::Update: - RemoveUpdateContent(program_id, type); - if (type != InstalledEntryType::Game) { + case QtCommon::Game::InstalledEntryType::Update: + QtCommon::Game::RemoveUpdateContent(program_id, type); + if (type != QtCommon::Game::InstalledEntryType::Game) { break; } [[fallthrough]]; - case InstalledEntryType::AddOnContent: - RemoveAddOnContent(program_id, type); + case QtCommon::Game::InstalledEntryType::AddOnContent: + QtCommon::Game::RemoveAddOnContent(program_id, type); break; } Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / @@ -2725,55 +2585,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { - const auto res = - ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed base game.")); - } else { - QMessageBox::warning( - this, GetGameListErrorRemoving(type), - tr("The base game is not installed in the NAND and cannot be removed.")); - } -} - -void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { - const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed update.")); - } else { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There is no update installed for this title.")); - } -} - -void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { - const size_t count = ContentManager::RemoveAllDLC(*system, program_id); - if (count == 0) { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There are no DLC installed for this title.")); - return; - } - - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed %1 installed DLC.").arg(count)); -} - -void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, +void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path) { const QString question = [target] { switch (target) { - case GameListRemoveTarget::GlShaderCache: + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: return tr("Delete OpenGL Transferable Shader Cache?"); - case GameListRemoveTarget::VkShaderCache: + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: return tr("Delete Vulkan Transferable Shader Cache?"); - case GameListRemoveTarget::AllShaderCache: + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: return tr("Delete All Transferable Shader Caches?"); - case GameListRemoveTarget::CustomConfiguration: + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: return tr("Remove Custom Game Configuration?"); - case GameListRemoveTarget::CacheStorage: + case QtCommon::Game::GameListRemoveTarget::CacheStorage: return tr("Remove Cache Storage?"); default: return QString{}; @@ -2786,20 +2610,20 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } switch (target) { - case GameListRemoveTarget::VkShaderCache: - RemoveVulkanDriverPipelineCache(program_id); + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: + QtCommon::Game::RemoveVulkanDriverPipelineCache(program_id); [[fallthrough]]; - case GameListRemoveTarget::GlShaderCache: - RemoveTransferableShaderCache(program_id, target); + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: + QtCommon::Game::RemoveTransferableShaderCache(program_id, target); break; - case GameListRemoveTarget::AllShaderCache: - RemoveAllTransferableShaderCaches(program_id); + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: + QtCommon::Game::RemoveAllTransferableShaderCaches(program_id); break; - case GameListRemoveTarget::CustomConfiguration: - RemoveCustomConfiguration(program_id, game_path); + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: + QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; - case GameListRemoveTarget::CacheStorage: - RemoveCacheStorage(program_id); + case QtCommon::Game::GameListRemoveTarget::CacheStorage: + QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); break; } } @@ -2815,107 +2639,6 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) { - const auto target_file_name = [target] { - switch (target) { - case GameListRemoveTarget::GlShaderCache: - return "opengl.bin"; - case GameListRemoveTarget::VkShaderCache: - return "vulkan.bin"; - default: - return ""; - } - }(); - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveFile(target_file)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader cache.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("Failed to remove the transferable shader cache.")); - } -} - -void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) { - static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; - - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - return; - } - if (!Common::FS::RemoveFile(target_file)) { - QMessageBox::warning(this, tr("Error Removing Vulkan Driver Pipeline Cache"), - tr("Failed to remove the driver pipeline cache.")); - } -} - -void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); - - if (!Common::FS::Exists(program_shader_cache_dir)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader caches.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("Failed to remove the transferable shader cache directory.")); - } -} - -void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { - const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); - const auto config_file_name = - program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini") - : fmt::format("{:016X}.ini", program_id); - const auto custom_config_file_path = - Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom" / config_file_name; - - if (!Common::FS::Exists(custom_config_file_path)) { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("A custom configuration for this title does not exist.")); - return; - } - - if (Common::FS::RemoveFile(custom_config_file_path)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the custom game configuration.")); - } else { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("Failed to remove the custom game configuration.")); - } -} - -void GMainWindow::RemoveCacheStorage(u64 program_id) { - const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); - auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); - - const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( - {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache, - 0 /* program_id */, {}, 0); - - const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); - - // Not an error if it wasn't cleared. - Common::FS::RemoveDirRecursively(path); -} - void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target) { const auto failed = [this] { @@ -3044,22 +2767,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { return progress.wasCanceled(); }; - const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); - const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); - progress.close(); - switch (result) { - case ContentManager::GameVerificationResult::Success: - QMessageBox::information(this, tr("Integrity verification succeeded!"), - resultString); - break; - case ContentManager::GameVerificationResult::Failed: - QMessageBox::critical(this, tr("Integrity verification failed!"), - resultString); - break; - case ContentManager::GameVerificationResult::NotImplemented: - QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), - resultString); - } + QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -4095,6 +3803,7 @@ void GMainWindow::OnLoadAmiibo() { LoadAmiibo(filename); } +// TODO(crueter): does this need to be ported to QML? bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { @@ -4146,27 +3855,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QtCommon::OpenRootDataFolder(); + QtCommon::Game::OpenRootDataFolder(); } void GMainWindow::OnOpenNANDFolder() { - QtCommon::OpenNANDFolder(); + QtCommon::Game::OpenNANDFolder(); } void GMainWindow::OnOpenSDMCFolder() { - QtCommon::OpenSDMCFolder(); + QtCommon::Game::OpenSDMCFolder(); } void GMainWindow::OnOpenModFolder() { - QtCommon::OpenModFolder(); + QtCommon::Game::OpenModFolder(); } void GMainWindow::OnOpenLogFolder() { - QtCommon::OpenLogFolder(); + QtCommon::Game::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4213,11 +3922,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); progress.close(); - if (result != QtCommon::FirmwareInstallResult::Success) return; + if (result != QtCommon::Content::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); @@ -4284,7 +3993,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); + const QString qCacheDir = QtCommon::Content::UnzipFirmwareToTmp(firmware_zip_location); // In this case, it has to be done recursively, since sometimes people // will pack it into a subdirectory after dumping @@ -4362,7 +4071,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // Resets metadata cache and reloads - QtCommon::ResetMetadata(); + QtCommon::Game::ResetMetadata(); game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4632,7 +4341,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } @@ -4666,7 +4375,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8d00fef4f8..f523561628 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,9 +17,10 @@ #include #include "common/common_types.h" -#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" +#include "qt_common/qt_config.h" +#include "qt_common/qt_game_util.h" #include "user_data_migration.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -53,10 +54,8 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListRemoveTarget; enum class GameListShortcutTarget; enum class DumpRomFSTarget; -enum class InstalledEntryType; class GameListPlaceholder; class QtAmiiboSettingsDialog; @@ -258,8 +257,6 @@ private: void LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed = false); - void RegisterMetaTypes(); - void InitializeWidgets(); void InitializeDebugWidgets(); void InitializeRecentFileMenuActions(); @@ -353,9 +350,8 @@ private slots: void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); - void OnTransferableShaderCacheOpenFile(u64 program_id); - void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); - void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, + void OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type); + void OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void OnGameListRemovePlayTimeData(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); @@ -436,16 +432,7 @@ private slots: #endif private: - QString GetGameListErrorRemoving(InstalledEntryType type) const; - void RemoveBaseContent(u64 program_id, InstalledEntryType type); - void RemoveUpdateContent(u64 program_id, InstalledEntryType type); - void RemoveAddOnContent(u64 program_id, InstalledEntryType type); - void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); - void RemoveVulkanDriverPipelineCache(u64 program_id); - void RemoveAllTransferableShaderCaches(u64 program_id); - void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemovePlayTimeData(u64 program_id); - void RemoveCacheStorage(u64 program_id); bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); ContentManager::InstallResult InstallNCA(const QString& filename);