Fully implement hash-based database lookup. Fix some bugs that caused startup crashes in previous revisions of mine.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3273 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-06-22 18:57:48 +00:00
parent f3ae10f5c3
commit 24ae022a74
17 changed files with 239 additions and 211 deletions

View File

@ -208,7 +208,7 @@ public:
hash_key_t operator()( const wxString& src ) const
{
return Hash( (const char *)src.data(), src.length() * sizeof( wchar_t ) );
return Hash( (const char *)src.data(), src.length() * sizeof( wxChar ) );
}
// Returns a hashcode for a character.
@ -555,12 +555,12 @@ public:
/// matter, don't use this class at all! Use the string-specialized classes <see cref="Dictionary" /> and
/// <see cref="UnicodeDictionary" />.
/// </remarks>
template< class Key, class T >
class HashMap : public google::dense_hash_map<Key, T, CommonHashClass>
template< class Key, class T, class HashFunctor=CommonHashClass >
class HashMap : public google::dense_hash_map<Key, T, HashFunctor>
{
DeclareNoncopyableObject( HashMap );
typedef typename google::dense_hash_map<Key, T, CommonHashClass> _parent;
typedef typename google::dense_hash_map<Key, T, HashFunctor> _parent;
public:
using _parent::operator[];
@ -577,7 +577,7 @@ public:
/// are *not* used as actual values in the set.
/// </remarks>
HashMap( const Key& emptyKey, const Key& deletedKey, int initialCapacity=33 ) :
google::dense_hash_map<Key, T, CommonHashClass>( initialCapacity )
google::dense_hash_map<Key, T, HashFunctor>( initialCapacity )
{
set_empty_key( emptyKey );
set_deleted_key( deletedKey );
@ -653,14 +653,14 @@ public:
}
template< class T >
class pxDictionary : public HashTools::HashMap<wxString, T>
template< class T, class HashFunctor=HashTools::CommonHashClass >
class pxDictionary : public HashTools::HashMap<wxString, T, HashFunctor>
{
public:
virtual ~pxDictionary() {}
pxDictionary( int initialCapacity=33, const wxString& emptyKey = L"@@-EMPTY-@@", const wxString& deletedKey = L"@@-DELETED-@@" )
: HashTools::HashMap<wxString, T>( emptyKey, deletedKey, initialCapacity)
: HashTools::HashMap<wxString, T, HashFunctor>( emptyKey, deletedKey, initialCapacity)
{
}
};

View File

@ -29,7 +29,11 @@
#include "ps2/BiosTools.h"
#include "GameDatabase.h"
wxString DiscID;
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
// If the disc is homebrew then it probably won't have a valid serial; in which case
// this string will be empty.
wxString DiscSerial;
static cdvdStruct cdvd;
@ -340,9 +344,9 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
if (!fname)
fname = elfpath.AfterLast(':');
if (fname.Matches(L"????_???.??*"))
DiscID = fname(0,4) + L"-" + fname(5,3) + fname(9,2);
DiscSerial = fname(0,4) + L"-" + fname(5,3) + fname(9,2);
Console.WriteLn("Disc ID = %s", DiscID.ToUTF8().data());
Console.WriteLn("Disc ID = %s", DiscSerial.ToUTF8().data());
elfptr = loadElf(elfpath);
ElfCRC = elfptr->getCRC();
@ -355,18 +359,13 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
// Set the Game DataBase to the correct game based on Game Serial Code...
if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) {
wxString gameSerial = DiscID;
if (gameSerial.IsEmpty()) { // Search for crc if no Serial Code
gameSerial = wxsFormat( L"%8.8x", ElfCRC );
}
wxString gameSerial( SysGetDiscID() );
wxString serialMsg;
if(!DiscID.IsEmpty())
serialMsg = L"serial=" + DiscID + L" ";
if(!DiscSerial.IsEmpty())
serialMsg = L"serial=" + DiscSerial + L" ";
//Game_Data CurrentGame;
//if (GameDB->getGame(CurrentGame, gameSerial))
if (GameDB->setGame(gameSerial))
Game_Data game;
if (GameDB->findGame(game, gameSerial))
{
Console.WriteLn(L"(GameDB) Found Game! %s [CRC=%8.8x]", serialMsg.c_str(), ElfCRC );
// [TODO] Display lots of other info from the database here!
@ -416,14 +415,14 @@ void cdvdReadKey(u8 arg0, u16 arg1, u32 arg2, u8* key)
cdvdReloadElfInfo();
// convert the number characters to a real 32 bit number
numbers = StrToS32(DiscID(5,5));
numbers = StrToS32(DiscSerial(5,5));
// combine the lower 7 bits of each char
// to make the 4 letters fit into a single u32
letters = (s32)((DiscID[3]&0x7F)<< 0) |
(s32)((DiscID[2]&0x7F)<< 7) |
(s32)((DiscID[1]&0x7F)<<14) |
(s32)((DiscID[0]&0x7F)<<21);
letters = (s32)((DiscSerial[3]&0x7F)<< 0) |
(s32)((DiscSerial[2]&0x7F)<< 7) |
(s32)((DiscSerial[1]&0x7F)<<14) |
(s32)((DiscSerial[0]&0x7F)<<21);
// calculate magic numbers
key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80

View File

@ -145,4 +145,4 @@ extern void cdvdWrite(u8 key, u8 rt);
extern void cdvdReloadElfInfo(wxString elfoverride = wxEmptyString);
extern wxString DiscID;
extern wxString DiscSerial;

View File

@ -18,89 +18,88 @@
// Sets the current game to the one matching the serial id given
// Returns true if game found, false if not found...
bool BaseGameDatabaseVector::setGame(const wxString& id) {
bool BaseGameDatabaseImpl::findGame(Game_Data& dest, const wxString& id) {
GameDataHash::const_iterator iter( gHash.find(id) );
if( iter == gHash.end() ) {
curGame = NULL;
dest.clear();
return false;
}
curGame = &gList[iter->second];
dest = gList[iter->second];
return true;
}
Game_Data* BaseGameDatabaseVector::createNewGame(const wxString& id) {
gList.push_back(Game_Data(id));
gHash[id] = gList.size()-1;
curGame = &(gList.end()-1)[0];
return curGame;
void BaseGameDatabaseImpl::addNewGame(const Game_Data& game)
{
gList.push_back(game);
gHash[game.id] = gList.size()-1;
}
void BaseGameDatabaseImpl::updateGame(const Game_Data& game)
{
GameDataHash::const_iterator iter( gHash.find(game.id) );
if( iter == gHash.end() ) {
gList.push_back(game);
gHash[game.id] = gList.size()-1;
}
else
{
// Re-assign existing vector/array entry!
gList[gHash[game.id]] = game;
}
}
// Searches the current game's data to see if the given key exists
bool BaseGameDatabaseVector::keyExists(const wxChar* key) {
if (curGame) {
KeyPairArray::iterator it( curGame->kList.begin() );
for ( ; it != curGame->kList.end(); ++it) {
bool Game_Data::keyExists(const wxChar* key) {
KeyPairArray::iterator it( kList.begin() );
for ( ; it != kList.end(); ++it) {
if (it[0].CompareKey(key)) {
return true;
}
}
}
else Console.Error("(GameDB) Game not set!");
return false;
}
// Totally Deletes the specified key/pair value from the current game's data
void BaseGameDatabaseVector::deleteKey(const wxChar* key) {
if (curGame) {
KeyPairArray::iterator it( curGame->kList.begin() );
for ( ; it != curGame->kList.end(); ++it) {
void Game_Data::deleteKey(const wxChar* key) {
KeyPairArray::iterator it( kList.begin() );
for ( ; it != kList.end(); ++it) {
if (it[0].CompareKey(key)) {
curGame->kList.erase(it);
kList.erase(it);
return;
}
}
}
else Console.Error("(GameDB) Game not set!");
}
// Gets a string representation of the 'value' for the given key
wxString BaseGameDatabaseVector::getString(const wxChar* key) {
if (curGame) {
KeyPairArray::iterator it( curGame->kList.begin() );
for ( ; it != curGame->kList.end(); ++it) {
wxString Game_Data::getString(const wxChar* key) {
KeyPairArray::iterator it( kList.begin() );
for ( ; it != kList.end(); ++it) {
if (it[0].CompareKey(key)) {
return it[0].value;
}
}
}
else Console.Error("(GameDB) Game not set!");
return wxString();
}
void BaseGameDatabaseVector::writeString(const wxString& key, const wxString& value) {
if (key.CmpNoCase(m_baseKey) == 0)
curGame = createNewGame(value);
if (curGame) {
KeyPairArray::iterator it( curGame->kList.begin() );
for ( ; it != curGame->kList.end(); ++it) {
void Game_Data::writeString(const wxString& key, const wxString& value) {
KeyPairArray::iterator it( kList.begin() );
for ( ; it != kList.end(); ++it) {
if (it[0].CompareKey(key)) {
if( value.IsEmpty() )
curGame->kList.erase(it);
kList.erase(it);
else
it[0].value = value;
return;
}
}
if( !value.IsEmpty() ) {
curGame->kList.push_back(key_pair(key, value));
kList.push_back(key_pair(key, value));
}
}
else Console.Error("(GameDB) Game not set!");
}
// Write a bool value to the specified key
void BaseGameDatabaseVector::writeBool(const wxString& key, bool value) {
void Game_Data::writeBool(const wxString& key, bool value) {
writeString(key, value ? L"1" : L"0");
}

View File

@ -15,14 +15,14 @@
#pragma once
#include "Common.h"
//#include "Common.h"
#include "AppConfig.h"
#include "Utilities/HashMap.h"
#include <wx/wfstream.h>
struct key_pair;
class Game_Data;
struct Game_Data;
typedef std::vector<key_pair> KeyPairArray;
@ -70,48 +70,41 @@ struct key_pair {
}
};
class Game_Data {
public:
// --------------------------------------------------------------------------------------
// Game_Data
// --------------------------------------------------------------------------------------
// This container is more or less required to be a simple struct (POD classification) --
// no virtuals and no inheritance. This is because it is used in a std::vector, so POD
// makes things... smoother.
struct Game_Data
{
wxString id; // Serial Identification Code
KeyPairArray kList; // List of all (key, value) pairs for game data
public:
Game_Data(const wxString& _id = wxEmptyString)
: id(_id) {}
void NewSerial( const wxString& _id ) {
id = _id;
// Performs a case-insensitive compare of two IDs, returns TRUE if the IDs match
// or FALSE if the ids differ in a case-insensitive way.
bool CompareId( const wxString& _id ) const {
return id.CmpNoCase(_id) == 0;
}
void clear() {
id.clear();
kList.clear();
}
bool keyExists(const wxChar* key);
void deleteKey(const wxChar* key);
wxString getString(const wxChar* key);
void writeString(const wxString& key, const wxString& value);
void writeBool(const wxString& key, bool value);
bool IsOk() const {
return !id.IsEmpty();
}
// Performs a case-insensitive compare of two IDs, returns TRUE if the IDs match
// or FALSE if the ids differ in a case-insensitive way.
bool CompareId( const wxString& _id ) const
{
return id.CmpNoCase(_id) == 0;
}
};
// --------------------------------------------------------------------------------------
// IGameDatabase
// --------------------------------------------------------------------------------------
class IGameDatabase
{
public:
virtual ~IGameDatabase() throw() {}
virtual wxString getBaseKey() const=0;
virtual bool gameLoaded()=0;
virtual bool setGame(const wxString& id)=0;
virtual Game_Data* createNewGame(const wxString& id=wxEmptyString)=0;
virtual bool keyExists(const wxChar* key)=0;
virtual void deleteKey(const wxChar* key)=0;
virtual wxString getString(const wxChar* key)=0;
bool sectionExists(const wxChar* key, const wxString& value) {
return keyExists(wxsFormat(L"[%s%s%s]", key, value.IsEmpty() ? L"" : L" = ", value.c_str()));
}
@ -154,57 +147,62 @@ public:
bool getBool(const char* key) {
return getBool(fromUTF8(key));
}
};
// Writes a string of data associated with the specified key to the current
// game database. If the key being written is the baseKey, then a new slot is
// created to account for it, or the existing slot is set as the current game.
//
virtual void writeString(const wxString& key, const wxString& value)=0;
virtual void writeBool(const wxString& key, bool value)=0;
// --------------------------------------------------------------------------------------
// IGameDatabase
// --------------------------------------------------------------------------------------
class IGameDatabase
{
public:
virtual ~IGameDatabase() throw() {}
virtual wxString getBaseKey() const=0;
virtual bool findGame(Game_Data& dest, const wxString& id)=0;
virtual void addNewGame(const Game_Data& game)=0;
virtual void updateGame(const Game_Data& game)=0;
};
class StringHashNoCase
{
public:
StringHashNoCase() {}
HashTools::hash_key_t operator()( const wxString& src ) const
{
return HashTools::Hash( (const char *)src.Lower().data(), src.length() * sizeof( wxChar ) );
}
};
typedef std::vector<Game_Data> GameDataArray;
typedef pxDictionary<int> GameDataHash;
typedef pxDictionary<int,StringHashNoCase> GameDataHash;
// --------------------------------------------------------------------------------------
// BaseGameDatabaseVector
// BaseGameDatabaseImpl
// --------------------------------------------------------------------------------------
// [TODO] Create a version of this that uses google hashsets; should be several magnitudes
// faster that way.
class BaseGameDatabaseVector : public IGameDatabase
class BaseGameDatabaseImpl : public IGameDatabase
{
public:
GameDataArray gList; // List of all game data
GameDataHash gHash; // hash table of game serials matched to their gList indexes!
Game_Data* curGame; // Current game data (index into gList)
wxString m_baseKey;
public:
BaseGameDatabaseVector()
BaseGameDatabaseImpl()
{
curGame = NULL;
m_baseKey = L"Serial";
}
virtual ~BaseGameDatabaseVector() throw() {}
virtual ~BaseGameDatabaseImpl() throw() {}
wxString getBaseKey() const { return m_baseKey; }
void setBaseKey( const wxString& key ) { m_baseKey = key; }
// Returns true if a game is currently loaded into the database
// Returns false if otherwise (this means you need to call setGame()
// or it could mean the game was not found in the database at all...)
bool gameLoaded() {
return curGame != NULL;
}
bool setGame(const wxString& id);
Game_Data* createNewGame(const wxString& id=wxEmptyString);
bool keyExists(const wxChar* key);
void deleteKey(const wxChar* key);
wxString getString(const wxChar* key);
void writeString(const wxString& key, const wxString& value);
void writeBool(const wxString& key, bool value);
bool findGame(Game_Data& dest, const wxString& id);
void addNewGame(const Game_Data& game);
void updateGame(const Game_Data& game);
};
extern IGameDatabase* AppHost_GetGameDatabase();

View File

@ -139,13 +139,14 @@ int InitPatches(const wxString& name)
if (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
{
if(GameDB->gameLoaded()) {
if (GameDB->sectionExists(L"patches", name)) {
patch = GameDB->getSection(L"patches", name);
Game_Data game;
if (GameDB->findGame(game,name)) {
if (game.sectionExists(L"patches", name)) {
patch = game.getSection(L"patches", name);
patchFound = true;
}
else if (GameDB->keyExists(L"[patches]")) {
patch = GameDB->getString(L"[patches]");
else if (game.keyExists(L"[patches]")) {
patch = game.getString(L"[patches]");
patchFound = true;
}
}

View File

@ -88,7 +88,7 @@ void cpuReset()
g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
ElfCRC = 0;
DiscID = L"";
DiscSerial = L"";
ElfEntry = -1;
LastELF = L"";
}

View File

@ -24,6 +24,7 @@
// cleaning up these things.
#include "sVU_zerorec.h"
#include "GameDatabase.h"
#include "Elfheader.h"
extern void closeNewVif(int idx);
extern void resetNewVif(int idx);
@ -434,3 +435,20 @@ u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
}
return Mem;
}
// This function always returns a valid DiscID -- using the Sony serial when possible, and
// falling back on the CRC checksum of the ELF binary if the PS2 software being run is
// homebrew or some other serial-less item.
wxString SysGetDiscID()
{
if( !DiscSerial.IsEmpty() ) return DiscSerial;
if( !ElfCRC )
{
// FIXME: If the system is currently running the BIOS, it should return a serial based on
// the BIOS being run (either a checksum of the BIOS roms, and/or a string based on BIOS
// region and revision).
}
return wxsFormat( L"%8.8x", ElfCRC );
}

View File

@ -67,11 +67,12 @@ extern SysCoreAllocations& GetSysCoreAlloc();
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame );
extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
extern wxString SysGetDiscID();
// --------------------------------------------------------------------------------------
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
// --------------------------------------------------------------------------------------

View File

@ -176,13 +176,14 @@ void AppCoreThread::OnResumeReady()
static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
if (!gameDB) gameDB = wxGetApp().GetGameDatabase();
if (!gameDB->gameLoaded()) return 0;
Game_Data game;
if (!gameDB->findGame(game, SysGetDiscID())) return 0;
int gf = 0;
if (gameDB->keyExists("eeRoundMode"))
if (game.keyExists("eeRoundMode"))
{
SSE_RoundMode eeRM = (SSE_RoundMode)gameDB->getInt("eeRoundMode");
SSE_RoundMode eeRM = (SSE_RoundMode)game.getInt("eeRoundMode");
if (EnumIsValid(eeRM))
{
Console.WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
@ -191,9 +192,9 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
}
}
if (gameDB->keyExists("vuRoundMode"))
if (game.keyExists("vuRoundMode"))
{
SSE_RoundMode vuRM = (SSE_RoundMode)gameDB->getInt("vuRoundMode");
SSE_RoundMode vuRM = (SSE_RoundMode)game.getInt("vuRoundMode");
if (EnumIsValid(vuRM))
{
Console.WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
@ -202,8 +203,8 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
}
}
if (gameDB->keyExists("eeClampMode")) {
int clampMode = gameDB->getInt("eeClampMode");
if (game.keyExists("eeClampMode")) {
int clampMode = game.getInt("eeClampMode");
Console.WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
dest.Recompiler.fpuOverflow = (clampMode >= 1);
dest.Recompiler.fpuExtraOverflow = (clampMode >= 2);
@ -211,8 +212,8 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
gf++;
}
if (gameDB->keyExists("vuClampMode")) {
int clampMode = gameDB->getInt("vuClampMode");
if (game.keyExists("vuClampMode")) {
int clampMode = game.getInt("vuClampMode");
Console.WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
dest.Recompiler.vuOverflow = (clampMode >= 1);
dest.Recompiler.vuExtraOverflow = (clampMode >= 2);
@ -225,9 +226,9 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
wxString key( EnumToString(id) );
key += L"Hack";
if (gameDB->keyExists(key))
if (game.keyExists(key))
{
bool enableIt = gameDB->getBool(key);
bool enableIt = game.getBool(key);
dest.Gamefixes.Set(id, enableIt );
Console.WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled" );
gf++;
@ -252,14 +253,15 @@ void AppCoreThread::ApplySettings( const Pcsx2Config& src )
wxString gameCompat;
if (ElfCRC) gameCRC.Printf( L"%8.8x", ElfCRC );
if (!DiscID.IsEmpty()) gameSerial = L" [" + DiscID + L"]";
if (!DiscSerial.IsEmpty()) gameSerial = L" [" + DiscSerial + L"]";
if (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
{
if (GameDB->gameLoaded()) {
int compat = GameDB->getInt("Compat");
gameName = GameDB->getString("Name");
gameName += L" (" + GameDB->getString("Region") + L")";
Game_Data game;
if (GameDB->findGame(game, SysGetDiscID())) {
int compat = game.getInt("Compat");
gameName = game.getString("Name");
gameName += L" (" + game.getString("Region") + L")";
gameCompat = L" [Status = "+compatToStringWX(compat)+L"]";
}

View File

@ -118,10 +118,14 @@ wxString DBLoaderHelper::ReadHeader()
void DBLoaderHelper::ReadGames()
{
Game_Data* game = m_gamedb.createNewGame();
Game_Data game;
if (m_keyPair.IsOk())
m_gamedb.writeString( m_keyPair.key, m_keyPair.value );
{
game.writeString(m_keyPair.key, m_keyPair.value);
if( m_keyPair.CompareKey(m_gamedb.getBaseKey()) )
game.id = m_keyPair.value;
}
while(!m_reader.Eof()) { // Fill game data, find new game, repeat...
pxReadLine(m_reader, m_dest, m_intermediate);
@ -132,7 +136,13 @@ void DBLoaderHelper::ReadGames()
if (!extractMultiLine()) extract();
if (!m_keyPair.IsOk()) continue;
m_gamedb.writeString( m_keyPair.key, m_keyPair.value );
if( m_keyPair.CompareKey(m_gamedb.getBaseKey()) )
{
m_gamedb.addNewGame(game);
game.clear();
game.id = m_keyPair.value;
}
game.writeString( m_keyPair.key, m_keyPair.value );
}
}
@ -161,8 +171,6 @@ AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& file, const wxStr
header = loader.ReadHeader();
loader.ReadGames();
curGame = NULL;
return *this;
}

View File

@ -39,7 +39,7 @@
// GameDatabase class's methods to get the other key's values.
// Such as dbLoader.getString("Region") returns "NTSC-U"
class AppGameDatabase : public BaseGameDatabaseVector
class AppGameDatabase : public BaseGameDatabaseImpl
{
protected:
wxString header; // Header of the database

View File

@ -30,6 +30,8 @@ void GSPanel::InitDefaultAccelerators()
typedef KeyAcceleratorCode AAC;
if( !m_Accels ) m_Accels = new AcceleratorDictionary;
m_Accels->Map( AAC( WXK_F1 ), "States_FreezeCurrentSlot" );
m_Accels->Map( AAC( WXK_F3 ), "States_DefrostCurrentSlot");
m_Accels->Map( AAC( WXK_F2 ), "States_CycleSlotForward" );

View File

@ -366,7 +366,7 @@ namespace Panels
void AppStatusEvent_OnSettingsApplied();
protected:
void PopulateFields();
void PopulateFields( const wxString& serial=wxEmptyString );
bool WriteFieldsToDB();
void Search_Click( wxCommandEvent& evt );
};

View File

@ -18,7 +18,7 @@
#include "AppGameDatabase.h"
#include "ConfigurationPanels.h"
extern wxString DiscID;
extern wxString DiscSerial;
using namespace pxSizerFlags;
#define blankLine() { \
@ -43,7 +43,6 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags =
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent )
{
//if (!GameDB) GameDB = new GameDatabase();
IGameDatabase* GameDB = AppHost_GetGameDatabase();
pxAssume( GameDB != NULL );
@ -96,33 +95,36 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
PopulateFields();
}
void Panels::GameDatabasePanel::PopulateFields() {
void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) {
IGameDatabase* GameDB = AppHost_GetGameDatabase();
if (!pxAssert(GameDB)) return;
if (GameDB->gameLoaded()) {
serialBox ->SetLabel(GameDB->getString("Serial"));
nameBox ->SetLabel(GameDB->getString("Name"));
regionBox ->SetLabel(GameDB->getString("Region"));
compatBox ->SetLabel(GameDB->getString("Compat"));
commentBox->SetLabel(GameDB->getString("[comments]"));
patchesBox->SetLabel(GameDB->getString("[patches]"));
Game_Data game;
if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id))
{
serialBox ->SetLabel(game.getString("Serial"));
nameBox ->SetLabel(game.getString("Name"));
regionBox ->SetLabel(game.getString("Region"));
compatBox ->SetLabel(game.getString("Compat"));
commentBox->SetLabel(game.getString("[comments]"));
patchesBox->SetLabel(game.getString("[patches]"));
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
{
wxString keyName (EnumToString(i)); keyName += L"Hack";
if( GameDB->keyExists(keyName) )
gameFixes[i]->SetValue(GameDB->getBool(keyName));
if( game.keyExists(keyName) )
gameFixes[i]->SetValue(game.getBool(keyName));
else
gameFixes[i]->SetIndeterminate();
}
}
else {
serialBox ->SetLabel(L"");
nameBox ->SetLabel(L"");
regionBox ->SetLabel(L"");
compatBox ->SetLabel(L"");
commentBox->SetLabel(L"");
patchesBox->SetLabel(L"");
serialBox ->SetLabel(wxEmptyString);
nameBox ->SetLabel(wxEmptyString);
regionBox ->SetLabel(wxEmptyString);
compatBox ->SetLabel(wxEmptyString);
commentBox->SetLabel(wxEmptyString);
patchesBox->SetLabel(wxEmptyString);
for (int i = 0; i < GamefixId_COUNT; i++) {
gameFixes[i]->SetValue(0);
}
@ -137,40 +139,39 @@ void Panels::GameDatabasePanel::PopulateFields() {
// returns True if the database is modified, or FALSE if no changes to save.
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
IGameDatabase* GameDB = AppHost_GetGameDatabase();
if (!GameDB) return false;
if (serialBox->GetValue().IsEmpty()) return false;
// Only write the serial if its been changed
if( !GameDB->setGame(serialBox->GetValue()) )
GameDB->writeString(L"Serial", serialBox->GetValue());
Game_Data game;
GameDB->findGame(game, serialBox->GetValue());
GameDB->writeString(L"Name", nameBox->GetValue());
GameDB->writeString(L"Region", regionBox->GetValue());
GameDB->writeString(L"Compat", compatBox->GetValue());
GameDB->writeString(L"[comments]", commentBox->GetValue());
GameDB->writeString(L"[patches]", patchesBox->GetValue());
game.id = serialBox->GetValue();
game.writeString(L"Serial", serialBox->GetValue());
game.writeString(L"Name", nameBox->GetValue());
game.writeString(L"Region", regionBox->GetValue());
game.writeString(L"Compat", compatBox->GetValue());
game.writeString(L"[comments]", commentBox->GetValue());
game.writeString(L"[patches]", patchesBox->GetValue());
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
wxString keyName (EnumToString(i)); keyName += L"Hack";
if (gameFixes[i]->IsIndeterminate())
GameDB->deleteKey(keyName);
game.deleteKey(keyName);
else
GameDB->writeBool(keyName, gameFixes[i]->GetValue());
game.writeBool(keyName, gameFixes[i]->GetValue());
}
GameDB->updateGame(game);
return true;
}
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
IGameDatabase* GameDB = AppHost_GetGameDatabase();
wxString wxStr = serialBox->GetValue();
if( !GameDB ) return;
if( wxStr.IsEmpty() ) wxStr = DiscID;
bool bySerial = 1;//searchType->GetSelection()==0;
if (bySerial) GameDB->setGame(wxStr);
PopulateFields();
PopulateFields( serialBox->GetValue() );
evt.Skip();
}

View File

@ -119,7 +119,6 @@ typedef signed long long int64;
// directx
//#include <ddraw.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3d9.h>