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);
}
std::string fmt::to_upper(const std::string& string)
std::string fmt::to_upper(std::string_view string)
{
std::string result;
result.resize(string.size());
@ -607,7 +607,7 @@ std::string fmt::to_upper(const std::string& string)
return result;
}
std::string fmt::to_lower(const std::string& string)
std::string fmt::to_lower(std::string_view string)
{
std::string result;
result.resize(string.size());

View File

@ -173,8 +173,8 @@ namespace fmt
return result;
}
std::string to_upper(const std::string& string);
std::string to_lower(const std::string& string);
std::string to_upper(std::string_view string);
std::string to_lower(std::string_view string);
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);
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)
{

View File

@ -242,7 +242,7 @@ void fixup_ppu_settings()
}
}
void Emulator::Init(bool add_only)
void Emulator::Init()
{
jit_runtime::initialize();
@ -325,7 +325,7 @@ void Emulator::Init(bool add_only)
const bool is_exitspawn = m_config_mode == cfg_mode::continuous;
// 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})
{
@ -352,7 +352,7 @@ void Emulator::Init(bool add_only)
}
// 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";
@ -379,12 +379,6 @@ void Emulator::Init(bool add_only)
// Backup config
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)
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;
}
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);
@ -759,7 +753,7 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&
{
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;
@ -769,32 +763,7 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&
{
ensure(!elf.empty());
m_path = elf;
result = Load(title_id, add_only);
}
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;
}
}
}
}
result = Load(title_id);
}
return restore_on_no_boot(result);
@ -805,11 +774,10 @@ void Emulator::SetForceBoot(bool 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();
if (!add_only)
{
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};
{
Init(add_only);
Init();
m_state_inspection_savestate = g_cfg.savestate.state_inspection_mode.get();
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()));
// 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))
{
@ -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);
}
_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_id = std::string(psf::get_string(_psf, "TITLE_ID"));
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("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()))
{
@ -1271,7 +1230,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// 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);
if (!add_only)
{
// Log some extra info in case of boot
#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
std::string bdvd_dir;
if (!add_only)
std::string bdvd_dir = g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir());
{
bdvd_dir = g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir());
if (!bdvd_dir.empty())
{
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)
if (!add_only && fs::is_dir(m_path))
if (fs::is_dir(m_path))
{
m_state = system_state::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 bool from_hdd0_game = IsPathInsideDir(m_path, hdd0_game);
#ifdef _WIN32
// 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()))))
if (game_boot_result error = VerifyPathCasing(m_path, hdd0_game, from_hdd0_game); error != game_boot_result::no_errors)
{
// Let's just abort to prevent errors down the line.
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;
return error;
}
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
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);
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);
@ -1534,17 +1487,13 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Check /dev_bdvd/
if (disc.empty() && !bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
fs::file sfb_file;
vfs::mount("/dev_bdvd", bdvd_dir);
sys_log.notice("Disc: %s", vfs::get("/dev_bdvd"));
vfs::mount("/dev_bdvd/PS3_GAME", bdvd_dir + m_game_dir + "/");
sys_log.notice("Game: %s", vfs::get("/dev_bdvd/PS3_GAME"));
const auto sfb_path = vfs::get("/dev_bdvd/PS3_DISC.SFB");
if (!sfb_file.open(sfb_path) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32)
if (const std::string sfb_path = vfs::get("/dev_bdvd/PS3_DISC.SFB"); !IsValidSfb(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;
@ -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;
// 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
if (m_games_config.add_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);
}
[[maybe_unused]] const bool res = m_games_config.add_external_hdd_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);
}
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
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
sys_log.success("Updates found at /dev_hdd0/game/%s/", m_title_id);
m_path = hdd0_boot;
return Load(m_title_id, false, true);
return Load(m_title_id, true);
}
if (!disc_psf_obj.empty())
@ -3115,7 +3045,7 @@ void Emulator::AddGamesFromDir(const std::string& path)
m_games_config.set_save_on_dirty(false);
// 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
}
@ -3132,7 +3062,7 @@ void Emulator::AddGamesFromDir(const std::string& path)
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
}
@ -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
{
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 + '/'));
};
}
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
{
@ -3169,7 +3249,7 @@ const std::string& Emulator::GetFakeCat() const
}
return m_cat;
};
}
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;
}
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);
@ -3346,6 +3426,12 @@ bool Emulator::IsVsh()
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)
{
std::string config_name;

View File

@ -210,7 +210,7 @@ public:
m_state = system_state::running;
}
void Init(bool add_only = false);
void Init();
std::vector<std::string> argv;
std::vector<std::string> envp;
@ -307,12 +307,12 @@ public:
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);
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 RunPPU();
void FixGuestTime();
@ -345,9 +345,12 @@ public:
std::set<std::string> GetGameDirs() const;
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
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();
game_boot_result InsertDisc(const std::string& path);
@ -357,6 +360,7 @@ public:
friend void init_fxo_for_exec(utils::serial*, bool);
static bool IsVsh();
static bool IsValidSfb(const std::string& path);
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;
}
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()
{
std::lock_guard lock(m_mutex);

View File

@ -17,6 +17,7 @@ public:
std::string get_path(const std::string& title_id) const;
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();
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;
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);

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);
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);
show_boot_error(error);