diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp
index 03d09672f2..ef82fa0394 100644
--- a/pcsx2/CDVD/CDVD.cpp
+++ b/pcsx2/CDVD/CDVD.cpp
@@ -27,7 +27,7 @@
#include "GS.h" // for gsRegionMode
#include "Elfheader.h"
#include "ps2/BiosTools.h"
-#include "DataBase_Loader.h"
+#include "GameDatabase.h"
wxString DiscID;
@@ -354,7 +354,7 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
elfptr.Delete();
// Set the Game DataBase to the correct game based on Game Serial Code...
- if (DataBase_Loader* GameDB = AppHost_GetGameDatabase()) {
+ if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) {
wxString gameSerial = DiscID;
if (DiscID.IsEmpty()) { // Search for crc if no Serial Code
gameSerial = wxString(wxsFormat( L"%8.8x", ElfCRC ));
diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt
index 89858892c2..7d39960efc 100644
--- a/pcsx2/CMakeLists.txt
+++ b/pcsx2/CMakeLists.txt
@@ -121,7 +121,7 @@ set(pcsx2Sources
COP0.cpp
COP2.cpp
Counters.cpp
- DataBase_Loader.cpp
+ GameDatabase.cpp
Dump.cpp
Elfheader.cpp
FiFo.cpp
@@ -194,7 +194,7 @@ set(pcsx2Headers
Counters.h
Dmac.h
Dump.h
- DataBase_Loader.h
+ GameDatabase.h
Elfheader.h
Gif.h
GS.h
@@ -290,6 +290,7 @@ set(pcsx2GuiSources
gui/AppCorePlugins.cpp
gui/AppCoreThread.cpp
gui/AppEventSources.cpp
+ gui/AppGameDatabase.cpp
gui/AppInit.cpp
gui/AppMain.cpp
gui/AppRes.cpp
@@ -355,6 +356,7 @@ set(pcsx2GuiHeaders
gui/AppCorePlugins.h
gui/AppEventListeners.h
gui/AppForwardDefs.h
+ gui/AppGameDatabase.h
gui/ConsoleLogger.h
gui/CpuUsageProvider.h
gui/Dialogs/ConfigurationDialog.h
diff --git a/pcsx2/DataBase_Loader.cpp b/pcsx2/DataBase_Loader.cpp
deleted file mode 100644
index 1e7d1ca54e..0000000000
--- a/pcsx2/DataBase_Loader.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-
-#include "PrecompiledHeader.h"
-#include "DataBase_Loader.h"
-
-//------------------------------------------------------------------
-// DataBase_Loader - Private Methods
-//------------------------------------------------------------------
-
-void DataBase_Loader::doError(const wxString& line, key_pair& keyPair, bool doMsg) {
- if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str());
- keyPair.Clear();
-}
-
-// Multiline Sections are in the form of:
-//
-// [section=value]
-// content
-// content
-// [/section]
-//
-// ... where the =value part is OPTIONAL.
-bool DataBase_Loader::extractMultiLine(const wxString& line, key_pair& keyPair, wxInputStream& ffile) {
-
- if (line[0] != L'[') return false; // All multiline sections begin with a '['!
-
- if (!line.EndsWith(L"]")) {
- doError(line, keyPair, true);
- return false;
- }
-
- keyPair.key = line;
-
- // Use Mid() to strip off the left and right side brackets.
- wxString midLine(line.Mid(1, line.Length()-2));
- wxString lvalue(midLine.BeforeFirst(L'=').Trim(true).Trim(false));
- //wxString rvalue(midLine.AfterFirst(L'=').Trim(true).Trim(false));
-
- wxString endString;
- endString.Printf( L"[/%s]", lvalue.c_str() );
-
- while(!ffile.Eof()) {
- pxReadLine( ffile, m_dest, m_intermediate );
- if (m_dest == endString) break;
- keyPair.value += m_dest + L"\n";
- }
- return true;
-}
-
-void DataBase_Loader::extract(const wxString& line, key_pair& keyPair, wxInputStream& reader) {
- keyPair.Clear();
-
- if( line.IsEmpty() ) return;
-
- if( extractMultiLine(line, keyPair, reader) ) return;
- if( !pxParseAssignmentString( line, keyPair.key, keyPair.value ) ) return;
- if( keyPair.value.IsEmpty() )
- doError(line, keyPair, true);
-}
diff --git a/pcsx2/DataBase_Loader.h b/pcsx2/DataBase_Loader.h
deleted file mode 100644
index ef073c2b89..0000000000
--- a/pcsx2/DataBase_Loader.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/* PCSX2 - PS2 Emulator for PCs
- * Copyright (C) 2002-2010 PCSX2 Dev Team
- *
- * PCSX2 is free software: you can redistribute it and/or modify it under the terms
- * of the GNU Lesser General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with PCSX2.
- * If not, see .
- */
-
-#pragma once
-
-#include "Common.h"
-#include "AppConfig.h"
-#include
-
-struct key_pair;
-class Game_Data;
-
-// This was originally configured to use deque, but there appear to be no uses of deque's sole
-// advantage: adding and removing items from the head of the list. So I changed it to vector
-// since it is a slightly lighter weight class. --air
-typedef std::vector GameDataArray;
-typedef std::vector 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();
- }
-
- wxString toString() const {
- if (key[0] == '[') {
- pxAssumeDev( key.EndsWith(L"]"), "Malformed multiline key detected: missing end bracket!" );
-
- // Terminating tag must be written without the "rvalue" -- in the form of:
- // [/patches]
- // Use Mid() to strip off the left and right side brackets.
- wxString midLine(key.Mid(1, key.Length()-2));
- wxString keyLvalue(midLine.BeforeFirst(L'=').Trim(true).Trim(false));
-
- return wxsFormat( L"%s\n%s[/%s]\n",
- key.c_str(), value.c_str(), keyLvalue.c_str()
- );
- }
- else {
- // Note: 6 char padding on the l-value makes things look nicer.
- return wxsFormat(L"%-6s = %s\n", key.c_str(), value.c_str() );
- }
-
- }
-};
-
-class Game_Data {
-public:
- 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;
- kList.clear();
- }
-
- bool IsOk() const {
- return !id.IsEmpty();
- }
-};
-
-
-// DataBase_Loader:
-// Give the starting Key and Value you're looking for,
-// and it will extract the necessary data from the database.
-// Example:
-// ---------------------------------------------
-// Serial = SLUS-20486
-// Name = Marvel vs. Capcom 2
-// Region = NTSC-U
-// ---------------------------------------------
-// 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
-// DataBase_Loader class's methods to get the other key's values.
-// Such as dbLoader.getString("Region") returns "NTSC-U"
-
-class DataBase_Loader {
-protected:
- bool isComment(const wxString& s);
- void doError(const wxString& line, key_pair& keyPair, bool doMsg = false);
- bool extractMultiLine(const wxString& line, key_pair& keyPair, wxInputStream& reader);
- void extract(const wxString& line, key_pair& keyPair, wxInputStream& 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;
-
-public:
- GameDataArray gList; // List of all game data
- Game_Data* curGame; // Current game data (index into gList)
- wxString header; // Header of the database
- wxString baseKey; // Key to separate games by ("Serial")
-
- DataBase_Loader(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial", const wxString& value = wxEmptyString )
- : baseKey( key )
- {
- curGame = NULL;
- if (!wxFileExists(file)) {
- Console.Error(L"DataBase_Loader: DataBase Not Found! [%s]", file.c_str());
- }
- wxFFileInputStream reader( file );
- key_pair keyPair;
- wxString s0;
- Game_Data game;
-
- while(!reader.Eof()) {
- while(!reader.Eof()) { // Find first game
- pxReadLine(reader, s0, m_intermediate);
- extract(s0.Trim(true).Trim(false), keyPair, reader);
- if (keyPair.CompareKey(key)) break;
- header += s0 + L'\n';
- }
- game.NewSerial( keyPair.value );
- game.kList.push_back(keyPair);
-
- while(!reader.Eof()) { // Fill game data, find new game, repeat...
- pxReadLine(reader, s0, m_intermediate);
- extract(s0.Trim(true).Trim(false), keyPair, reader);
- if (!keyPair.IsOk()) continue;
- if (keyPair.CompareKey(key)) {
- gList.push_back(game);
- game.NewSerial(keyPair.value);
- }
- game.kList.push_back(keyPair);
- }
- }
-
- if (game.IsOk()) gList.push_back(game);
-
- if (value.IsEmpty()) return;
- if (setGame(value)) Console.WriteLn(L"DataBase_Loader: Found Game! [%s]", value.c_str());
- else Console.Warning(L"DataBase_Loader: Game Not Found! [%s]", value.c_str());
- }
-
- virtual ~DataBase_Loader() throw() {
- // deque deletes its contents automatically.
- Console.WriteLn( "(GameDB) Destroying..." );
- }
-
- // Sets the current game to the one matching the serial id given
- // Returns true if game found, false if not found...
- bool setGame(const wxString& id) {
- GameDataArray::iterator it( gList.begin() );
- for ( ; it != gList.end(); ++it) {
- if (it[0].id == id) {
- curGame = &it[0];
- return true;
- }
- }
- curGame = NULL;
- return false;
- }
-
- // 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;
- }
-
- // Saves changes to the database
- void saveToFile(const wxString& file = L"GameIndex.dbf") {
- wxFFileOutputStream writer( file );
- pxWriteMultiline(writer, header);
- GameDataArray::iterator it( gList.begin() );
- for ( ; it != gList.end(); ++it) {
- KeyPairArray::iterator i = it[0].kList.begin();
- for ( ; i != it[0].kList.end(); ++i) {
- pxWriteMultiline(writer, i[0].toString() );
- }
- pxWriteLine(writer, L"---------------------------------------------");
- }
- }
-
- // Adds new game data to the database, and sets curGame to the new game...
- // If searchDB is true, it searches the database to see if game already exists.
- void addGame(const wxString& id, bool searchDB = true) {
- if (searchDB && setGame(id)) return;
- Game_Data game(id);
- key_pair kp(baseKey, id);
- game.kList.push_back(kp);
- gList.push_back(game);
- curGame = &(gList.end()-1)[0];
- }
-
- // Searches the current game's data to see if the given key exists
- bool keyExists(const wxChar* key) {
- if (curGame) {
- KeyPairArray::iterator it( curGame->kList.begin() );
- for ( ; it != curGame->kList.end(); ++it) {
- if (it[0].CompareKey(key)) {
- return true;
- }
- }
- }
- else Console.Error("DataBase_Loader: Game not set!");
- return false;
- }
-
- // Totally Deletes the specified key/pair value from the current game's data
- void deleteKey(const wxChar* key) {
- if (curGame) {
- KeyPairArray::iterator it( curGame->kList.begin() );
- for ( ; it != curGame->kList.end(); ++it) {
- if (it[0].CompareKey(key)) {
- curGame->kList.erase(it);
- return;
- }
- }
- }
- else Console.Error("DataBase_Loader: Game not set!");
- }
-
- // Gets a string representation of the 'value' for the given key
- wxString getString(const wxChar* key) {
- if (curGame) {
- KeyPairArray::iterator it( curGame->kList.begin() );
- for ( ; it != curGame->kList.end(); ++it) {
- if (it[0].CompareKey(key)) {
- return it[0].value;
- }
- }
- }
- else Console.Error("DataBase_Loader: Game not set!");
- return wxString();
- }
-
- bool sectionExists(const wxChar* key, const wxString& value) {
- return keyExists( wxsFormat(L"[%s = %s]", key, value.c_str()) );
- }
-
- wxString getSection(const wxChar* key, const wxString& value) {
- return getString( wxsFormat(L"[%s = %s]", key, value.c_str()) );
- }
-
- // Gets an integer representation of the 'value' for the given key
- int getInt(const wxChar* key) {
- return wxStrtoul(getString(key), NULL, 0);
- }
-
- // Gets a u8 representation of the 'value' for the given key
- u8 getU8(const wxChar* key) {
- return (u8)wxAtoi(getString(key));
- }
-
- // Gets a bool representation of the 'value' for the given key
- bool getBool(const wxChar* key) {
- return !!wxAtoi(getString(key));
- }
-
- wxString getString(const char* key) {
- return getString(fromUTF8(key));
- }
-
- bool keyExists(const char* key) {
- return keyExists(fromUTF8(key));
- }
-
- int getInt(const char* key) {
- return getInt(fromUTF8(key));
- }
-
- u8 getU8(const char* key) {
- return getU8(fromUTF8(key));
- }
-
- bool getBool(const char* key) {
- return getBool(fromUTF8(key));
- }
-
- // Write a string value to the specified key
- void writeString(const wxString& key, const wxString& value) {
- if (curGame) {
- KeyPairArray::iterator it( curGame->kList.begin() );
- for ( ; it != curGame->kList.end(); ++it) {
- if (it[0].CompareKey(key)) {
- it[0].value = value;
- return;
- }
- }
- key_pair tKey(key, value);
- curGame->kList.push_back(tKey);
- }
- else Console.Error("DataBase_Loader: Game not set!");
- }
-
- // Write a bool value to the specified key
- void writeBool(const wxString& key, bool value) {
- writeString(key, value ? L"1" : L"0");
- }
-};
-
-static wxString compatToStringWX(int compat) {
- switch (compat) {
- case 6: return L"Perfect";
- case 5: return L"Playable";
- case 4: return L"In-Game";
- case 3: return L"Menu";
- case 2: return L"Intro";
- case 1: return L"Nothing";
- default: return L"Unknown";
- }
-}
-
-#define checkGamefix(gFix) { \
- if (gameDB->keyExists(#gFix)) { \
- SetGameFixConfig().gFix = gameDB->getBool(#gFix); \
- Console.WriteLn("Loading Gamefix: " #gFix); \
- gf++; \
- } \
-}
-
-// Load Game Settings found in database
-// (game fixes, round modes, clamp modes, etc...)
-// Returns number of gamefixes set
-static int loadGameSettings(DataBase_Loader* gameDB) {
- if (gameDB && gameDB->gameLoaded()) {
- SSE_MXCSR eeMX = EmuConfig.Cpu.sseMXCSR;
- SSE_MXCSR vuMX = EmuConfig.Cpu.sseVUMXCSR;
- int eeRM = eeMX.GetRoundMode();
- int vuRM = vuMX.GetRoundMode();
- bool rm = 0;
- int gf = 0;
- if (gameDB->keyExists("eeRoundMode")) { eeRM = gameDB->getInt("eeRoundMode"); rm=1; gf++; }
- if (gameDB->keyExists("vuRoundMode")) { vuRM = gameDB->getInt("vuRoundMode"); rm=1; gf++; }
- if (rm && eeRM<4 && vuRM<4) {
- Console.WriteLn("Game DataBase: Changing roundmodes! [ee=%d] [vu=%d]", eeRM, vuRM);
- SetCPUState(eeMX.SetRoundMode((SSE_RoundMode)eeRM), vuMX.SetRoundMode((SSE_RoundMode)vuRM));
- }
- if (gameDB->keyExists("eeClampMode")) {
- int clampMode = gameDB->getInt("eeClampMode");
- Console.WriteLn("Game DataBase: Changing EE/FPU clamp mode [mode=%d]", clampMode);
- SetRecompilerConfig().fpuOverflow = clampMode >= 1;
- SetRecompilerConfig().fpuExtraOverflow = clampMode >= 2;
- SetRecompilerConfig().fpuFullMode = clampMode >= 3;
- gf++;
- }
- if (gameDB->keyExists("vuClampMode")) {
- int clampMode = gameDB->getInt("vuClampMode");
- Console.WriteLn("Game DataBase: Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
- SetRecompilerConfig().vuOverflow = clampMode >= 1;
- SetRecompilerConfig().vuExtraOverflow = clampMode >= 2;
- SetRecompilerConfig().vuSignOverflow = clampMode >= 3;
- gf++;
- }
- checkGamefix(VuAddSubHack);
- checkGamefix(VuClipFlagHack);
- checkGamefix(FpuCompareHack);
- checkGamefix(FpuMulHack);
- checkGamefix(FpuNegDivHack);
- checkGamefix(XgKickHack);
- checkGamefix(IPUWaitHack);
- checkGamefix(EETimingHack);
- checkGamefix(SkipMPEGHack);
- return gf;
- }
- return 0;
-}
-
-extern DataBase_Loader* AppHost_GetGameDatabase();
\ No newline at end of file
diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp
new file mode 100644
index 0000000000..4291ab4a9d
--- /dev/null
+++ b/pcsx2/GameDatabase.cpp
@@ -0,0 +1,107 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2010 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+#include "GameDatabase.h"
+
+// 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) {
+ GameDataArray::iterator it( gList.begin() );
+ for ( ; it != gList.end(); ++it) {
+ if (it[0].CompareId(id)) {
+ curGame = &it[0];
+ return true;
+ }
+ }
+ curGame = NULL;
+ return false;
+}
+
+Game_Data* BaseGameDatabaseVector::createNewGame(const wxString& id) {
+ gList.push_back(Game_Data(id));
+ curGame = &(gList.end()-1)[0];
+ return curGame;
+}
+
+// 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) {
+ 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) {
+ if (it[0].CompareKey(key)) {
+ curGame->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) {
+ 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) {
+ if (it[0].CompareKey(key)) {
+ if( value.IsEmpty() )
+ curGame->kList.erase(it);
+ else
+ it[0].value = value;
+ return;
+ }
+ }
+ if( !value.IsEmpty() ) {
+ key_pair tKey(key, value);
+ curGame->kList.push_back(tKey);
+ }
+ }
+ else Console.Error("(GameDB) Game not set!");
+}
+
+// Write a bool value to the specified key
+void BaseGameDatabaseVector::writeBool(const wxString& key, bool value) {
+ writeString(key, value ? L"1" : L"0");
+}
\ No newline at end of file
diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h
new file mode 100644
index 0000000000..8a5319d360
--- /dev/null
+++ b/pcsx2/GameDatabase.h
@@ -0,0 +1,206 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2010 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+
+#include "Common.h"
+#include "AppConfig.h"
+#include
+
+struct key_pair;
+class Game_Data;
+
+typedef std::vector 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();
+ }
+
+ wxString toString() const {
+ if (key[0] == '[') {
+ pxAssumeDev( key.EndsWith(L"]"), "Malformed multiline key detected: missing end bracket!" );
+
+ // Terminating tag must be written without the "rvalue" -- in the form of:
+ // [/patches]
+ // Use Mid() to strip off the left and right side brackets.
+ wxString midLine(key.Mid(1, key.Length()-2));
+ wxString keyLvalue(midLine.BeforeFirst(L'=').Trim(true).Trim(false));
+
+ return wxsFormat( L"%s\n%s[/%s]\n",
+ key.c_str(), value.c_str(), keyLvalue.c_str()
+ );
+ }
+ else {
+ // Note: 6 char padding on the l-value makes things look nicer.
+ return wxsFormat(L"%-6s = %s\n", key.c_str(), value.c_str() );
+ }
+
+ }
+};
+
+class Game_Data {
+public:
+ 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;
+ kList.clear();
+ }
+
+ 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()));
+ }
+
+ wxString getSection(const wxChar* key, const wxString& value) {
+ return getString(wxsFormat(L"[%s%s%s]", key, value.IsEmpty() ? L"" : L" = ", value.c_str()));
+ }
+
+ // Gets an integer representation of the 'value' for the given key
+ int getInt(const wxChar* key) {
+ return wxStrtoul(getString(key), NULL, 0);
+ }
+
+ // Gets a u8 representation of the 'value' for the given key
+ u8 getU8(const wxChar* key) {
+ return (u8)wxAtoi(getString(key));
+ }
+
+ // Gets a bool representation of the 'value' for the given key
+ bool getBool(const wxChar* key) {
+ return !!wxAtoi(getString(key));
+ }
+
+ bool keyExists(const char* key) {
+ return keyExists(fromUTF8(key));
+ }
+
+ wxString getString(const char* key) {
+ return getString(fromUTF8(key));
+ }
+
+ int getInt(const char* key) {
+ return getInt(fromUTF8(key));
+ }
+
+ u8 getU8(const char* key) {
+ return getU8(fromUTF8(key));
+ }
+
+ 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;
+};
+
+typedef std::vector GameDataArray;
+
+// --------------------------------------------------------------------------------------
+// BaseGameDatabaseVector
+// --------------------------------------------------------------------------------------
+// [TODO] Create a version of this that uses google hashsets; should be several magnitudes
+// faster that way.
+class BaseGameDatabaseVector : public IGameDatabase
+{
+public:
+ GameDataArray gList; // List of all game data
+ Game_Data* curGame; // Current game data (index into gList)
+ wxString m_baseKey;
+
+public:
+ BaseGameDatabaseVector()
+ {
+ curGame = NULL;
+ m_baseKey = L"Serial";
+ }
+
+ virtual ~BaseGameDatabaseVector() 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);
+};
+
+extern IGameDatabase* AppHost_GetGameDatabase();
\ No newline at end of file
diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp
index 05e280909c..efd5622b7e 100644
--- a/pcsx2/Linux/pcsx2.cbp
+++ b/pcsx2/Linux/pcsx2.cbp
@@ -204,8 +204,8 @@
-
-
+
+
@@ -359,6 +359,8 @@
+
+
diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp
index f2aa235c83..e934955b10 100644
--- a/pcsx2/Patch.cpp
+++ b/pcsx2/Patch.cpp
@@ -19,7 +19,7 @@
#include "IopCommon.h"
#include "Patch.h"
-#include "DataBase_Loader.h"
+#include "GameDatabase.h"
#include
IniPatch Patch[ MAX_PATCH ];
@@ -133,12 +133,11 @@ void TrimPatches(wxString& s)
// Returns number of patches loaded
int InitPatches(const wxString& name)
{
- bool patchFound = false;
+ bool patchFound = false;
wxString patch;
- const wxString crc( L"[patches = " + name + L"]" );
patchnumber = 0;
-
- if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() )
+
+ if (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
{
if(GameDB->gameLoaded()) {
if (GameDB->sectionExists(L"patches", name)) {
diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp
index abd0c6081c..908d3b6a77 100644
--- a/pcsx2/R5900.cpp
+++ b/pcsx2/R5900.cpp
@@ -30,7 +30,7 @@
#include "Elfheader.h"
#include "CDVD/CDVD.h"
#include "Patch.h"
-#include "DataBase_Loader.h"
+#include "GameDatabase.h"
#include "SamplProf.h"
using namespace R5900; // for R5900 disasm tools
@@ -574,60 +574,22 @@ __forceinline void CPU_INT( u32 n, s32 ecycle)
cpuSetNextBranchDelta( cpuRegs.eCycle[n] );
}
+// Called from recompilers; __fastcall define is mandatory.
void __fastcall eeGameStarting()
{
- if (!g_GameStarted && ElfCRC) {
- wxString gameCRC( wxsFormat( L"%8.8x", ElfCRC ) );
- wxString gameName = L"Unknown Game (\?\?\?)";
- wxString gameSerial = L" [" + DiscID + L"]";
- wxString gameCompat = L" [Status = Unknown]";
- wxString gamePatch = L"";
- wxString gameFixes = L"";
- wxString gameCheats = L"";
-
- if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() )
- {
- if (GameDB->gameLoaded()) {
- int compat = GameDB->getInt("Compat");
- gameName = GameDB->getString("Name");
- gameName += L" (" + GameDB->getString("Region") + L")";
- gameCompat = L" [Status = "+compatToStringWX(compat)+L"]";
- }
-
- if (EmuConfig.EnablePatches) {
- int patches = InitPatches(gameCRC);
- if (patches) {
- wxString pString( wxsFormat( L"%d", patches ) );
- gamePatch = L" [Patches = " + pString + L"]";
- }
- int fixes = loadGameSettings(GameDB);
- if (fixes) {
- wxString pString( wxsFormat( L"%d", fixes ) );
- gameFixes = L" [Fixes = " + pString + L"]";
- }
- }
- }
-
- if (EmuConfig.EnableCheats) {
- int cheats = InitCheats(gameCRC);
- if (cheats) {
- wxString cString( wxsFormat( L"%d", cheats ) );
- gameCheats = L" [Cheats = " + cString + L"]";
- }
- }
-
- Console.SetTitle(gameName+gameSerial+gameCompat+gameFixes+gamePatch+gameCheats);
-
- GetMTGS().SendGameCRC(ElfCRC);
+ if (!g_GameStarted)
+ {
+ Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
g_GameStarted = true;
-
- if (0) ProfilerSetEnabled(true);
+ GetCoreThread().GameStartingInThread();
+ }
+ else
+ {
+ Console.WriteLn( Color_Green, "(R5900) Re-executed ELF Entry point (ignored) [addr=0x%08X]", ElfEntry );
}
-
- if (EmuConfig.EnablePatches) ApplyPatch(0);
- if (EmuConfig.EnableCheats) ApplyCheat(0);
}
+// Called from recompilers; __fastcall define is mandatory.
void __fastcall eeloadReplaceOSDSYS()
{
g_SkipBiosHack = false;
diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h
index 586b804378..78a440a646 100644
--- a/pcsx2/R5900.h
+++ b/pcsx2/R5900.h
@@ -257,17 +257,17 @@ void intSetBranch();
void __fastcall intDoBranch(u32 target);
// modules loaded at hardcoded addresses by the kernel
-const u32 EEKERNEL_START = 0;
-const u32 EENULL_START = 0x81FC0;
-const u32 EELOAD_START = 0x82000;
-const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
+const u32 EEKERNEL_START = 0;
+const u32 EENULL_START = 0x81FC0;
+const u32 EELOAD_START = 0x82000;
+const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
-void __fastcall eeGameStarting();
-void __fastcall eeloadReplaceOSDSYS();
+extern void __fastcall eeGameStarting();
+extern void __fastcall eeloadReplaceOSDSYS();
-////////////////////////////////////////////////////////////////////
-// R5900 Public Interface / API
-//
+// --------------------------------------------------------------------------------------
+// R5900cpu
+// --------------------------------------------------------------------------------------
// [TODO] : This is on the list to get converted to a proper C++ class. I'm putting it
// off until I get my new IOPint and IOPrec re-merged. --air
//
diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp
index a2be1c1f93..9236810ecb 100644
--- a/pcsx2/System.cpp
+++ b/pcsx2/System.cpp
@@ -23,7 +23,7 @@
// Includes needed for cleanup, since we don't have a good system (yet) for
// cleaning up these things.
#include "sVU_zerorec.h"
-#include "DataBase_Loader.h"
+#include "GameDatabase.h"
extern void closeNewVif(int idx);
extern void resetNewVif(int idx);
diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp
index be3ea2d878..6dd9c95ca3 100644
--- a/pcsx2/System/SysCoreThread.cpp
+++ b/pcsx2/System/SysCoreThread.cpp
@@ -182,10 +182,6 @@ void SysCoreThread::DoCpuReset()
cpuReset();
}
-void SysCoreThread::PostVsyncToUI()
-{
-}
-
// This is called from the PS2 VM at the start of every vsync (either 59.94 or 50 hz by PS2
// clock scale, which does not correlate to the actual host machine vsync).
//
@@ -197,11 +193,18 @@ void SysCoreThread::PostVsyncToUI()
//
void SysCoreThread::VsyncInThread()
{
- PostVsyncToUI();
if (EmuConfig.EnablePatches) ApplyPatch();
if (EmuConfig.EnableCheats) ApplyCheat();
}
+void SysCoreThread::GameStartingInThread()
+{
+ GetMTGS().SendGameCRC(ElfCRC);
+
+ if (EmuConfig.EnablePatches) ApplyPatch(0);
+ if (EmuConfig.EnableCheats) ApplyCheat(0);
+}
+
void SysCoreThread::StateCheckInThread()
{
GetMTGS().RethrowException();
diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h
index 6fe663ed92..cdc5c0eaa0 100644
--- a/pcsx2/System/SysThreads.h
+++ b/pcsx2/System/SysThreads.h
@@ -186,7 +186,7 @@ public:
virtual void StateCheckInThread();
virtual void VsyncInThread();
- virtual void PostVsyncToUI()=0;
+ virtual void GameStartingInThread();
virtual void ApplySettings( const Pcsx2Config& src );
virtual void UploadStateCopy( const VmStateBuffer& copy );
diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h
index 06930cae49..753d240ccd 100644
--- a/pcsx2/gui/App.h
+++ b/pcsx2/gui/App.h
@@ -26,7 +26,7 @@
#include "AppCommon.h"
#include "AppCoreThread.h"
#include "RecentIsoList.h"
-#include "DataBase_Loader.h"
+#include "AppGameDatabase.h"
#include "System.h"
#include "System/SysThreads.h"
@@ -318,7 +318,7 @@ struct pxAppResources
ScopedPtr ToolbarImages;
ScopedPtr IconBundle;
ScopedPtr Bitmap_Logo;
- ScopedPtr GameDB;
+ ScopedPtr GameDB;
pxAppResources();
virtual ~pxAppResources() throw() { }
@@ -568,6 +568,7 @@ public:
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
void SysShutdown();
void LogicalVsync();
+ void GameStarting();
GSFrame& GetGsFrame() const;
MainEmuFrame& GetMainFrame() const;
@@ -618,7 +619,7 @@ public:
return m_Resources->ImageId;
}
- DataBase_Loader* GetGameDatabase();
+ AppGameDatabase* GetGameDatabase();
// --------------------------------------------------------------------------
// Overrides of wxApp virtuals:
diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp
index db2d76c4f3..3dc8c3bf17 100644
--- a/pcsx2/gui/AppCoreThread.cpp
+++ b/pcsx2/gui/AppCoreThread.cpp
@@ -144,9 +144,12 @@ void AppCoreThread::ChangeCdvdSource()
// TODO: Add a listener for CDVDsource changes? Or should we bother?
}
+extern int loadGameSettings(IGameDatabase* gameDB=NULL);
+
void AppCoreThread::OnResumeReady()
{
ApplySettings( g_Conf->EmuOptions );
+ loadGameSettings();
CDVD_SourceType cdvdsrc( g_Conf->CdvdSource );
if( cdvdsrc != CDVDsys_GetSourceType() || (cdvdsrc==CDVDsrc_Iso && (CDVDsys_GetFile(cdvdsrc) != g_Conf->CurrentIso)) )
@@ -230,9 +233,16 @@ void AppCoreThread::OnCleanupInThread()
_parent::OnCleanupInThread();
}
-void AppCoreThread::PostVsyncToUI()
+void AppCoreThread::VsyncInThread()
{
wxGetApp().LogicalVsync();
+ _parent::VsyncInThread();
+}
+
+void AppCoreThread::GameStartingInThread()
+{
+ wxGetApp().GameStarting();
+ _parent::GameStartingInThread();
}
void AppCoreThread::StateCheckInThread()
diff --git a/pcsx2/gui/AppCoreThread.h b/pcsx2/gui/AppCoreThread.h
index 1b941bd219..b96473178e 100644
--- a/pcsx2/gui/AppCoreThread.h
+++ b/pcsx2/gui/AppCoreThread.h
@@ -144,7 +144,8 @@ protected:
virtual void OnResumeInThread( bool IsSuspended );
virtual void OnSuspendInThread();
virtual void OnCleanupInThread();
- virtual void PostVsyncToUI();
+ virtual void VsyncInThread();
+ virtual void GameStartingInThread();
virtual void ExecuteTaskInThread();
virtual void DoCpuReset();
};
diff --git a/pcsx2/gui/AppGameDatabase.cpp b/pcsx2/gui/AppGameDatabase.cpp
new file mode 100644
index 0000000000..38538c3f88
--- /dev/null
+++ b/pcsx2/gui/AppGameDatabase.cpp
@@ -0,0 +1,186 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2010 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+#include "App.h"
+#include "AppGameDatabase.h"
+
+class DBLoaderHelper
+{
+ DeclareNoncopyableObject( DBLoaderHelper );
+
+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)
+ {
+ }
+
+ wxString ReadHeader();
+ void ReadGames();
+
+protected:
+ void doError(bool doMsg = false);
+ bool extractMultiLine();
+ void extract();
+};
+
+void DBLoaderHelper::doError(bool doMsg) {
+ if (doMsg) Console.Error("GameDatabase: Bad file data [%s]", m_dest.c_str());
+ 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(true);
+ 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 endString;
+ endString.Printf( L"[/%s]", lvalue.c_str() );
+
+ while(!m_reader.Eof()) {
+ pxReadLine( m_reader, m_dest, m_intermediate );
+ if (m_dest.CmpNoCase(endString) == 0) break;
+ m_keyPair.value += m_dest + L"\n";
+ }
+ return true;
+}
+
+void DBLoaderHelper::extract() {
+
+ if( !pxParseAssignmentString( m_dest, m_keyPair.key, m_keyPair.value ) ) return;
+ if( m_keyPair.value.IsEmpty() ) doError(true);
+}
+
+wxString DBLoaderHelper::ReadHeader()
+{
+ wxString header;
+ header.reserve(2048);
+
+ while(!m_reader.Eof()) {
+ pxReadLine(m_reader, m_dest, m_intermediate);
+ m_dest.Trim(false).Trim(true);
+ if( !(m_dest.IsEmpty() || m_dest.StartsWith(L"--") || m_dest.StartsWith( L"//" ) || m_dest.StartsWith( L";" )) ) break;
+ header += m_dest + L'\n';
+ }
+
+ if( !m_dest.IsEmpty() )
+ {
+ m_keyPair.Clear();
+ if( !extractMultiLine() ) extract();
+ }
+ return header;
+}
+
+void DBLoaderHelper::ReadGames()
+{
+ Game_Data* game = m_gamedb.createNewGame();
+
+ if (m_keyPair.IsOk())
+ m_gamedb.writeString( m_keyPair.key, m_keyPair.value );
+
+ while(!m_reader.Eof()) { // Fill game data, find new game, repeat...
+ 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;
+ m_gamedb.writeString( m_keyPair.key, m_keyPair.value );
+ }
+}
+
+// --------------------------------------------------------------------------------------
+// AppGameDatabase (implementations)
+// --------------------------------------------------------------------------------------
+
+AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& file, const wxString& key )
+{
+ if (!wxFileExists(file))
+ {
+ Console.Error(L"GameDatabase: DataBase Not Found! [%s]", file.c_str());
+ return *this;
+ }
+
+ wxFFileInputStream reader( file );
+
+ if (!reader.IsOk())
+ {
+ //throw Exception::FileNotFound( file );
+ Console.Error(L"GameDatabase: Could not access file (permission denied?) [%s]", file.c_str());
+ }
+
+ DBLoaderHelper loader( reader, *this );
+
+ header = loader.ReadHeader();
+ loader.ReadGames();
+
+ //if (setGame(value)) Console.WriteLn(L"GameDatabase: Found Game! [%s]", value.c_str());
+ //else Console.Warning(L"GameDatabase: Game Not Found! [%s]", value.c_str());
+
+ // Clear the current key after loading.
+ curGame = NULL;
+
+ return *this;
+}
+
+// Saves changes to the database
+void AppGameDatabase::SaveToFile(const wxString& file) {
+ wxFFileOutputStream writer( file );
+ pxWriteMultiline(writer, header);
+ GameDataArray::iterator it( gList.begin() );
+ for ( ; it != gList.end(); ++it) {
+ KeyPairArray::iterator i = it[0].kList.begin();
+ for ( ; i != it[0].kList.end(); ++i) {
+ pxWriteMultiline(writer, i[0].toString() );
+ }
+ pxWriteLine(writer, L"---------------------------------------------");
+ }
+}
+
diff --git a/pcsx2/gui/AppGameDatabase.h b/pcsx2/gui/AppGameDatabase.h
new file mode 100644
index 0000000000..8aabf4888b
--- /dev/null
+++ b/pcsx2/gui/AppGameDatabase.h
@@ -0,0 +1,69 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2010 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+
+#include "GameDatabase.h"
+
+// --------------------------------------------------------------------------------------
+// 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 BaseGameDatabaseVector
+{
+protected:
+ wxString header; // Header of the database
+ wxString baseKey; // Key to separate games by ("Serial")
+
+public:
+ AppGameDatabase() {}
+ virtual ~AppGameDatabase() throw() {
+ // deque deletes its contents automatically.
+ Console.WriteLn( "(GameDB) Destroying..." );
+ }
+
+ AppGameDatabase& LoadFromFile(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial" );
+ void SaveToFile(const wxString& file = L"GameIndex.dbf");
+};
+
+static wxString compatToStringWX(int compat) {
+ switch (compat) {
+ case 6: return L"Perfect";
+ case 5: return L"Playable";
+ case 4: return L"In-Game";
+ case 3: return L"Menu";
+ case 2: return L"Intro";
+ case 1: return L"Nothing";
+ default: return L"Unknown";
+ }
+}
diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp
index 6da400906e..777a5a7d32 100644
--- a/pcsx2/gui/AppMain.cpp
+++ b/pcsx2/gui/AppMain.cpp
@@ -332,6 +332,127 @@ void Pcsx2App::LogicalVsync()
}
}
+// Load Game Settings found in database
+// (game fixes, round modes, clamp modes, etc...)
+// Returns number of gamefixes set
+int loadGameSettings(IGameDatabase* gameDB) {
+ if (!gameDB)
+ gameDB = wxGetApp().GetGameDatabase();
+
+ if(!gameDB->gameLoaded()) return 0;
+
+ Pcsx2Config sysLocal( EmuConfig );
+
+ int gf = 0;
+
+ bool rm = false;
+ if (gameDB->keyExists("eeRoundMode"))
+ {
+ SSE_RoundMode eeRM = (SSE_RoundMode)gameDB->getInt("eeRoundMode");
+ if (EnumIsValid(eeRM))
+ {
+ Console.WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
+ sysLocal.Cpu.sseMXCSR.SetRoundMode(eeRM);
+ rm = true;
+ ++gf;
+ }
+ }
+
+ if (gameDB->keyExists("vuRoundMode"))
+ {
+ SSE_RoundMode vuRM = (SSE_RoundMode)gameDB->getInt("vuRoundMode");
+ if (EnumIsValid(vuRM))
+ {
+ Console.WriteLn("(GameDB) Changing VU0/VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
+ sysLocal.Cpu.sseVUMXCSR.SetRoundMode(vuRM);
+ rm = true;
+ ++gf;
+ }
+ }
+
+ if (gameDB->keyExists("eeClampMode")) {
+ int clampMode = gameDB->getInt("eeClampMode");
+ Console.WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
+ sysLocal.Recompiler.fpuOverflow = (clampMode >= 1);
+ sysLocal.Recompiler.fpuExtraOverflow = (clampMode >= 2);
+ sysLocal.Recompiler.fpuFullMode = (clampMode >= 3);
+ gf++;
+ }
+
+ if (gameDB->keyExists("vuClampMode")) {
+ int clampMode = gameDB->getInt("vuClampMode");
+ Console.WriteLn("(GameDB) Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
+ sysLocal.Recompiler.vuOverflow = (clampMode >= 1);
+ sysLocal.Recompiler.vuExtraOverflow = (clampMode >= 2);
+ sysLocal.Recompiler.vuSignOverflow = (clampMode >= 3);
+ gf++;
+ }
+
+ for( GamefixId id=GamefixId_FIRST; idkeyExists(key))
+ {
+ bool enableIt = gameDB->getBool(key);
+ sysLocal.Gamefixes.Set(id, enableIt );
+ Console.WriteLn(L"(GameDB) %s Gamefix: " + key, enableIt ? L"Enabled" : L"Disabled" );
+ gf++;
+ }
+ }
+
+ GetCoreThread().ApplySettings( sysLocal );
+
+ return gf;
+}
+
+#include "cdvd/CDVD.h"
+#include "Elfheader.h"
+#include "Patch.h"
+
+
+void Pcsx2App::GameStarting()
+{
+ if( PostAppMethodMyself( &Pcsx2App::GameStarting ) ) return;
+
+ wxString gameCRC;
+ wxString gameName (L"Unknown Game (\?\?\?)");
+ wxString gameSerial (L" [" + DiscID + L"]");
+ wxString gameCompat (L" [Status = Unknown]");
+ wxString gamePatch;
+ wxString gameFixes;
+ wxString gameCheats;
+
+ if( ElfCRC ) gameCRC.Printf( L"%8.8x", ElfCRC );
+
+ if (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
+ {
+ if (GameDB->gameLoaded()) {
+ int compat = GameDB->getInt("Compat");
+ gameName = GameDB->getString("Name");
+ gameName += L" (" + GameDB->getString("Region") + L")";
+ gameCompat = L" [Status = "+compatToStringWX(compat)+L"]";
+ }
+
+ if (EmuConfig.EnablePatches) {
+ if (int patches = InitPatches(gameCRC)) {
+ gamePatch.Printf(L" [%d Patches]", patches);
+ }
+ if (int fixes = loadGameSettings(GameDB)) {
+ gameFixes.Printf(L" [%d Fixes]", fixes);
+ }
+ }
+ }
+
+ if (EmuConfig.EnableCheats) {
+ if (int cheats = InitCheats(gameCRC)) {
+ gameCheats.Printf(L" [Cheats = %d]", cheats);
+ }
+ }
+
+ Console.SetTitle(gameName+gameSerial+gameCompat+gameFixes+gamePatch+gameCheats);
+}
// ----------------------------------------------------------------------------
// Pcsx2App Event Handlers
@@ -987,16 +1108,20 @@ SysCoreAllocations& GetSysCoreAlloc()
return *wxGetApp().m_CoreAllocs;
}
-DataBase_Loader* Pcsx2App::GetGameDatabase()
+AppGameDatabase* Pcsx2App::GetGameDatabase()
{
pxAppResources& res( GetResourceCache() );
-
+
ScopedLock lock( m_mtx_LoadingGameDB );
- if( !res.GameDB ) res.GameDB = new DataBase_Loader();
+ if( !res.GameDB )
+ {
+ res.GameDB = new AppGameDatabase();
+ res.GameDB->LoadFromFile();
+ }
return res.GameDB;
}
-DataBase_Loader* AppHost_GetGameDatabase()
+IGameDatabase* AppHost_GetGameDatabase()
{
return wxGetApp().GetGameDatabase();
}
\ No newline at end of file
diff --git a/pcsx2/gui/Panels/GameDatabasePanel.cpp b/pcsx2/gui/Panels/GameDatabasePanel.cpp
index b278bce9cd..914e04bc1f 100644
--- a/pcsx2/gui/Panels/GameDatabasePanel.cpp
+++ b/pcsx2/gui/Panels/GameDatabasePanel.cpp
@@ -14,7 +14,7 @@
*/
#include "PrecompiledHeader.h"
-#include "DataBase_Loader.h"
+#include "App.h"
#include "ConfigurationPanels.h"
extern wxString DiscID;
@@ -42,11 +42,11 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags =
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent )
{
- //if (!GameDB) GameDB = new DataBase_Loader();
- DataBase_Loader* GameDB = AppHost_GetGameDatabase();
+ //if (!GameDB) GameDB = new GameDatabase();
+ IGameDatabase* GameDB = AppHost_GetGameDatabase();
pxAssume( GameDB != NULL );
- searchBtn = new wxButton (this, wxID_DEFAULT, L"Search");
+ searchBtn = new wxButton (this, wxID_ANY, _("Search"));
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
@@ -56,11 +56,11 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
- gameFixes[i] = new pxCheckBox(this, EnumToString(i));
+ gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER );
*this += Heading(_("Game Database Editor")).Bold() | StdExpand();
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
-
+
wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding));
sizer1.AddGrowableCol(0);
@@ -70,7 +70,7 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
sizer1 += serialBox | pxCenter;
sizer1 += 5;
sizer1 += searchBtn;
-
+
placeTextBox(nameBox, "Name: ");
placeTextBox(regionBox, "Region: ");
placeTextBox(compatBox, "Compatibility: ");
@@ -96,7 +96,7 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
}
void Panels::GameDatabasePanel::PopulateFields() {
- DataBase_Loader* GameDB = AppHost_GetGameDatabase();
+ IGameDatabase* GameDB = AppHost_GetGameDatabase();
if (GameDB->gameLoaded()) {
serialBox ->SetLabel(GameDB->getString("Serial"));
@@ -107,7 +107,13 @@ void Panels::GameDatabasePanel::PopulateFields() {
patchesBox->SetLabel(GameDB->getString("[patches]"));
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
- gameFixes[i]->SetValue(GameDB->getBool(EnumToString(i)+wxString(L"Hack")));
+ {
+ wxString keyName (EnumToString(i)); keyName += L"Hack";
+ if( GameDB->keyExists(keyName) )
+ gameFixes[i]->SetValue(GameDB->getBool(keyName));
+ else
+ gameFixes[i]->SetIndeterminate();
+ }
}
else {
serialBox ->SetLabel(L"");
@@ -129,35 +135,37 @@ void Panels::GameDatabasePanel::PopulateFields() {
// returns True if the database is modified, or FALSE if no changes to save.
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
- DataBase_Loader* GameDB = AppHost_GetGameDatabase();
- wxString wxStr( serialBox->GetValue() );
+ IGameDatabase* GameDB = AppHost_GetGameDatabase();
- if (wxStr.IsEmpty()) return false;
- if (wxStr != GameDB->getString("Serial")) {
- GameDB->addGame(wxStr);
- }
+ if (serialBox->GetValue().IsEmpty()) return false;
- writeTextBoxToDB("Name", nameBox->GetValue());
- writeTextBoxToDB("Region", regionBox->GetValue());
- writeTextBoxToDB("Compat", compatBox->GetValue());
- writeTextBoxToDB("[comments]", commentBox->GetValue());
- writeTextBoxToDB("[patches]", patchesBox->GetValue());
+ // Only write the serial if its been changed
+ if( !GameDB->setGame(serialBox->GetValue()) )
+ GameDB->writeString(L"Serial", 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());
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
- const bool val = gameFixes[i]->GetValue();
- wxString keyName( EnumToString(i) ); keyName += L"Hack";
- if (!val) GameDB->deleteKey(keyName);
- else GameDB->writeBool(keyName, val);
+ wxString keyName (EnumToString(i)); keyName += L"Hack";
+
+ if (gameFixes[i]->IsIndeterminate())
+ GameDB->deleteKey(keyName);
+ else
+ GameDB->writeBool(keyName, gameFixes[i]->GetValue());
}
return true;
}
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
- DataBase_Loader* GameDB = AppHost_GetGameDatabase();
+ IGameDatabase* GameDB = AppHost_GetGameDatabase();
wxString wxStr = serialBox->GetValue();
-
+
if( wxStr.IsEmpty() ) wxStr = DiscID;
-
+
bool bySerial = 1;//searchType->GetSelection()==0;
if (bySerial) GameDB->setGame(wxStr);
@@ -166,49 +174,14 @@ void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
}
void Panels::GameDatabasePanel::Apply() {
- DataBase_Loader* GameDB = AppHost_GetGameDatabase();
+ AppGameDatabase* GameDB = wxGetApp().GetGameDatabase();
if( WriteFieldsToDB() )
{
Console.WriteLn("Saving changes to Game Database...");
- GameDB->saveToFile();
+ GameDB->SaveToFile();
}
}
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
{
}
-
-/*
- //#define lineIndent(_wxSizer, txt) {_wxSizer+=5;_wxSizer+=5;_wxSizer+=Heading(txt);_wxSizer+=5;_wxSizer+=5;}
-
- //searchBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
- //searchType = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
- //searchList = new wxListBox (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB);
- //searchList->SetFont (wxFont(searchList->GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console"));
- //searchList->SetMinSize(wxSize(wxDefaultCoord, std::max(searchList->GetMinSize().GetHeight(), 96)));
-
- searchType->Append(L"Game Serial", (void*)0);
- searchType->Append(L"Game Name" , (void*)0);
- searchType->SetSelection(0);
-
- sizer1 += searchType;
- sizer1 += 5;
- sizer1 += searchBox | pxCenter;
- sizer1 += 5;
- sizer1 += searchBtn;
-
- sizer1 += 5;
- sizer1 += 5;
- sizer1 += searchList | StdExpand();// pxCenter;
- sizer1 += 5;
- sizer1 += 5;
-
- lineIndent(sizer1, L"");
- sizer1 += 5;
- sizer1 += 5;
- sizer1 += new wxStaticLine(this) | StdExpand();
- sizer1 += 5;
- sizer1 += 5;
- lineIndent(sizer1, L"");
- lineIndent(sizer1, L"Game Info");
-*/
diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
index e775aa4d91..b893b3e8a8 100644
--- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
+++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
@@ -260,6 +260,14 @@
RelativePath="..\..\Utilities\folderdesc.txt"
>
+
+
+
+
@@ -312,22 +320,6 @@
>
-
-
-
-
-
-
-
-
@@ -467,10 +459,6 @@
RelativePath="..\..\System\PageFaultSource.h"
>
-
-
@@ -1896,6 +1884,10 @@
RelativePath="..\..\gui\AppEventSources.cpp"
>
+
+
@@ -2657,6 +2649,10 @@
RelativePath="..\..\gui\AppForwardDefs.h"
>
+
+
diff --git a/pcsx2/x86/iMisc.cpp b/pcsx2/x86/iMisc.cpp
index 98996511b0..361afa4629 100644
--- a/pcsx2/x86/iMisc.cpp
+++ b/pcsx2/x86/iMisc.cpp
@@ -17,18 +17,17 @@
#include "PrecompiledHeader.h"
#include
-SSE_MXCSR g_sseMXCSR = { DEFAULT_sseMXCSR };
-SSE_MXCSR g_sseVUMXCSR = { DEFAULT_sseVUMXCSR };
+SSE_MXCSR g_sseMXCSR = { DEFAULT_sseMXCSR };
+SSE_MXCSR g_sseVUMXCSR = { DEFAULT_sseVUMXCSR };
-//////////////////////////////////////////////////////////////////////////////////////////
// SetCPUState -- for assignment of SSE roundmodes and clampmodes.
//
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVUMXCSR)
{
//Msgbox::Alert("SetCPUState: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR);
- g_sseMXCSR = sseMXCSR.ApplyReserveMask();
- g_sseVUMXCSR = sseVUMXCSR.ApplyReserveMask();
+ g_sseMXCSR = sseMXCSR.ApplyReserveMask();
+ g_sseVUMXCSR = sseVUMXCSR.ApplyReserveMask();
_mm_setcsr( g_sseMXCSR.bitmask );
}