From 2a7c948a57b7df022fd5dd091ebfb694874f0adf Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 11 Dec 2021 12:01:23 +1000 Subject: [PATCH] GameDatabase: Store enums instead of strings --- pcsx2/GameDatabase.cpp | 68 ++++++++++++++++++++++--------------- pcsx2/GameDatabase.h | 7 ++-- pcsx2/gui/AppCoreThread.cpp | 40 ++++++++-------------- 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index 18a329b1b1..cff0204906 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -127,51 +127,63 @@ static bool parseAndInsert(std::string serial, const YAML::Node& node) } // Validate game fixes, invalid ones will be dropped! - for (std::string& fix : node["gameFixes"].as>(std::vector())) + if (auto gameFixes = node["gameFixes"]) { - bool fixValidated = false; - for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++) + gameEntry.gameFixes.reserve(gameFixes.size()); + for (std::string& fix : gameFixes.as>(std::vector())) { - std::string validFix = fmt::format("{}Hack", EnumToString(id)); - if (validFix == fix) + // Enum values don't end with Hack, but gamedb does, so remove it before comparing. + bool fixValidated = false; + if (StringUtil::EndsWith(fix, "Hack")) { - fixValidated = true; - break; + 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()) + { + 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) - { - gameEntry.gameFixes.push_back(fix); - } - else - { - Console.Error(fmt::format("[GameDB] Invalid gamefix: '{}', specified for serial: '{}'. Dropping!", fix, serial)); } } // Validate speed hacks, invalid ones will be dropped! - if (YAML::Node speedHacksNode = node["speedHacks"]) + if (auto speedHacksNode = node["speedHacks"]) { + gameEntry.speedHacks.reserve(speedHacksNode.size()); for (const auto& entry : speedHacksNode) { - std::string speedHack = entry.first.as(); bool speedHackValidated = false; - for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++) + std::string speedHack(entry.first.as()); + + // Same deal with SpeedHacks + if (StringUtil::EndsWith(speedHack, "SpeedHack")) { - std::string validSpeedHack = fmt::format("{}SpeedHack", EnumToString(id)); - if (validSpeedHack == speedHack) + speedHack.erase(speedHack.size() - 9); + for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++) { - speedHackValidated = true; - break; + 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()); + speedHackValidated = true; + break; + } } } - if (speedHackValidated) + + if (!speedHackValidated) { - gameEntry.speedHacks[speedHack] = entry.second.as(); - } - else - { - Console.Error(fmt::format("[GameDB] Invalid speedhack: '{}', specified for serial: '{}'. Dropping!", speedHack, serial)); + Console.Error("[GameDB] Invalid speedhack: '%s', specified for serial: '%s'. Dropping!", speedHack.c_str(), serial.c_str()); } } } diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h index f09f5daaca..cfdc16f72d 100644 --- a/pcsx2/GameDatabase.h +++ b/pcsx2/GameDatabase.h @@ -19,6 +19,9 @@ #include #include +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 @@ -65,8 +68,8 @@ public: RoundMode vuRoundMode = RoundMode::Undefined; ClampMode eeClampMode = ClampMode::Undefined; ClampMode vuClampMode = ClampMode::Undefined; - std::vector gameFixes; - std::unordered_map speedHacks; + std::vector gameFixes; + std::vector> speedHacks; std::vector memcardFilters; std::unordered_map patches; diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index bc8c798929..374afac547 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -309,40 +309,28 @@ static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEnt gf++; } - // TODO - config - this could be simplified with maps instead of bitfields and enums - for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++) + for (const auto& [id, mode] : game.speedHacks) { - std::string key = fmt::format("{}SpeedHack", EnumToString(id)); - // Gamefixes are already guaranteed to be valid, any invalid ones are dropped - if (game.speedHacks.count(key) == 1) - { - // Legacy note - speedhacks are setup in the GameDB as integer values, but - // are effectively booleans like the gamefixes - bool mode = game.speedHacks.at(key) ? 1 : 0; - dest.Speedhacks.Set(id, mode); - PatchesCon->WriteLn(fmt::format("(GameDB) Setting Speedhack '{}' to [mode={}]", key, (int)mode)); - gf++; - } + // Legacy note - speedhacks are setup in the GameDB as integer values, but + // are effectively booleans like the gamefixes + dest.Speedhacks.Set(id, mode != 0); + PatchesCon->WriteLn("(GameDB) Setting Speedhack '%s' to [mode=%d]", EnumToString(id), static_cast(mode != 0)); + gf++; } // TODO - config - this could be simplified with maps instead of bitfields and enums - for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; id++) + for (const GamefixId id : game.gameFixes) { - std::string key = fmt::format("{}Hack", EnumToString(id)); - // Gamefixes are already guaranteed to be valid, any invalid ones are dropped - if (std::find(game.gameFixes.begin(), game.gameFixes.end(), key) != game.gameFixes.end()) - { - // if the fix is present, it is said to be enabled - dest.Gamefixes.Set(id, true); - PatchesCon->WriteLn("(GameDB) Enabled Gamefix: " + key); - gf++; + // if the fix is present, it is said to be enabled + dest.Gamefixes.Set(id, true); + PatchesCon->WriteLn("(GameDB) Enabled Gamefix: %s", EnumToString(id)); + gf++; - // The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB) - if (id == Fix_GoemonTlbMiss && true) - vtlb_Alloc_Ppmap(); - } + // The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB) + if (id == Fix_GoemonTlbMiss && true) + vtlb_Alloc_Ppmap(); } return gf;