GameDatabase: Store enums instead of strings

This commit is contained in:
Connor McLaughlin 2021-12-11 12:01:23 +10:00 committed by refractionpcsx2
parent 46912595ea
commit 2a7c948a57
3 changed files with 59 additions and 56 deletions

View File

@ -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<std::string>>(std::vector<std::string>()))
if (auto gameFixes = node["gameFixes"])
{
gameEntry.gameFixes.reserve(gameFixes.size());
for (std::string& fix : gameFixes.as<std::vector<std::string>>(std::vector<std::string>()))
{
// 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++)
{
std::string validFix = fmt::format("{}Hack", EnumToString(id));
if (validFix == fix)
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)
{
gameEntry.gameFixes.push_back(fix);
}
else
if (!fixValidated)
{
Console.Error(fmt::format("[GameDB] Invalid gamefix: '{}', specified for serial: '{}'. Dropping!", fix, serial));
Console.Error("[GameDB] Invalid gamefix: '%s', specified for serial: '%s'. Dropping!", fix.c_str(), serial.c_str());
}
}
}
// 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<std::string>();
bool speedHackValidated = false;
std::string speedHack(entry.first.as<std::string>());
// Same deal with SpeedHacks
if (StringUtil::EndsWith(speedHack, "SpeedHack"))
{
speedHack.erase(speedHack.size() - 9);
for (SpeedhackId id = SpeedhackId_FIRST; id < pxEnumEnd; id++)
{
std::string validSpeedHack = fmt::format("{}SpeedHack", EnumToString(id));
if (validSpeedHack == speedHack)
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;
}
}
if (speedHackValidated)
{
gameEntry.speedHacks[speedHack] = entry.second.as<int>();
}
else
if (!speedHackValidated)
{
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());
}
}
}

View File

@ -19,6 +19,9 @@
#include <vector>
#include <string>
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<std::string> gameFixes;
std::unordered_map<std::string, int> speedHacks;
std::vector<GamefixId> gameFixes;
std::vector<std::pair<SpeedhackId, int>> speedHacks;
std::vector<std::string> memcardFilters;
std::unordered_map<std::string, Patch> patches;

View File

@ -309,41 +309,29 @@ 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));
dest.Speedhacks.Set(id, mode != 0);
PatchesCon->WriteLn("(GameDB) Setting Speedhack '%s' to [mode=%d]", EnumToString(id), static_cast<int>(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);
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();
}
}
return gf;
}