mirror of https://github.com/PCSX2/pcsx2.git
GameDB: Add new GameDB implementation
vendor new yaml file, this one is OUT OF DATE! Resolve a slew of compiler errors Down to just the weird _Target_ usage in 5900.cpp
This commit is contained in:
parent
03445d0b55
commit
675a60b3d4
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -14,63 +14,128 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
BaseGameDatabaseImpl::BaseGameDatabaseImpl()
|
#include "yaml-cpp/yaml.h"
|
||||||
: gHash( 9900 )
|
|
||||||
, m_baseKey( L"Serial" )
|
std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString()
|
||||||
{
|
{
|
||||||
}
|
if (memcardFilters.empty())
|
||||||
|
return "";
|
||||||
|
|
||||||
// Sets the current game to the one matching the serial id given
|
std::string filters;
|
||||||
// Returns true if game found, false if not found...
|
for (int i = 0; i < memcardFilters.size(); i++)
|
||||||
bool BaseGameDatabaseImpl::findGame(Game_Data& dest, const wxString& id) {
|
|
||||||
|
|
||||||
GameDataHash::const_iterator iter( gHash.find(id) );
|
|
||||||
if( iter == gHash.end() ) {
|
|
||||||
dest.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
dest = iter->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game_Data* BaseGameDatabaseImpl::createNewGame( const wxString& id )
|
|
||||||
{
|
{
|
||||||
return &gHash.emplace(id, Game_Data{id}).first->second;
|
std::string f = memcardFilters.at(i);
|
||||||
|
filters.append(f);
|
||||||
|
if (i != memcardFilters.size() - 1)
|
||||||
|
filters.append(",");
|
||||||
|
}
|
||||||
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches the current game's data to see if the given key exists
|
/// TODO - the following helper functions can realistically be put in some sort of general yaml utility library
|
||||||
bool Game_Data::keyExists(const wxString& key) const {
|
// TODO - might be a way to condense this with templates? get it working first
|
||||||
for (auto it = kList.begin(); it != kList.end(); ++it) {
|
std::string YamlGameDatabaseImpl::safeGetString(const YAML::Node& n, std::string key, std::string def)
|
||||||
if (it->CompareKey(key)) {
|
{
|
||||||
return true;
|
if (!n[key])
|
||||||
|
return def;
|
||||||
|
// TODO - test this safety consideration (parse a value that isn't actually a string
|
||||||
|
return n[key].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int YamlGameDatabaseImpl::safeGetInt(const YAML::Node& n, std::string key, int def)
|
||||||
|
{
|
||||||
|
if (!n[key])
|
||||||
|
return def;
|
||||||
|
// TODO - test this safety consideration (parse a value that isn't actually an int
|
||||||
|
return n[key].as<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> YamlGameDatabaseImpl::safeGetStringList(const YAML::Node& n, std::string key, std::vector<std::string> def)
|
||||||
|
{
|
||||||
|
if (!n[key])
|
||||||
|
return def;
|
||||||
|
// TODO - test this safety consideration (parse a value that isn't actually a string
|
||||||
|
return n[key].as<std::vector<std::string>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const YAML::Node& node)
|
||||||
|
{
|
||||||
|
GameDatabaseSchema::GameEntry entry;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
entry.name = safeGetString(node, "name");
|
||||||
|
entry.region = safeGetString(node, "region");
|
||||||
|
entry.compat = static_cast<GameDatabaseSchema::Compatibility>(safeGetInt(node, "compat"));
|
||||||
|
entry.eeRoundMode = static_cast<GameDatabaseSchema::RoundMode>(safeGetInt(node, "eeRoundMode"));
|
||||||
|
entry.vuRoundMode = static_cast<GameDatabaseSchema::RoundMode>(safeGetInt(node, "vuRoundMode"));
|
||||||
|
entry.eeClampMode = static_cast<GameDatabaseSchema::ClampMode>(safeGetInt(node, "eeClampMode"));
|
||||||
|
entry.vuClampMode = static_cast<GameDatabaseSchema::ClampMode>(safeGetInt(node, "vuClampMode"));
|
||||||
|
entry.gameFixes = safeGetStringList(node, "gameFixes");
|
||||||
|
entry.speedHacks = safeGetStringList(node, "speedHacks");
|
||||||
|
entry.memcardFilters = safeGetStringList(node, "memcardFilters");
|
||||||
|
|
||||||
|
if (YAML::Node patches = node["patches"])
|
||||||
|
{
|
||||||
|
for (YAML::const_iterator it = patches.begin(); it != patches.end(); ++it)
|
||||||
|
{
|
||||||
|
YAML::Node key = it->first;
|
||||||
|
YAML::Node val = it->second;
|
||||||
|
GameDatabaseSchema::PatchCollection patchCol;
|
||||||
|
patchCol.author = safeGetString(val, "author");
|
||||||
|
patchCol.patchLines = safeGetStringList(val, "patchLines");
|
||||||
|
entry.patches[key.as<std::string>()] = patchCol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
entry.isValid = false;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::findGame(const std::string serial)
|
||||||
|
{
|
||||||
|
if (gameDb.count(serial) == 1)
|
||||||
|
return gameDb[serial];
|
||||||
|
|
||||||
|
GameDatabaseSchema::GameEntry entry;
|
||||||
|
entry.isValid = false;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
int YamlGameDatabaseImpl::numGames()
|
||||||
|
{
|
||||||
|
return gameDb.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// yaml-cpp definitely takes longer to parse this giant file, but the library feels more mature
|
||||||
|
// rapidyaml exists and I have it mostly setup in another branch which could be easily dropped in as a replacement if needed
|
||||||
|
//
|
||||||
|
// the problem i ran into with rapidyaml is there is a lack of usage/documentation as it's new
|
||||||
|
// and i didn't like the default way it handles exceptions (seemed to be configurable, but i didn't have much luck)
|
||||||
|
|
||||||
|
bool YamlGameDatabaseImpl::initDatabase(const std::string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// yaml-cpp has memory leak issues, convert to a map and throw it away!
|
||||||
|
YAML::Node data = YAML::LoadFile(filePath);
|
||||||
|
for (YAML::const_iterator entry = data.begin(); entry != data.end(); entry++)
|
||||||
|
{
|
||||||
|
// TODO - helper function to throw an error gracefully if an entry is malformed
|
||||||
|
std::string serial = entry->first.as<std::string>();
|
||||||
|
gameDb[serial] = entryFromYaml(entry->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
// TODO - error log
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a string representation of the 'value' for the given key
|
return true;
|
||||||
wxString Game_Data::getString(const wxString& key) const {
|
|
||||||
for (auto it = kList.begin(); it != kList.end(); ++it) {
|
|
||||||
if (it->CompareKey(key)) {
|
|
||||||
return it->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wxString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game_Data::writeString(const wxString& key, const wxString& value) {
|
|
||||||
for (auto it = kList.begin(); it != kList.end(); ++it) {
|
|
||||||
if (it->CompareKey(key)) {
|
|
||||||
if( value.IsEmpty() )
|
|
||||||
kList.erase(it);
|
|
||||||
else
|
|
||||||
it->value = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( !value.IsEmpty() ) {
|
|
||||||
kList.push_back(key_pair(key, value));
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -15,8 +15,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//#include "Common.h"
|
#include "yaml-cpp/yaml.h"
|
||||||
#include "AppConfig.h"
|
|
||||||
|
// TODO - config - is this still required? not needed on our integration branch
|
||||||
|
|
||||||
// _Target_ is defined by R300A.h and R5900.h and the definition leaks to here.
|
// _Target_ is defined by R300A.h and R5900.h and the definition leaks to here.
|
||||||
// The problem, at least with Visual Studio 2019 on Windows,
|
// The problem, at least with Visual Studio 2019 on Windows,
|
||||||
|
@ -24,138 +25,118 @@
|
||||||
// parameter. Unless we undef it here, the build breaks with a cryptic error message.
|
// parameter. Unless we undef it here, the build breaks with a cryptic error message.
|
||||||
#undef _Target_
|
#undef _Target_
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <wx/wfstream.h>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
struct key_pair;
|
// Since this is kinda yaml specific, might be a good idea to
|
||||||
struct Game_Data;
|
// relocate this into the yaml class
|
||||||
|
// or put the serialization methods inside the yaml
|
||||||
struct StringHash
|
class GameDatabaseSchema
|
||||||
{
|
{
|
||||||
std::size_t operator()( const wxString& src ) const
|
public:
|
||||||
|
enum class Compatibility
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
Unknown = 0,
|
||||||
return std::hash<std::wstring>{}(src.ToStdWstring());
|
Nothing,
|
||||||
#else
|
Intro,
|
||||||
return std::hash<std::string>{}({src.utf8_str()});
|
Menu,
|
||||||
#endif
|
InGame,
|
||||||
}
|
Playable,
|
||||||
|
Perfect
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class RoundMode
|
||||||
typedef std::vector<key_pair> KeyPairArray;
|
|
||||||
|
|
||||||
struct key_pair {
|
|
||||||
wxString key;
|
|
||||||
wxString value;
|
|
||||||
|
|
||||||
key_pair() {}
|
|
||||||
key_pair(const wxString& _key, const wxString& _value)
|
|
||||||
: key(_key) , value(_value) {}
|
|
||||||
|
|
||||||
void Clear() {
|
|
||||||
key.clear();
|
|
||||||
value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performs case-insensitive compare against the key value.
|
|
||||||
bool CompareKey( const wxString& cmpto ) const {
|
|
||||||
return key.CmpNoCase(cmpto) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsOk() const {
|
|
||||||
return !key.IsEmpty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// Game_Data
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
struct Game_Data
|
|
||||||
{
|
{
|
||||||
wxString id; // Serial Identification Code
|
Nearest = 0,
|
||||||
KeyPairArray kList; // List of all (key, value) pairs for game data
|
NegativeInfinity,
|
||||||
|
PositiveInfinity,
|
||||||
Game_Data(const wxString& _id = wxEmptyString)
|
ChopZero
|
||||||
: id(_id) {}
|
};
|
||||||
|
|
||||||
// Performs a case-insensitive compare of two IDs, returns TRUE if the IDs match
|
enum class ClampMode
|
||||||
// or FALSE if the ids differ in a case-insensitive way.
|
{
|
||||||
bool CompareId( const wxString& _id ) const {
|
Disabled = 0,
|
||||||
return id.CmpNoCase(_id) == 0;
|
Normal,
|
||||||
}
|
Extra,
|
||||||
|
Full
|
||||||
void clear() {
|
};
|
||||||
id.clear();
|
|
||||||
kList.clear();
|
// No point in using enums because i need to convert from a string then
|
||||||
}
|
// left here incase i turn these into lists to validate against
|
||||||
|
/*enum class GameFix
|
||||||
bool keyExists(const wxString& key) const;
|
{
|
||||||
wxString getString(const wxString& key) const;
|
VuAddSubHack = 0,
|
||||||
void writeString(const wxString& key, const wxString& value);
|
FpuCompareHack,
|
||||||
|
FpuMulHack,
|
||||||
bool IsOk() const {
|
FpuNegDivHack,
|
||||||
return !id.IsEmpty();
|
XgKickHack,
|
||||||
}
|
IPUWaitHack,
|
||||||
|
EETimingHack,
|
||||||
bool sectionExists(const wxString& key, const wxString& value) const {
|
SkipMPEGHack,
|
||||||
return keyExists("[" + key + (value.empty() ? "" : " = ") + value + "]");
|
OPHFLagHack,
|
||||||
}
|
DMABusyHack,
|
||||||
|
VIFFIFOHack,
|
||||||
wxString getSection(const wxString& key, const wxString& value) const {
|
VIF1StallHack,
|
||||||
return getString("[" + key + (value.empty() ? "" : " = ") + value + "]");
|
GIFFIFOHack,
|
||||||
}
|
FMVinSoftwareHack,
|
||||||
|
ScarfaceIbitHack,
|
||||||
// Gets an integer representation of the 'value' for the given key
|
CrashTagTeamRacingIbit,
|
||||||
int getInt(const wxString& key) const {
|
VU0KickstartHack,
|
||||||
unsigned long val;
|
};
|
||||||
getString(key).ToULong(&val);
|
|
||||||
return val;
|
enum class SpeedHacks
|
||||||
}
|
{
|
||||||
|
mvuFlagSpeedHack = 0
|
||||||
// Gets a u8 representation of the 'value' for the given key
|
};*/
|
||||||
u8 getU8(const wxString& key) const {
|
|
||||||
return (u8)wxAtoi(getString(key));
|
struct PatchCollection
|
||||||
}
|
{
|
||||||
|
std::string author;
|
||||||
// Gets a bool representation of the 'value' for the given key
|
std::vector<std::string> patchLines;
|
||||||
bool getBool(const wxString& key) const {
|
};
|
||||||
return !!wxAtoi(getString(key));
|
|
||||||
}
|
struct GameEntry
|
||||||
|
{
|
||||||
|
bool isValid = true;
|
||||||
|
std::string name;
|
||||||
|
std::string region;
|
||||||
|
Compatibility compat = Compatibility::Unknown;
|
||||||
|
RoundMode eeRoundMode = RoundMode::Nearest;
|
||||||
|
RoundMode vuRoundMode = RoundMode::Nearest;
|
||||||
|
ClampMode eeClampMode = ClampMode::Disabled;
|
||||||
|
ClampMode vuClampMode = ClampMode::Disabled;
|
||||||
|
std::vector<std::string> gameFixes;
|
||||||
|
std::vector<std::string> speedHacks;
|
||||||
|
std::vector<std::string> memcardFilters;
|
||||||
|
std::unordered_map<std::string, PatchCollection> patches;
|
||||||
|
|
||||||
|
std::string memcardFiltersAsString();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// IGameDatabase
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
class IGameDatabase
|
class IGameDatabase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IGameDatabase() = default;
|
virtual bool initDatabase(const std::string filePath) = 0;
|
||||||
|
virtual GameDatabaseSchema::GameEntry findGame(const std::string serial) = 0;
|
||||||
virtual wxString getBaseKey() const=0;
|
virtual int numGames() = 0;
|
||||||
virtual bool findGame(Game_Data& dest, const wxString& id)=0;
|
|
||||||
virtual Game_Data* createNewGame( const wxString& id )=0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using GameDataHash = std::unordered_map<wxString, Game_Data, StringHash>;
|
class YamlGameDatabaseImpl : public IGameDatabase
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// BaseGameDatabaseImpl
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
class BaseGameDatabaseImpl : public IGameDatabase
|
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
GameDataHash gHash; // hash table of game serials matched to their gList indexes!
|
|
||||||
wxString m_baseKey;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseGameDatabaseImpl();
|
bool initDatabase(const std::string filePath) override;
|
||||||
virtual ~BaseGameDatabaseImpl() = default;
|
GameDatabaseSchema::GameEntry findGame(const std::string serial) override;
|
||||||
|
int numGames() override;
|
||||||
|
|
||||||
wxString getBaseKey() const { return m_baseKey; }
|
private:
|
||||||
void setBaseKey( const wxString& key ) { m_baseKey = key; }
|
std::unordered_map<std::string, GameDatabaseSchema::GameEntry> gameDb;
|
||||||
|
GameDatabaseSchema::GameEntry entryFromYaml(const YAML::Node& node);
|
||||||
|
|
||||||
bool findGame(Game_Data& dest, const wxString& id);
|
// TODO move these into a generic library
|
||||||
Game_Data* createNewGame( const wxString& id );
|
std::string safeGetString(const YAML::Node& n, std::string key, std::string def = "");
|
||||||
|
int safeGetInt(const YAML::Node& n, std::string key, int def = 0);
|
||||||
|
std::vector<std::string> safeGetStringList(const YAML::Node& n, std::string key, std::vector<std::string> def = {});
|
||||||
};
|
};
|
||||||
|
|
||||||
extern IGameDatabase* AppHost_GetGameDatabase();
|
extern IGameDatabase* AppHost_GetGameDatabase();
|
|
@ -27,6 +27,8 @@
|
||||||
#include <wx/dir.h>
|
#include <wx/dir.h>
|
||||||
#include <wx/txtstrm.h>
|
#include <wx/txtstrm.h>
|
||||||
#include <wx/zipstrm.h>
|
#include <wx/zipstrm.h>
|
||||||
|
#include <wx/wfstream.h>
|
||||||
|
#include <PathDefs.h>
|
||||||
|
|
||||||
// This is a declaration for PatchMemory.cpp::_ApplyPatch where we're (patch.cpp)
|
// This is a declaration for PatchMemory.cpp::_ApplyPatch where we're (patch.cpp)
|
||||||
// the only consumer, so it's not made public via Patch.h
|
// the only consumer, so it's not made public via Patch.h
|
||||||
|
@ -120,37 +122,31 @@ static void inifile_command(const wxString& cmd)
|
||||||
/*int code = */PatchTableExecute(set, commands_patch);
|
/*int code = */PatchTableExecute(set, commands_patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine receives a string containing patches, trims it,
|
|
||||||
// Then sends the command to be parsed.
|
|
||||||
void TrimPatches(wxString& s)
|
|
||||||
{
|
|
||||||
wxStringTokenizer tkn( s, L"\n" );
|
|
||||||
|
|
||||||
while(tkn.HasMoreTokens()) {
|
|
||||||
inifile_command(tkn.GetNextToken());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This routine loads patches from the game database (but not the config/game fixes/hacks)
|
// This routine loads patches from the game database (but not the config/game fixes/hacks)
|
||||||
// Returns number of patches loaded
|
// Returns number of patches loaded
|
||||||
int LoadPatchesFromGamesDB(const wxString& crc, const Game_Data& game)
|
int LoadPatchesFromGamesDB(const wxString& crc, const GameDatabaseSchema::GameEntry& game)
|
||||||
{
|
{
|
||||||
bool patchFound = false;
|
if (game.isValid)
|
||||||
wxString patch;
|
|
||||||
|
|
||||||
if (game.IsOk())
|
|
||||||
{
|
{
|
||||||
if (game.sectionExists(L"patches", crc)) {
|
GameDatabaseSchema::PatchCollection patchCollection;
|
||||||
patch = game.getSection(L"patches", crc);
|
if (game.patches.count(std::string(crc)) == 1)
|
||||||
patchFound = true;
|
{
|
||||||
}
|
patchCollection = game.patches.at(std::string(crc));
|
||||||
else if (game.keyExists(L"[patches]")) {
|
|
||||||
patch = game.getString(L"[patches]");
|
|
||||||
patchFound = true;
|
|
||||||
}
|
}
|
||||||
|
else if (game.patches.count("default") == 1)
|
||||||
|
{
|
||||||
|
patchCollection = game.patches.at("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patchFound) TrimPatches(patch);
|
if (patchCollection.patchLines.size() > 0)
|
||||||
|
{
|
||||||
|
for (auto line : patchCollection.patchLines)
|
||||||
|
{
|
||||||
|
inifile_command(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Patch.size();
|
return Patch.size();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
#include "Pcsx2Defs.h"
|
#include "Pcsx2Defs.h"
|
||||||
#include "SysForwardDefs.h"
|
#include "SysForwardDefs.h"
|
||||||
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
enum patch_cpu_type {
|
enum patch_cpu_type {
|
||||||
NO_CPU,
|
NO_CPU,
|
||||||
|
@ -102,7 +103,7 @@ namespace PatchFunc
|
||||||
// The following LoadPatchesFrom* functions:
|
// The following LoadPatchesFrom* functions:
|
||||||
// - do not reset/unload previously loaded patches (use ForgetLoadedPatches() for that)
|
// - do not reset/unload previously loaded patches (use ForgetLoadedPatches() for that)
|
||||||
// - do not actually patch the emulation memory (that happens at ApplyLoadedPatches(...) )
|
// - do not actually patch the emulation memory (that happens at ApplyLoadedPatches(...) )
|
||||||
extern int LoadPatchesFromGamesDB(const wxString& name, const Game_Data& game);
|
extern int LoadPatchesFromGamesDB(const wxString& crc, const GameDatabaseSchema::GameEntry& game);
|
||||||
extern int LoadPatchesFromDir(wxString name, const wxDirName& folderName, const wxString& friendlyName);
|
extern int LoadPatchesFromDir(wxString name, const wxDirName& folderName, const wxString& friendlyName);
|
||||||
extern int LoadPatchesFromZip(wxString gameCRC, const wxString& cheatsArchiveFilename);
|
extern int LoadPatchesFromZip(wxString gameCRC, const wxString& cheatsArchiveFilename);
|
||||||
|
|
||||||
|
|
|
@ -371,17 +371,17 @@ wxString InputRecording::resolveGameName()
|
||||||
const wxString gameKey(SysGetDiscID());
|
const wxString gameKey(SysGetDiscID());
|
||||||
if (!gameKey.IsEmpty())
|
if (!gameKey.IsEmpty())
|
||||||
{
|
{
|
||||||
if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
|
if (IGameDatabase* gameDB = AppHost_GetGameDatabase())
|
||||||
{
|
{
|
||||||
Game_Data game;
|
GameDatabaseSchema::GameEntry game = gameDB->findGame(std::string(gameKey));
|
||||||
if (GameDB->findGame(game, gameKey))
|
if (game.isValid)
|
||||||
{
|
{
|
||||||
gameName = game.getString("Name");
|
gameName = game.name;
|
||||||
gameName += L" (" + game.getString("Region") + L")";
|
gameName += L" (" + game.region + L")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !gameName.IsEmpty() ? gameName : Path::GetFilename(g_Conf->CurrentIso);
|
return !gameName.IsEmpty() ? gameName : (wxString)Path::GetFilename(g_Conf->CurrentIso);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,5 +23,3 @@ static const bool PCSX2_isReleaseVersion = 0;
|
||||||
class SysCoreThread;
|
class SysCoreThread;
|
||||||
|
|
||||||
class CpuInitializerSet;
|
class CpuInitializerSet;
|
||||||
|
|
||||||
struct Game_Data;
|
|
||||||
|
|
|
@ -243,91 +243,91 @@ void AppCoreThread::OnPauseDebug()
|
||||||
// Load Game Settings found in database
|
// Load Game Settings found in database
|
||||||
// (game fixes, round modes, clamp modes, etc...)
|
// (game fixes, round modes, clamp modes, etc...)
|
||||||
// Returns number of gamefixes set
|
// Returns number of gamefixes set
|
||||||
static int loadGameSettings(Pcsx2Config& dest, const Game_Data& game)
|
static int loadGameSettings(Pcsx2Config& dest, const GameDatabaseSchema::GameEntry& game)
|
||||||
{
|
{
|
||||||
if (!game.IsOk())
|
//if (!game.IsOk())
|
||||||
return 0;
|
// return 0;
|
||||||
|
|
||||||
int gf = 0;
|
//int gf = 0;
|
||||||
|
|
||||||
if (game.keyExists("eeRoundMode"))
|
//if (game.keyExists("eeRoundMode"))
|
||||||
{
|
//{
|
||||||
SSE_RoundMode eeRM = (SSE_RoundMode)game.getInt("eeRoundMode");
|
// SSE_RoundMode eeRM = (SSE_RoundMode)game.getInt("eeRoundMode");
|
||||||
if (EnumIsValid(eeRM))
|
// if (EnumIsValid(eeRM))
|
||||||
{
|
// {
|
||||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
// PatchesCon->WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
||||||
dest.Cpu.sseMXCSR.SetRoundMode(eeRM);
|
// dest.Cpu.sseMXCSR.SetRoundMode(eeRM);
|
||||||
++gf;
|
// ++gf;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (game.keyExists("vuRoundMode"))
|
//if (game.keyExists("vuRoundMode"))
|
||||||
{
|
//{
|
||||||
SSE_RoundMode vuRM = (SSE_RoundMode)game.getInt("vuRoundMode");
|
// SSE_RoundMode vuRM = (SSE_RoundMode)game.getInt("vuRoundMode");
|
||||||
if (EnumIsValid(vuRM))
|
// if (EnumIsValid(vuRM))
|
||||||
{
|
// {
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
// PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||||
dest.Cpu.sseVUMXCSR.SetRoundMode(vuRM);
|
// dest.Cpu.sseVUMXCSR.SetRoundMode(vuRM);
|
||||||
++gf;
|
// ++gf;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (game.keyExists("eeClampMode"))
|
//if (game.keyExists("eeClampMode"))
|
||||||
{
|
//{
|
||||||
int clampMode = game.getInt("eeClampMode");
|
// int clampMode = game.getInt("eeClampMode");
|
||||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
// PatchesCon->WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
||||||
dest.Cpu.Recompiler.fpuOverflow = (clampMode >= 1);
|
// dest.Cpu.Recompiler.fpuOverflow = (clampMode >= 1);
|
||||||
dest.Cpu.Recompiler.fpuExtraOverflow = (clampMode >= 2);
|
// dest.Cpu.Recompiler.fpuExtraOverflow = (clampMode >= 2);
|
||||||
dest.Cpu.Recompiler.fpuFullMode = (clampMode >= 3);
|
// dest.Cpu.Recompiler.fpuFullMode = (clampMode >= 3);
|
||||||
gf++;
|
// gf++;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (game.keyExists("vuClampMode"))
|
//if (game.keyExists("vuClampMode"))
|
||||||
{
|
//{
|
||||||
int clampMode = game.getInt("vuClampMode");
|
// int clampMode = game.getInt("vuClampMode");
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
|
// PatchesCon->WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
|
||||||
dest.Cpu.Recompiler.vuOverflow = (clampMode >= 1);
|
// dest.Cpu.Recompiler.vuOverflow = (clampMode >= 1);
|
||||||
dest.Cpu.Recompiler.vuExtraOverflow = (clampMode >= 2);
|
// dest.Cpu.Recompiler.vuExtraOverflow = (clampMode >= 2);
|
||||||
dest.Cpu.Recompiler.vuSignOverflow = (clampMode >= 3);
|
// dest.Cpu.Recompiler.vuSignOverflow = (clampMode >= 3);
|
||||||
gf++;
|
// gf++;
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
if (game.keyExists("mvuFlagSpeedHack"))
|
//if (game.keyExists("mvuFlagSpeedHack"))
|
||||||
{
|
//{
|
||||||
bool vuFlagHack = game.getInt("mvuFlagSpeedHack") ? 1 : 0;
|
// bool vuFlagHack = game.getInt("mvuFlagSpeedHack") ? 1 : 0;
|
||||||
PatchesCon->WriteLn("(GameDB) Changing mVU flag speed hack [mode=%d]", vuFlagHack);
|
// PatchesCon->WriteLn("(GameDB) Changing mVU flag speed hack [mode=%d]", vuFlagHack);
|
||||||
dest.Speedhacks.vuFlagHack = vuFlagHack;
|
// dest.Speedhacks.vuFlagHack = vuFlagHack;
|
||||||
gf++;
|
// gf++;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (game.keyExists("InstantVU1SpeedHack"))
|
//if (game.keyExists("InstantVU1SpeedHack"))
|
||||||
{
|
//{
|
||||||
bool vu1InstantHack = game.getInt("InstantVU1SpeedHack") ? 1 : 0;
|
// bool vu1InstantHack = game.getInt("InstantVU1SpeedHack") ? 1 : 0;
|
||||||
PatchesCon->WriteLn("(GameDB) Changing Instant VU1 speedhack [mode=%d]", vu1InstantHack);
|
// PatchesCon->WriteLn("(GameDB) Changing Instant VU1 speedhack [mode=%d]", vu1InstantHack);
|
||||||
dest.Speedhacks.vu1Instant = vu1InstantHack;
|
// dest.Speedhacks.vu1Instant = vu1InstantHack;
|
||||||
gf++;
|
// gf++;
|
||||||
}
|
//}
|
||||||
|
|
||||||
for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; ++id)
|
//for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; ++id)
|
||||||
{
|
//{
|
||||||
wxString key(EnumToString(id));
|
// wxString key(EnumToString(id));
|
||||||
key += L"Hack";
|
// key += L"Hack";
|
||||||
|
|
||||||
if (game.keyExists(key))
|
// if (game.keyExists(key))
|
||||||
{
|
// {
|
||||||
bool enableIt = game.getBool(key);
|
// bool enableIt = game.getBool(key);
|
||||||
dest.Gamefixes.Set(id, enableIt);
|
// dest.Gamefixes.Set(id, enableIt);
|
||||||
PatchesCon->WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled");
|
// PatchesCon->WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled");
|
||||||
gf++;
|
// gf++;
|
||||||
|
|
||||||
// The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB)
|
// // The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB)
|
||||||
if (id == Fix_GoemonTlbMiss && enableIt)
|
// if (id == Fix_GoemonTlbMiss && enableIt)
|
||||||
vtlb_Alloc_Ppmap();
|
// vtlb_Alloc_Ppmap();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
return gf;
|
//return gf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to track the current game serial/id, and used to disable verbose logging of
|
// Used to track the current game serial/id, and used to disable verbose logging of
|
||||||
|
@ -432,14 +432,13 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup)
|
||||||
{
|
{
|
||||||
if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
|
if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
|
||||||
{
|
{
|
||||||
Game_Data game;
|
GameDatabaseSchema::GameEntry game = GameDB->findGame(std::string(curGameKey));
|
||||||
if (GameDB->findGame(game, curGameKey))
|
if (game.isValid)
|
||||||
{
|
{
|
||||||
int compat = game.getInt("Compat");
|
gameName = game.name;
|
||||||
gameName = game.getString("Name");
|
gameName += L" (" + game.region + L")";
|
||||||
gameName += L" (" + game.getString("Region") + L")";
|
gameCompat = L" [Status = " + compatToStringWX(game.compat) + L"]";
|
||||||
gameCompat = L" [Status = " + compatToStringWX(compat) + L"]";
|
gameMemCardFilter = game.memcardFiltersAsString();
|
||||||
gameMemCardFilter = game.getString("MemCardFilter");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixup.EnablePatches)
|
if (fixup.EnablePatches)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -14,126 +14,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "App.h"
|
||||||
|
#include "AppGameDatabase.h"
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
#include "AppGameDatabase.h"
|
#include "AppGameDatabase.h"
|
||||||
#include <wx/stdpaths.h>
|
#include <wx/stdpaths.h>
|
||||||
|
#include "fmt/core.h"
|
||||||
|
|
||||||
class DBLoaderHelper
|
// TODO - check that this is being threaded properly, remove from
|
||||||
|
AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file)
|
||||||
{
|
{
|
||||||
DeclareNoncopyableObject( DBLoaderHelper );
|
// TODO - config - kill this with fire with std::filesystem
|
||||||
|
|
||||||
protected:
|
|
||||||
IGameDatabase& m_gamedb;
|
|
||||||
wxInputStream& m_reader;
|
|
||||||
|
|
||||||
// temp areas used as buffers for accelerated loading of database content. These strings are
|
|
||||||
// allocated and grown only once, and then reused for the duration of the database loading
|
|
||||||
// process; saving thousands of heapp allocation operations.
|
|
||||||
|
|
||||||
wxString m_dest;
|
|
||||||
std::string m_intermediate;
|
|
||||||
|
|
||||||
key_pair m_keyPair;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DBLoaderHelper( wxInputStream& reader, IGameDatabase& db )
|
|
||||||
: m_gamedb(db)
|
|
||||||
, m_reader(reader)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadGames();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void doError(const wxString& msg);
|
|
||||||
bool extractMultiLine();
|
|
||||||
void extract();
|
|
||||||
};
|
|
||||||
|
|
||||||
void DBLoaderHelper::doError(const wxString& msg) {
|
|
||||||
Console.Error(msg);
|
|
||||||
m_keyPair.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiline Sections are in the form of:
|
|
||||||
//
|
|
||||||
// [section=value]
|
|
||||||
// content
|
|
||||||
// content
|
|
||||||
// [/section]
|
|
||||||
//
|
|
||||||
// ... where the =value part is OPTIONAL.
|
|
||||||
bool DBLoaderHelper::extractMultiLine() {
|
|
||||||
|
|
||||||
if (m_dest[0] != L'[') return false; // All multiline sections begin with a '['!
|
|
||||||
|
|
||||||
if (!m_dest.EndsWith(L"]")) {
|
|
||||||
doError("GameDatabase: Malformed section start tag: " + m_dest);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_keyPair.key = m_dest;
|
|
||||||
|
|
||||||
// Use Mid() to strip off the left and right side brackets.
|
|
||||||
wxString midLine(m_dest.Mid(1, m_dest.Length()-2));
|
|
||||||
wxString lvalue(midLine.BeforeFirst(L'=').Trim(true).Trim(false));
|
|
||||||
wxString rvalue(midLine.AfterFirst(L'=').Trim(true).Trim(false));
|
|
||||||
|
|
||||||
wxString key = '[' + lvalue + (rvalue.empty() ? "" : " = ") + rvalue + ']';
|
|
||||||
if (key != m_keyPair.key)
|
|
||||||
Console.Warning("GameDB: Badly formatted section start tag.\nActual: " + m_keyPair.key + "\nExpected: " + key);
|
|
||||||
|
|
||||||
wxString endString;
|
|
||||||
endString.Printf( L"[/%s]", lvalue.c_str() );
|
|
||||||
|
|
||||||
while(!m_reader.Eof()) {
|
|
||||||
pxReadLine( m_reader, m_dest, m_intermediate );
|
|
||||||
// Abort if the closing tag is missing/incorrect so subsequent database entries aren't affected.
|
|
||||||
if (m_dest == "---------------------------------------------")
|
|
||||||
break;
|
|
||||||
if (m_dest.CmpNoCase(endString) == 0)
|
|
||||||
return true;
|
|
||||||
m_keyPair.value += m_dest + L"\n";
|
|
||||||
}
|
|
||||||
doError("GameDatabase: Missing or incorrect section end tag:\n" + m_keyPair.key + "\n" + m_keyPair.value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DBLoaderHelper::extract() {
|
|
||||||
|
|
||||||
if( !pxParseAssignmentString( m_dest, m_keyPair.key, m_keyPair.value ) ) return;
|
|
||||||
if( m_keyPair.value.IsEmpty() ) doError("GameDatabase: Bad file data: " + m_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DBLoaderHelper::ReadGames()
|
|
||||||
{
|
|
||||||
Game_Data* game = NULL;
|
|
||||||
|
|
||||||
while(!m_reader.Eof()) { // Fill game data, find new game, repeat...
|
|
||||||
pthread_testcancel();
|
|
||||||
pxReadLine(m_reader, m_dest, m_intermediate);
|
|
||||||
m_dest.Trim(true).Trim(false);
|
|
||||||
if( m_dest.IsEmpty() ) continue;
|
|
||||||
|
|
||||||
m_keyPair.Clear();
|
|
||||||
if (!extractMultiLine()) extract();
|
|
||||||
|
|
||||||
if (!m_keyPair.IsOk()) continue;
|
|
||||||
if (m_keyPair.CompareKey(m_gamedb.getBaseKey())) {
|
|
||||||
game = m_gamedb.createNewGame(m_keyPair.value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
game->writeString( m_keyPair.key, m_keyPair.value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// AppGameDatabase (implementations)
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file, const wxString& key )
|
|
||||||
{
|
|
||||||
wxString file(_file);
|
wxString file(_file);
|
||||||
if (wxFileName(file).IsRelative())
|
if (wxFileName(file).IsRelative())
|
||||||
{
|
{
|
||||||
|
@ -158,22 +52,20 @@ AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file, const wxSt
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFFileInputStream reader( file );
|
u64 qpc_Start = GetCPUTicks();
|
||||||
|
YamlGameDatabaseImpl gameDb = YamlGameDatabaseImpl();
|
||||||
|
|
||||||
if (!reader.IsOk())
|
// TODO - thread the load!
|
||||||
|
if (!gameDb.initDatabase(std::string(file)))
|
||||||
{
|
{
|
||||||
//throw Exception::FileNotFound( file );
|
Console.Error(L"(GameDB) Database could not be loaded successfully");
|
||||||
Console.Error(L"(GameDB) Could not access file (permission denied?) [%s]", WX_STR(file));
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBLoaderHelper loader( reader, *this );
|
|
||||||
|
|
||||||
u64 qpc_Start = GetCPUTicks();
|
|
||||||
loader.ReadGames();
|
|
||||||
u64 qpc_end = GetCPUTicks();
|
u64 qpc_end = GetCPUTicks();
|
||||||
|
|
||||||
Console.WriteLn( "(GameDB) %d games on record (loaded in %ums)",
|
Console.WriteLn(fmt::format("(GameDB) {} games on record (loaded in {}ms)", gameDb.numGames(),
|
||||||
gHash.size(), (u32)(((qpc_end-qpc_Start)*1000) / GetTickFrequency()) );
|
(u32)(((qpc_end - qpc_Start) * 1000) / GetTickFrequency())));
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -17,50 +17,39 @@
|
||||||
|
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
class AppGameDatabase : public YamlGameDatabaseImpl
|
||||||
// AppGameDatabase
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// This class extends BaseGameDatabase_Impl and provides interfaces for loading and saving
|
|
||||||
// the text-formatted game database.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// ---------------------------------------------
|
|
||||||
// Serial = SLUS-20486
|
|
||||||
// Name = Marvel vs. Capcom 2
|
|
||||||
// Region = NTSC-U
|
|
||||||
// ---------------------------------------------
|
|
||||||
//
|
|
||||||
// [-- separators are a standard part of the formatting]
|
|
||||||
//
|
|
||||||
|
|
||||||
// To Load this game data, use "Serial" as the initial Key
|
|
||||||
// then specify "SLUS-20486" as the value in the constructor.
|
|
||||||
// After the constructor loads the game data, you can use the
|
|
||||||
// GameDatabase class's methods to get the other key's values.
|
|
||||||
// Such as dbLoader.getString("Region") returns "NTSC-U"
|
|
||||||
|
|
||||||
class AppGameDatabase : public BaseGameDatabaseImpl
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AppGameDatabase() {}
|
AppGameDatabase() {}
|
||||||
virtual ~AppGameDatabase() {
|
virtual ~AppGameDatabase()
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
Console.WriteLn("(GameDB) Unloading...");
|
Console.WriteLn("(GameDB) Unloading...");
|
||||||
}
|
}
|
||||||
DESTRUCTOR_CATCHALL
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
AppGameDatabase& LoadFromFile(const wxString& file = Path::Combine( PathDefs::GetProgramDataDir(), wxFileName(L"GameIndex.dbf") ), const wxString& key = L"Serial" );
|
AppGameDatabase& LoadFromFile(const wxString& file = Path::Combine(PathDefs::GetProgramDataDir(), wxFileName(L"GameIndex.yaml")));
|
||||||
};
|
};
|
||||||
|
|
||||||
static wxString compatToStringWX(int compat) {
|
static wxString compatToStringWX(GameDatabaseSchema::Compatibility compat)
|
||||||
switch (compat) {
|
{
|
||||||
case 6: return L"Perfect";
|
switch (compat)
|
||||||
case 5: return L"Playable";
|
{
|
||||||
case 4: return L"In-Game";
|
case GameDatabaseSchema::Compatibility::Perfect:
|
||||||
case 3: return L"Menu";
|
return L"Perfect";
|
||||||
case 2: return L"Intro";
|
case GameDatabaseSchema::Compatibility::Playable:
|
||||||
case 1: return L"Nothing";
|
return L"Playable";
|
||||||
default: return L"Unknown";
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue