Loader: split add_only into own function

The new code does not require any modifications apart from loading vfs
This commit is contained in:
Megamouse 2023-04-25 03:41:03 +02:00
parent f080798000
commit ad5a62b62d
9 changed files with 217 additions and 108 deletions

View file

@ -599,7 +599,7 @@ std::string fmt::trim(const std::string& source, const std::string& values)
return source.substr(begin, source.find_last_not_of(values) + 1); return source.substr(begin, source.find_last_not_of(values) + 1);
} }
std::string fmt::to_upper(const std::string& string) std::string fmt::to_upper(std::string_view string)
{ {
std::string result; std::string result;
result.resize(string.size()); result.resize(string.size());
@ -607,7 +607,7 @@ std::string fmt::to_upper(const std::string& string)
return result; return result;
} }
std::string fmt::to_lower(const std::string& string) std::string fmt::to_lower(std::string_view string)
{ {
std::string result; std::string result;
result.resize(string.size()); result.resize(string.size());

View file

@ -173,8 +173,8 @@ namespace fmt
return result; return result;
} }
std::string to_upper(const std::string& string); std::string to_upper(std::string_view string);
std::string to_lower(const std::string& string); std::string to_lower(std::string_view string);
bool match(const std::string& source, const std::string& mask); bool match(const std::string& source, const std::string& mask);

View file

@ -472,7 +472,7 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector<std::string>& argv, std::vector<
Emu.SetForceBoot(true); Emu.SetForceBoot(true);
auto res = Emu.BootGame(path, "", true, false, cfg_mode::continuous, old_config); auto res = Emu.BootGame(path, "", true, cfg_mode::continuous, old_config);
if (res != game_boot_result::no_errors) if (res != game_boot_result::no_errors)
{ {

View file

@ -242,7 +242,7 @@ void fixup_ppu_settings()
} }
} }
void Emulator::Init(bool add_only) void Emulator::Init()
{ {
jit_runtime::initialize(); jit_runtime::initialize();
@ -325,7 +325,7 @@ void Emulator::Init(bool add_only)
const bool is_exitspawn = m_config_mode == cfg_mode::continuous; const bool is_exitspawn = m_config_mode == cfg_mode::continuous;
// Load config file // Load config file
if (m_config_mode == cfg_mode::config_override && !add_only) if (m_config_mode == cfg_mode::config_override)
{ {
if (const fs::file cfg_file{m_config_path, fs::read + fs::create}) if (const fs::file cfg_file{m_config_path, fs::read + fs::create})
{ {
@ -352,7 +352,7 @@ void Emulator::Init(bool add_only)
} }
// Reload global configuration // Reload global configuration
if (m_config_mode != cfg_mode::config_override && m_config_mode != cfg_mode::default_config && !add_only) if (m_config_mode != cfg_mode::config_override && m_config_mode != cfg_mode::default_config)
{ {
const auto cfg_path = fs::get_config_dir() + "/config.yml"; const auto cfg_path = fs::get_config_dir() + "/config.yml";
@ -379,12 +379,6 @@ void Emulator::Init(bool add_only)
// Backup config // Backup config
g_backup_cfg.from_string(g_cfg.to_string()); g_backup_cfg.from_string(g_cfg.to_string());
if (add_only)
{
// We don't need to initialize the rest if we only add games
return;
}
// Create directories (can be disabled if necessary) // Create directories (can be disabled if necessary)
auto make_path_verbose = [&](const std::string& path, bool must_exist_outside_emu_dir) auto make_path_verbose = [&](const std::string& path, bool must_exist_outside_emu_dir)
{ {
@ -735,7 +729,7 @@ game_boot_result Emulator::GetElfPathFromDir(std::string& elf_path, const std::s
return game_boot_result::invalid_file_or_folder; return game_boot_result::invalid_file_or_folder;
} }
game_boot_result Emulator::BootGame(const std::string& path, const std::string& title_id, bool direct, bool add_only, cfg_mode config_mode, const std::string& config_path) game_boot_result Emulator::BootGame(const std::string& path, const std::string& title_id, bool direct, cfg_mode config_mode, const std::string& config_path)
{ {
auto save_args = std::make_tuple(m_path, argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_mode); auto save_args = std::make_tuple(m_path, argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_mode);
@ -759,7 +753,7 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&
{ {
m_path = path; m_path = path;
return restore_on_no_boot(Load(title_id, add_only)); return restore_on_no_boot(Load(title_id));
} }
game_boot_result result = game_boot_result::nothing_to_boot; game_boot_result result = game_boot_result::nothing_to_boot;
@ -769,32 +763,7 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&
{ {
ensure(!elf.empty()); ensure(!elf.empty());
m_path = elf; m_path = elf;
result = Load(title_id, add_only); result = Load(title_id);
}
if (add_only)
{
for (auto&& entry : fs::dir{ path })
{
if (entry.name == "." || entry.name == "..")
{
continue;
}
if (entry.is_directory && std::regex_match(entry.name, std::regex("^PS3_GM[[:digit:]]{2}$")))
{
const std::string elf = path + "/" + entry.name + "/USRDIR/EBOOT.BIN";
if (fs::is_file(elf))
{
m_path = elf;
if (const auto err = Load(title_id, add_only); err != game_boot_result::no_errors)
{
result = err;
}
}
}
}
} }
return restore_on_no_boot(result); return restore_on_no_boot(result);
@ -805,11 +774,10 @@ void Emulator::SetForceBoot(bool force_boot)
m_force_boot = force_boot; m_force_boot = force_boot;
} }
game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool is_disc_patch) game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch)
{ {
m_ar.reset(); m_ar.reset();
if (!add_only)
{ {
if (m_config_mode == cfg_mode::continuous) if (m_config_mode == cfg_mode::continuous)
{ {
@ -872,7 +840,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
} cleanup{this}; } cleanup{this};
{ {
Init(add_only); Init();
m_state_inspection_savestate = g_cfg.savestate.state_inspection_mode.get(); m_state_inspection_savestate = g_cfg.savestate.state_inspection_mode.get();
m_savestate_extension_flags1 = {}; m_savestate_extension_flags1 = {};
@ -1142,14 +1110,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
vfs::mount("/app_home", g_cfg_vfs.app_home.to_string().empty() ? elf_dir + '/' : g_cfg_vfs.get(g_cfg_vfs.app_home, rpcs3::utils::get_emu_dir())); vfs::mount("/app_home", g_cfg_vfs.app_home.to_string().empty() ? elf_dir + '/' : g_cfg_vfs.get(g_cfg_vfs.app_home, rpcs3::utils::get_emu_dir()));
// Load PARAM.SFO (TODO) // Load PARAM.SFO (TODO)
psf::registry _psf;
const std::string sfo_path = elf_dir + "/sce_sys/param.sfo";
if (fs::file sfov{sfo_path})
{
m_sfo_dir = elf_dir;
_psf = psf::load_object(sfov, sfo_path);
}
else
{ {
if (fs::is_dir(m_path)) if (fs::is_dir(m_path))
{ {
@ -1176,10 +1136,10 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
{ {
m_sfo_dir = rpcs3::utils::get_sfo_dir_from_game_path(fs::get_parent_dir(elf_dir), m_title_id); m_sfo_dir = rpcs3::utils::get_sfo_dir_from_game_path(fs::get_parent_dir(elf_dir), m_title_id);
} }
_psf = psf::load_object(m_sfo_dir + "/PARAM.SFO");
} }
const psf::registry _psf = psf::load_object(m_sfo_dir + "/PARAM.SFO");
m_title = std::string(psf::get_string(_psf, "TITLE", std::string_view(m_path).substr(m_path.find_last_of(fs::delim) + 1))); m_title = std::string(psf::get_string(_psf, "TITLE", std::string_view(m_path).substr(m_path.find_last_of(fs::delim) + 1)));
m_title_id = std::string(psf::get_string(_psf, "TITLE_ID")); m_title_id = std::string(psf::get_string(_psf, "TITLE_ID"));
m_cat = std::string(psf::get_string(_psf, "CATEGORY")); m_cat = std::string(psf::get_string(_psf, "CATEGORY"));
@ -1199,7 +1159,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
sys_log.notice("Category: %s", GetCat()); sys_log.notice("Category: %s", GetCat());
sys_log.notice("Version: APP_VER=%s VERSION=%s", version_app, version_disc); sys_log.notice("Version: APP_VER=%s VERSION=%s", version_app, version_disc);
if (!add_only)
{ {
if (m_config_mode == cfg_mode::custom_selection || (m_config_mode == cfg_mode::continuous && !m_config_path.empty())) if (m_config_mode == cfg_mode::custom_selection || (m_config_mode == cfg_mode::continuous && !m_config_path.empty()))
{ {
@ -1271,7 +1230,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Set RTM usage // Set RTM usage
g_use_rtm = utils::has_rtm() && (((utils::has_mpx() && !utils::has_tsx_force_abort()) && g_cfg.core.enable_TSX == tsx_usage::enabled) || g_cfg.core.enable_TSX == tsx_usage::forced); g_use_rtm = utils::has_rtm() && (((utils::has_mpx() && !utils::has_tsx_force_abort()) && g_cfg.core.enable_TSX == tsx_usage::enabled) || g_cfg.core.enable_TSX == tsx_usage::forced);
if (!add_only)
{ {
// Log some extra info in case of boot // Log some extra info in case of boot
#if defined(HAVE_VULKAN) #if defined(HAVE_VULKAN)
@ -1304,12 +1262,8 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
} }
// Set bdvd_dir // Set bdvd_dir
std::string bdvd_dir; std::string bdvd_dir = g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir());
if (!add_only)
{ {
bdvd_dir = g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir());
if (!bdvd_dir.empty()) if (!bdvd_dir.empty())
{ {
if (bdvd_dir.back() != fs::delim[0] && bdvd_dir.back() != fs::delim[1]) if (bdvd_dir.back() != fs::delim[0] && bdvd_dir.back() != fs::delim[1])
@ -1336,7 +1290,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
} }
// Special boot mode (directory scan) // Special boot mode (directory scan)
if (!add_only && fs::is_dir(m_path)) if (fs::is_dir(m_path))
{ {
m_state = system_state::ready; m_state = system_state::ready;
GetCallbacks().on_ready(); GetCallbacks().on_ready();
@ -1472,16 +1426,15 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
const std::string hdd0_game = vfs::get("/dev_hdd0/game/"); const std::string hdd0_game = vfs::get("/dev_hdd0/game/");
const bool from_hdd0_game = IsPathInsideDir(m_path, hdd0_game); const bool from_hdd0_game = IsPathInsideDir(m_path, hdd0_game);
#ifdef _WIN32 if (game_boot_result error = VerifyPathCasing(m_path, hdd0_game, from_hdd0_game); error != game_boot_result::no_errors)
// m_path might be passed from command line with differences in uppercase/lowercase on windows.
if ((!from_hdd0_game && IsPathInsideDir(fmt::to_lower(m_path), fmt::to_lower(hdd0_game))) ||
(!from_dev_flash && IsPathInsideDir(fmt::to_lower(m_path), fmt::to_lower(g_cfg_vfs.get_dev_flash()))))
{ {
// Let's just abort to prevent errors down the line. return error;
sys_log.error("The boot path seems to contain incorrectly cased characters. Please adjust the path and try again."); }
return game_boot_result::invalid_file_or_folder;
if (game_boot_result error = VerifyPathCasing(m_path, g_cfg_vfs.get_dev_flash(), from_dev_flash); error != game_boot_result::no_errors)
{
return error;
} }
#endif
// Mount /dev_bdvd/ if necessary // Mount /dev_bdvd/ if necessary
if (bdvd_dir.empty() && disc.empty()) if (bdvd_dir.empty() && disc.empty())
@ -1502,7 +1455,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
{ {
sys_log.success("Disc game %s moved to special location '%s'", m_title_id, dst_dir); sys_log.success("Disc game %s moved to special location '%s'", m_title_id, dst_dir);
m_path = games_common + m_path.substr(hdd0_game.size()); m_path = games_common + m_path.substr(hdd0_game.size());
return Load(m_title_id, add_only); return Load(m_title_id);
} }
sys_log.error("Failed to move disc game %s to '%s' (%s)", m_title_id, dst_dir, fs::g_tls_error); sys_log.error("Failed to move disc game %s to '%s' (%s)", m_title_id, dst_dir, fs::g_tls_error);
@ -1534,17 +1487,13 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Check /dev_bdvd/ // Check /dev_bdvd/
if (disc.empty() && !bdvd_dir.empty() && fs::is_dir(bdvd_dir)) if (disc.empty() && !bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{ {
fs::file sfb_file;
vfs::mount("/dev_bdvd", bdvd_dir); vfs::mount("/dev_bdvd", bdvd_dir);
sys_log.notice("Disc: %s", vfs::get("/dev_bdvd")); sys_log.notice("Disc: %s", vfs::get("/dev_bdvd"));
vfs::mount("/dev_bdvd/PS3_GAME", bdvd_dir + m_game_dir + "/"); vfs::mount("/dev_bdvd/PS3_GAME", bdvd_dir + m_game_dir + "/");
sys_log.notice("Game: %s", vfs::get("/dev_bdvd/PS3_GAME")); sys_log.notice("Game: %s", vfs::get("/dev_bdvd/PS3_GAME"));
const auto sfb_path = vfs::get("/dev_bdvd/PS3_DISC.SFB"); if (const std::string sfb_path = vfs::get("/dev_bdvd/PS3_DISC.SFB"); !IsValidSfb(sfb_path))
if (!sfb_file.open(sfb_path) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32)
{ {
sys_log.error("Invalid disc directory for the disc game %s. (%s)", m_title_id, sfb_path); sys_log.error("Invalid disc directory for the disc game %s. (%s)", m_title_id, sfb_path);
return game_boot_result::invalid_file_or_folder; return game_boot_result::invalid_file_or_folder;
@ -1622,21 +1571,8 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
{ {
std::string game_dir = m_sfo_dir; std::string game_dir = m_sfo_dir;
// Don't use the C00 subdirectory in our game list
if (game_dir.ends_with("/C00") || game_dir.ends_with("\\C00"))
{
game_dir = game_dir.substr(0, game_dir.size() - 4);
}
// Add HG games not in HDD0 to games.yml // Add HG games not in HDD0 to games.yml
if (m_games_config.add_game(m_title_id, game_dir)) [[maybe_unused]] const bool res = m_games_config.add_external_hdd_game(m_title_id, game_dir);
{
sys_log.notice("Registered HG game directory for title '%s': %s", m_title_id, game_dir);
}
else
{
sys_log.error("Failed to save HG game location of title '%s' (error=%s)", m_title_id, fs::g_tls_error);
}
vfs::mount("/dev_hdd0/game/" + m_title_id, game_dir + '/'); vfs::mount("/dev_hdd0/game/" + m_title_id, game_dir + '/');
} }
@ -1670,12 +1606,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
sys_log.notice("Disk: %s, Dir: %s", vfs::get("/dev_bdvd"), m_game_dir); sys_log.notice("Disk: %s, Dir: %s", vfs::get("/dev_bdvd"), m_game_dir);
} }
if (add_only)
{
sys_log.notice("Finished to add data to games.yml by boot for: %s", m_path);
return game_boot_result::no_errors;
}
// Initialize progress dialog // Initialize progress dialog
g_fxo->init<named_thread<progress_dialog_server>>(); g_fxo->init<named_thread<progress_dialog_server>>();
@ -1784,7 +1714,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Booting game update // Booting game update
sys_log.success("Updates found at /dev_hdd0/game/%s/", m_title_id); sys_log.success("Updates found at /dev_hdd0/game/%s/", m_title_id);
m_path = hdd0_boot; m_path = hdd0_boot;
return Load(m_title_id, false, true); return Load(m_title_id, true);
} }
if (!disc_psf_obj.empty()) if (!disc_psf_obj.empty())
@ -3115,7 +3045,7 @@ void Emulator::AddGamesFromDir(const std::string& path)
m_games_config.set_save_on_dirty(false); m_games_config.set_save_on_dirty(false);
// search dropped path first or else the direct parent to an elf is wrongly skipped // search dropped path first or else the direct parent to an elf is wrongly skipped
if (const auto error = BootGame(path, "", false, true); error == game_boot_result::no_errors) if (const auto error = AddGame(path); error == game_boot_result::no_errors)
{ {
// Nothing to do // Nothing to do
} }
@ -3132,7 +3062,7 @@ void Emulator::AddGamesFromDir(const std::string& path)
const std::string dir_path = path + '/' + dir_entry.name; const std::string dir_path = path + '/' + dir_entry.name;
if (const auto error = BootGame(dir_path, "", false, true); error == game_boot_result::no_errors) if (const auto error = AddGame(dir_path); error == game_boot_result::no_errors)
{ {
// Nothing to do // Nothing to do
} }
@ -3148,12 +3078,162 @@ void Emulator::AddGamesFromDir(const std::string& path)
} }
} }
game_boot_result Emulator::AddGame(const std::string& path)
{
// Handle files directly
if (!fs::is_dir(path))
{
return AddGameToYml(path);
}
game_boot_result result = game_boot_result::nothing_to_boot;
std::string elf;
if (const game_boot_result res = GetElfPathFromDir(elf, path); res == game_boot_result::no_errors)
{
ensure(!elf.empty());
result = AddGameToYml(elf);
}
for (auto&& entry : fs::dir{ path })
{
if (entry.name == "." || entry.name == "..")
{
continue;
}
if (entry.is_directory && std::regex_match(entry.name, std::regex("^PS3_GM[[:digit:]]{2}$")))
{
const std::string elf = path + "/" + entry.name + "/USRDIR/EBOOT.BIN";
if (fs::is_file(elf))
{
if (const auto err = AddGameToYml(elf); err != game_boot_result::no_errors)
{
result = err;
}
}
}
}
return result;
}
game_boot_result Emulator::AddGameToYml(const std::string& path)
{
// Detect boot location
const auto is_invalid_path = [this](std::string_view path, std::string_view dir) -> game_boot_result
{
if (IsPathInsideDir(path, dir))
{
sys_log.error("Adding games from dev_flash is not allowed.");
return game_boot_result::invalid_file_or_folder;
}
return VerifyPathCasing(path, dir, false);
};
if (game_boot_result error = is_invalid_path(path, rpcs3::utils::get_hdd0_dir()); error != game_boot_result::no_errors)
{
sys_log.error("Adding games from dev_hdd0 is not allowed.");
return error;
}
if (game_boot_result error = is_invalid_path(path, g_cfg_vfs.get_dev_flash()); error != game_boot_result::no_errors)
{
sys_log.error("Adding games from dev_flash is not allowed.");
return error;
}
// Load PARAM.SFO
const std::string elf_dir = fs::get_parent_dir(path);
std::string sfo_dir = rpcs3::utils::get_sfo_dir_from_game_path(fs::get_parent_dir(elf_dir));
const psf::registry _psf = psf::load_object(sfo_dir + "/PARAM.SFO");
const std::string title_id = std::string(psf::get_string(_psf, "TITLE_ID"));
const std::string cat = std::string(psf::get_string(_psf, "CATEGORY"));
if (!_psf.empty() && cat.empty())
{
sys_log.fatal("Corrupted PARAM.SFO found! Try reinstalling the game.");
return game_boot_result::invalid_file_or_folder;
}
if (title_id.empty())
{
sys_log.notice("Can not add binary without TITLE_ID to games.yml. (path=%s, category=%s)", path, cat);
return game_boot_result::invalid_file_or_folder;
}
if (cat == "GD")
{
sys_log.notice("Can not add game data to games.yml. (path=%s, title_id=%s, category=%s)", path, title_id, cat);
return game_boot_result::invalid_file_or_folder;
}
// Set bdvd_dir
std::string bdvd_dir;
std::string game_dir;
std::string sfb_dir;
GetBdvdDir(bdvd_dir, sfb_dir, game_dir, elf_dir);
// Check /dev_bdvd/
if (bdvd_dir.empty())
{
// Add HG games not in HDD0 to games.yml
if (cat == "HG")
{
if (m_games_config.add_external_hdd_game(title_id, sfo_dir))
{
return game_boot_result::no_errors;
}
return game_boot_result::generic_error;
}
}
else if (fs::is_dir(bdvd_dir))
{
if (const std::string sfb_path = bdvd_dir + "/PS3_DISC.SFB"; !IsValidSfb(sfb_path))
{
sys_log.error("Invalid disc directory for the disc game %s. (%s)", title_id, sfb_path);
return game_boot_result::invalid_file_or_folder;
}
// Store /dev_bdvd/ location
if (m_games_config.add_game(title_id, bdvd_dir))
{
sys_log.notice("Registered BDVD game directory for title '%s': %s", title_id, bdvd_dir);
return game_boot_result::no_errors;
}
sys_log.error("Failed to save BDVD location of title '%s' (error=%s)", title_id, fs::g_tls_error);
return game_boot_result::generic_error;
}
sys_log.notice("Nothing to add in path %s (title_id=%s, category=%s)", path, title_id, cat);
return game_boot_result::invalid_file_or_folder;
}
bool Emulator::IsPathInsideDir(std::string_view path, std::string_view dir) const bool Emulator::IsPathInsideDir(std::string_view path, std::string_view dir) const
{ {
const std::string dir_path = GetCallbacks().resolve_path(dir); const std::string dir_path = GetCallbacks().resolve_path(dir);
return !dir_path.empty() && (GetCallbacks().resolve_path(path) + '/').starts_with((dir_path.back() == '/') ? dir_path : (dir_path + '/')); return !dir_path.empty() && (GetCallbacks().resolve_path(path) + '/').starts_with((dir_path.back() == '/') ? dir_path : (dir_path + '/'));
}; }
game_boot_result Emulator::VerifyPathCasing(std::string_view path, std::string_view dir, bool from_dir) const
{
#ifdef _WIN32
// path might be passed from command line with differences in uppercase/lowercase on windows.
if (!from_dir && IsPathInsideDir(fmt::to_lower(path), fmt::to_lower(dir)))
{
// Let's just abort to prevent errors down the line.
sys_log.error("The path seems to contain incorrectly cased characters. Please adjust the path and try again.");
return game_boot_result::invalid_file_or_folder;
}
#endif
return game_boot_result::no_errors;
}
const std::string& Emulator::GetFakeCat() const const std::string& Emulator::GetFakeCat() const
{ {
@ -3169,7 +3249,7 @@ const std::string& Emulator::GetFakeCat() const
} }
return m_cat; return m_cat;
}; }
const std::string Emulator::GetSfoDir(bool prefer_disc_sfo) const const std::string Emulator::GetSfoDir(bool prefer_disc_sfo) const
{ {
@ -3202,7 +3282,7 @@ void Emulator::GetBdvdDir(std::string& bdvd_dir, std::string& sfb_dir, std::stri
break; break;
} }
if (fs::file sfb_file{parent_dir + "/PS3_DISC.SFB", fs::read + fs::isfile}; sfb_file && sfb_file.size() >= 4 && sfb_file.read<u32>() == ".SFB"_u32) if (IsValidSfb(parent_dir + "/PS3_DISC.SFB"))
{ {
main_dir_name = std::string_view{search_dir}.substr(search_dir.find_last_of(fs::delim) + 1); main_dir_name = std::string_view{search_dir}.substr(search_dir.find_last_of(fs::delim) + 1);
@ -3346,6 +3426,12 @@ bool Emulator::IsVsh()
return g_ps3_process_info.get_cellos_appname() == "vsh.self"sv; return g_ps3_process_info.get_cellos_appname() == "vsh.self"sv;
} }
bool Emulator::IsValidSfb(const std::string& path)
{
fs::file sfb_file{path, fs::read + fs::isfile};
return sfb_file && sfb_file.size() >= 4 && sfb_file.read<u32>() == ".SFB"_u32;
}
void Emulator::SaveSettings(const std::string& settings, const std::string& title_id) void Emulator::SaveSettings(const std::string& settings, const std::string& title_id)
{ {
std::string config_name; std::string config_name;

View file

@ -210,7 +210,7 @@ public:
m_state = system_state::running; m_state = system_state::running;
} }
void Init(bool add_only = false); void Init();
std::vector<std::string> argv; std::vector<std::string> argv;
std::vector<std::string> envp; std::vector<std::string> envp;
@ -307,12 +307,12 @@ public:
return m_config_path; return m_config_path;
} }
game_boot_result BootGame(const std::string& path, const std::string& title_id = "", bool direct = false, bool add_only = false, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = ""); game_boot_result BootGame(const std::string& path, const std::string& title_id = "", bool direct = false, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = "");
bool BootRsxCapture(const std::string& path); bool BootRsxCapture(const std::string& path);
void SetForceBoot(bool force_boot); void SetForceBoot(bool force_boot);
game_boot_result Load(const std::string& title_id = "", bool add_only = false, bool is_disc_patch = false); game_boot_result Load(const std::string& title_id = "", bool is_disc_patch = false);
void Run(bool start_playtime); void Run(bool start_playtime);
void RunPPU(); void RunPPU();
void FixGuestTime(); void FixGuestTime();
@ -345,9 +345,12 @@ public:
std::set<std::string> GetGameDirs() const; std::set<std::string> GetGameDirs() const;
void AddGamesFromDir(const std::string& path); void AddGamesFromDir(const std::string& path);
game_boot_result AddGame(const std::string& path);
game_boot_result AddGameToYml(const std::string& path);
// Check if path is inside the specified directory // Check if path is inside the specified directory
bool IsPathInsideDir(std::string_view path, std::string_view dir) const; bool IsPathInsideDir(std::string_view path, std::string_view dir) const;
game_boot_result VerifyPathCasing(std::string_view path, std::string_view dir, bool from_dir) const;
void EjectDisc(); void EjectDisc();
game_boot_result InsertDisc(const std::string& path); game_boot_result InsertDisc(const std::string& path);
@ -357,6 +360,7 @@ public:
friend void init_fxo_for_exec(utils::serial*, bool); friend void init_fxo_for_exec(utils::serial*, bool);
static bool IsVsh(); static bool IsVsh();
static bool IsValidSfb(const std::string& path);
static void SaveSettings(const std::string& settings, const std::string& title_id); static void SaveSettings(const std::string& settings, const std::string& title_id);
}; };

View file

@ -72,6 +72,24 @@ bool games_config::add_game(const std::string& key, const std::string& path)
return true; return true;
} }
bool games_config::add_external_hdd_game(const std::string& key, std::string& path)
{
// Don't use the C00 subdirectory in our game list
if (path.ends_with("/C00") || path.ends_with("\\C00"))
{
path = path.substr(0, path.size() - 4);
}
if (add_game(key, path))
{
cfg_log.notice("Registered HG game directory for title '%s': %s", key, path);
return true;
}
cfg_log.error("Failed to save HG game location of title '%s' (error=%s)", key, fs::g_tls_error);
return false;
}
bool games_config::save() bool games_config::save()
{ {
std::lock_guard lock(m_mutex); std::lock_guard lock(m_mutex);

View file

@ -17,6 +17,7 @@ public:
std::string get_path(const std::string& title_id) const; std::string get_path(const std::string& title_id) const;
bool add_game(const std::string& key, const std::string& path); bool add_game(const std::string& key, const std::string& path);
bool add_external_hdd_game(const std::string& key, std::string& path);
bool save(); bool save();
private: private:

View file

@ -1260,7 +1260,7 @@ int main(int argc, char** argv)
const cfg_mode config_mode = config_path.empty() ? cfg_mode::custom : cfg_mode::config_override; const cfg_mode config_mode = config_path.empty() ? cfg_mode::custom : cfg_mode::config_override;
if (const game_boot_result error = Emu.BootGame(path, "", false, false, config_mode, config_path); error != game_boot_result::no_errors) if (const game_boot_result error = Emu.BootGame(path, "", false, config_mode, config_path); error != game_boot_result::no_errors)
{ {
sys_log.error("Booting '%s' with cli argument failed: reason: %s", path, error); sys_log.error("Booting '%s' with cli argument failed: reason: %s", path, error);

View file

@ -466,7 +466,7 @@ void main_window::Boot(const std::string& path, const std::string& title_id, boo
m_app_icon = gui::utils::get_app_icon_from_path(path, title_id); m_app_icon = gui::utils::get_app_icon_from_path(path, title_id);
if (const auto error = Emu.BootGame(path, title_id, direct, false, config_mode, config_path); error != game_boot_result::no_errors) if (const auto error = Emu.BootGame(path, title_id, direct, config_mode, config_path); error != game_boot_result::no_errors)
{ {
gui_log.error("Boot failed: reason: %s, path: %s", error, path); gui_log.error("Boot failed: reason: %s, path: %s", error, path);
show_boot_error(error); show_boot_error(error);