From 2602be426f8ca8200c9ff1f1cb23805f576ca6fd Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 7 Dec 2020 19:10:34 +0200 Subject: [PATCH] Allow emulation to work without firmware (#9367) * Allow emulation to work without firmware * Fix HLE prx path detection. * Fix manual list loading bugs. * Fix HLE gcm * GUI: Fix fonts search * GUI: Hardcode sprx list Do not depend on /dev_flash/sys/external/ contents. --- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 2 +- rpcs3/Emu/Cell/PPUModule.cpp | 42 ++-- rpcs3/Emu/Cell/lv2/sys_prx.cpp | 260 +++++++++++++++-------- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 1 - rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp | 3 + rpcs3/Emu/RSX/RSXThread.cpp | 7 + rpcs3/Emu/System.cpp | 14 +- rpcs3/Emu/System.h | 1 + rpcs3/Loader/ELF.cpp | 2 +- rpcs3/rpcs3qt/gui_application.cpp | 5 + rpcs3/rpcs3qt/gui_settings.cpp | 30 ++- rpcs3/rpcs3qt/gui_settings.h | 4 +- rpcs3/rpcs3qt/main_window.cpp | 10 +- rpcs3/rpcs3qt/settings_dialog.cpp | 35 +-- 14 files changed, 257 insertions(+), 159 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index c0cd5caeb7..e14b59190f 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -1077,7 +1077,7 @@ error_code GcmUnmapIoAddress(ppu_thread& ppu, gcm_config* cfg, u32 io) { if (u32 ea = cfg->offsetTable.eaAddress[io >>= 20], size = cfg->IoMapTable[ea]; size) { - if (auto error = sys_rsx_context_iounmap(ppu, 0x55555555, io, size << 20)) + if (auto error = sys_rsx_context_iounmap(ppu, 0x55555555, io << 20, size << 20)) { return error; } diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 589ece45c1..9b1b881e43 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1387,26 +1387,27 @@ void ppu_load_exec(const ppu_exec_object& elf) // Initialize process std::vector> loaded_modules; - // Get LLE module list + // Module list to load at startup std::set load_libs; - if (g_cfg.core.lib_loading == lib_loading_type::manual) + if ((g_cfg.core.lib_loading != lib_loading_type::hybrid && g_cfg.core.lib_loading != lib_loading_type::manual) || g_cfg.core.load_libraries.get_set().count("liblv2.sprx")) { - // Load required set of modules (lib_loading_type::both processed in sys_prx.cpp) - load_libs = g_cfg.core.load_libraries.get_set(); + // Will load libsysmodule.sprx internally + load_libs.emplace("liblv2.sprx"); } - else + else if (g_cfg.core.lib_loading == lib_loading_type::hybrid) { - if (g_cfg.core.lib_loading != lib_loading_type::hybrid || g_cfg.core.load_libraries.get_set().count("liblv2.sprx")) - { - // Will load libsysmodule.sprx internally - load_libs.emplace("liblv2.sprx"); - } - else - { - // Load only libsysmodule.sprx - load_libs.emplace("libsysmodule.sprx"); - } + // Load only libsysmodule.sprx + load_libs.emplace("libsysmodule.sprx"); + } + + const std::string lle_dir = vfs::get("/dev_flash/sys/external/"); + + if (!fs::is_file(lle_dir + "liblv2.sprx")) + { + ppu_loader.error("PS3 firmware is not installed or the installed firmware is invalid." + "\nYou should install the PS3 Firmware (Menu: File -> Install Firmware)." + "\nVisit https://rpcs3.net/ for Quickstart Guide and more information."); } // Program entry @@ -1414,15 +1415,6 @@ void ppu_load_exec(const ppu_exec_object& elf) if (!load_libs.empty()) { - const std::string lle_dir = vfs::get("/dev_flash/sys/external/"); - - if (!fs::is_dir(lle_dir) || !fs::is_file(lle_dir + "libsysmodule.sprx")) - { - ppu_loader.error("PS3 firmware is not installed or the installed firmware is invalid." - "\nYou should install the PS3 Firmware (Menu: File -> Install Firmware)." - "\nVisit https://rpcs3.net/ for Quickstart Guide and more information."); - } - for (const auto& name : load_libs) { const ppu_prx_object obj = decrypt_self(fs::file(lle_dir + name)); @@ -1455,7 +1447,7 @@ void ppu_load_exec(const ppu_exec_object& elf) } else { - fmt::throw_exception("Failed to load /dev_flash/sys/external/%s: %s", name, obj.get_error()); + ppu_loader.error("Failed to load /dev_flash/sys/external/%s: %s (forcing HLE implementation)", name, obj.get_error()); } } } diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 231aed8c2e..ddc5486104 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -21,67 +21,150 @@ extern void ppu_initialize(const ppu_module&); LOG_CHANNEL(sys_prx); -static const std::unordered_map s_prx_ignore +extern const std::unordered_map g_prx_list { - { "/dev_flash/sys/external/libaudio.sprx", 0 }, - { "/dev_flash/sys/external/libcamera.sprx", 0 }, - { "/dev_flash/sys/external/libgem.sprx", 0 }, - { "/dev_flash/sys/external/libio.sprx", 0 }, - { "/dev_flash/sys/external/libmedi.sprx", 0 }, - { "/dev_flash/sys/external/libmic.sprx", 0 }, - { "/dev_flash/sys/external/libnetctl.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_ap.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_authdialog.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_avc_ext.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_avc2.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_avconf_ext.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_bgdl.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_cross_controller.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_dec_psnvideo.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_dtcp_ip.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_game.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_game_exec.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_imejp.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_misc.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_music.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_music_decode.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_music_export.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_clans.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_commerce2.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_eula.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_installer.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_sns.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_trophy.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_tus.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np_util.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_np2.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_oskdialog_ext.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_pesm.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_photo_decode.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_photo_export.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_photo_export2.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_photo_import.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_photo_network_sharing.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_print.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_rec.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_remoteplay.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_rtcalarm.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_savedata.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_savedata_psp.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_screenshot.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_search.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_storagedata.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_subdisplay.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_syschat.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_sysconf_ext.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_userinfo.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_video_export.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_video_player.sprx", 0 }, - { "/dev_flash/sys/external/libsysutil_video_upload.sprx", 0 }, - { "/dev_flash/sys/external/libvdec.sprx", 0 }, - { "/dev_flash/sys/external/libvoice.sprx", 0 }, + { "libaacenc.sprx", 0 }, + { "libaacenc_spurs.sprx", 0 }, + { "libac3dec.sprx", 0 }, + { "libac3dec2.sprx", 0 }, + { "libadec.sprx", 0 }, + { "libadec2.sprx", 0 }, + { "libadec_internal.sprx", 0 }, + { "libad_async.sprx", 0 }, + { "libad_billboard_util.sprx", 0 }, + { "libad_core.sprx", 0 }, + { "libapostsrc_mini.sprx", 0 }, + { "libasfparser2_astd.sprx", 0 }, + { "libat3dec.sprx", 0 }, + { "libat3multidec.sprx", 0 }, + { "libatrac3multi.sprx", 0 }, + { "libatrac3plus.sprx", 0 }, + { "libatxdec.sprx", 0 }, + { "libatxdec2.sprx", 0 }, + { "libaudio.sprx", 1 }, + { "libavcdec.sprx", 0 }, + { "libavcenc.sprx", 0 }, + { "libavcenc_small.sprx", 0 }, + { "libavchatjpgdec.sprx", 0 }, + { "libbeisobmf.sprx", 0 }, + { "libbemp2sys.sprx", 0 }, + { "libcamera.sprx", 1 }, + { "libcelp8dec.sprx", 0 }, + { "libcelp8enc.sprx", 0 }, + { "libcelpdec.sprx", 0 }, + { "libcelpenc.sprx", 0 }, + { "libddpdec.sprx", 0 }, + { "libdivxdec.sprx", 0 }, + { "libdmux.sprx", 0 }, + { "libdmuxpamf.sprx", 0 }, + { "libdtslbrdec.sprx", 0 }, + { "libfiber.sprx", 0 }, + { "libfont.sprx", 0 }, + { "libfontFT.sprx", 0 }, + { "libfreetype.sprx", 0 }, + { "libfreetypeTT.sprx", 0 }, + { "libfs.sprx", 0 }, + { "libfs_155.sprx", 0 }, + { "libgcm_sys.sprx", 0 }, + { "libgem.sprx", 1 }, + { "libgifdec.sprx", 0 }, + { "libhttp.sprx", 0 }, + { "libio.sprx", 1 }, + { "libjpgdec.sprx", 0 }, + { "libjpgenc.sprx", 0 }, + { "libkey2char.sprx", 0 }, + { "libl10n.sprx", 0 }, + { "liblv2.sprx", 0 }, + { "liblv2coredump.sprx", 0 }, + { "liblv2dbg_for_cex.sprx", 0 }, + { "libm2bcdec.sprx", 0 }, + { "libm4aacdec.sprx", 0 }, + { "libm4aacdec2ch.sprx", 0 }, + { "libm4hdenc.sprx", 0 }, + { "libm4venc.sprx", 0 }, + { "libmedi.sprx", 1 }, + { "libmic.sprx", 1 }, + { "libmp3dec.sprx", 0 }, + { "libmp4.sprx", 0 }, + { "libmpl1dec.sprx", 0 }, + { "libmvcdec.sprx", 0 }, + { "libnet.sprx", 0 }, + { "libnetctl.sprx", 1 }, + { "libpamf.sprx", 0 }, + { "libpngdec.sprx", 0 }, + { "libpngenc.sprx", 0 }, + { "libresc.sprx", 0 }, + { "librtc.sprx", 0 }, + { "librudp.sprx", 0 }, + { "libsail.sprx", 0 }, + { "libsail_avi.sprx", 0 }, + { "libsail_rec.sprx", 0 }, + { "libsjvtd.sprx", 0 }, + { "libsmvd2.sprx", 0 }, + { "libsmvd4.sprx", 0 }, + { "libspurs_jq.sprx", 0 }, + { "libsre.sprx", 0 }, + { "libssl.sprx", 0 }, + { "libsvc1d.sprx", 0 }, + { "libsync2.sprx", 0 }, + { "libsysmodule.sprx", 0 }, + { "libsysutil.sprx", 1 }, + { "libsysutil_ap.sprx", 1 }, + { "libsysutil_authdialog.sprx", 1 }, + { "libsysutil_avc2.sprx", 1 }, + { "libsysutil_avconf_ext.sprx", 1 }, + { "libsysutil_avc_ext.sprx", 1 }, + { "libsysutil_bgdl.sprx", 1 }, + { "libsysutil_cross_controller.sprx", 1 }, + { "libsysutil_dec_psnvideo.sprx", 1 }, + { "libsysutil_dtcp_ip.sprx", 1 }, + { "libsysutil_game.sprx", 1 }, + { "libsysutil_game_exec.sprx", 1 }, + { "libsysutil_imejp.sprx", 1 }, + { "libsysutil_misc.sprx", 1 }, + { "libsysutil_music.sprx", 1 }, + { "libsysutil_music_decode.sprx", 1 }, + { "libsysutil_music_export.sprx", 1 }, + { "libsysutil_np.sprx", 1 }, + { "libsysutil_np2.sprx", 1 }, + { "libsysutil_np_clans.sprx", 1 }, + { "libsysutil_np_commerce2.sprx", 1 }, + { "libsysutil_np_eula.sprx", 1 }, + { "libsysutil_np_installer.sprx", 1 }, + { "libsysutil_np_sns.sprx", 1 }, + { "libsysutil_np_trophy.sprx", 1 }, + { "libsysutil_np_tus.sprx", 1 }, + { "libsysutil_np_util.sprx", 1 }, + { "libsysutil_oskdialog_ext.sprx", 1 }, + { "libsysutil_pesm.sprx", 1 }, + { "libsysutil_photo_decode.sprx", 1 }, + { "libsysutil_photo_export.sprx", 1 }, + { "libsysutil_photo_export2.sprx", 1 }, + { "libsysutil_photo_import.sprx", 1 }, + { "libsysutil_photo_network_sharing.sprx", 1 }, + { "libsysutil_print.sprx", 1 }, + { "libsysutil_rec.sprx", 1 }, + { "libsysutil_remoteplay.sprx", 1 }, + { "libsysutil_rtcalarm.sprx", 1 }, + { "libsysutil_savedata.sprx", 1 }, + { "libsysutil_savedata_psp.sprx", 1 }, + { "libsysutil_screenshot.sprx", 1 }, + { "libsysutil_search.sprx", 1 }, + { "libsysutil_storagedata.sprx", 1 }, + { "libsysutil_subdisplay.sprx", 1 }, + { "libsysutil_syschat.sprx", 1 }, + { "libsysutil_sysconf_ext.sprx", 1 }, + { "libsysutil_userinfo.sprx", 1 }, + { "libsysutil_video_export.sprx", 1 }, + { "libsysutil_video_player.sprx", 1 }, + { "libsysutil_video_upload.sprx", 1 }, + { "libusbd.sprx", 0 }, + { "libusbpspcm.sprx", 0 }, + { "libvdec.sprx", 1 }, + { "libvoice.sprx", 1 }, + { "libvpost.sprx", 0 }, + { "libvpost2.sprx", 0 }, + { "libwmadec.sprx", 0 }, }; static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr pOpt, fs::file src = {}) @@ -101,17 +184,13 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr([&](u32, lv2_prx& prx) { - if (prx.name == name && prx.path == path) - { - return true; - } - - return false; + return prx.path == path; }); if (existing) @@ -121,28 +200,32 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr(); @@ -152,6 +235,11 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr context_id, vm render->current_display_buffer = 0; render->label_addr = vm::cast(*lpar_reports, HERE); render->device_addr = rsx_cfg->device_addr; - render->dma_address = rsx_cfg->dma_address; render->local_mem_size = rsx_cfg->memory_size; render->init(vm::cast(*lpar_dma_control, HERE)); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp b/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp index 9636cdf4c7..24c84c499c 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp @@ -119,6 +119,7 @@ namespace rsx case language_class::default_: { result.font_names.emplace_back("Arial.ttf"); + result.font_names.emplace_back("arial.ttf"); #ifndef _WIN32 result.font_names.emplace_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"); // ubuntu result.font_names.emplace_back("/usr/share/fonts/TTF/DejaVuSans.ttf"); // arch @@ -137,6 +138,7 @@ namespace rsx // Known system font as last fallback result.font_names.emplace_back("Yu Gothic.ttf"); + result.font_names.emplace_back("YuGothR.ttc"); break; } case language_class::hangul: @@ -149,6 +151,7 @@ namespace rsx // Known system font as last fallback result.font_names.emplace_back("Malgun Gothic.ttf"); + result.font_names.emplace_back("malgun.ttf"); break; } } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 232f18fc3d..11e8bfdd42 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -452,6 +452,12 @@ namespace rsx // Wait for startup (TODO) while (m_rsx_thread_exiting) { + // Wait for external pause events + if (external_interrupt_lock) + { + wait_pause(); + } + thread_ctrl::wait_for(1000); if (Emu.IsStopped()) @@ -1957,6 +1963,7 @@ namespace rsx void thread::init(u32 ctrlAddress) { + dma_address = ctrlAddress; ctrl = vm::_ptr(ctrlAddress); flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 4c48eb58b0..459a7b3558 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1059,11 +1059,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool sys_log.notice("Hdd1: %s", vfs::get("/dev_hdd1")); } - if (!fs::is_file(g_cfg.vfs.get_dev_flash() + "sys/external/liblv2.sprx")) - { - return game_boot_result::firmware_missing; - } - // Special boot mode (directory scan) if (!add_only && fs::is_dir(m_path)) { @@ -1682,6 +1677,15 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool { if (ppu_exec == elf_error::ok) { + if (!fs::is_file(g_cfg.vfs.get_dev_flash() + "sys/external/liblv2.sprx")) + { + if (!GetCallbacks().on_missing_fw()) + { + Stop(); + return game_boot_result::firmware_missing; + } + } + Run(true); } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 92eb7ea1b9..1953f7134b 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -41,6 +41,7 @@ struct EmuCallbacks std::function on_resume; std::function on_stop; std::function on_ready; + std::function on_missing_fw; std::function exit; // (force_quit) close RPCS3 std::function handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit std::function init_kb_handler; diff --git a/rpcs3/Loader/ELF.cpp b/rpcs3/Loader/ELF.cpp index 933225de6d..fcb4312406 100644 --- a/rpcs3/Loader/ELF.cpp +++ b/rpcs3/Loader/ELF.cpp @@ -11,7 +11,7 @@ void fmt_class_string::format(std::string& out, u64 arg) { case elf_error::ok: return "OK"; - case elf_error::stream: return "Invalid stream or file not found"; + case elf_error::stream: return "File not found"; case elf_error::stream_header: return "Failed to read ELF header"; case elf_error::stream_phdrs: return "Failed to read ELF program headers"; case elf_error::stream_shdrs: return "Failed to read ELF section headers"; diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 076db6f1b1..6542d99dd4 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -344,6 +344,11 @@ void gui_application::InitializeCallbacks() callbacks.on_stop = [this]() { OnEmulatorStop(); }; callbacks.on_ready = [this]() { OnEmulatorReady(); }; + callbacks.on_missing_fw = [this]() + { + return m_gui_settings->GetBootConfirmation(m_main_window, gui::ib_confirm_fw); + }; + callbacks.handle_taskbar_progress = [this](s32 type, s32 value) { if (m_game_window) diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index 18a911a758..037a33ac17 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -154,9 +154,9 @@ void gui_settings::SetCategoryVisibility(int cat, const bool& val) SetValue(value, val); } -void gui_settings::ShowBox(bool confirm, const QString& title, const QString& text, const gui_save& entry, int* result = nullptr, QWidget* parent = nullptr, bool always_on_top = false) +void gui_settings::ShowBox(QMessageBox::Icon icon, const QString& title, const QString& text, const gui_save& entry, int* result = nullptr, QWidget* parent = nullptr, bool always_on_top = false) { - const std::string dialog_type = confirm ? "Confirmation" : "Info"; + const std::string dialog_type = icon != QMessageBox::Information ? "Confirmation" : "Info"; const bool has_gui_setting = !entry.name.isEmpty(); if (has_gui_setting && !GetValue(entry).toBool()) @@ -165,13 +165,13 @@ void gui_settings::ShowBox(bool confirm, const QString& title, const QString& te return; } - const QFlags buttons = confirm ? QMessageBox::Yes | QMessageBox::No : QMessageBox::Ok; - const QMessageBox::Icon icon = confirm ? QMessageBox::Question : QMessageBox::Information; + const QFlags buttons = icon != QMessageBox::Information ? QMessageBox::Yes | QMessageBox::No : QMessageBox::Ok; QMessageBox* mb = new QMessageBox(icon, title, text, buttons, parent, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | (always_on_top ? Qt::WindowStaysOnTopHint : Qt::Widget)); mb->deleteLater(); + mb->setTextFormat(Qt::RichText); - if (has_gui_setting) + if (has_gui_setting && icon != QMessageBox::Critical) { mb->setCheckBox(new QCheckBox(tr("Don't show again"))); } @@ -182,7 +182,10 @@ void gui_settings::ShowBox(bool confirm, const QString& title, const QString& te { *result = res; } - if (has_gui_setting && mb->checkBox()->isChecked()) + + const auto checkBox = mb->checkBox(); + + if (checkBox && checkBox->isChecked()) { SetValue(entry, false); cfg_log.notice("%s Dialog for Entry %s is now disabled", dialog_type, sstr(entry.name)); @@ -194,12 +197,12 @@ void gui_settings::ShowBox(bool confirm, const QString& title, const QString& te void gui_settings::ShowConfirmationBox(const QString& title, const QString& text, const gui_save& entry, int* result = nullptr, QWidget* parent = nullptr) { - ShowBox(true, title, text, entry, result, parent, true); + ShowBox(QMessageBox::Question, title, text, entry, result, parent, true); } void gui_settings::ShowInfoBox(const QString& title, const QString& text, const gui_save& entry, QWidget* parent = nullptr) { - ShowBox(false, title, text, entry, nullptr, parent, false); + ShowBox(QMessageBox::Information, title, text, entry, nullptr, parent, false); } bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save_entry) @@ -208,6 +211,7 @@ bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save { QString title = tr("Close Running Game?"); QString message = tr("Performing this action will close the current game.\nDo you really want to continue?\n\nAny unsaved progress will be lost!\n"); + auto icon = QMessageBox::Question; if (gui_save_entry == gui::ib_confirm_boot) { @@ -218,10 +222,18 @@ bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save title = tr("Exit RPCS3?"); message = tr("A game is currently running. Do you really want to close RPCS3?\n\nAny unsaved progress will be lost!\n"); } + else if (gui_save_entry == gui::ib_confirm_fw) + { + title = tr("Missing Firmware Detected!"); + message = tr("Install the PS3 Firmware (Menu: File -> Install Firmware)." + "\n
For more information read the quickstart guide." + "\nCommercial games do not work without firmware! Do you wish to continue!?"); + icon = QMessageBox::Critical; + } int result = QMessageBox::Yes; - ShowConfirmationBox(title, message, gui_save_entry, &result, parent); + ShowBox(icon, title, message, gui_save_entry, &result, parent); if (result != QMessageBox::Yes) { diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index efebe101e6..3f7237873c 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace gui { @@ -120,6 +121,7 @@ namespace gui const gui_save ib_show_welcome = gui_save(main_window, "infoBoxEnabledWelcome", true); const gui_save ib_confirm_exit = gui_save(main_window, "confirmationBoxExitGame", true); const gui_save ib_confirm_boot = gui_save(main_window, "confirmationBoxBootGame", true); + const gui_save ib_confirm_fw = gui_save(main_window, "confirmationMissingFW", true); const gui_save fd_install_pkg = gui_save(main_window, "lastExplorePathPKG", ""); const gui_save fd_install_pup = gui_save(main_window, "lastExplorePathPUP", ""); @@ -273,7 +275,7 @@ public Q_SLOTS: private: void SaveConfigNameToDefault(const QString& config_name); void BackupSettingsToTarget(const QString& config_name); - void ShowBox(bool confirm, const QString& title, const QString& text, const gui_save& entry, int* result, QWidget* parent, bool always_on_top); + void ShowBox(QMessageBox::Icon icon, const QString& title, const QString& text, const gui_save& entry, int* result, QWidget* parent, bool always_on_top); QString m_current_name; }; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 1b7943ae20..69ffc15f8a 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -300,10 +300,6 @@ void main_window::OnPlayOrPause() void main_window::show_boot_error(game_boot_result status) { - if (status == game_boot_result::no_errors) - { - return; - } QString message; switch (status) { @@ -325,9 +321,9 @@ void main_window::show_boot_error(game_boot_result status) case game_boot_result::file_creation_error: message = tr("The emulator could not create files required for booting."); break; - case game_boot_result::firmware_missing: - message = tr("Firmware has not been installed. Install firmware with the \"File > Install Firmware\" menu option."); - break; + case game_boot_result::firmware_missing: // Handled elsewhere + case game_boot_result::no_errors: + return; case game_boot_result::generic_error: default: message = tr("Unknown error."); diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 7068b8c679..05d599d45c 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -30,6 +30,7 @@ #include "Crypto/unself.h" #include "Utilities/sysinfo.h" +#include #include #include @@ -41,6 +42,7 @@ LOG_CHANNEL(cfg_log, "CFG"); inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QVariant& _in) { return sstr(_in.toString()); } +inline QString qsv(std::string_view sv) { return QString(sv.data()); } settings_dialog::settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, const int& tab_index, QWidget *parent, const GameInfo* game) : QDialog(parent) @@ -1026,47 +1028,28 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceRadioButton(lib_mode_bg, emu_settings_type::LibLoadOptions); - // Sort string vector alphabetically - static const auto sort_string_vector = [](std::vector& vec) - { - std::sort(vec.begin(), vec.end(), [](const std::string &str1, const std::string &str2) { return str1 < str2; }); - }; - std::vector loadedLibs = m_emu_settings->GetLoadedLibraries(); - sort_string_vector(loadedLibs); + std::set set(loadedLibs.begin(), loadedLibs.end()); - for (const auto& lib : loadedLibs) + for (const auto& lib : set) { - QListWidgetItem* item = new QListWidgetItem(qstr(lib), ui->lleList); + QListWidgetItem* item = new QListWidgetItem(qsv(lib), ui->lleList); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag item->setCheckState(Qt::Checked); // AND initialize check state ui->lleList->addItem(item); } - const std::string lle_dir = g_cfg.vfs.get_dev_flash() + "sys/external/"; + extern const std::unordered_map g_prx_list; - std::unordered_set set(loadedLibs.begin(), loadedLibs.end()); - std::vector lle_module_list_unselected; - - for (const auto& prxf : fs::dir(lle_dir)) + for (const auto& lib : g_prx_list) { - // List found unselected modules - if (prxf.is_directory || (prxf.name.substr(std::max(size_t(3), prxf.name.length()) - 4)) != "sprx") + if (set.count(lib.first)) { continue; } - if (verify_npdrm_self_headers(fs::file(lle_dir + prxf.name)) && !set.count(prxf.name)) - { - lle_module_list_unselected.push_back(prxf.name); - } - } - sort_string_vector(lle_module_list_unselected); - - for (const auto& lib : lle_module_list_unselected) - { - QListWidgetItem* item = new QListWidgetItem(qstr(lib), ui->lleList); + QListWidgetItem* item = new QListWidgetItem(qsv(lib.first), ui->lleList); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag item->setCheckState(Qt::Unchecked); // AND initialize check state ui->lleList->addItem(item);