mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
Emu: Cache games.yml and only save when necessary
This commit is contained in:
parent
500f7901ac
commit
2c71d08ea2
8 changed files with 188 additions and 93 deletions
|
@ -1,5 +1,6 @@
|
|||
add_library(rpcs3_emu
|
||||
cache_utils.cpp
|
||||
games_config.cpp
|
||||
IdManager.cpp
|
||||
localized_string.cpp
|
||||
savestate_utils.cpp
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "../Crypto/unself.h"
|
||||
#include "util/yaml.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/serialization.hpp"
|
||||
|
||||
|
@ -875,26 +874,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
{
|
||||
Init(add_only);
|
||||
|
||||
// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations)
|
||||
YAML::Node games;
|
||||
|
||||
if (fs::file f{fs::get_config_dir() + "/games.yml", fs::read + fs::create})
|
||||
{
|
||||
auto [result, error] = yaml_load(f.to_string());
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
sys_log.error("Failed to load games.yml: %s", error);
|
||||
}
|
||||
|
||||
games = result;
|
||||
}
|
||||
|
||||
if (!games.IsMap())
|
||||
{
|
||||
games.reset();
|
||||
}
|
||||
|
||||
m_state_inspection_savestate = g_cfg.savestate.state_inspection_mode.get();
|
||||
m_savestate_extension_flags1 = {};
|
||||
|
||||
|
@ -956,9 +935,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
m_title_id = disc_info;
|
||||
|
||||
// Load /dev_bdvd/ from game list if available
|
||||
if (auto node = games[m_title_id])
|
||||
if (std::string game_path = m_games_config.get_path(m_title_id); !game_path.empty())
|
||||
{
|
||||
disc = node.Scalar();
|
||||
disc = std::move(game_path);
|
||||
}
|
||||
else if (!g_cfg.savestate.state_inspection_mode)
|
||||
{
|
||||
|
@ -1070,9 +1049,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
std::string title_path;
|
||||
|
||||
// const overload does not create new node on failure
|
||||
if (auto node = std::as_const(games)[m_title_id])
|
||||
if (std::string game_path = m_games_config.get_path(m_title_id); !game_path.empty())
|
||||
{
|
||||
title_path = node.Scalar();
|
||||
title_path = std::move(game_path);
|
||||
}
|
||||
|
||||
for (std::string test_path :
|
||||
|
@ -1113,9 +1092,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
title_id = title_id.substr(0, title_id.find_first_of('/'));
|
||||
|
||||
// Try to load game directory from list if available
|
||||
if (auto node = (title_id.empty() ? YAML::Node{} : games[title_id]))
|
||||
if (std::string game_path = m_games_config.get_path(m_title_id); !game_path.empty())
|
||||
{
|
||||
disc = node.Scalar();
|
||||
disc = std::move(game_path);
|
||||
m_path = disc + argv[0].substr(game0_path.size() + title_id.size());
|
||||
}
|
||||
}
|
||||
|
@ -1541,9 +1520,9 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
if ((is_disc_patch || m_cat == "GD") && bdvd_dir.empty() && disc.empty())
|
||||
{
|
||||
// Load /dev_bdvd/ from game list if available
|
||||
if (auto node = games[m_title_id])
|
||||
if (std::string game_path = m_games_config.get_path(m_title_id); !game_path.empty())
|
||||
{
|
||||
bdvd_dir = node.Scalar();
|
||||
bdvd_dir = std::move(game_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1552,35 +1531,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
}
|
||||
}
|
||||
|
||||
auto try_register_game_location = [&](const std::string& key, const std::string& loc)
|
||||
{
|
||||
// Access or create node if does not exist
|
||||
auto node = games[key];
|
||||
|
||||
if (node && node.Scalar() == loc)
|
||||
{
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write to node
|
||||
node = loc;
|
||||
|
||||
YAML::Emitter out;
|
||||
out << games;
|
||||
|
||||
fs::pending_file temp(fs::get_config_dir() + "/games.yml");
|
||||
|
||||
// Do not update games.yml when TITLE_ID is empty
|
||||
if (temp.file && temp.file.write(out.c_str(), out.size()), temp.commit())
|
||||
{
|
||||
m_games_yml_invalidated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check /dev_bdvd/
|
||||
if (disc.empty() && !bdvd_dir.empty() && fs::is_dir(bdvd_dir))
|
||||
{
|
||||
|
@ -1617,7 +1567,11 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
}
|
||||
|
||||
// Store /dev_bdvd/ location
|
||||
if (!try_register_game_location(m_title_id, bdvd_dir))
|
||||
if (m_games_config.add_game(m_title_id, bdvd_dir))
|
||||
{
|
||||
sys_log.notice("Registered BDVD game directory for title '%s': %s", m_title_id, bdvd_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_log.error("Failed to save BDVD location of title '%s' (error=%s)", m_title_id, fs::g_tls_error);
|
||||
}
|
||||
|
@ -1675,7 +1629,11 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
|
|||
}
|
||||
|
||||
// Add HG games not in HDD0 to games.yml
|
||||
if (!try_register_game_location(m_title_id, game_dir))
|
||||
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);
|
||||
}
|
||||
|
@ -3154,15 +3112,12 @@ void Emulator::AddGamesFromDir(const std::string& path)
|
|||
if (!IsStopped())
|
||||
return;
|
||||
|
||||
m_games_yml_invalidated = false;
|
||||
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 (std::exchange(m_games_yml_invalidated, false))
|
||||
{
|
||||
sys_log.notice("Registered game directory: %s", path);
|
||||
}
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
// search direct subdirectories, that way we can drop one folder containing all games
|
||||
|
@ -3177,12 +3132,16 @@ void Emulator::AddGamesFromDir(const std::string& path)
|
|||
|
||||
if (const auto error = BootGame(dir_path, "", false, true); error == game_boot_result::no_errors)
|
||||
{
|
||||
if (std::exchange(m_games_yml_invalidated, false))
|
||||
{
|
||||
sys_log.notice("Registered game directory: %s", dir_path);
|
||||
}
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
m_games_config.set_save_on_dirty(true);
|
||||
|
||||
if (m_games_config.is_dirty() && !m_games_config.save())
|
||||
{
|
||||
sys_log.error("Failed to save games.yml after adding games");
|
||||
}
|
||||
}
|
||||
|
||||
bool Emulator::IsPathInsideDir(std::string_view path, std::string_view dir) const
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "Utilities/bit_set.h"
|
||||
#include "games_config.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -119,7 +120,7 @@ class Emulator final
|
|||
atomic_t<u64> m_pause_amend_time{0}; // increased when resumed
|
||||
atomic_t<u64> m_stop_ctr{0}; // Increments when emulation is stopped
|
||||
|
||||
bool m_games_yml_invalidated = false;
|
||||
games_config m_games_config;
|
||||
|
||||
video_renderer m_default_renderer;
|
||||
std::string m_default_graphics_adapter;
|
||||
|
@ -287,6 +288,11 @@ public:
|
|||
return m_usr;
|
||||
}
|
||||
|
||||
const games_config& GetGamesConfig() const
|
||||
{
|
||||
return m_games_config;
|
||||
}
|
||||
|
||||
// Get deserialization manager
|
||||
utils::serial* DeserialManager() const;
|
||||
|
||||
|
|
112
rpcs3/Emu/games_config.cpp
Normal file
112
rpcs3/Emu/games_config.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "stdafx.h"
|
||||
#include "games_config.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/yaml.hpp"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
games_config::games_config()
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
games_config::~games_config()
|
||||
{
|
||||
if (m_dirty)
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
std::string games_config::get_path(const std::string& title_id) const
|
||||
{
|
||||
if (title_id.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto it = m_games.find(title_id); it != m_games.cend())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool games_config::add_game(const std::string& key, const std::string& path)
|
||||
{
|
||||
// Access or create node if does not exist
|
||||
if (auto it = m_games.find(key); it != m_games.end())
|
||||
{
|
||||
if (it->second == path)
|
||||
{
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
it->second = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_games.emplace(key, path);
|
||||
}
|
||||
|
||||
m_dirty = true;
|
||||
|
||||
if (m_save_on_dirty)
|
||||
{
|
||||
return save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool games_config::save()
|
||||
{
|
||||
YAML::Emitter out;
|
||||
out << m_games;
|
||||
|
||||
fs::pending_file temp(fs::get_config_dir() + "/games.yml");
|
||||
|
||||
if (temp.file && temp.file.write(out.c_str(), out.size()), temp.commit())
|
||||
{
|
||||
m_dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
cfg_log.error("Failed to save games.yml: %s", fs::g_tls_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
void games_config::load()
|
||||
{
|
||||
m_games.clear();
|
||||
|
||||
if (fs::file f{fs::get_config_dir() + "/games.yml", fs::read + fs::create})
|
||||
{
|
||||
auto [result, error] = yaml_load(f.to_string());
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
cfg_log.error("Failed to load games.yml: %s", error);
|
||||
}
|
||||
|
||||
if (!result.IsMap())
|
||||
{
|
||||
if (!result.IsNull())
|
||||
{
|
||||
cfg_log.error("Failed to load games.yml: type %d not a map", result.Type());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& entry : result)
|
||||
{
|
||||
if (!entry.first.Scalar().empty() && entry.second.IsScalar() && !entry.second.Scalar().empty())
|
||||
{
|
||||
m_games.emplace(entry.first.Scalar(), entry.second.Scalar());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
rpcs3/Emu/games_config.h
Normal file
28
rpcs3/Emu/games_config.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
class games_config
|
||||
{
|
||||
public:
|
||||
games_config();
|
||||
virtual ~games_config();
|
||||
|
||||
void set_save_on_dirty(bool enabled) { m_save_on_dirty = enabled; }
|
||||
|
||||
const std::map<std::string, std::string>& get_games() const { return m_games; }
|
||||
bool is_dirty() const { return m_dirty; }
|
||||
|
||||
std::string get_path(const std::string& title_id) const;
|
||||
|
||||
bool add_game(const std::string& key, const std::string& path);
|
||||
bool save();
|
||||
|
||||
private:
|
||||
void load();
|
||||
|
||||
std::map<std::string, std::string> m_games;
|
||||
|
||||
bool m_dirty = false;
|
||||
bool m_save_on_dirty = true;
|
||||
};
|
|
@ -67,6 +67,7 @@
|
|||
<ClCompile Include="Emu\Cell\Modules\libfs_utility_init.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_crashdump.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\HLE_PATCHES.cpp" />
|
||||
<ClCompile Include="Emu\games_config.cpp" />
|
||||
<ClCompile Include="Emu\Io\camera_config.cpp" />
|
||||
<ClCompile Include="Emu\Io\recording_config.cpp" />
|
||||
<ClCompile Include="Emu\Io\Turntable.cpp" />
|
||||
|
@ -497,6 +498,7 @@
|
|||
<ClInclude Include="Emu\Cell\Modules\libfs_utility_init.h" />
|
||||
<ClInclude Include="Emu\Cell\Modules\sys_crashdump.h" />
|
||||
<ClInclude Include="Emu\CPU\sse2neon.h" />
|
||||
<ClInclude Include="Emu\games_config.h" />
|
||||
<ClInclude Include="Emu\Io\camera_config.h" />
|
||||
<ClInclude Include="Emu\Io\camera_handler_base.h" />
|
||||
<ClInclude Include="Emu\Io\music_handler_base.h" />
|
||||
|
|
|
@ -1147,6 +1147,9 @@
|
|||
<ClCompile Include="Emu\RSX\Overlays\overlay_manager.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\games_config.cpp">
|
||||
<Filter>Emu</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
@ -2311,6 +2314,9 @@
|
|||
<ClInclude Include="io_buffer.h">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\games_config.h">
|
||||
<Filter>Emu</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||
|
|
|
@ -516,28 +516,9 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after)
|
|||
add_dir(_hdd + "game/", false);
|
||||
add_dir(_hdd + "disc/", true); // Deprecated
|
||||
|
||||
auto get_games = []() -> YAML::Node
|
||||
for (const auto& [serial, path] : Emu.GetGamesConfig().get_games())
|
||||
{
|
||||
if (const fs::file games = fs::file(fs::get_config_dir() + "/games.yml", fs::read + fs::create))
|
||||
{
|
||||
auto [result, error] = yaml_load(games.to_string());
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
game_list_log.error("Failed to load games.yml: %s", error);
|
||||
return {};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
game_list_log.error("Failed to load games.yml, check permissions.");
|
||||
return {};
|
||||
};
|
||||
|
||||
for (auto&& pair : get_games())
|
||||
{
|
||||
std::string game_dir = pair.second.Scalar();
|
||||
std::string game_dir = path;
|
||||
|
||||
game_dir.resize(game_dir.find_last_not_of('/') + 1);
|
||||
|
||||
|
@ -569,7 +550,7 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after)
|
|||
// Check if the remaining part is the only path component
|
||||
if (frag.find_first_of('/') + 1 == 0)
|
||||
{
|
||||
game_list_log.trace("Removed duplicate for %s: %s", pair.first.Scalar(), pair.second.Scalar());
|
||||
game_list_log.trace("Removed duplicate for %s: %s", serial, path);
|
||||
|
||||
if (static std::unordered_set<std::string> warn_once_list; warn_once_list.emplace(game_dir).second)
|
||||
{
|
||||
|
@ -589,7 +570,7 @@ void game_list_frame::Refresh(const bool from_drive, const bool scroll_after)
|
|||
}
|
||||
else
|
||||
{
|
||||
game_list_log.trace("Invalid game path registered for %s: %s", pair.first.Scalar(), pair.second.Scalar());
|
||||
game_list_log.trace("Invalid game path registered for %s: %s", serial, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue