From 66e1cf96e2ac8401603ae4f657ed0acec6badcd9 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 1 Jun 2023 02:08:09 +0200 Subject: [PATCH] Qt/Loader: Let users choose which packages to install --- rpcs3/Emu/System.cpp | 37 ++++++++++---- rpcs3/Emu/System.h | 1 + rpcs3/main_application.cpp | 13 +++++ rpcs3/rpcs3qt/gui_application.cpp | 15 ++++++ rpcs3/rpcs3qt/main_window.cpp | 85 +++++++++++++++++++------------ rpcs3/rpcs3qt/main_window.h | 4 +- 6 files changed, 111 insertions(+), 44 deletions(-) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index f069e6dd44..5b185a88a8 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1645,17 +1645,19 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, } } + std::vector pkgs; + if (!lock_file && !ins_dir.empty()) { sys_log.notice("Found INSDIR: %s", ins_dir); for (auto&& entry : fs::dir{ins_dir}) { - const std::string pkg = ins_dir + entry.name; - if (!entry.is_directory && entry.name.ends_with(".PKG") && !rpcs3::utils::install_pkg(pkg)) + const std::string pkg_file = ins_dir + entry.name; + + if (!entry.is_directory && entry.name.ends_with(".PKG")) { - sys_log.error("Failed to install %s", pkg); - return game_boot_result::install_failed; + pkgs.push_back(pkg_file); } } } @@ -1670,10 +1672,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, { const std::string pkg_file = pkg_dir + entry.name + "/INSTALL.PKG"; - if (fs::is_file(pkg_file) && !rpcs3::utils::install_pkg(pkg_file)) + if (fs::is_file(pkg_file)) { - sys_log.error("Failed to install %s", pkg_file); - return game_boot_result::install_failed; + pkgs.push_back(pkg_file); } } } @@ -1689,15 +1690,31 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, { const std::string pkg_file = extra_dir + entry.name + "/DATA000.PKG"; - if (fs::is_file(pkg_file) && !rpcs3::utils::install_pkg(pkg_file)) + if (fs::is_file(pkg_file)) { - sys_log.error("Failed to install %s", pkg_file); - return game_boot_result::install_failed; + pkgs.push_back(pkg_file); } } } } + if (!pkgs.empty()) + { + bool install_success = true; + BlockingCallFromMainThread([this, &pkgs, &install_success]() + { + if (!GetCallbacks().on_install_pkgs(pkgs)) + { + install_success = false; + } + }); + if (!install_success) + { + sys_log.error("Failed to install packages"); + return game_boot_result::install_failed; + } + } + if (!lock_file) { // Create lock file to prevent double installation diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 2bd017caa3..86f262c94e 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -95,6 +95,7 @@ struct EmuCallbacks std::function get_scaled_image; // (filename, target_width, target_height, width, height, dst, force_fit) std::string(*resolve_path)(std::string_view) = [](std::string_view arg){ return std::string{arg}; }; // Resolve path using Qt std::function()> get_font_dirs; + std::function&)> on_install_pkgs; }; namespace utils diff --git a/rpcs3/main_application.cpp b/rpcs3/main_application.cpp index 42c8667312..de8eafc6c8 100644 --- a/rpcs3/main_application.cpp +++ b/rpcs3/main_application.cpp @@ -348,5 +348,18 @@ EmuCallbacks main_application::CreateCallbacks() return font_dirs; }; + callbacks.on_install_pkgs = [](const std::vector& pkgs) + { + for (const std::string& pkg : pkgs) + { + if (!rpcs3::utils::install_pkg(pkg)) + { + sys_log.error("Failed to install %s", pkg); + return false; + } + } + return true; + }; + return callbacks; } diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 388f3086c2..9b92cfdab3 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -554,6 +554,21 @@ void gui_application::InitializeCallbacks() }); }; + if (m_show_gui) // If this is false, we already have a fallback in the main_application. + { + callbacks.on_install_pkgs = [this](const std::vector& pkgs) + { + ensure(m_main_window); + ensure(!pkgs.empty()); + QStringList pkg_list; + for (const std::string& pkg : pkgs) + { + pkg_list << QString::fromStdString(pkg); + } + return m_main_window->InstallPackages(pkg_list, true); + }; + } + Emu.SetCallbacks(std::move(callbacks)); } diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 3d52b88a67..02fbb31aed 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -710,10 +710,12 @@ bool main_window::InstallFileInExData(const std::string& extension, const QStrin return to.commit(); } -void main_window::InstallPackages(QStringList file_paths) +bool main_window::InstallPackages(QStringList file_paths, bool from_boot) { if (file_paths.isEmpty()) { + ensure(!from_boot); + // If this function was called without a path, ask the user for files to install. const QString path_last_pkg = m_gui_settings->GetValue(gui::fd_install_pkg).toString(); const QStringList paths = QFileDialog::getOpenFileNames(this, tr("Select packages and/or rap files to install"), @@ -721,7 +723,7 @@ void main_window::InstallPackages(QStringList file_paths) if (paths.isEmpty()) { - return; + return true; } file_paths.append(paths); @@ -739,7 +741,7 @@ void main_window::InstallPackages(QStringList file_paths) if (!info.is_valid) { QMessageBox::warning(this, tr("Invalid package!"), tr("The selected package is invalid!\n\nPath:\n%0").arg(file_path)); - return; + return false; } if (info.type != compat::package_type::other) @@ -780,21 +782,10 @@ void main_window::InstallPackages(QStringList file_paths) QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) { gui_log.notice("PKG: Cancelled installation from drop.\n%s", sstr(info_string)); - return; + return true; } } - if (!m_gui_settings->GetBootConfirmation(this)) - { - // Last chance to cancel the operation - return; - } - - if (!Emu.IsStopped()) - { - Emu.GracefulShutdown(false); - } - // Install rap files if available int installed_rap_and_edat_count = 0; @@ -818,8 +809,22 @@ void main_window::InstallPackages(QStringList file_paths) } }; - install_filetype("rap"); - install_filetype("edat"); + if (!from_boot) + { + if (!m_gui_settings->GetBootConfirmation(this)) + { + // Last chance to cancel the operation + return true; + } + + if (!Emu.IsStopped()) + { + Emu.GracefulShutdown(false); + } + + install_filetype("rap"); + install_filetype("edat"); + } if (installed_rap_and_edat_count > 0) { @@ -830,21 +835,30 @@ void main_window::InstallPackages(QStringList file_paths) // Find remaining package files file_paths = file_paths.filter(QRegularExpression(".*\\.pkg", QRegularExpression::PatternOption::CaseInsensitiveOption)); - if (!file_paths.isEmpty()) + if (file_paths.isEmpty()) { - // Handle further installations with a timeout. Otherwise the source explorer instance is not usable during the following file processing. - QTimer::singleShot(0, [this, paths = std::move(file_paths)]() - { - HandlePackageInstallation(paths); - }); + return true; } + + if (from_boot) + { + return HandlePackageInstallation(file_paths, true); + } + + // Handle further installations with a timeout. Otherwise the source explorer instance is not usable during the following file processing. + QTimer::singleShot(0, [this, paths = std::move(file_paths)]() + { + HandlePackageInstallation(paths, false); + }); + + return true; } -void main_window::HandlePackageInstallation(QStringList file_paths) +bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_boot) { if (file_paths.empty()) { - return; + return false; } std::vector packages; @@ -868,15 +882,18 @@ void main_window::HandlePackageInstallation(QStringList file_paths) if (packages.empty()) { - return; + return true; } - if (!m_gui_settings->GetBootConfirmation(this)) + if (!from_boot) { - return; - } + if (!m_gui_settings->GetBootConfirmation(this)) + { + return true; + } - Emu.GracefulShutdown(false); + Emu.GracefulShutdown(false); + } std::vector path_vec; for (const compat::package_info& pkg : packages) @@ -973,7 +990,9 @@ void main_window::HandlePackageInstallation(QStringList file_paths) } } - if (worker()) + const bool success = worker(); + + if (success) { pdlg.SetValue(pdlg.maximum()); std::this_thread::sleep_for(100ms); @@ -1032,7 +1051,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths) if (bootable_paths_installed.empty()) { m_gui_settings->ShowInfoBox(tr("Success!"), tr("Successfully installed software from package(s)!"), gui::ib_pkg_success, this); - return; + return true; } auto dlg = new QDialog(this); @@ -1144,6 +1163,8 @@ void main_window::HandlePackageInstallation(QStringList file_paths) } } } + + return success; } void main_window::ExtractMSELF() diff --git a/rpcs3/rpcs3qt/main_window.h b/rpcs3/rpcs3qt/main_window.h index 9dd84bcba8..edcb4d130e 100644 --- a/rpcs3/rpcs3qt/main_window.h +++ b/rpcs3/rpcs3qt/main_window.h @@ -86,7 +86,7 @@ public: bool Init(bool with_cli_boot); QIcon GetAppIcon() const; bool OnMissingFw(); - void InstallPackages(QStringList file_paths = QStringList()); + bool InstallPackages(QStringList file_paths = {}, bool from_boot = false); void InstallPup(QString file_path = ""); Q_SIGNALS: @@ -149,7 +149,7 @@ private: static bool InstallFileInExData(const std::string& extension, const QString& path, const std::string& filename); - void HandlePackageInstallation(QStringList file_paths); + bool HandlePackageInstallation(QStringList file_paths, bool from_boot); void HandlePupInstallation(const QString& file_path, const QString& dir_path = ""); void ExtractPup();