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.
This commit is contained in:
Eladash 2020-12-07 19:10:34 +02:00 committed by GitHub
parent 51dcb4a79d
commit 2602be426f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 257 additions and 159 deletions

View File

@ -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;
}

View File

@ -1387,26 +1387,27 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Initialize process
std::vector<std::shared_ptr<lv2_prx>> loaded_modules;
// Get LLE module list
// Module list to load at startup
std::set<std::string> 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());
}
}
}

View File

@ -21,67 +21,150 @@ extern void ppu_initialize(const ppu_module&);
LOG_CHANNEL(sys_prx);
static const std::unordered_map<std::string, int> s_prx_ignore
extern const std::unordered_map<std::string_view, int> 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<sys_prx_load_module_option_t> pOpt, fs::file src = {})
@ -101,17 +184,13 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
fmt::throw_exception("sys_prx: Unimplemented fixed address allocations" HERE);
}
std::string name = vpath.substr(vpath.find_last_of('/') + 1);
std::string path = vfs::get(vpath);
std::string vpath0;
const std::string path = vfs::get(vpath, nullptr, &vpath0);
const std::string name = vpath0.substr(vpath0.find_last_of('/') + 1);
const auto existing = idm::select<lv2_obj, lv2_prx>([&](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<s
bool ignore = false;
if (g_cfg.core.lib_loading == lib_loading_type::liblv2list)
constexpr std::string_view firmware_sprx_dir = "/dev_flash/sys/external/";
const bool is_firmware_sprx = vpath0.starts_with(firmware_sprx_dir) && g_prx_list.count(std::string_view(vpath0).substr(firmware_sprx_dir.size()));
if (is_firmware_sprx)
{
if (vpath.starts_with("/dev_flash/sys/external/") && vpath != "/dev_flash/sys/external/libsysmodule.sprx"sv)
// First condition, LLE for selected libs
ignore = g_cfg.core.load_libraries.get_set().count(name) == 0;
if (g_cfg.core.lib_loading != lib_loading_type::liblv2list && g_cfg.core.lib_loading != lib_loading_type::manual)
{
ignore = g_cfg.core.load_libraries.get_set().count(name) == 0;
// Override list setting condition for liblv2only
// For the other modes g_prx_list is a second condition which filters HLE selected libs by list setting
if (ignore || g_cfg.core.lib_loading == lib_loading_type::liblv2only)
{
ignore = g_prx_list.at(name) != 0;
}
}
}
else
else if (vpath0.starts_with("/"))
{
ignore = s_prx_ignore.count(vpath) != 0;
// Special case (currently unused): HLE for files outside of "/dev_flash/sys/external/"
// Have to specify full path for them
ignore = g_prx_list.count(vpath0) && g_prx_list.at(vpath0);
}
if (ignore && (g_cfg.core.lib_loading == lib_loading_type::hybrid || g_cfg.core.lib_loading == lib_loading_type::liblv2both))
{
// Ignore ignore list if the library is selected in 'both' mode
if (g_cfg.core.load_libraries.get_set().count(name) != 0)
{
ignore = false;
}
}
if (ignore)
auto hle_load = [&]()
{
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
@ -152,6 +235,11 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
sys_prx.warning(u8"Ignored module: “%s” (id=0x%x)", vpath, idm::last_id());
return not_an_error(idm::last_id());
};
if (ignore)
{
return hle_load();
}
if (!src)
@ -160,6 +248,12 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
if (fs_error)
{
if (fs_error + 0u == CELL_ENOENT && is_firmware_sprx)
{
sys_prx.error(u8"firmware SPRX not found: “%s” (forcing HLE implementation)", vpath, idm::last_id());
return hle_load();
}
return {fs_error, vpath};
}

View File

@ -270,7 +270,6 @@ error_code sys_rsx_context_allocate(cpu_thread& cpu, vm::ptr<u32> 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));

View File

@ -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;
}
}

View File

@ -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<RsxDmaControl>(ctrlAddress);
flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;

View File

@ -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);
}

View File

@ -41,6 +41,7 @@ struct EmuCallbacks
std::function<void()> on_resume;
std::function<void()> on_stop;
std::function<void()> on_ready;
std::function<bool()> on_missing_fw;
std::function<bool(bool)> exit; // (force_quit) close RPCS3
std::function<void(s32, s32)> handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit
std::function<void()> init_kb_handler;

View File

@ -11,7 +11,7 @@ void fmt_class_string<elf_error>::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";

View File

@ -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)

View File

@ -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<QMessageBox::StandardButton> buttons = confirm ? QMessageBox::Yes | QMessageBox::No : QMessageBox::Ok;
const QMessageBox::Icon icon = confirm ? QMessageBox::Question : QMessageBox::Information;
const QFlags<QMessageBox::StandardButton> 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<br>For more information read the <a href=\"https://rpcs3.net/quickstart\">quickstart guide</a>."
"\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)
{

View File

@ -6,6 +6,7 @@
#include <QVariant>
#include <QSize>
#include <QColor>
#include <QMessageBox>
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;
};

View File

@ -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.");

View File

@ -30,6 +30,7 @@
#include "Crypto/unself.h"
#include "Utilities/sysinfo.h"
#include <set>
#include <unordered_set>
#include <thread>
@ -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> gui_settings, std::shared_ptr<emu_settings> 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> 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<std::string>& vec)
{
std::sort(vec.begin(), vec.end(), [](const std::string &str1, const std::string &str2) { return str1 < str2; });
};
std::vector<std::string> loadedLibs = m_emu_settings->GetLoadedLibraries();
sort_string_vector(loadedLibs);
std::set<std::string_view> 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<std::string_view, int> g_prx_list;
std::unordered_set<std::string> set(loadedLibs.begin(), loadedLibs.end());
std::vector<std::string> 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>(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);