GameDatabase: Move out of gui

This commit is contained in:
Connor McLaughlin 2021-11-06 11:49:18 +10:00 committed by refractionpcsx2
parent 120ee6c673
commit 46912595ea
17 changed files with 157 additions and 364 deletions

View File

@ -900,7 +900,6 @@ set(pcsx2GuiSources
gui/AppConfig.cpp
gui/AppCoreThread.cpp
gui/AppEventSources.cpp
gui/AppGameDatabase.cpp
gui/AppHost.cpp
gui/AppUserMode.cpp
gui/AppInit.cpp
@ -977,7 +976,6 @@ set(pcsx2GuiHeaders
gui/AppCoreThread.h
gui/AppEventListeners.h
gui/AppForwardDefs.h
gui/AppGameDatabase.h
gui/App.h
gui/ApplyState.h
gui/AppSaveStates.h
@ -1498,9 +1496,7 @@ if (APPLE)
)
target_sources(PCSX2 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/gui/Resources/PCSX2.icns")
target_sources(PCSX2 PRIVATE "${CMAKE_SOURCE_DIR}/bin/GameIndex.yaml")
set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gui/Resources/PCSX2.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set_source_files_properties("${CMAKE_SOURCE_DIR}/bin/GameIndex.yaml" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Add in shaders and other resources.
file(GLOB resource_files "${CMAKE_SOURCE_DIR}/bin/resources/*")
@ -1559,5 +1555,5 @@ source_group(System/Ps2/USB REGULAR_EXPRESSION USB/*)
source_group(Resources/GUI FILES ${pcsx2GuiResources})
source_group(Resources/PAD FILES ${pcsx2PADResources})
source_group(Resources/Recording FILES ${pcsx2RecordingVirtualPadResources})
source_group(Resources FILES ../bin/GameIndex.yaml gui/Resources/PCSX2.icns)
source_group(Resources FILES gui/Resources/PCSX2.icns)
source_group(Resources REGULAR_EXPRESSION ${CMAKE_CURRENT_BINARY_DIR}/*)

View File

@ -16,54 +16,83 @@
#include "PrecompiledHeader.h"
#include "GameDatabase.h"
#include "Config.h"
#include "Host.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include "common/Timer.h"
#include "fmt/core.h"
#include "fmt/ranges.h"
#include "yaml-cpp/yaml.h"
#include <fstream>
#include <algorithm>
#include <mutex>
#include <thread>
std::string strToLower(std::string str)
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); });
[](unsigned char c) { return std::tolower(c); });
return str;
}
bool compareStrNoCase(const std::string str1, const std::string str2)
{
return std::equal(str1.begin(), str1.end(), str2.begin(),
[](char a, char b) {
return tolower(a) == tolower(b);
});
}
std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString() const
std::string GameDatabaseSchema::GameEntry::MemcardFiltersAsString() const
{
return fmt::to_string(fmt::join(memcardFilters, "/"));
}
bool GameDatabaseSchema::GameEntry::findPatch(const std::string crc, Patch& patch) const
const GameDatabaseSchema::Patch* GameDatabaseSchema::GameEntry::FindPatch(const std::string& crc) const
{
std::string crcLower = strToLower(crc);
const std::string crcLower(strToLower(crc));
Console.WriteLn(fmt::format("[GameDB] Searching for patch with CRC '{}'", crc));
if (patches.count(crcLower) == 1)
auto it = patches.find(crcLower);
if (it != patches.end())
{
Console.WriteLn(fmt::format("[GameDB] Found patch with CRC '{}'", crc));
patch = patches.at(crcLower);
return true;
return &it->second;
}
else if (patches.count("default") == 1)
it = patches.find("default");
if (it != patches.end())
{
Console.WriteLn("[GameDB] Found and falling back to default patch");
patch = patches.at("default");
return true;
return &it->second;
}
Console.WriteLn("[GameDB] No CRC-specific patch or default patch found");
return false;
return nullptr;
}
std::vector<std::string> YamlGameDatabaseImpl::convertMultiLineStringToVector(const std::string multiLineString)
const char* GameDatabaseSchema::compatToString(Compatibility compat)
{
switch (compat)
{
case GameDatabaseSchema::Compatibility::Perfect:
return "Perfect";
case GameDatabaseSchema::Compatibility::Playable:
return "Playable";
case GameDatabaseSchema::Compatibility::InGame:
return "In-Game";
case GameDatabaseSchema::Compatibility::Menu:
return "Menu";
case GameDatabaseSchema::Compatibility::Intro:
return "Intro";
case GameDatabaseSchema::Compatibility::Nothing:
return "Nothing";
default:
return "Unknown";
}
}
static std::vector<std::string> convertMultiLineStringToVector(const std::string& multiLineString)
{
std::vector<std::string> lines;
std::istringstream stream(multiLineString);
@ -77,7 +106,7 @@ std::vector<std::string> YamlGameDatabaseImpl::convertMultiLineStringToVector(co
return lines;
}
GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::string serial, const YAML::Node& node)
static bool parseAndInsert(std::string serial, const YAML::Node& node)
{
GameDatabaseSchema::GameEntry gameEntry;
try
@ -161,60 +190,38 @@ GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::str
}
YAML::Node patchNode = entry.second;
GameDatabaseSchema::Patch patchCol;
patchCol.author = patchNode["author"].as<std::string>("");
patchCol.patchLines = convertMultiLineStringToVector(patchNode["content"].as<std::string>(""));
gameEntry.patches[crc] = patchCol;
gameEntry.patches[crc] = convertMultiLineStringToVector(patchNode["content"].as<std::string>(""));
}
}
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));
gameEntry.isValid = false;
}
catch (const std::exception& e)
{
Console.Error(fmt::format("[GameDB] Unexpected error occurred when reading serial: '{}'. Error Details - {}", serial, e.what()));
gameEntry.isValid = false;
}
return gameEntry;
}
GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::findGame(const std::string serial)
{
std::string serialLower = strToLower(serial);
Console.WriteLn(fmt::format("[GameDB] Searching for '{}' in GameDB", serialLower));
if (gameDb.count(serialLower) == 1)
{
Console.WriteLn(fmt::format("[GameDB] Found '{}' in GameDB", serialLower));
return gameDb[serialLower];
}
Console.Error(fmt::format("[GameDB] Could not find '{}' in GameDB", serialLower));
GameDatabaseSchema::GameEntry entry;
entry.isValid = false;
return entry;
return false;
}
int YamlGameDatabaseImpl::numGames()
{
return gameDb.size();
}
bool YamlGameDatabaseImpl::initDatabase(std::ifstream& stream)
static bool LoadYamlFile()
{
try
{
if (!stream)
std::optional<std::string> file_data(Host::ReadResourceFileToString(GAMEDB_YAML_FILE_NAME));
if (!file_data.has_value())
{
Console.Error("[GameDB] Unable to open GameDB file.");
return false;
}
// 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(stream);
YAML::Node data = YAML::Load(file_data.value());
for (const auto& entry : data)
{
// we don't want to throw away the entire GameDB file if a single entry is made incorrectly,
@ -225,13 +232,13 @@ bool YamlGameDatabaseImpl::initDatabase(std::ifstream& stream)
// 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 (gameDb.count(serial) == 1)
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;
}
gameDb[serial] = entryFromYaml(serial, entry.second);
parseAndInsert(std::move(serial), entry.second);
}
catch (const YAML::RepresentationException& e)
{
@ -247,3 +254,36 @@ bool YamlGameDatabaseImpl::initDatabase(std::ifstream& stream)
return true;
}
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("[GameDB] %zu games on record (loaded in %.2fms)", s_game_db.size(), timer.GetTimeMilliseconds());
});
}
const GameDatabaseSchema::GameEntry* GameDatabase::FindGame(const std::string& serial)
{
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())
{
Console.Error("[GameDB] Could not find '%s' in GameDB", serialLower.c_str());
return nullptr;
}
Console.WriteLn("[GameDB] Found '%s' in GameDB", serialLower.c_str());
return &iter->second;
}

View File

@ -15,8 +15,6 @@
#pragma once
#include "yaml-cpp/yaml.h"
#include <unordered_map>
#include <vector>
#include <string>
@ -56,15 +54,10 @@ public:
Full
};
struct Patch
{
std::string author;
std::vector<std::string> patchLines;
};
using Patch = std::vector<std::string>;
struct GameEntry
{
bool isValid = true;
std::string name;
std::string region;
Compatibility compat = Compatibility::Unknown;
@ -78,33 +71,16 @@ public:
std::unordered_map<std::string, Patch> patches;
// Returns the list of memory card serials as a `/` delimited string
std::string memcardFiltersAsString() const;
bool findPatch(const std::string crc, Patch& patch) const;
std::string MemcardFiltersAsString() const;
const Patch* FindPatch(const std::string& crc) const;
};
static const char* compatToString(GameDatabaseSchema::Compatibility compat);
};
class IGameDatabase
namespace GameDatabase
{
public:
virtual bool initDatabase(std::ifstream& stream) = 0;
virtual GameDatabaseSchema::GameEntry findGame(const std::string serial) = 0;
virtual int numGames() = 0;
};
void EnsureLoaded();
class YamlGameDatabaseImpl : public IGameDatabase
{
public:
bool initDatabase(std::ifstream& stream) override;
GameDatabaseSchema::GameEntry findGame(const std::string serial) override;
int numGames() override;
private:
std::unordered_map<std::string, GameDatabaseSchema::GameEntry> gameDb;
GameDatabaseSchema::GameEntry entryFromYaml(const std::string serial, const YAML::Node& node);
std::vector<std::string> convertMultiLineStringToVector(const std::string multiLineString);
};
extern IGameDatabase* AppHost_GetGameDatabase();
extern std::string strToLower(std::string str);
extern bool compareStrNoCase(const std::string str1, const std::string str2);
const GameDatabaseSchema::GameEntry* FindGame(const std::string& serial);
}; // namespace GameDatabase

View File

@ -17,6 +17,7 @@
#define _PC_ // disables MIPS opcode macros.
#include "common/StringUtil.h"
#include "IopCommon.h"
#include "Patch.h"
#include "Config.h"
@ -129,19 +130,13 @@ static void inifile_command(const wxString& cmd)
// This routine loads patches from the game database (but not the config/game fixes/hacks)
// Returns number of patches loaded
int LoadPatchesFromGamesDB(const wxString& crc, const GameDatabaseSchema::GameEntry& game)
int LoadPatchesFromGamesDB(const std::string& crc, const GameDatabaseSchema::GameEntry& game)
{
if (game.isValid)
const GameDatabaseSchema::Patch* patch = game.FindPatch(crc);
if (patch)
{
GameDatabaseSchema::Patch patch;
bool patchFound = game.findPatch(std::string(crc.ToUTF8()), patch);
if (patchFound && patch.patchLines.size() > 0)
{
for (auto line : patch.patchLines)
{
inifile_command(fromUTF8(line));
}
}
for (const std::string& line : *patch)
inifile_command(StringUtil::UTF8StringToWxString(line));
}
return Patch.size();
@ -209,20 +204,19 @@ static int _LoadPatchFiles(const wxDirName& folderName, wxString& fileSpec, cons
// Returns number of patches loaded
// Note: does not reset previously loaded patches (use ForgetLoadedPatches() for that)
// Note: only load patches from the root folder of the zip
int LoadPatchesFromZip(wxString gameCRC, const wxString& patchesArchiveFilename)
int LoadPatchesFromZip(const wxString& gameCRC, const wxString& patchesArchiveFilename, wxInputStream* stream)
{
gameCRC.MakeUpper();
wxString upperGameCRC(gameCRC.Upper());
int before = Patch.size();
std::unique_ptr<wxZipEntry> entry;
wxFFileInputStream in(patchesArchiveFilename);
wxZipInputStream zip(in);
wxZipInputStream zip(stream);
while (entry.reset(zip.GetNextEntry()), entry.get() != NULL)
{
wxString name = entry->GetName();
name.MakeUpper();
if (name.Find(gameCRC) == 0 && name.Find(L".PNACH") + 6u == name.Length())
if (name.Find(upperGameCRC) == 0 && name.Find(L".PNACH") + 6u == name.Length())
{
PatchesCon->WriteLn(Color_Green, L"Loading patch '%s' from archive '%s'",
WX_STR(entry->GetName()), WX_STR(patchesArchiveFilename));
@ -240,7 +234,7 @@ int LoadPatchesFromZip(wxString gameCRC, const wxString& patchesArchiveFilename)
// This routine loads patches from *.pnach files
// Returns number of patches loaded
// Note: does not reset previously loaded patches (use ForgetLoadedPatches() for that)
int LoadPatchesFromDir(wxString name, const wxDirName& folderName, const wxString& friendlyName)
int LoadPatchesFromDir(const wxString& name, const wxDirName& folderName, const wxString& friendlyName)
{
int loaded = 0;
int numberFoundPatchFiles;
@ -250,7 +244,7 @@ int LoadPatchesFromDir(wxString name, const wxDirName& folderName, const wxStrin
if (folderName.ToString().IsSameAs(EmuFolders::Cheats.ToString()) && numberFoundPatchFiles == 0)
{
wxString pathName = Path::Combine(folderName, name.MakeUpper() + L".pnach");
wxString pathName = Path::Combine(folderName, name.Upper() + L".pnach");
PatchesCon->WriteLn(Color_Gray, L"Not found %s file: %s", WX_STR(friendlyName), WX_STR(pathName));
}

View File

@ -37,7 +37,9 @@
#include "common/Pcsx2Defs.h"
#include "SysForwardDefs.h"
#include "gui/AppGameDatabase.h"
#include "GameDatabase.h"
class wxInputStream;
enum patch_cpu_type {
NO_CPU,
@ -106,9 +108,9 @@ 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 wxString& crc, const GameDatabaseSchema::GameEntry& game);
extern int LoadPatchesFromDir(wxString name, const wxDirName& folderName, const wxString& friendlyName);
extern int LoadPatchesFromZip(wxString gameCRC, const wxString& cheatsArchiveFilename);
extern int LoadPatchesFromGamesDB(const std::string& crc, const GameDatabaseSchema::GameEntry& game);
extern int LoadPatchesFromDir(const wxString& name, const wxDirName& folderName, const wxString& friendlyName);
extern int LoadPatchesFromZip(const wxString& gameCRC, const wxString& patchesArchiveFilename, wxInputStream* stream);
// Patches the emulation memory by applying all the loaded patches with a specific place value.
// Note: unless you know better, there's no need to check whether or not different patch sources

View File

@ -15,18 +15,21 @@
#include "PrecompiledHeader.h"
#include "gui/AppSaveStates.h"
#include "common/StringUtil.h"
#include "Counters.h"
#include "SaveState.h"
#ifndef DISABLE_RECORDING
#include "gui/AppGameDatabase.h"
#include "GameDatabase.h"
#include "DebugTools/Debug.h"
#include "InputRecording.h"
#include "InputRecordingControls.h"
#include "Utilities/InputRecordingLogger.h"
#include "gui/AppSaveStates.h"
#include <fmt/format.h>
#endif
@ -448,21 +451,18 @@ void InputRecording::GoToFirstFrame(wxWindow* parent)
wxString InputRecording::resolveGameName()
{
// Code loosely taken from AppCoreThread::_ApplySettings to resolve the Game Name
wxString gameName;
const wxString gameKey(SysGetDiscID());
if (!gameKey.IsEmpty())
std::string gameName;
const std::string gameKey(StringUtil::wxStringToUTF8String(SysGetDiscID()));
if (!gameKey.empty())
{
if (IGameDatabase* gameDB = AppHost_GetGameDatabase())
const GameDatabaseSchema::GameEntry* game = GameDatabase::FindGame(gameKey);
if (game)
{
GameDatabaseSchema::GameEntry game = gameDB->findGame(std::string(gameKey.ToUTF8()));
if (game.isValid)
{
gameName = fromUTF8(game.name);
gameName += L" (" + fromUTF8(game.region) + L")";
}
gameName = game->name;
gameName += " (" + game->region + ")";
}
}
return !gameName.IsEmpty() ? gameName : (wxString)Path::GetFilename(g_Conf->CurrentIso);
return !gameName.empty() ? StringUtil::UTF8StringToWxString(gameName) : Path::GetFilename(g_Conf->CurrentIso);
}
#endif

View File

@ -279,7 +279,6 @@ public:
std::unique_ptr<wxIconBundle> IconBundle;
std::unique_ptr<wxBitmap> Bitmap_Logo;
std::unique_ptr<wxBitmap> ScreenshotBitmap;
std::unique_ptr<AppGameDatabase> GameDB;
pxAppResources();
virtual ~pxAppResources();
@ -592,7 +591,6 @@ public:
wxImageList& GetImgList_Toolbars();
const AppImageIds& GetImgId() const;
AppGameDatabase* GetGameDatabase();
// --------------------------------------------------------------------------
// Overrides of wxApp virtuals:

View File

@ -16,9 +16,10 @@
#include "PrecompiledHeader.h"
#include "App.h"
#include "AppSaveStates.h"
#include "AppGameDatabase.h"
#include "GameDatabase.h"
#include <wx/stdpaths.h>
#include <wx/wfstream.h>
#include "fmt/core.h"
#include "common/StringUtil.h"
@ -264,9 +265,6 @@ void AppCoreThread::OnPauseDebug()
// Returns number of gamefixes set
static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEntry& game)
{
if (!game.isValid)
return 0;
int gf = 0;
if (game.eeRoundMode != GameDatabaseSchema::RoundMode::Undefined)
@ -450,33 +448,29 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
if (!curGameKey.IsEmpty())
{
if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
const GameDatabaseSchema::GameEntry* game = GameDatabase::FindGame(StringUtil::wxStringToUTF8String(curGameKey));
if (game)
{
GameDatabaseSchema::GameEntry game = GameDB->findGame(std::string(curGameKey.ToUTF8()));
if (game.isValid)
{
GameInfo::gameName = fromUTF8(game.name);
GameInfo::gameName += L" (" + fromUTF8(game.region) + L")";
gameCompat = L" [Status = " + compatToStringWX(game.compat) + L"]";
gameMemCardFilter = fromUTF8(game.memcardFiltersAsString());
}
else
{
// Set correct title for loading standalone/homebrew ELFs
GameInfo::gameName = LastELF.AfterLast('\\');
}
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());
if (fixup.EnablePatches)
{
if (int patches = LoadPatchesFromGamesDB(GameInfo::gameCRC, game))
if (int patches = LoadPatchesFromGamesDB(GameInfo::gameCRC.ToStdString(), *game))
{
gamePatch.Printf(L" [%d Patches]", patches);
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patches);
}
if (int fixes = loadGameSettings(fixup, game))
if (int fixes = loadGameSettings(fixup, *game))
gameFixes.Printf(L" [%d Fixes]", fixes);
}
}
else
{
// Set correct title for loading standalone/homebrew ELFs
GameInfo::gameName = LastELF.AfterLast('\\');
}
}
if (!gameMemCardFilter.IsEmpty())
@ -516,9 +510,12 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
{
// No ws cheat files found at the cheats_ws folder, try the ws cheats zip file.
wxString cheats_ws_archive = Path::Combine(PathDefs::GetProgramDataDir(), wxFileName(L"cheats_ws.zip"));
int numberDbfCheatsLoaded = LoadPatchesFromZip(GameInfo::gameCRC, cheats_ws_archive);
PatchesCon->WriteLn(Color_Green, "(Wide Screen Cheats DB) Patches Loaded: %d", numberDbfCheatsLoaded);
gameWsHacks.Printf(L" [%d widescreen hacks]", numberDbfCheatsLoaded);
if (wxFile::Exists(cheats_ws_archive))
{
int numberDbfCheatsLoaded = LoadPatchesFromZip(GameInfo::gameCRC, cheats_ws_archive, new wxFFileInputStream(cheats_ws_archive));
PatchesCon->WriteLn(Color_Green, "(Wide Screen Cheats DB) Patches Loaded: %d", numberDbfCheatsLoaded);
gameWsHacks.Printf(L" [%d widescreen hacks]", numberDbfCheatsLoaded);
}
}
}

View File

@ -33,7 +33,6 @@ class PipeRedirectionBase;
class AppCoreThread;
class Pcsx2AppMethodEvent;
class pxAppResources;
class AppGameDatabase;
class IScopedCoreThread;
struct KeyAcceleratorCode;

View File

@ -1,96 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "App.h"
#include "AppGameDatabase.h"
#include <wx/stdpaths.h>
#include "fmt/core.h"
#include <fstream>
std::ifstream AppGameDatabase::getFileAsStream(const wxString& file)
{
// TODO - config - refactor with std::filesystem/ghc::filesystem
#ifdef _WIN32
return std::ifstream(file.wc_str());
#else
return std::ifstream(file.c_str());
#endif
}
AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file)
{
// TODO - config - refactor with std::filesystem/ghc::filesystem
wxString file(_file);
if (wxFileName(file).IsRelative())
{
// InstallFolder is the preferred base directory for the DB file, but the registry can point to previous
// installs if uninstall wasn't done properly.
// Since the games DB file is considered part of pcsx2.exe itself, look for it at the exe folder
// regardless of any other settings.
// Note 1: Portable setup didn't suffer from this as install folder pointed already to the exe folder in portable.
// Note 2: Other folders are either configurable (memcards, etc) or create their content automatically (inis)
// So the games DB was really the only one that suffers from residues of prior installs.
//wxDirName dir = InstallFolder;
wxDirName dir = (wxDirName)wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath();
file = (dir + file).GetFullPath();
}
if (!wxFileExists(file))
{
Console.Error(L"[GameDB] Database Not Found! [%s]", WX_STR(file));
return *this;
}
const u64 qpc_Start = GetCPUTicks();
std::ifstream fileStream = getFileAsStream(file);
if (!this->initDatabase(fileStream))
{
Console.Error(L"[GameDB] Database could not be loaded successfully");
return *this;
}
const u64 qpc_end = GetCPUTicks();
Console.WriteLn(fmt::format("[GameDB] {} games on record (loaded in {}ms)", this->numGames(),
(u32)(((qpc_end - qpc_Start) * 1000) / GetTickFrequency())));
return *this;
}
AppGameDatabase* Pcsx2App::GetGameDatabase()
{
pxAppResources& res(GetResourceCache());
ScopedLock lock(m_mtx_LoadingGameDB);
if (!res.GameDB)
{
res.GameDB = std::make_unique<AppGameDatabase>();
res.GameDB->LoadFromFile();
}
return res.GameDB.get();
}
IGameDatabase* AppHost_GetGameDatabase()
{
return wxGetApp().GetGameDatabase();
}

View File

@ -1,60 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "GameDatabase.h"
#include "AppConfig.h"
class AppGameDatabase : public YamlGameDatabaseImpl
{
public:
AppGameDatabase() {}
virtual ~AppGameDatabase()
{
try
{
Console.WriteLn("(GameDB) Unloading...");
}
DESTRUCTOR_CATCHALL
}
AppGameDatabase& LoadFromFile(const wxString& file = Path::Combine(PathDefs::GetProgramDataDir(), wxFileName(L"GameIndex.yaml")));
private:
std::ifstream getFileAsStream(const wxString& file);
};
static wxString compatToStringWX(GameDatabaseSchema::Compatibility compat)
{
switch (compat)
{
case GameDatabaseSchema::Compatibility::Perfect:
return L"Perfect";
case GameDatabaseSchema::Compatibility::Playable:
return L"Playable";
case GameDatabaseSchema::Compatibility::InGame:
return L"In-Game";
case GameDatabaseSchema::Compatibility::Menu:
return L"Menu";
case GameDatabaseSchema::Compatibility::Intro:
return L"Intro";
case GameDatabaseSchema::Compatibility::Nothing:
return L"Nothing";
default:
return L"Unknown";
}
}

View File

@ -352,47 +352,6 @@ bool Pcsx2App::OnCmdLineParsed(wxCmdLineParser& parser)
typedef void (wxEvtHandler::*pxInvokeAppMethodEventFunction)(Pcsx2AppMethodEvent&);
typedef void (wxEvtHandler::*pxStuckThreadEventHandler)(pxMessageBoxEvent&);
// --------------------------------------------------------------------------------------
// GameDatabaseLoaderThread
// --------------------------------------------------------------------------------------
class GameDatabaseLoaderThread : public pxThread, EventListener_AppStatus
{
typedef pxThread _parent;
public:
GameDatabaseLoaderThread()
: pxThread(L"GameDatabaseLoader")
{
}
virtual ~GameDatabaseLoaderThread()
{
try
{
_parent::Cancel();
}
DESTRUCTOR_CATCHALL
}
protected:
void ExecuteTaskInThread()
{
Sleep(2);
wxGetApp().GetGameDatabase();
}
void OnCleanupInThread()
{
_parent::OnCleanupInThread();
wxGetApp().DeleteThread(this);
}
void AppStatusEvent_OnExit()
{
Block();
}
};
bool Pcsx2App::OnInit()
{
EnableAllLogging();
@ -464,8 +423,6 @@ bool Pcsx2App::OnInit()
OpenMainFrame();
(new GameDatabaseLoaderThread())->Start();
// By default no IRX injection
EmuConfig.CurrentIRX.clear();

View File

@ -20,7 +20,6 @@
#include "GS.h"
#include "Host.h"
#include "AppSaveStates.h"
#include "AppGameDatabase.h"
#include "AppAccelerators.h"
#include "PAD/Gamepad.h"

View File

@ -15,7 +15,6 @@
#include "PrecompiledHeader.h"
#include "MainFrame.h"
#include "AppGameDatabase.h"
#include <wx/zipstrm.h>
#include <wx/wfstream.h>

View File

@ -307,7 +307,6 @@
<ClCompile Include="Gif_Unit.cpp" />
<ClCompile Include="GS\Renderers\DX11\D3D.cpp" />
<ClCompile Include="GS\Window\GSwxDialog.cpp" />
<ClCompile Include="gui\AppGameDatabase.cpp" />
<ClCompile Include="gui\AppHost.cpp" />
<ClCompile Include="gui\AppUserMode.cpp" />
<ClCompile Include="gui\CheckedStaticBox.cpp" />
@ -746,7 +745,6 @@
<ClInclude Include="Gif_Unit.h" />
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
<ClInclude Include="GS\Window\GSwxDialog.h" />
<ClInclude Include="gui\AppGameDatabase.h" />
<ClInclude Include="gui\CheckedStaticBox.h" />
<ClInclude Include="gui\i18n.h" />
<ClInclude Include="gui\DriveList.h" />

View File

@ -884,9 +884,6 @@
<ClCompile Include="gui\AppUserMode.cpp">
<Filter>AppHost</Filter>
</ClCompile>
<ClCompile Include="gui\AppGameDatabase.cpp">
<Filter>AppHost</Filter>
</ClCompile>
<ClCompile Include="gui\Dialogs\McdConfigDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
@ -2008,9 +2005,6 @@
<ClInclude Include="IPU\IPUdma.h">
<Filter>System\Ps2\IPU</Filter>
</ClInclude>
<ClInclude Include="gui\AppGameDatabase.h">
<Filter>AppHost</Filter>
</ClInclude>
<ClInclude Include="gui\i18n.h">
<Filter>AppHost</Filter>
</ClInclude>