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 ); }