Patch: Store gamedb patches as single string

This commit is contained in:
Connor McLaughlin 2022-04-12 18:59:59 +10:00 committed by refractionpcsx2
parent 29cea58471
commit 5fa9427323
6 changed files with 41 additions and 56 deletions

View File

@ -57,23 +57,22 @@ std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString() const
return fmt::to_string(fmt::join(memcardFilters, "/"));
}
const GameDatabaseSchema::Patch* GameDatabaseSchema::GameEntry::findPatch(const std::string_view& crc) const
const std::string* GameDatabaseSchema::GameEntry::findPatch(u32 crc) const
{
std::string crcLower = StringUtil::toLower(crc);
Console.WriteLn(fmt::format("[GameDB] Searching for patch with CRC '{}'", crc));
Console.WriteLn(fmt::format("[GameDB] Searching for patch with CRC '{:08X}'", crc));
auto it = patches.find(crcLower);
auto it = patches.find(crc);
if (it != patches.end())
{
Console.WriteLn(fmt::format("[GameDB] Found patch with CRC '{}'", crc));
return &patches.at(crcLower);
Console.WriteLn(fmt::format("[GameDB] Found patch with CRC '{:08X}'", crc));
return &it->second;
}
it = patches.find("default");
it = patches.find(0);
if (it != patches.end())
{
Console.WriteLn("[GameDB] Found and falling back to default patch");
return &patches.at("default");
return &it->second;
}
Console.WriteLn("[GameDB] No CRC-specific patch or default patch found");
return nullptr;
@ -245,20 +244,24 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
{
for (const ryml::NodeRef& n : node["patches"].children())
{
auto crc = StringUtil::toLower(std::string(n.key().str, n.key().len));
if (gameEntry.patches.count(crc) == 1)
// use a crc of 0 for default patches
const std::string_view crc_str(n.key().str, n.key().len);
const std::optional<u32> crc = (StringUtil::compareNoCase(crc_str, "default")) ? std::optional<u32>(0) : StringUtil::FromChars<u32>(crc_str, 16);
if (!crc.has_value())
{
Console.Error(fmt::format("[GameDB] Duplicate CRC '{}' found for serial: '{}'. Skipping, CRCs are case-insensitive!", crc, serial));
Console.Error(fmt::format("[GameDB] Invalid CRC '{}' found for serial: '{}'. Skipping!", crc_str, serial));
continue;
}
GameDatabaseSchema::Patch patch;
if (n.has_child("content"))
if (gameEntry.patches.find(crc.value()) != gameEntry.patches.end())
{
std::string patchLines;
n["content"] >> patchLines;
patch = StringUtil::splitOnNewLine(patchLines);
Console.Error(fmt::format("[GameDB] Duplicate CRC '{}' found for serial: '{}'. Skipping, CRCs are case-insensitive!", crc_str, serial));
continue;
}
gameEntry.patches[crc] = patch;
std::string patch;
if (n.has_child("content"))
n["content"] >> patch;
gameEntry.patches.emplace(crc.value(), std::move(patch));
}
}

View File

@ -86,8 +86,6 @@ namespace GameDatabaseSchema
Count
};
using Patch = std::vector<std::string>;
struct GameEntry
{
std::string name;
@ -101,11 +99,11 @@ namespace GameDatabaseSchema
std::vector<std::pair<SpeedhackId, int>> speedHacks;
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
std::vector<std::string> memcardFilters;
std::unordered_map<std::string, Patch> patches;
std::unordered_map<u32, std::string> patches;
// Returns the list of memory card serials as a `/` delimited string
std::string memcardFiltersAsString() const;
const Patch* findPatch(const std::string_view& crc) const;
const std::string* findPatch(u32 crc) const;
const char* compatAsString() const;
/// Applies Core game fixes to an existing config. Returns the number of applied fixes.

View File

@ -120,23 +120,11 @@ static void inifile_command(const std::string& cmd)
/*int code = */ PatchTableExecute(key, value, commands_patch);
}
// This routine loads patches from the game database (but not the config/game fixes/hacks)
// Returns number of patches loaded
int LoadPatchesFromGamesDB(const std::string& crc, const GameDatabaseSchema::GameEntry& game)
int LoadPatchesFromString(const std::string& patches)
{
const GameDatabaseSchema::Patch* patch = game.findPatch(crc);
if (patch)
{
for (const std::string& line : *patch)
inifile_command(line);
}
const size_t before = Patch.size();
return Patch.size();
}
static void inifile_processString(const std::string& inStr)
{
std::istringstream ss(inStr);
std::istringstream ss(patches);
std::string line;
while (std::getline(ss, line))
{
@ -144,6 +132,8 @@ static void inifile_processString(const std::string& inStr)
if (!line.empty())
inifile_command(line);
}
return static_cast<int>(Patch.size() - before);
}
void ForgetLoadedPatches()
@ -162,18 +152,13 @@ int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_da
if (!zf)
return 0;
const int before = Patch.size();
const std::string pnach_filename(crc + ".pnach");
std::optional<std::string> pnach_data(ReadFileInZipToString(zf.get(), pnach_filename.c_str()));
if (!pnach_data.has_value())
return 0;
PatchesCon->WriteLn(Color_Green, "Loading patch '%s' from archive.", pnach_filename.c_str());
inifile_processString(pnach_data.value());
return Patch.size() - before;
return LoadPatchesFromString(pnach_data.value());
}
@ -198,7 +183,7 @@ int LoadPatchesFromDir(const std::string& crc, const wxDirName& folder, const ch
friendly_name, folder.ToUTF8().data(), crc.c_str());
}
const size_t before_all = Patch.size();
int total_loaded = 0;
for (const FILESYSTEM_FIND_DATA& fd : files)
{
@ -209,17 +194,13 @@ int LoadPatchesFromDir(const std::string& crc, const wxDirName& folder, const ch
if (!pnach_data.has_value())
continue;
const size_t before = Patch.size();
inifile_processString(pnach_data.value());
const size_t loaded = Patch.size() - before;
PatchesCon->WriteLn((loaded ? Color_Green : Color_Gray), "Loaded %zu %s from '%.*s'.",
const int loaded = LoadPatchesFromString(pnach_data.value());
PatchesCon->WriteLn((loaded ? Color_Green : Color_Gray), "Loaded %d %s from '%.*s'.",
loaded, friendly_name, static_cast<int>(name.size()), name.data());
}
const size_t loaded = Patch.size() - before_all;
PatchesCon->WriteLn((loaded ? Color_Green : Color_Gray), "Overall %zu %s loaded", loaded, friendly_name);
return loaded;
PatchesCon->WriteLn((total_loaded ? Color_Green : Color_Gray), "Overall %d %s loaded", total_loaded, friendly_name);
return total_loaded;
}
// PatchFunc Functions.

View File

@ -107,7 +107,7 @@ namespace PatchFunc
// The following LoadPatchesFrom* functions:
// - do not reset/unload previously loaded patches (use ForgetLoadedPatches() for that)
// - do not actually patch the emulation memory (that happens at ApplyLoadedPatches(...) )
extern int LoadPatchesFromGamesDB(const std::string& crc, const GameDatabaseSchema::GameEntry& game);
extern int LoadPatchesFromString(const std::string& patches);
extern int LoadPatchesFromDir(const std::string& crc, const wxDirName& folder, const char* friendly_name, bool show_error_when_missing);
extern int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_data_size);

View File

@ -337,7 +337,8 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool
if (EmuConfig.EnablePatches)
{
const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(s_game_serial);
if (game && (patch_count = LoadPatchesFromGamesDB(crc_string, *game)) > 0)
const std::string* patches = game ? game->findPatch(s_game_crc) : nullptr;
if (patches && (patch_count = LoadPatchesFromString(*patches)) > 0)
{
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patch_count);
message.Write("%u game patches", patch_count);

View File

@ -391,10 +391,12 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
if (fixup.EnablePatches)
{
if (int patches = LoadPatchesFromGamesDB(GameInfo::gameCRC.ToStdString(), *game))
const std::string* patches = ingame ? game->findPatch(ElfCRC) : 0;
int numPatches;
if (patches && (numPatches = LoadPatchesFromString(*patches)) > 0)
{
gamePatch.Printf(L" [%d Patches]", patches);
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patches);
gamePatch.Printf(L" [%d Patches]", numPatches);
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", numPatches);
}
}
if (int fixes = loadGameSettings(fixup, *game))