mirror of https://github.com/PCSX2/pcsx2.git
GameDatabase / Patches:
* Made all database key comparisons case-insensitive, so that "patches" and "Patches" both work as expected, etc. * Applied patches should be remembered properly now when using suspend/resume and savestates (hopefully -- didn't test savestates yet). DevNotes: * Reorganized all game database code into a generic interface used by the emulation core (IGameDatabase), and app-side implementation (AppGameDatabase) that loads the files and provides info in a thread-safe manner. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3223 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
b5a0a7186e
commit
914474ebc9
|
@ -27,7 +27,7 @@
|
||||||
#include "GS.h" // for gsRegionMode
|
#include "GS.h" // for gsRegionMode
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "ps2/BiosTools.h"
|
#include "ps2/BiosTools.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
wxString DiscID;
|
wxString DiscID;
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ static __forceinline void _reloadElfInfo(wxString elfpath)
|
||||||
elfptr.Delete();
|
elfptr.Delete();
|
||||||
|
|
||||||
// Set the Game DataBase to the correct game based on Game Serial Code...
|
// Set the Game DataBase to the correct game based on Game Serial Code...
|
||||||
if (DataBase_Loader* GameDB = AppHost_GetGameDatabase()) {
|
if (IGameDatabase* GameDB = AppHost_GetGameDatabase()) {
|
||||||
wxString gameSerial = DiscID;
|
wxString gameSerial = DiscID;
|
||||||
if (DiscID.IsEmpty()) { // Search for crc if no Serial Code
|
if (DiscID.IsEmpty()) { // Search for crc if no Serial Code
|
||||||
gameSerial = wxString(wxsFormat( L"%8.8x", ElfCRC ));
|
gameSerial = wxString(wxsFormat( L"%8.8x", ElfCRC ));
|
||||||
|
|
|
@ -121,7 +121,7 @@ set(pcsx2Sources
|
||||||
COP0.cpp
|
COP0.cpp
|
||||||
COP2.cpp
|
COP2.cpp
|
||||||
Counters.cpp
|
Counters.cpp
|
||||||
DataBase_Loader.cpp
|
GameDatabase.cpp
|
||||||
Dump.cpp
|
Dump.cpp
|
||||||
Elfheader.cpp
|
Elfheader.cpp
|
||||||
FiFo.cpp
|
FiFo.cpp
|
||||||
|
@ -194,7 +194,7 @@ set(pcsx2Headers
|
||||||
Counters.h
|
Counters.h
|
||||||
Dmac.h
|
Dmac.h
|
||||||
Dump.h
|
Dump.h
|
||||||
DataBase_Loader.h
|
GameDatabase.h
|
||||||
Elfheader.h
|
Elfheader.h
|
||||||
Gif.h
|
Gif.h
|
||||||
GS.h
|
GS.h
|
||||||
|
@ -290,6 +290,7 @@ set(pcsx2GuiSources
|
||||||
gui/AppCorePlugins.cpp
|
gui/AppCorePlugins.cpp
|
||||||
gui/AppCoreThread.cpp
|
gui/AppCoreThread.cpp
|
||||||
gui/AppEventSources.cpp
|
gui/AppEventSources.cpp
|
||||||
|
gui/AppGameDatabase.cpp
|
||||||
gui/AppInit.cpp
|
gui/AppInit.cpp
|
||||||
gui/AppMain.cpp
|
gui/AppMain.cpp
|
||||||
gui/AppRes.cpp
|
gui/AppRes.cpp
|
||||||
|
@ -355,6 +356,7 @@ set(pcsx2GuiHeaders
|
||||||
gui/AppCorePlugins.h
|
gui/AppCorePlugins.h
|
||||||
gui/AppEventListeners.h
|
gui/AppEventListeners.h
|
||||||
gui/AppForwardDefs.h
|
gui/AppForwardDefs.h
|
||||||
|
gui/AppGameDatabase.h
|
||||||
gui/ConsoleLogger.h
|
gui/ConsoleLogger.h
|
||||||
gui/CpuUsageProvider.h
|
gui/CpuUsageProvider.h
|
||||||
gui/Dialogs/ConfigurationDialog.h
|
gui/Dialogs/ConfigurationDialog.h
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "AppConfig.h"
|
|
||||||
#include <wx/wfstream.h>
|
|
||||||
|
|
||||||
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<Game_Data> GameDataArray;
|
|
||||||
typedef std::vector<key_pair> KeyPairArray;
|
|
||||||
|
|
||||||
struct key_pair {
|
|
||||||
wxString key;
|
|
||||||
wxString value;
|
|
||||||
|
|
||||||
key_pair() {}
|
|
||||||
key_pair(const wxString& _key, const wxString& _value)
|
|
||||||
: key(_key) , value(_value) {}
|
|
||||||
|
|
||||||
void Clear() {
|
|
||||||
key.clear();
|
|
||||||
value.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performs case-insensitive compare against the key value.
|
|
||||||
bool CompareKey( const wxString& cmpto ) const {
|
|
||||||
return key.CmpNoCase(cmpto) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsOk() const {
|
|
||||||
return !key.IsEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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");
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "AppConfig.h"
|
||||||
|
#include <wx/wfstream.h>
|
||||||
|
|
||||||
|
struct key_pair;
|
||||||
|
class Game_Data;
|
||||||
|
|
||||||
|
typedef std::vector<key_pair> KeyPairArray;
|
||||||
|
|
||||||
|
struct key_pair {
|
||||||
|
wxString key;
|
||||||
|
wxString value;
|
||||||
|
|
||||||
|
key_pair() {}
|
||||||
|
key_pair(const wxString& _key, const wxString& _value)
|
||||||
|
: key(_key) , value(_value) {}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
|
key.clear();
|
||||||
|
value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performs case-insensitive compare against the key value.
|
||||||
|
bool CompareKey( const wxString& cmpto ) const {
|
||||||
|
return key.CmpNoCase(cmpto) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOk() const {
|
||||||
|
return !key.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Game_Data> 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();
|
|
@ -204,8 +204,8 @@
|
||||||
<Unit filename="../Config.h" />
|
<Unit filename="../Config.h" />
|
||||||
<Unit filename="../Counters.cpp" />
|
<Unit filename="../Counters.cpp" />
|
||||||
<Unit filename="../Counters.h" />
|
<Unit filename="../Counters.h" />
|
||||||
<Unit filename="../DataBase_Loader.cpp" />
|
<Unit filename="../GameDatabase.cpp" />
|
||||||
<Unit filename="../DataBase_Loader.h" />
|
<Unit filename="../GameDatabase.h" />
|
||||||
<Unit filename="../DebugTools/Debug.h" />
|
<Unit filename="../DebugTools/Debug.h" />
|
||||||
<Unit filename="../DebugTools/DisASM.h" />
|
<Unit filename="../DebugTools/DisASM.h" />
|
||||||
<Unit filename="../DebugTools/DisR3000A.cpp" />
|
<Unit filename="../DebugTools/DisR3000A.cpp" />
|
||||||
|
@ -359,6 +359,8 @@
|
||||||
<Unit filename="../gui/AppEventListeners.h" />
|
<Unit filename="../gui/AppEventListeners.h" />
|
||||||
<Unit filename="../gui/AppEventSources.cpp" />
|
<Unit filename="../gui/AppEventSources.cpp" />
|
||||||
<Unit filename="../gui/AppForwardDefs.h" />
|
<Unit filename="../gui/AppForwardDefs.h" />
|
||||||
|
<Unit filename="../gui/AppGameDatabase.cpp" />
|
||||||
|
<Unit filename="../gui/AppGameDatabase.h" />
|
||||||
<Unit filename="../gui/AppInit.cpp" />
|
<Unit filename="../gui/AppInit.cpp" />
|
||||||
<Unit filename="../gui/AppMain.cpp" />
|
<Unit filename="../gui/AppMain.cpp" />
|
||||||
<Unit filename="../gui/AppRes.cpp" />
|
<Unit filename="../gui/AppRes.cpp" />
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "IopCommon.h"
|
#include "IopCommon.h"
|
||||||
#include "Patch.h"
|
#include "Patch.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "GameDatabase.h"
|
||||||
#include <wx/textfile.h>
|
#include <wx/textfile.h>
|
||||||
|
|
||||||
IniPatch Patch[ MAX_PATCH ];
|
IniPatch Patch[ MAX_PATCH ];
|
||||||
|
@ -135,10 +135,9 @@ int InitPatches(const wxString& name)
|
||||||
{
|
{
|
||||||
bool patchFound = false;
|
bool patchFound = false;
|
||||||
wxString patch;
|
wxString patch;
|
||||||
const wxString crc( L"[patches = " + name + L"]" );
|
|
||||||
patchnumber = 0;
|
patchnumber = 0;
|
||||||
|
|
||||||
if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() )
|
if (IGameDatabase* GameDB = AppHost_GetGameDatabase() )
|
||||||
{
|
{
|
||||||
if(GameDB->gameLoaded()) {
|
if(GameDB->gameLoaded()) {
|
||||||
if (GameDB->sectionExists(L"patches", name)) {
|
if (GameDB->sectionExists(L"patches", name)) {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
#include "Patch.h"
|
#include "Patch.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "GameDatabase.h"
|
||||||
#include "SamplProf.h"
|
#include "SamplProf.h"
|
||||||
|
|
||||||
using namespace R5900; // for R5900 disasm tools
|
using namespace R5900; // for R5900 disasm tools
|
||||||
|
@ -574,60 +574,22 @@ __forceinline void CPU_INT( u32 n, s32 ecycle)
|
||||||
cpuSetNextBranchDelta( cpuRegs.eCycle[n] );
|
cpuSetNextBranchDelta( cpuRegs.eCycle[n] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called from recompilers; __fastcall define is mandatory.
|
||||||
void __fastcall eeGameStarting()
|
void __fastcall eeGameStarting()
|
||||||
{
|
{
|
||||||
if (!g_GameStarted && ElfCRC) {
|
if (!g_GameStarted)
|
||||||
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()) {
|
Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
|
||||||
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);
|
|
||||||
g_GameStarted = true;
|
g_GameStarted = true;
|
||||||
|
GetCoreThread().GameStartingInThread();
|
||||||
if (0) ProfilerSetEnabled(true);
|
}
|
||||||
|
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()
|
void __fastcall eeloadReplaceOSDSYS()
|
||||||
{
|
{
|
||||||
g_SkipBiosHack = false;
|
g_SkipBiosHack = false;
|
||||||
|
|
|
@ -262,12 +262,12 @@ const u32 EENULL_START = 0x81FC0;
|
||||||
const u32 EELOAD_START = 0x82000;
|
const u32 EELOAD_START = 0x82000;
|
||||||
const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
|
const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
|
||||||
|
|
||||||
void __fastcall eeGameStarting();
|
extern void __fastcall eeGameStarting();
|
||||||
void __fastcall eeloadReplaceOSDSYS();
|
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
|
// [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
|
// off until I get my new IOPint and IOPrec re-merged. --air
|
||||||
//
|
//
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
// Includes needed for cleanup, since we don't have a good system (yet) for
|
// Includes needed for cleanup, since we don't have a good system (yet) for
|
||||||
// cleaning up these things.
|
// cleaning up these things.
|
||||||
#include "sVU_zerorec.h"
|
#include "sVU_zerorec.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
extern void closeNewVif(int idx);
|
extern void closeNewVif(int idx);
|
||||||
extern void resetNewVif(int idx);
|
extern void resetNewVif(int idx);
|
||||||
|
|
|
@ -182,10 +182,6 @@ void SysCoreThread::DoCpuReset()
|
||||||
cpuReset();
|
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
|
// 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).
|
// clock scale, which does not correlate to the actual host machine vsync).
|
||||||
//
|
//
|
||||||
|
@ -197,11 +193,18 @@ void SysCoreThread::PostVsyncToUI()
|
||||||
//
|
//
|
||||||
void SysCoreThread::VsyncInThread()
|
void SysCoreThread::VsyncInThread()
|
||||||
{
|
{
|
||||||
PostVsyncToUI();
|
|
||||||
if (EmuConfig.EnablePatches) ApplyPatch();
|
if (EmuConfig.EnablePatches) ApplyPatch();
|
||||||
if (EmuConfig.EnableCheats) ApplyCheat();
|
if (EmuConfig.EnableCheats) ApplyCheat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::GameStartingInThread()
|
||||||
|
{
|
||||||
|
GetMTGS().SendGameCRC(ElfCRC);
|
||||||
|
|
||||||
|
if (EmuConfig.EnablePatches) ApplyPatch(0);
|
||||||
|
if (EmuConfig.EnableCheats) ApplyCheat(0);
|
||||||
|
}
|
||||||
|
|
||||||
void SysCoreThread::StateCheckInThread()
|
void SysCoreThread::StateCheckInThread()
|
||||||
{
|
{
|
||||||
GetMTGS().RethrowException();
|
GetMTGS().RethrowException();
|
||||||
|
|
|
@ -186,7 +186,7 @@ public:
|
||||||
|
|
||||||
virtual void StateCheckInThread();
|
virtual void StateCheckInThread();
|
||||||
virtual void VsyncInThread();
|
virtual void VsyncInThread();
|
||||||
virtual void PostVsyncToUI()=0;
|
virtual void GameStartingInThread();
|
||||||
|
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "AppCommon.h"
|
#include "AppCommon.h"
|
||||||
#include "AppCoreThread.h"
|
#include "AppCoreThread.h"
|
||||||
#include "RecentIsoList.h"
|
#include "RecentIsoList.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "AppGameDatabase.h"
|
||||||
|
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
#include "System/SysThreads.h"
|
#include "System/SysThreads.h"
|
||||||
|
@ -318,7 +318,7 @@ struct pxAppResources
|
||||||
ScopedPtr<wxImageList> ToolbarImages;
|
ScopedPtr<wxImageList> ToolbarImages;
|
||||||
ScopedPtr<wxIconBundle> IconBundle;
|
ScopedPtr<wxIconBundle> IconBundle;
|
||||||
ScopedPtr<wxBitmap> Bitmap_Logo;
|
ScopedPtr<wxBitmap> Bitmap_Logo;
|
||||||
ScopedPtr<DataBase_Loader> GameDB;
|
ScopedPtr<AppGameDatabase> GameDB;
|
||||||
|
|
||||||
pxAppResources();
|
pxAppResources();
|
||||||
virtual ~pxAppResources() throw() { }
|
virtual ~pxAppResources() throw() { }
|
||||||
|
@ -568,6 +568,7 @@ public:
|
||||||
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
|
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
|
||||||
void SysShutdown();
|
void SysShutdown();
|
||||||
void LogicalVsync();
|
void LogicalVsync();
|
||||||
|
void GameStarting();
|
||||||
|
|
||||||
GSFrame& GetGsFrame() const;
|
GSFrame& GetGsFrame() const;
|
||||||
MainEmuFrame& GetMainFrame() const;
|
MainEmuFrame& GetMainFrame() const;
|
||||||
|
@ -618,7 +619,7 @@ public:
|
||||||
return m_Resources->ImageId;
|
return m_Resources->ImageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataBase_Loader* GetGameDatabase();
|
AppGameDatabase* GetGameDatabase();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Overrides of wxApp virtuals:
|
// Overrides of wxApp virtuals:
|
||||||
|
|
|
@ -144,9 +144,12 @@ void AppCoreThread::ChangeCdvdSource()
|
||||||
// TODO: Add a listener for CDVDsource changes? Or should we bother?
|
// TODO: Add a listener for CDVDsource changes? Or should we bother?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int loadGameSettings(IGameDatabase* gameDB=NULL);
|
||||||
|
|
||||||
void AppCoreThread::OnResumeReady()
|
void AppCoreThread::OnResumeReady()
|
||||||
{
|
{
|
||||||
ApplySettings( g_Conf->EmuOptions );
|
ApplySettings( g_Conf->EmuOptions );
|
||||||
|
loadGameSettings();
|
||||||
|
|
||||||
CDVD_SourceType cdvdsrc( g_Conf->CdvdSource );
|
CDVD_SourceType cdvdsrc( g_Conf->CdvdSource );
|
||||||
if( cdvdsrc != CDVDsys_GetSourceType() || (cdvdsrc==CDVDsrc_Iso && (CDVDsys_GetFile(cdvdsrc) != g_Conf->CurrentIso)) )
|
if( cdvdsrc != CDVDsys_GetSourceType() || (cdvdsrc==CDVDsrc_Iso && (CDVDsys_GetFile(cdvdsrc) != g_Conf->CurrentIso)) )
|
||||||
|
@ -230,9 +233,16 @@ void AppCoreThread::OnCleanupInThread()
|
||||||
_parent::OnCleanupInThread();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::PostVsyncToUI()
|
void AppCoreThread::VsyncInThread()
|
||||||
{
|
{
|
||||||
wxGetApp().LogicalVsync();
|
wxGetApp().LogicalVsync();
|
||||||
|
_parent::VsyncInThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppCoreThread::GameStartingInThread()
|
||||||
|
{
|
||||||
|
wxGetApp().GameStarting();
|
||||||
|
_parent::GameStartingInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::StateCheckInThread()
|
void AppCoreThread::StateCheckInThread()
|
||||||
|
|
|
@ -144,7 +144,8 @@ protected:
|
||||||
virtual void OnResumeInThread( bool IsSuspended );
|
virtual void OnResumeInThread( bool IsSuspended );
|
||||||
virtual void OnSuspendInThread();
|
virtual void OnSuspendInThread();
|
||||||
virtual void OnCleanupInThread();
|
virtual void OnCleanupInThread();
|
||||||
virtual void PostVsyncToUI();
|
virtual void VsyncInThread();
|
||||||
|
virtual void GameStartingInThread();
|
||||||
virtual void ExecuteTaskInThread();
|
virtual void ExecuteTaskInThread();
|
||||||
virtual void DoCpuReset();
|
virtual void DoCpuReset();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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"---------------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; id<pxEnumEnd; ++id )
|
||||||
|
{
|
||||||
|
wxString key( EnumToString(id) );
|
||||||
|
key += L"Hack";
|
||||||
|
|
||||||
|
if (gameDB->keyExists(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
|
// Pcsx2App Event Handlers
|
||||||
|
@ -987,16 +1108,20 @@ SysCoreAllocations& GetSysCoreAlloc()
|
||||||
return *wxGetApp().m_CoreAllocs;
|
return *wxGetApp().m_CoreAllocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataBase_Loader* Pcsx2App::GetGameDatabase()
|
AppGameDatabase* Pcsx2App::GetGameDatabase()
|
||||||
{
|
{
|
||||||
pxAppResources& res( GetResourceCache() );
|
pxAppResources& res( GetResourceCache() );
|
||||||
|
|
||||||
ScopedLock lock( m_mtx_LoadingGameDB );
|
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;
|
return res.GameDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataBase_Loader* AppHost_GetGameDatabase()
|
IGameDatabase* AppHost_GetGameDatabase()
|
||||||
{
|
{
|
||||||
return wxGetApp().GetGameDatabase();
|
return wxGetApp().GetGameDatabase();
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "DataBase_Loader.h"
|
#include "App.h"
|
||||||
#include "ConfigurationPanels.h"
|
#include "ConfigurationPanels.h"
|
||||||
|
|
||||||
extern wxString DiscID;
|
extern wxString DiscID;
|
||||||
|
@ -42,11 +42,11 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags =
|
||||||
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
||||||
: BaseApplicableConfigPanel( parent )
|
: BaseApplicableConfigPanel( parent )
|
||||||
{
|
{
|
||||||
//if (!GameDB) GameDB = new DataBase_Loader();
|
//if (!GameDB) GameDB = new GameDatabase();
|
||||||
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
|
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||||
pxAssume( GameDB != NULL );
|
pxAssume( GameDB != NULL );
|
||||||
|
|
||||||
searchBtn = new wxButton (this, wxID_DEFAULT, L"Search");
|
searchBtn = new wxButton (this, wxID_ANY, _("Search"));
|
||||||
|
|
||||||
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||||
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||||
|
@ -56,7 +56,7 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
||||||
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
||||||
|
|
||||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
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(_("Game Database Editor")).Bold() | StdExpand();
|
||||||
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
|
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
|
||||||
|
@ -96,7 +96,7 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::GameDatabasePanel::PopulateFields() {
|
void Panels::GameDatabasePanel::PopulateFields() {
|
||||||
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
|
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||||
|
|
||||||
if (GameDB->gameLoaded()) {
|
if (GameDB->gameLoaded()) {
|
||||||
serialBox ->SetLabel(GameDB->getString("Serial"));
|
serialBox ->SetLabel(GameDB->getString("Serial"));
|
||||||
|
@ -107,7 +107,13 @@ void Panels::GameDatabasePanel::PopulateFields() {
|
||||||
patchesBox->SetLabel(GameDB->getString("[patches]"));
|
patchesBox->SetLabel(GameDB->getString("[patches]"));
|
||||||
|
|
||||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
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 {
|
else {
|
||||||
serialBox ->SetLabel(L"");
|
serialBox ->SetLabel(L"");
|
||||||
|
@ -129,31 +135,33 @@ void Panels::GameDatabasePanel::PopulateFields() {
|
||||||
|
|
||||||
// returns True if the database is modified, or FALSE if no changes to save.
|
// returns True if the database is modified, or FALSE if no changes to save.
|
||||||
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
|
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
|
||||||
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
|
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||||
wxString wxStr( serialBox->GetValue() );
|
|
||||||
|
|
||||||
if (wxStr.IsEmpty()) return false;
|
if (serialBox->GetValue().IsEmpty()) return false;
|
||||||
if (wxStr != GameDB->getString("Serial")) {
|
|
||||||
GameDB->addGame(wxStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeTextBoxToDB("Name", nameBox->GetValue());
|
// Only write the serial if its been changed
|
||||||
writeTextBoxToDB("Region", regionBox->GetValue());
|
if( !GameDB->setGame(serialBox->GetValue()) )
|
||||||
writeTextBoxToDB("Compat", compatBox->GetValue());
|
GameDB->writeString(L"Serial", serialBox->GetValue());
|
||||||
writeTextBoxToDB("[comments]", commentBox->GetValue());
|
|
||||||
writeTextBoxToDB("[patches]", patchesBox->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) {
|
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
|
||||||
const bool val = gameFixes[i]->GetValue();
|
wxString keyName (EnumToString(i)); keyName += L"Hack";
|
||||||
wxString keyName( EnumToString(i) ); keyName += L"Hack";
|
|
||||||
if (!val) GameDB->deleteKey(keyName);
|
if (gameFixes[i]->IsIndeterminate())
|
||||||
else GameDB->writeBool(keyName, val);
|
GameDB->deleteKey(keyName);
|
||||||
|
else
|
||||||
|
GameDB->writeBool(keyName, gameFixes[i]->GetValue());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
|
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
|
||||||
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
|
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||||
wxString wxStr = serialBox->GetValue();
|
wxString wxStr = serialBox->GetValue();
|
||||||
|
|
||||||
if( wxStr.IsEmpty() ) wxStr = DiscID;
|
if( wxStr.IsEmpty() ) wxStr = DiscID;
|
||||||
|
@ -166,49 +174,14 @@ void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::GameDatabasePanel::Apply() {
|
void Panels::GameDatabasePanel::Apply() {
|
||||||
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
|
AppGameDatabase* GameDB = wxGetApp().GetGameDatabase();
|
||||||
if( WriteFieldsToDB() )
|
if( WriteFieldsToDB() )
|
||||||
{
|
{
|
||||||
Console.WriteLn("Saving changes to Game Database...");
|
Console.WriteLn("Saving changes to Game Database...");
|
||||||
GameDB->saveToFile();
|
GameDB->SaveToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
|
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");
|
|
||||||
*/
|
|
||||||
|
|
|
@ -260,6 +260,14 @@
|
||||||
RelativePath="..\..\Utilities\folderdesc.txt"
|
RelativePath="..\..\Utilities\folderdesc.txt"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\GameDatabase.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\GameDatabase.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\PrecompiledHeader.cpp"
|
RelativePath="..\..\PrecompiledHeader.cpp"
|
||||||
>
|
>
|
||||||
|
@ -312,22 +320,6 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
|
||||||
Name="Game DataBase"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\DataBase_Loader.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\DataBase_Loader.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\File_Reader.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
<Filter
|
||||||
Name="Patch"
|
Name="Patch"
|
||||||
>
|
>
|
||||||
|
@ -467,10 +459,6 @@
|
||||||
RelativePath="..\..\System\PageFaultSource.h"
|
RelativePath="..\..\System\PageFaultSource.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\Paths.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Plugins.h"
|
RelativePath="..\..\Plugins.h"
|
||||||
>
|
>
|
||||||
|
@ -1896,6 +1884,10 @@
|
||||||
RelativePath="..\..\gui\AppEventSources.cpp"
|
RelativePath="..\..\gui\AppEventSources.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\gui\AppGameDatabase.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\AppInit.cpp"
|
RelativePath="..\..\gui\AppInit.cpp"
|
||||||
>
|
>
|
||||||
|
@ -2657,6 +2649,10 @@
|
||||||
RelativePath="..\..\gui\AppForwardDefs.h"
|
RelativePath="..\..\gui\AppForwardDefs.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\gui\AppGameDatabase.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\ApplyState.h"
|
RelativePath="..\..\gui\ApplyState.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
SSE_MXCSR g_sseMXCSR = { DEFAULT_sseMXCSR };
|
SSE_MXCSR g_sseMXCSR = { DEFAULT_sseMXCSR };
|
||||||
SSE_MXCSR g_sseVUMXCSR = { DEFAULT_sseVUMXCSR };
|
SSE_MXCSR g_sseVUMXCSR = { DEFAULT_sseVUMXCSR };
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SetCPUState -- for assignment of SSE roundmodes and clampmodes.
|
// SetCPUState -- for assignment of SSE roundmodes and clampmodes.
|
||||||
//
|
//
|
||||||
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVUMXCSR)
|
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVUMXCSR)
|
||||||
|
|
Loading…
Reference in New Issue