mirror of https://github.com/PCSX2/pcsx2.git
gamedb: migrate GameDB implementation to `rapidyaml`
This commit is contained in:
parent
4719e52c6e
commit
83e5aa6137
|
@ -24,54 +24,45 @@
|
|||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
static constexpr char GAMEDB_YAML_FILE_NAME[] = "GameIndex.yaml";
|
||||
|
||||
static std::unordered_map<std::string, GameDatabaseSchema::GameEntry> s_game_db;
|
||||
static std::once_flag s_load_once_flag;
|
||||
|
||||
static std::string strToLower(std::string str)
|
||||
{
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string GameDatabaseSchema::GameEntry::MemcardFiltersAsString() const
|
||||
std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString() const
|
||||
{
|
||||
return fmt::to_string(fmt::join(memcardFilters, "/"));
|
||||
}
|
||||
|
||||
const GameDatabaseSchema::Patch* GameDatabaseSchema::GameEntry::FindPatch(const std::string& crc) const
|
||||
const GameDatabaseSchema::Patch* GameDatabaseSchema::GameEntry::findPatch(const std::string_view& crc) const
|
||||
{
|
||||
const std::string crcLower(strToLower(crc));
|
||||
std::string crcLower = StringUtil::toLower(crc);
|
||||
Console.WriteLn(fmt::format("[GameDB] Searching for patch with CRC '{}'", crc));
|
||||
|
||||
auto it = patches.find(crcLower);
|
||||
if (it != patches.end())
|
||||
{
|
||||
Console.WriteLn(fmt::format("[GameDB] Found patch with CRC '{}'", crc));
|
||||
return &it->second;
|
||||
return &patches.at(crcLower);
|
||||
}
|
||||
|
||||
it = patches.find("default");
|
||||
if (it != patches.end())
|
||||
{
|
||||
Console.WriteLn("[GameDB] Found and falling back to default patch");
|
||||
return &it->second;
|
||||
return &patches.at("default");
|
||||
}
|
||||
Console.WriteLn("[GameDB] No CRC-specific patch or default patch found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* GameDatabaseSchema::compatToString(Compatibility compat)
|
||||
const char* GameDatabaseSchema::GameEntry::compatAsString() const
|
||||
{
|
||||
switch (compat)
|
||||
{
|
||||
|
@ -92,210 +83,250 @@ const char* GameDatabaseSchema::compatToString(Compatibility compat)
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> convertMultiLineStringToVector(const std::string& multiLineString)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream stream(multiLineString);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(stream, line))
|
||||
{
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
static bool parseAndInsert(std::string serial, const YAML::Node& node)
|
||||
void parseAndInsert(const std::string_view& serial, const c4::yml::NodeRef& node)
|
||||
{
|
||||
GameDatabaseSchema::GameEntry gameEntry;
|
||||
try
|
||||
if (node.has_child("name"))
|
||||
{
|
||||
gameEntry.name = node["name"].as<std::string>("");
|
||||
gameEntry.region = node["region"].as<std::string>("");
|
||||
gameEntry.compat = static_cast<GameDatabaseSchema::Compatibility>(node["compat"].as<int>(enum_cast(gameEntry.compat)));
|
||||
// Safely grab round mode and clamp modes from the YAML, otherwise use defaults
|
||||
if (YAML::Node roundModeNode = node["roundModes"])
|
||||
node["name"] >> gameEntry.name;
|
||||
}
|
||||
if (node.has_child("region"))
|
||||
{
|
||||
node["region"] >> gameEntry.region;
|
||||
}
|
||||
if (node.has_child("compat"))
|
||||
{
|
||||
int val = 0;
|
||||
node["compat"] >> val;
|
||||
gameEntry.compat = static_cast<GameDatabaseSchema::Compatibility>(val);
|
||||
}
|
||||
if (node.has_child("roundModes"))
|
||||
{
|
||||
if (node.has_child("eeRoundMode"))
|
||||
{
|
||||
gameEntry.eeRoundMode = static_cast<GameDatabaseSchema::RoundMode>(roundModeNode["eeRoundMode"].as<int>(enum_cast(gameEntry.eeRoundMode)));
|
||||
gameEntry.vuRoundMode = static_cast<GameDatabaseSchema::RoundMode>(roundModeNode["vuRoundMode"].as<int>(enum_cast(gameEntry.vuRoundMode)));
|
||||
int eeVal = -1;
|
||||
node["eeRoundMode"] >> eeVal;
|
||||
gameEntry.eeRoundMode = static_cast<GameDatabaseSchema::RoundMode>(eeVal);
|
||||
}
|
||||
if (YAML::Node clampModeNode = node["clampModes"])
|
||||
if (node.has_child("vuRoundMode"))
|
||||
{
|
||||
gameEntry.eeClampMode = static_cast<GameDatabaseSchema::ClampMode>(clampModeNode["eeClampMode"].as<int>(enum_cast(gameEntry.eeClampMode)));
|
||||
gameEntry.vuClampMode = static_cast<GameDatabaseSchema::ClampMode>(clampModeNode["vuClampMode"].as<int>(enum_cast(gameEntry.vuClampMode)));
|
||||
int vuVal = -1;
|
||||
node["vuRoundMode"] >> vuVal;
|
||||
gameEntry.vuRoundMode = static_cast<GameDatabaseSchema::RoundMode>(vuVal);
|
||||
}
|
||||
}
|
||||
if (node.has_child("clampModes"))
|
||||
{
|
||||
if (node.has_child("eeClampMode"))
|
||||
{
|
||||
int eeVal = -1;
|
||||
node["eeClampMode"] >> eeVal;
|
||||
gameEntry.eeClampMode = static_cast<GameDatabaseSchema::ClampMode>(eeVal);
|
||||
}
|
||||
if (node.has_child("vuClampMode"))
|
||||
{
|
||||
int vuVal = -1;
|
||||
node["vuClampMode"] >> vuVal;
|
||||
gameEntry.vuClampMode = static_cast<GameDatabaseSchema::ClampMode>(vuVal);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate game fixes, invalid ones will be dropped!
|
||||
if (auto gameFixes = node["gameFixes"])
|
||||
// Validate game fixes, invalid ones will be dropped!
|
||||
if (node.has_child("gameFixes") && node["gameFixes"].has_children())
|
||||
{
|
||||
for (const ryml::NodeRef& n : node["gameFixes"].children())
|
||||
{
|
||||
gameEntry.gameFixes.reserve(gameFixes.size());
|
||||
for (std::string& fix : gameFixes.as<std::vector<std::string>>(std::vector<std::string>()))
|
||||
bool fixValidated = false;
|
||||
auto fix = std::string(n.val().str, n.val().len);
|
||||
|
||||
// Enum values don't end with Hack, but gamedb does, so remove it before comparing.
|
||||
if (StringUtil::EndsWith(fix, "Hack"))
|
||||
{
|
||||
// Enum values don't end with Hack, but gamedb does, so remove it before comparing.
|
||||
bool fixValidated = false;
|
||||
if (StringUtil::EndsWith(fix, "Hack"))
|
||||
fix.erase(fix.size() - 4);
|
||||
for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++)
|
||||
{
|
||||
fix.erase(fix.size() - 4);
|
||||
for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++)
|
||||
if (fix.compare(EnumToString(id)) == 0 &&
|
||||
std::find(gameEntry.gameFixes.begin(), gameEntry.gameFixes.end(), id) == gameEntry.gameFixes.end())
|
||||
{
|
||||
if (fix.compare(EnumToString(id)) == 0 &&
|
||||
std::find(gameEntry.gameFixes.begin(), gameEntry.gameFixes.end(), id) == gameEntry.gameFixes.end())
|
||||
{
|
||||
gameEntry.gameFixes.push_back(id);
|
||||
fixValidated = true;
|
||||
break;
|
||||
}
|
||||
gameEntry.gameFixes.push_back(id);
|
||||
fixValidated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fixValidated)
|
||||
{
|
||||
Console.Error("[GameDB] Invalid gamefix: '%s', specified for serial: '%s'. Dropping!", fix.c_str(), serial.c_str());
|
||||
}
|
||||
if (!fixValidated)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Invalid gamefix: '{}', specified for serial: '{}'. Dropping!", fix, serial));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate speed hacks, invalid ones will be dropped!
|
||||
if (auto speedHacksNode = node["speedHacks"])
|
||||
// Validate speed hacks, invalid ones will be dropped!
|
||||
if (node.has_child("speedHacks") && node["speedHacks"].has_children())
|
||||
{
|
||||
for (const ryml::NodeRef& n : node["speedHacks"].children())
|
||||
{
|
||||
gameEntry.speedHacks.reserve(speedHacksNode.size());
|
||||
for (const auto& entry : speedHacksNode)
|
||||
{
|
||||
bool speedHackValidated = false;
|
||||
std::string speedHack(entry.first.as<std::string>());
|
||||
bool speedHackValidated = false;
|
||||
auto speedHack = std::string(n.key().str, n.key().len);
|
||||
|
||||
// Same deal with SpeedHacks
|
||||
if (StringUtil::EndsWith(speedHack, "SpeedHack"))
|
||||
// Same deal with SpeedHacks
|
||||
if (StringUtil::EndsWith(speedHack, "SpeedHack"))
|
||||
{
|
||||
speedHack.erase(speedHack.size() - 9);
|
||||
for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++)
|
||||
{
|
||||
speedHack.erase(speedHack.size() - 9);
|
||||
for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++)
|
||||
if (speedHack.compare(EnumToString(id)) == 0 &&
|
||||
std::none_of(gameEntry.speedHacks.begin(), gameEntry.speedHacks.end(), [id](const auto& it) { return it.first == id; }))
|
||||
{
|
||||
if (speedHack.compare(EnumToString(id)) == 0 &&
|
||||
std::none_of(gameEntry.speedHacks.begin(), gameEntry.speedHacks.end(), [id](const auto& it) { return it.first == id; }))
|
||||
{
|
||||
gameEntry.speedHacks.emplace_back(id, entry.second.as<int>());
|
||||
speedHackValidated = true;
|
||||
break;
|
||||
}
|
||||
gameEntry.speedHacks.emplace_back(id, std::atoi(n.val().str));
|
||||
speedHackValidated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!speedHackValidated)
|
||||
{
|
||||
Console.Error("[GameDB] Invalid speedhack: '%s', specified for serial: '%s'. Dropping!", speedHack.c_str(), serial.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gameEntry.memcardFilters = node["memcardFilters"].as<std::vector<std::string>>(std::vector<std::string>());
|
||||
|
||||
if (YAML::Node patches = node["patches"])
|
||||
{
|
||||
for (const auto& entry : patches)
|
||||
if (!speedHackValidated)
|
||||
{
|
||||
std::string crc = strToLower(entry.first.as<std::string>());
|
||||
if (gameEntry.patches.count(crc) == 1)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Duplicate CRC '{}' found for serial: '{}'. Skipping, CRCs are case-insensitive!", crc, serial));
|
||||
continue;
|
||||
}
|
||||
YAML::Node patchNode = entry.second;
|
||||
|
||||
gameEntry.patches[crc] = convertMultiLineStringToVector(patchNode["content"].as<std::string>(""));
|
||||
Console.Error(fmt::format("[GameDB] Invalid speedhack: '{}', specified for serial: '{}'. Dropping!", speedHack.c_str(), serial));
|
||||
}
|
||||
}
|
||||
|
||||
s_game_db.emplace(std::move(serial), std::move(gameEntry));
|
||||
return true;
|
||||
}
|
||||
catch (const YAML::RepresentationException& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Invalid GameDB syntax detected on serial: '{}'. Error Details - {}", serial, e.msg));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Unexpected error occurred when reading serial: '{}'. Error Details - {}", serial, e.what()));
|
||||
}
|
||||
|
||||
return false;
|
||||
// Memory Card Filters - Store as a vector to allow flexibility in the future
|
||||
// - currently they are used as a '\n' delimited string in the app
|
||||
if (node.has_child("memcardFilters") && node["memcardFilters"].has_children())
|
||||
{
|
||||
for (const ryml::NodeRef& n : node["memcardFilters"].children())
|
||||
{
|
||||
auto memcardFilter = std::string(n.val().str, n.val().len);
|
||||
gameEntry.memcardFilters.emplace_back(std::move(memcardFilter));
|
||||
}
|
||||
}
|
||||
|
||||
// Game Patches
|
||||
if (node.has_child("patches") && node["patches"].has_children())
|
||||
{
|
||||
for (const ryml::NodeRef& n : node["patches"].children())
|
||||
{
|
||||
auto crc = std::string(n.key().str, n.key().len);
|
||||
if (gameEntry.patches.count(crc) == 1)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Duplicate CRC '{}' found for serial: '{}'. Skipping, CRCs are case-insensitive!", crc, serial));
|
||||
continue;
|
||||
}
|
||||
GameDatabaseSchema::Patch patch;
|
||||
if (n.has_child("content"))
|
||||
{
|
||||
std::string patchLines;
|
||||
n["content"] >> patchLines;
|
||||
patch = StringUtil::splitOnNewLine(patchLines);
|
||||
}
|
||||
gameEntry.patches[crc] = patch;
|
||||
}
|
||||
}
|
||||
|
||||
s_game_db.emplace(std::move(serial), std::move(gameEntry));
|
||||
}
|
||||
|
||||
static bool LoadYamlFile()
|
||||
static std::ifstream getFileStream(std::string path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return std::ifstream(StringUtil::UTF8StringToWideString(path));
|
||||
#else
|
||||
return std::ifstream(path.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initDatabase()
|
||||
{
|
||||
const ryml::Callbacks preserve_callbacks = ryml::get_callbacks();
|
||||
const c4::error_callback_type preserve_c4_callback = c4::get_error_callback();
|
||||
auto callbacks = ryml::get_callbacks();
|
||||
callbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location loc, void*) {
|
||||
throw std::runtime_error(fmt::format("[YAML] Parsing error at {}:{} (bufpos={}): {}",
|
||||
loc.line, loc.col, loc.offset, msg));
|
||||
};
|
||||
c4::set_error_callback([](const char* msg, size_t msg_size) {
|
||||
throw std::runtime_error(fmt::format("[YAML] Internal Parsing error: {}",
|
||||
msg));
|
||||
});
|
||||
try
|
||||
{
|
||||
std::optional<std::string> file_data(Host::ReadResourceFileToString(GAMEDB_YAML_FILE_NAME));
|
||||
if (!file_data.has_value())
|
||||
auto filePath = Host::getResourceFilePath(GAMEDB_YAML_FILE_NAME);
|
||||
if (!filePath.has_value())
|
||||
{
|
||||
Console.Error("[GameDB] Unable to open GameDB file.");
|
||||
return false;
|
||||
Console.Error("[GameDB] Unable to open GameDB file, file does not exist.");
|
||||
return;
|
||||
}
|
||||
// yaml-cpp has memory leak issues if you persist and modify a YAML::Node
|
||||
// convert to a map and throw it away instead!
|
||||
YAML::Node data = YAML::Load(file_data.value());
|
||||
for (const auto& entry : data)
|
||||
|
||||
auto dbStream = getFileStream(filePath.value());
|
||||
|
||||
dbStream.seekg(0, std::ios::end);
|
||||
const size_t size = dbStream.tellg();
|
||||
dbStream.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<char> buf(size);
|
||||
dbStream.read(buf.data(), size);
|
||||
dbStream.close();
|
||||
|
||||
const ryml::substr view = c4::basic_substring<char>(buf.data(), size);
|
||||
ryml::Tree tree = ryml::parse(view);
|
||||
ryml::NodeRef root = tree.rootref();
|
||||
|
||||
for (const ryml::NodeRef& n : root.children())
|
||||
{
|
||||
// we don't want to throw away the entire GameDB file if a single entry is made incorrectly,
|
||||
// but we do want to yell about it so it can be corrected
|
||||
try
|
||||
auto serial = StringUtil::toLower(std::string(n.key().str, n.key().len));
|
||||
|
||||
// Serials and CRCs must be inserted as lower-case, as that is how they are retrieved
|
||||
// this is because the application may pass a lowercase CRC or serial along
|
||||
//
|
||||
// However, YAML's keys are as expected case-sensitive, so we have to explicitly do our own duplicate checking
|
||||
if (s_game_db.count(serial) == 1)
|
||||
{
|
||||
// Serials and CRCs must be inserted as lower-case, as that is how they are retrieved
|
||||
// this is because the application may pass a lowercase CRC or serial along
|
||||
//
|
||||
// However, YAML's keys are as expected case-sensitive, so we have to explicitly do our own duplicate checking
|
||||
std::string serial(strToLower(entry.first.as<std::string>()));
|
||||
if (s_game_db.count(serial) == 1)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Duplicate serial '{}' found in GameDB. Skipping, Serials are case-insensitive!", serial));
|
||||
continue;
|
||||
}
|
||||
parseAndInsert(std::move(serial), entry.second);
|
||||
Console.Error(fmt::format("[GameDB] Duplicate serial '{}' found in GameDB. Skipping, Serials are case-insensitive!", serial));
|
||||
continue;
|
||||
}
|
||||
catch (const YAML::RepresentationException& e)
|
||||
if (n.is_map())
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Invalid GameDB syntax detected. Error Details - {}", e.msg));
|
||||
parseAndInsert(serial, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Error occured when initializing GameDB: {}", e.what()));
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
ryml::set_callbacks(preserve_callbacks);
|
||||
c4::set_error_callback(preserve_c4_callback);
|
||||
}
|
||||
|
||||
void GameDatabase::EnsureLoaded()
|
||||
|
||||
|
||||
void GameDatabase::ensureLoaded()
|
||||
{
|
||||
std::call_once(s_load_once_flag, []() {
|
||||
Common::Timer timer;
|
||||
|
||||
if (!LoadYamlFile())
|
||||
{
|
||||
Console.Error("GameDB: Failed to load YAML file");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLn(fmt::format("[GameDB] Has not been initialized yet, initializing..."));
|
||||
initDatabase();
|
||||
Console.WriteLn("[GameDB] %zu games on record (loaded in %.2fms)", s_game_db.size(), timer.GetTimeMilliseconds());
|
||||
});
|
||||
}
|
||||
|
||||
const GameDatabaseSchema::GameEntry* GameDatabase::FindGame(const std::string& serial)
|
||||
const GameDatabaseSchema::GameEntry* GameDatabase::findGame(const std::string_view& serial)
|
||||
{
|
||||
EnsureLoaded();
|
||||
GameDatabase::ensureLoaded();
|
||||
|
||||
const std::string serialLower(strToLower(serial));
|
||||
Console.WriteLn("[GameDB] Searching for '%s' in GameDB", serialLower.c_str());
|
||||
|
||||
auto iter = s_game_db.find(serialLower);
|
||||
if (iter == s_game_db.end())
|
||||
std::string serialLower = StringUtil::toLower(serial);
|
||||
Console.WriteLn(fmt::format("[GameDB] Searching for '{}' in GameDB", serialLower));
|
||||
const auto gameEntry = s_game_db.find(serialLower);
|
||||
if (gameEntry != s_game_db.end())
|
||||
{
|
||||
Console.Error("[GameDB] Could not find '%s' in GameDB", serialLower.c_str());
|
||||
return nullptr;
|
||||
Console.WriteLn(fmt::format("[GameDB] Found '{}' in GameDB", serialLower));
|
||||
return &gameEntry->second;
|
||||
}
|
||||
|
||||
Console.WriteLn("[GameDB] Found '%s' in GameDB", serialLower.c_str());
|
||||
return &iter->second;
|
||||
Console.Error(fmt::format("[GameDB] Could not find '{}' in GameDB", serialLower));
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ryml_std.hpp"
|
||||
#include "ryml.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
@ -22,9 +25,6 @@
|
|||
enum GamefixId;
|
||||
enum SpeedhackId;
|
||||
|
||||
// Since this is kinda yaml specific, might be a good idea to
|
||||
// relocate this into the yaml class
|
||||
// or put the serialization methods inside the yaml
|
||||
class GameDatabaseSchema
|
||||
{
|
||||
public:
|
||||
|
@ -74,16 +74,14 @@ public:
|
|||
std::unordered_map<std::string, Patch> patches;
|
||||
|
||||
// Returns the list of memory card serials as a `/` delimited string
|
||||
std::string MemcardFiltersAsString() const;
|
||||
const Patch* FindPatch(const std::string& crc) const;
|
||||
std::string memcardFiltersAsString() const;
|
||||
const Patch* findPatch(const std::string_view& crc) const;
|
||||
const char* compatAsString() const;
|
||||
};
|
||||
|
||||
static const char* compatToString(GameDatabaseSchema::Compatibility compat);
|
||||
};
|
||||
|
||||
namespace GameDatabase
|
||||
{
|
||||
void EnsureLoaded();
|
||||
|
||||
const GameDatabaseSchema::GameEntry* FindGame(const std::string& serial);
|
||||
void ensureLoaded();
|
||||
const GameDatabaseSchema::GameEntry* findGame(const std::string_view& serial);
|
||||
}; // namespace GameDatabase
|
||||
|
|
|
@ -131,7 +131,7 @@ static void inifile_command(const wxString& cmd)
|
|||
// Returns number of patches loaded
|
||||
int LoadPatchesFromGamesDB(const std::string& crc, const GameDatabaseSchema::GameEntry& game)
|
||||
{
|
||||
const GameDatabaseSchema::Patch* patch = game.FindPatch(crc);
|
||||
const GameDatabaseSchema::Patch* patch = game.findPatch(crc);
|
||||
if (patch)
|
||||
{
|
||||
for (const std::string& line : *patch)
|
||||
|
|
|
@ -450,12 +450,11 @@ void InputRecording::GoToFirstFrame(wxWindow* parent)
|
|||
|
||||
wxString InputRecording::resolveGameName()
|
||||
{
|
||||
// Code loosely taken from AppCoreThread::_ApplySettings to resolve the Game Name
|
||||
std::string gameName;
|
||||
const std::string gameKey(StringUtil::wxStringToUTF8String(SysGetDiscID()));
|
||||
if (!gameKey.empty())
|
||||
{
|
||||
const GameDatabaseSchema::GameEntry* game = GameDatabase::FindGame(gameKey);
|
||||
auto game = GameDatabase::findGame(gameKey);
|
||||
if (game)
|
||||
{
|
||||
gameName = game->name;
|
||||
|
|
|
@ -270,7 +270,7 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
|
|||
|
||||
if (game.eeRoundMode != GameDatabaseSchema::RoundMode::Undefined)
|
||||
{
|
||||
SSE_RoundMode eeRM = (SSE_RoundMode)enum_cast(game.eeRoundMode);
|
||||
const SSE_RoundMode eeRM = (SSE_RoundMode)enum_cast(game.eeRoundMode);
|
||||
if (EnumIsValid(eeRM))
|
||||
{
|
||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
||||
|
@ -281,7 +281,7 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
|
|||
|
||||
if (game.vuRoundMode != GameDatabaseSchema::RoundMode::Undefined)
|
||||
{
|
||||
SSE_RoundMode vuRM = (SSE_RoundMode)enum_cast(game.vuRoundMode);
|
||||
const SSE_RoundMode vuRM = (SSE_RoundMode)enum_cast(game.vuRoundMode);
|
||||
if (EnumIsValid(vuRM))
|
||||
{
|
||||
PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||
|
@ -292,8 +292,8 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
|
|||
|
||||
if (game.eeClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
||||
{
|
||||
int clampMode = enum_cast(game.eeClampMode);
|
||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
||||
const int clampMode = enum_cast(game.eeClampMode);
|
||||
PatchesCon->WriteLn(L"(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
||||
dest.Cpu.Recompiler.fpuOverflow = (clampMode >= 1);
|
||||
dest.Cpu.Recompiler.fpuExtraOverflow = (clampMode >= 2);
|
||||
dest.Cpu.Recompiler.fpuFullMode = (clampMode >= 3);
|
||||
|
@ -302,7 +302,7 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
|
|||
|
||||
if (game.vuClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
||||
{
|
||||
int clampMode = enum_cast(game.vuClampMode);
|
||||
const int clampMode = enum_cast(game.vuClampMode);
|
||||
PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
|
||||
dest.Cpu.Recompiler.vuOverflow = (clampMode >= 1);
|
||||
dest.Cpu.Recompiler.vuExtraOverflow = (clampMode >= 2);
|
||||
|
@ -320,7 +320,6 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt
|
|||
gf++;
|
||||
}
|
||||
|
||||
// TODO - config - this could be simplified with maps instead of bitfields and enums
|
||||
for (const GamefixId id : game.gameFixes)
|
||||
{
|
||||
// Gamefixes are already guaranteed to be valid, any invalid ones are dropped
|
||||
|
@ -437,12 +436,12 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
|
|||
|
||||
if (!curGameKey.IsEmpty())
|
||||
{
|
||||
const GameDatabaseSchema::GameEntry* game = GameDatabase::FindGame(StringUtil::wxStringToUTF8String(curGameKey));
|
||||
auto game = GameDatabase::findGame(std::string(curGameKey.ToUTF8()));
|
||||
if (game)
|
||||
{
|
||||
GameInfo::gameName = StringUtil::UTF8StringToWxString(StringUtil::StdStringFromFormat("%s (%s)", game->name.c_str(), game->region.c_str()));
|
||||
gameCompat.Printf(" [Status = %s]", GameDatabaseSchema::compatToString(game->compat));
|
||||
gameMemCardFilter = StringUtil::UTF8StringToWxString(game->MemcardFiltersAsString());
|
||||
gameCompat.Printf(" [Status = %s]", game->compatAsString());
|
||||
gameMemCardFilter = StringUtil::UTF8StringToWxString(game->memcardFiltersAsString());
|
||||
|
||||
if (fixup.EnablePatches)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue