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 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. // 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 /// matter, don't use this class at all! Use the string-specialized classes <see cref="Dictionary" /> and
/// <see cref="UnicodeDictionary" />. /// <see cref="UnicodeDictionary" />.
/// </remarks> /// </remarks>
template< class Key, class T > template< class Key, class T, class HashFunctor=CommonHashClass >
class HashMap : public google::dense_hash_map<Key, T, CommonHashClass> class HashMap : public google::dense_hash_map<Key, T, HashFunctor>
{ {
DeclareNoncopyableObject( HashMap ); DeclareNoncopyableObject( HashMap );
typedef typename google::dense_hash_map<Key, T, CommonHashClass> _parent; typedef typename google::dense_hash_map<Key, T, HashFunctor> _parent;
public: public:
using _parent::operator[]; using _parent::operator[];
@ -577,7 +577,7 @@ public:
/// are *not* used as actual values in the set. /// are *not* used as actual values in the set.
/// </remarks> /// </remarks>
HashMap( const Key& emptyKey, const Key& deletedKey, int initialCapacity=33 ) : 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_empty_key( emptyKey );
set_deleted_key( deletedKey ); set_deleted_key( deletedKey );
@ -653,14 +653,14 @@ public:
} }
template< class T > template< class T, class HashFunctor=HashTools::CommonHashClass >
class pxDictionary : public HashTools::HashMap<wxString, T> class pxDictionary : public HashTools::HashMap<wxString, T, HashFunctor>
{ {
public: public:
virtual ~pxDictionary() {} virtual ~pxDictionary() {}
pxDictionary( int initialCapacity=33, const wxString& emptyKey = L"@@-EMPTY-@@", const wxString& deletedKey = L"@@-DELETED-@@" ) 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 "ps2/BiosTools.h"
#include "GameDatabase.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; static cdvdStruct cdvd;
@ -340,9 +344,9 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
if (!fname) if (!fname)
fname = elfpath.AfterLast(':'); fname = elfpath.AfterLast(':');
if (fname.Matches(L"????_???.??*")) 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); elfptr = loadElf(elfpath);
ElfCRC = elfptr->getCRC(); 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... // Set the Game DataBase to the correct game based on Game Serial Code...
if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) { if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) {
wxString gameSerial = DiscID; wxString gameSerial( SysGetDiscID() );
if (gameSerial.IsEmpty()) { // Search for crc if no Serial Code
gameSerial = wxsFormat( L"%8.8x", ElfCRC );
}
wxString serialMsg; wxString serialMsg;
if(!DiscID.IsEmpty()) if(!DiscSerial.IsEmpty())
serialMsg = L"serial=" + DiscID + L" "; serialMsg = L"serial=" + DiscSerial + L" ";
//Game_Data CurrentGame; Game_Data game;
//if (GameDB->getGame(CurrentGame, gameSerial)) if (GameDB->findGame(game, gameSerial))
if (GameDB->setGame(gameSerial))
{ {
Console.WriteLn(L"(GameDB) Found Game! %s [CRC=%8.8x]", serialMsg.c_str(), ElfCRC ); Console.WriteLn(L"(GameDB) Found Game! %s [CRC=%8.8x]", serialMsg.c_str(), ElfCRC );
// [TODO] Display lots of other info from the database here! // [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(); cdvdReloadElfInfo();
// convert the number characters to a real 32 bit number // 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 // combine the lower 7 bits of each char
// to make the 4 letters fit into a single u32 // to make the 4 letters fit into a single u32
letters = (s32)((DiscID[3]&0x7F)<< 0) | letters = (s32)((DiscSerial[3]&0x7F)<< 0) |
(s32)((DiscID[2]&0x7F)<< 7) | (s32)((DiscSerial[2]&0x7F)<< 7) |
(s32)((DiscID[1]&0x7F)<<14) | (s32)((DiscSerial[1]&0x7F)<<14) |
(s32)((DiscID[0]&0x7F)<<21); (s32)((DiscSerial[0]&0x7F)<<21);
// calculate magic numbers // calculate magic numbers
key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80 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 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 // Sets the current game to the one matching the serial id given
// Returns true if game found, false if not found... // 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) ); GameDataHash::const_iterator iter( gHash.find(id) );
if( iter == gHash.end() ) { if( iter == gHash.end() ) {
curGame = NULL; dest.clear();
return false; return false;
} }
curGame = &gList[iter->second]; dest = gList[iter->second];
return true; return true;
} }
Game_Data* BaseGameDatabaseVector::createNewGame(const wxString& id) { void BaseGameDatabaseImpl::addNewGame(const Game_Data& game)
gList.push_back(Game_Data(id)); {
gHash[id] = gList.size()-1; gList.push_back(game);
curGame = &(gList.end()-1)[0]; gHash[game.id] = gList.size()-1;
return curGame; }
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 // Searches the current game's data to see if the given key exists
bool BaseGameDatabaseVector::keyExists(const wxChar* key) { bool Game_Data::keyExists(const wxChar* key) {
if (curGame) { KeyPairArray::iterator it( kList.begin() );
KeyPairArray::iterator it( curGame->kList.begin() ); for ( ; it != kList.end(); ++it) {
for ( ; it != curGame->kList.end(); ++it) { if (it[0].CompareKey(key)) {
if (it[0].CompareKey(key)) { return true;
return true;
}
} }
} }
else Console.Error("(GameDB) Game not set!");
return false; return false;
} }
// Totally Deletes the specified key/pair value from the current game's data // Totally Deletes the specified key/pair value from the current game's data
void BaseGameDatabaseVector::deleteKey(const wxChar* key) { void Game_Data::deleteKey(const wxChar* key) {
if (curGame) { KeyPairArray::iterator it( kList.begin() );
KeyPairArray::iterator it( curGame->kList.begin() ); for ( ; it != kList.end(); ++it) {
for ( ; it != curGame->kList.end(); ++it) { if (it[0].CompareKey(key)) {
if (it[0].CompareKey(key)) { kList.erase(it);
curGame->kList.erase(it); return;
return;
}
} }
} }
else Console.Error("(GameDB) Game not set!");
} }
// Gets a string representation of the 'value' for the given key // Gets a string representation of the 'value' for the given key
wxString BaseGameDatabaseVector::getString(const wxChar* key) { wxString Game_Data::getString(const wxChar* key) {
if (curGame) { KeyPairArray::iterator it( kList.begin() );
KeyPairArray::iterator it( curGame->kList.begin() ); for ( ; it != kList.end(); ++it) {
for ( ; it != curGame->kList.end(); ++it) { if (it[0].CompareKey(key)) {
if (it[0].CompareKey(key)) { return it[0].value;
return it[0].value;
}
} }
} }
else Console.Error("(GameDB) Game not set!");
return wxString(); return wxString();
} }
void BaseGameDatabaseVector::writeString(const wxString& key, const wxString& value) { void Game_Data::writeString(const wxString& key, const wxString& value) {
if (key.CmpNoCase(m_baseKey) == 0) KeyPairArray::iterator it( kList.begin() );
curGame = createNewGame(value); for ( ; it != kList.end(); ++it) {
if (it[0].CompareKey(key)) {
if (curGame) { if( value.IsEmpty() )
KeyPairArray::iterator it( curGame->kList.begin() ); kList.erase(it);
for ( ; it != curGame->kList.end(); ++it) { else
if (it[0].CompareKey(key)) { it[0].value = value;
if( value.IsEmpty() ) return;
curGame->kList.erase(it);
else
it[0].value = value;
return;
}
}
if( !value.IsEmpty() ) {
curGame->kList.push_back(key_pair(key, value));
} }
} }
else Console.Error("(GameDB) Game not set!"); if( !value.IsEmpty() ) {
kList.push_back(key_pair(key, value));
}
} }
// Write a bool value to the specified key // 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"); writeString(key, value ? L"1" : L"0");
} }

View File

@ -15,14 +15,14 @@
#pragma once #pragma once
#include "Common.h" //#include "Common.h"
#include "AppConfig.h" #include "AppConfig.h"
#include "Utilities/HashMap.h" #include "Utilities/HashMap.h"
#include <wx/wfstream.h> #include <wx/wfstream.h>
struct key_pair; struct key_pair;
class Game_Data; struct Game_Data;
typedef std::vector<key_pair> KeyPairArray; 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 wxString id; // Serial Identification Code
KeyPairArray kList; // List of all (key, value) pairs for game data KeyPairArray kList; // List of all (key, value) pairs for game data
public:
Game_Data(const wxString& _id = wxEmptyString) Game_Data(const wxString& _id = wxEmptyString)
: id(_id) {} : id(_id) {}
void NewSerial( const wxString& _id ) { // Performs a case-insensitive compare of two IDs, returns TRUE if the IDs match
id = _id; // 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(); 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 { bool IsOk() const {
return !id.IsEmpty(); 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) { bool sectionExists(const wxChar* key, const wxString& value) {
return keyExists(wxsFormat(L"[%s%s%s]", key, value.IsEmpty() ? L"" : L" = ", value.c_str())); 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) { bool getBool(const char* key) {
return getBool(fromUTF8(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;
}; };
typedef std::vector<Game_Data> GameDataArray; // --------------------------------------------------------------------------------------
typedef pxDictionary<int> GameDataHash; // 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,StringHashNoCase> GameDataHash;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// BaseGameDatabaseVector // BaseGameDatabaseImpl
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// [TODO] Create a version of this that uses google hashsets; should be several magnitudes // [TODO] Create a version of this that uses google hashsets; should be several magnitudes
// faster that way. // faster that way.
class BaseGameDatabaseVector : public IGameDatabase class BaseGameDatabaseImpl : public IGameDatabase
{ {
public: public:
GameDataArray gList; // List of all game data GameDataArray gList; // List of all game data
GameDataHash gHash; // hash table of game serials matched to their gList indexes! GameDataHash gHash; // hash table of game serials matched to their gList indexes!
Game_Data* curGame; // Current game data (index into gList)
wxString m_baseKey; wxString m_baseKey;
public: public:
BaseGameDatabaseVector() BaseGameDatabaseImpl()
{ {
curGame = NULL;
m_baseKey = L"Serial"; m_baseKey = L"Serial";
} }
virtual ~BaseGameDatabaseVector() throw() {} virtual ~BaseGameDatabaseImpl() throw() {}
wxString getBaseKey() const { return m_baseKey; } wxString getBaseKey() const { return m_baseKey; }
void setBaseKey( const wxString& key ) { m_baseKey = key; } void setBaseKey( const wxString& key ) { m_baseKey = key; }
// Returns true if a game is currently loaded into the database bool findGame(Game_Data& dest, const wxString& id);
// Returns false if otherwise (this means you need to call setGame() void addNewGame(const Game_Data& game);
// or it could mean the game was not found in the database at all...) void updateGame(const Game_Data& game);
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);
}; };
extern IGameDatabase* AppHost_GetGameDatabase(); extern IGameDatabase* AppHost_GetGameDatabase();

View File

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

View File

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

View File

@ -24,6 +24,7 @@
// cleaning up these things. // cleaning up these things.
#include "sVU_zerorec.h" #include "sVU_zerorec.h"
#include "GameDatabase.h" #include "GameDatabase.h"
#include "Elfheader.h"
extern void closeNewVif(int idx); extern void closeNewVif(int idx);
extern void resetNewVif(int idx); extern void resetNewVif(int idx);
@ -406,9 +407,9 @@ void SysClearExecutionCache()
// allocation is below a certain memory address (specified in "bounds" parameter). // allocation is below a certain memory address (specified in "bounds" parameter).
// The allocated block has code execution privileges. // The allocated block has code execution privileges.
// Returns NULL on allocation failure. // Returns NULL on allocation failure.
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
{ {
u8 *Mem = (u8*)HostSys::Mmap( base, size ); u8* Mem = (u8*)HostSys::Mmap( base, size );
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) ) if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
{ {
@ -434,3 +435,20 @@ u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
} }
return Mem; 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 SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches! extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed"); extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame ); extern void vSyncDebugStuff( uint frame );
extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true ); extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
extern wxString SysGetDiscID();
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support. // 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) { static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
if (!gameDB) gameDB = wxGetApp().GetGameDatabase(); if (!gameDB) gameDB = wxGetApp().GetGameDatabase();
if (!gameDB->gameLoaded()) return 0; Game_Data game;
if (!gameDB->findGame(game, SysGetDiscID())) return 0;
int gf = 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)) if (EnumIsValid(eeRM))
{ {
Console.WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(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)) if (EnumIsValid(vuRM))
{ {
Console.WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(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")) { if (game.keyExists("eeClampMode")) {
int clampMode = gameDB->getInt("eeClampMode"); int clampMode = game.getInt("eeClampMode");
Console.WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode); Console.WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
dest.Recompiler.fpuOverflow = (clampMode >= 1); dest.Recompiler.fpuOverflow = (clampMode >= 1);
dest.Recompiler.fpuExtraOverflow = (clampMode >= 2); dest.Recompiler.fpuExtraOverflow = (clampMode >= 2);
@ -211,8 +212,8 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
gf++; gf++;
} }
if (gameDB->keyExists("vuClampMode")) { if (game.keyExists("vuClampMode")) {
int clampMode = gameDB->getInt("vuClampMode"); int clampMode = game.getInt("vuClampMode");
Console.WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode); Console.WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
dest.Recompiler.vuOverflow = (clampMode >= 1); dest.Recompiler.vuOverflow = (clampMode >= 1);
dest.Recompiler.vuExtraOverflow = (clampMode >= 2); dest.Recompiler.vuExtraOverflow = (clampMode >= 2);
@ -225,9 +226,9 @@ static int loadGameSettings(Pcsx2Config& dest, IGameDatabase* gameDB) {
wxString key( EnumToString(id) ); wxString key( EnumToString(id) );
key += L"Hack"; 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 ); dest.Gamefixes.Set(id, enableIt );
Console.WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled" ); Console.WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled" );
gf++; gf++;
@ -252,14 +253,15 @@ void AppCoreThread::ApplySettings( const Pcsx2Config& src )
wxString gameCompat; wxString gameCompat;
if (ElfCRC) gameCRC.Printf( L"%8.8x", ElfCRC ); 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 (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
{ {
if (GameDB->gameLoaded()) { Game_Data game;
int compat = GameDB->getInt("Compat"); if (GameDB->findGame(game, SysGetDiscID())) {
gameName = GameDB->getString("Name"); int compat = game.getInt("Compat");
gameName += L" (" + GameDB->getString("Region") + L")"; gameName = game.getString("Name");
gameName += L" (" + game.getString("Region") + L")";
gameCompat = L" [Status = "+compatToStringWX(compat)+L"]"; gameCompat = L" [Status = "+compatToStringWX(compat)+L"]";
} }

View File

@ -118,10 +118,14 @@ wxString DBLoaderHelper::ReadHeader()
void DBLoaderHelper::ReadGames() void DBLoaderHelper::ReadGames()
{ {
Game_Data* game = m_gamedb.createNewGame(); Game_Data game;
if (m_keyPair.IsOk()) 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... while(!m_reader.Eof()) { // Fill game data, find new game, repeat...
pxReadLine(m_reader, m_dest, m_intermediate); pxReadLine(m_reader, m_dest, m_intermediate);
@ -132,7 +136,13 @@ void DBLoaderHelper::ReadGames()
if (!extractMultiLine()) extract(); if (!extractMultiLine()) extract();
if (!m_keyPair.IsOk()) continue; 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(); header = loader.ReadHeader();
loader.ReadGames(); loader.ReadGames();
curGame = NULL;
return *this; return *this;
} }

View File

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

View File

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

View File

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

View File

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

View File

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