Commandline, UI, and Game Database Work:

* Improved console window behavior during startup and shutdown (also fixes minor threading issues)
 * Added better failsafes for avoiding "rouge" pcsx2 processes left behind when wxWidgets would fail to "notice" window closures properly.
 * Database loader is now thread-safe and cleans itself up properly on exit.
 * Added some handy enumeration tools for the gamefixes (prep work for making them commandline controllable).
 * ... and more prelim commandline work!  (actual functional implementations coming very soon)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3212 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-06-15 14:13:23 +00:00
parent dce5ca9aca
commit 2300f972e4
22 changed files with 596 additions and 243 deletions

View File

@ -561,7 +561,9 @@ protected:
void OnDialogCreated( wxCommandEvent& evt );
void OnOkCancel(wxCommandEvent& evt);
void OnCloseWindow(wxCloseEvent& event);
bool ShouldPreventAppExit() const { return false; }
void DoAutoCenter();
};

View File

@ -29,8 +29,6 @@
#include "ps2/BiosTools.h"
#include "DataBase_Loader.h"
ScopedPtr<DataBase_Loader> GameDB;
wxString DiscID;
static cdvdStruct cdvd;
@ -356,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 (GameDB) {
if (DataBase_Loader* GameDB = AppHost_GetGameDatabase()) {
wxString gameSerial = DiscID;
if (DiscID.IsEmpty()) { // Search for crc if no Serial Code
gameSerial = wxString(wxsFormat( L"%8.8x", ElfCRC ));
@ -555,8 +553,6 @@ void cdvdReset()
cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9);
cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
if( !GameDB ) GameDB = new DataBase_Loader();
}
struct Freeze_v10Compat

View File

@ -19,6 +19,25 @@
class IniInterface;
class pxEnumEnd_t { };
const pxEnumEnd_t pxEnumEnd = {};
// [TODO] Add assertion checks to ++/-- operators!
#define ImplementEnumOperators( enumName ) \
static __forceinline GamefixId& operator++( enumName& src ) { src = (enumName)((int)src+1); return src; } \
static __forceinline GamefixId& operator--( enumName& src ) { src = (enumName)((int)src-1); return src; } \
static __forceinline GamefixId operator++( enumName& src, int ) { enumName orig = src; src = (enumName)((int)src+1); return orig; } \
static __forceinline GamefixId operator--( enumName& src, int ) { enumName orig = src; src = (enumName)((int)src-1); return src; } \
\
static __forceinline bool operator<( const enumName& left, const pxEnumEnd_t& ) { return (int)left < enumName##_COUNT; } \
static __forceinline bool operator!=( const enumName& left, const pxEnumEnd_t& ) { return (int)left != enumName##_COUNT; } \
static __forceinline bool operator==( const enumName& left, const pxEnumEnd_t& ) { return (int)left == enumName##_COUNT; } \
\
static __forceinline void EnumAssertOnBounds( enumName id ) { \
pxAssume( ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT ) ); } \
\
extern const wxChar* EnumToString( enumName id )
enum PluginsEnum_t
{
PluginId_GS = 0,
@ -37,6 +56,25 @@ enum PluginsEnum_t
PluginId_Mcd
};
enum GamefixId
{
GamefixId_FIRST = 0,
Fix_VuAddSub = GamefixId_FIRST,
Fix_VuClipFlag,
Fix_FpuCompare,
Fix_FpuMultiply,
Fix_FpuNegDiv,
Fix_XGKick,
Fix_IpuWait,
Fix_EETiming,
Fix_SkipMpeg,
GamefixId_COUNT
};
ImplementEnumOperators( GamefixId );
//------------ DEFAULT sseMXCSR VALUES ---------------
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
@ -440,6 +478,13 @@ struct Pcsx2Config
GamefixOptions() : bitset( 0 ) {}
void LoadSave( IniInterface& conf );
void Set( const wxString& list, bool enabled=true );
bool Clear( const wxString& list ) { Set( list, false ); }
bool Get( GamefixId id ) const;
void Set( GamefixId id, bool enabled=true );
bool Clear( GamefixId id ) { Set( id, false ); }
bool operator ==( const GamefixOptions& right ) const
{
return OpEqu( bitset );
@ -562,8 +607,6 @@ TraceLogFilters& SetTraceConfig();
#define CHECK_IOPREC (EmuConfig.Cpu.Recompiler.EnableIOP && GetSysCoreAlloc().IsRecAvailable_IOP())
//------------ SPECIAL GAME FIXES!!! ---------------
#define NUM_OF_GAME_FIXES 9
#define CHECK_VUADDSUBHACK (EmuConfig.Gamefixes.VuAddSubHack) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate.
#define CHECK_FPUCOMPAREHACK (EmuConfig.Gamefixes.FpuCompareHack) // Special Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
#define CHECK_VUCLIPFLAGHACK (EmuConfig.Gamefixes.VuClipFlagHack) // Special Fix for Persona games, maybe others. It's to do with the VU clip flag (again).

View File

@ -8,7 +8,7 @@
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.key.clear();
keyPair.Clear();
}
// Multiline Sections are in the form of:
@ -47,8 +47,7 @@ bool DataBase_Loader::extractMultiLine(const wxString& line, key_pair& keyPair,
}
void DataBase_Loader::extract(const wxString& line, key_pair& keyPair, wxInputStream& reader) {
keyPair.key.clear();
keyPair.value.clear();
keyPair.Clear();
if( line.IsEmpty() ) return;

View File

@ -28,6 +28,20 @@ struct 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!" );
@ -54,8 +68,17 @@ class Game_Data {
public:
wxString id; // Serial Identification Code
deque<key_pair> kList; // List of all (key, value) pairs for game data
Game_Data(const wxString& _id)
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:
@ -83,8 +106,9 @@ protected:
const wxString m_emptyString; // empty string for returning stuff .. never modify!
wxString m_dest;
std::string m_intermediate;
public:
deque<Game_Data*> gList; // List of all game data
deque<Game_Data> gList; // List of all game data
Game_Data* curGame; // Current game data
wxString header; // Header of the database
wxString baseKey; // Key to separate games by ("Serial")
@ -99,34 +123,34 @@ public:
wxFFileInputStream reader( file );
key_pair keyPair;
wxString s0;
Game_Data* game = NULL;
Game_Data game;
try {
while(!reader.Eof()) {
while(!reader.Eof()) { // Find first game
pxReadLine(reader, s0, m_intermediate);
extract(s0.Trim(true).Trim(false), keyPair, reader);
if (keyPair.key == key) break;
if (keyPair.CompareKey(key)) break;
header += s0 + L'\n';
}
game = new Game_Data(keyPair.value);
game->kList.push_back(keyPair);
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.key.IsEmpty()) continue;
if (keyPair.key == key) {
if (!keyPair.IsOk()) continue;
if (keyPair.CompareKey(key)) {
gList.push_back(game);
game = new Game_Data(keyPair.value);
game.NewSerial(keyPair.value);
}
game->kList.push_back(keyPair);
game.kList.push_back(keyPair);
}
}
}
catch( Exception::EndOfStream& ) {}
if (game) gList.push_back(game);
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());
@ -135,15 +159,16 @@ public:
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) {
deque<Game_Data*>::iterator it = gList.begin();
deque<Game_Data>::iterator it = gList.begin();
for ( ; it != gList.end(); ++it) {
if (it[0]->id == id) {
curGame = it[0];
if (it[0].id == id) {
curGame = &it[0];
return true;
}
}
@ -162,10 +187,10 @@ public:
void saveToFile(const wxString& file = L"GameIndex.dbf") {
wxFFileOutputStream writer( file );
pxWriteMultiline(writer, header);
deque<Game_Data*>::iterator it = gList.begin();
deque<Game_Data>::iterator it = gList.begin();
for ( ; it != gList.end(); ++it) {
deque<key_pair>::iterator i = it[0]->kList.begin();
for ( ; i != it[0]->kList.end(); ++i) {
deque<key_pair>::iterator i = it[0].kList.begin();
for ( ; i != it[0].kList.end(); ++i) {
pxWriteMultiline(writer, i[0].toString() );
}
pxWriteLine(writer, L"---------------------------------------------");
@ -176,11 +201,11 @@ public:
// 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 = new Game_Data(id);
key_pair kp(baseKey, id);
game->kList.push_back(kp);
Game_Data game(id);
key_pair kp(baseKey, id);
game.kList.push_back(kp);
gList.push_back(game);
curGame = game;
curGame = &(gList.end()-1)[0];
}
// Searches the current game's data to see if the given key exists
@ -188,7 +213,7 @@ public:
if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) {
if (it[0].key == key) {
if (it[0].CompareKey(key)) {
return true;
}
}
@ -202,7 +227,7 @@ public:
if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) {
if (it[0].key == key) {
if (it[0].CompareKey(key)) {
curGame->kList.erase(it);
return;
}
@ -216,7 +241,7 @@ public:
if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) {
if (it[0].key == key) {
if (it[0].CompareKey(key)) {
return it[0].value;
}
}
@ -273,7 +298,7 @@ public:
if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) {
if (it[0].key == key) {
if (it[0].CompareKey(key)) {
it[0].value = value;
return;
}
@ -357,4 +382,4 @@ static int loadGameSettings(DataBase_Loader* gameDB) {
return 0;
}
extern ScopedPtr<DataBase_Loader> GameDB;
extern DataBase_Loader* AppHost_GetGameDatabase();

View File

@ -138,14 +138,17 @@ int InitPatches(const wxString& name)
const wxString crc( L"[patches = " + name + L"]" );
patchnumber = 0;
if (GameDB && GameDB->gameLoaded()) {
if (GameDB->sectionExists(L"patches", name)) {
patch = GameDB->getSection(L"patches", name);
patchFound = true;
}
else if (GameDB->keyExists(L"[patches]")) {
patch = GameDB->getString(L"[patches]");
patchFound = true;
if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() )
{
if(GameDB->gameLoaded()) {
if (GameDB->sectionExists(L"patches", name)) {
patch = GameDB->getSection(L"patches", name);
patchFound = true;
}
else if (GameDB->keyExists(L"[patches]")) {
patch = GameDB->getString(L"[patches]");
patchFound = true;
}
}
}

View File

@ -246,6 +246,85 @@ void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini )
IniEntry( FramesToSkip );
}
const wxChar *const tbl_GamefixNames[] =
{
L"VuAddSub",
L"VuClipFlag",
L"FpuCompare",
L"FpuMul",
L"FpuNegDiv",
L"XGKick",
L"IpuWait",
L"EETiming",
L"SkipMpeg"
};
const __forceinline wxChar* EnumToString( GamefixId id )
{
return tbl_GamefixNames[id];
}
// Enables a full list of gamefixes. The list can be either comma or pipe-delimited.
// Example: "XGKick,IpuWait" or "EEtiming,FpuCompare"
// If an unrecognized tag is encountered, a warning is printed to the console, but no error
// is generated. This allows the system to function in the event that future versions of
// PCSX2 remove old hacks once they become obsolete.
void Pcsx2Config::GamefixOptions::Set( const wxString& list, bool enabled )
{
wxStringTokenizer izer( list, L",|", wxTOKEN_STRTOK );
while( izer.HasMoreTokens() )
{
wxString token( izer.GetNextToken() );
GamefixId i;
for (i=GamefixId_FIRST; i < pxEnumEnd; ++i)
{
if( token.CmpNoCase( EnumToString(i) ) == 0 ) break;
}
if( i < pxEnumEnd ) Set( i );
}
}
void Pcsx2Config::GamefixOptions::Set( GamefixId id, bool enabled )
{
EnumAssertOnBounds( id );
switch(id)
{
case Fix_VuAddSub: VuAddSubHack = enabled; break;
case Fix_VuClipFlag: VuClipFlagHack = enabled; break;
case Fix_FpuCompare: FpuCompareHack = enabled; break;
case Fix_FpuMultiply: FpuMulHack = enabled; break;
case Fix_FpuNegDiv: FpuNegDivHack = enabled; break;
case Fix_XGKick: XgKickHack = enabled; break;
case Fix_IpuWait: IPUWaitHack = enabled; break;
case Fix_EETiming: EETimingHack = enabled; break;
case Fix_SkipMpeg: SkipMPEGHack = enabled; break;
jNO_DEFAULT;
}
}
bool Pcsx2Config::GamefixOptions::Get( GamefixId id ) const
{
EnumAssertOnBounds( id );
switch(id)
{
case Fix_VuAddSub: return VuAddSubHack;
case Fix_VuClipFlag: return VuClipFlagHack;
case Fix_FpuCompare: return FpuCompareHack;
case Fix_FpuMultiply: return FpuMulHack;
case Fix_FpuNegDiv: return FpuNegDivHack;
case Fix_XGKick: return XgKickHack;
case Fix_IpuWait: return IPUWaitHack;
case Fix_EETiming: return EETimingHack;
case Fix_SkipMpeg: return SkipMPEGHack;
jNO_DEFAULT
}
return false; // unreachable, but we still need to suppress warnings >_<
}
void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini )
{
GamefixOptions defaults;

View File

@ -585,23 +585,26 @@ void __fastcall eeGameStarting()
wxString gameFixes = L"";
wxString gameCheats = L"";
if (GameDB && 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"]";
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"]";
}
int fixes = loadGameSettings(GameDB);
if (fixes) {
wxString pString( wxsFormat( L"%d", fixes ) );
gameFixes = L" [Fixes = " + pString + 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"]";
}
}
}

View File

@ -328,7 +328,6 @@ void SysCoreAllocations::CleanupMess() throw()
{
try
{
GameDB.Delete();
closeNewVif(0);
closeNewVif(1);

View File

@ -22,7 +22,11 @@
BaseCompressThread::~BaseCompressThread() throw()
{
if( m_PendingSaveFlag ) wxGetApp().ClearPendingSave();
if( m_PendingSaveFlag )
{
wxGetApp().ClearPendingSave();
m_PendingSaveFlag = false;
}
}
void BaseCompressThread::SetPendingSave()

View File

@ -26,6 +26,7 @@
#include "AppCommon.h"
#include "AppCoreThread.h"
#include "RecentIsoList.h"
#include "DataBase_Loader.h"
#include "System.h"
#include "System/SysThreads.h"
@ -317,6 +318,7 @@ struct pxAppResources
ScopedPtr<wxImageList> ToolbarImages;
ScopedPtr<wxIconBundle> IconBundle;
ScopedPtr<wxBitmap> Bitmap_Logo;
ScopedPtr<DataBase_Loader> GameDB;
pxAppResources();
virtual ~pxAppResources() throw() { }
@ -359,6 +361,78 @@ public:
double GetFramerate() const;
};
class StartupOptions
{
public:
bool ForceWizard;
bool ForceConsole;
// Disables the fast boot option when auto-running games. This option only applies
// if SysAutoRun is also true.
bool NoFastBoot;
// Specifies the Iso file to boot; used only if SysAutoRun is enabled and CdvdSource
// is set to ISO.
wxString IsoFile;
// Specifies the CDVD source type to use when AutoRunning
CDVD_SourceType CdvdSource;
// Indicates if PCSX2 should autorun the configured CDVD source and/or ISO file.
bool SysAutoRun;
StartupOptions()
{
ForceWizard = false;
NoFastBoot = false;
ForceConsole = false;
SysAutoRun = false;
CdvdSource = CDVDsrc_NoDisc;
}
};
class CommandlineOverrides
{
public:
AppConfig::FilenameOptions Filenames;
wxDirName SettingsFolder;
wxFileName SettingsFile;
bool DisableSpeedhacks;
// Note that gamefixes in this array should only be honored if the
// "HasCustomGamefixes" boolean is also enabled.
bool UseGamefix[GamefixId_COUNT];
bool ApplyCustomGamefixes;
public:
CommandlineOverrides()
{
DisableSpeedhacks = false;
ApplyCustomGamefixes = false;
}
// Returns TRUE if either speedhacks or gamefixes are being overridden.
bool HasCustomHacks() const
{
return DisableSpeedhacks || ApplyCustomGamefixes;
}
bool HasSettingsOverride() const
{
return SettingsFolder.IsOk() || SettingsFile.IsOk();
}
bool HasPluginsOverride() const
{
for( int i=0; i<PluginId_Count; ++i )
if( Filenames.Plugins[i].IsOk() ) return true;
return false;
}
};
// =====================================================================================================
// Pcsx2App - main wxApp class
// =====================================================================================================
@ -446,12 +520,18 @@ public:
protected:
int m_PendingSaves;
bool m_ScheduledTermination;
bool m_UseGUI;
public:
FramerateManager FpsManager;
CommandDictionary GlobalCommands;
AcceleratorDictionary GlobalAccels;
StartupOptions Startup;
CommandlineOverrides Overrides;
wxTimer* m_timer_Termination;
protected:
ScopedPtr<PipeRedirectionBase> m_StdoutRedirHandle;
ScopedPtr<PipeRedirectionBase> m_StderrRedirHandle;
@ -459,11 +539,13 @@ protected:
ScopedPtr<RecentIsoList> m_RecentIsoList;
ScopedPtr<pxAppResources> m_Resources;
Threading::Mutex m_mtx_Resources;
Threading::Mutex m_mtx_LoadingGameDB;
public:
// Executor Thread for complex VM/System tasks. This thread is used to execute such tasks
// in parallel to the main message pump, to allow the main pump to run without fear of
// blocked threads stalling the GUI.
public:
ExecutorThread SysExecutorThread;
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
@ -535,6 +617,8 @@ public:
{
return m_Resources->ImageId;
}
DataBase_Loader* GetGameDatabase();
// --------------------------------------------------------------------------
// Overrides of wxApp virtuals:
@ -546,17 +630,23 @@ public:
void OnInitCmdLine( wxCmdLineParser& parser );
bool OnCmdLineParsed( wxCmdLineParser& parser );
bool OnCmdLineError( wxCmdLineParser& parser );
bool ParseOverrides( wxCmdLineParser& parser );
#ifdef __WXDEBUG__
void OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg );
#endif
Threading::MutexRecursive m_mtx_ProgramLog;
ConsoleLogFrame* m_ptr_ProgramLog;
// ----------------------------------------------------------------------------
// Console / Program Logging Helpers
// ----------------------------------------------------------------------------
ConsoleLogFrame* GetProgramLog();
const ConsoleLogFrame* GetProgramLog() const;
void ProgramLog_PostEvent( wxEvent& evt );
Threading::Mutex& GetProgramLogLock();
void EnableAllLogging();
void DisableWindowLogging() const;
void DisableDiskLogging() const;
@ -577,6 +667,7 @@ protected:
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const;
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event);
void OnScheduledTermination( wxTimerEvent& evt );
void OnEmuKeyDown( wxKeyEvent& evt );
void OnSysExecutorTaskTimeout( wxTimerEvent& evt );
void OnDestroyWindow( wxWindowDestroyEvent& evt );

View File

@ -331,12 +331,16 @@ wxDirName GetLogFolder()
wxDirName GetSettingsFolder()
{
if( wxGetApp().Overrides.SettingsFolder.IsOk() )
return wxGetApp().Overrides.SettingsFolder;
return UseDefaultSettingsFolder ? PathDefs::GetSettings() : SettingsFolder;
}
wxString GetSettingsFilename()
{
return GetSettingsFolder().Combine( FilenameDefs::GetConfig() ).GetFullPath();
wxFileName fname( wxGetApp().Overrides.SettingsFile.IsOk() ? wxGetApp().Overrides.SettingsFile : FilenameDefs::GetConfig() );
return GetSettingsFolder().Combine( fname ).GetFullPath();
}

View File

@ -254,14 +254,6 @@ public:
void LoadSaveMemcards( IniInterface& ini );
};
struct ConfigOverrides
{
AppConfig::FilenameOptions Filenames;
wxString SettingsFolder;
};
extern ConfigOverrides OverrideOptions;
extern wxFileConfig* OpenFileConfig( const wxString& filename );
extern void RelocateLogfile();
extern void AppConfig_OnChangedSettingsFolder( bool overwrite = false );

View File

@ -91,7 +91,7 @@ static void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] )
{
const PluginInfo* pi = tbl_PluginInfo; do
{
passins[pi->id] = OverrideOptions.Filenames[pi->id].GetFullPath();
passins[pi->id] = wxGetApp().Overrides.Filenames[pi->id].GetFullPath();
if( passins[pi->id].IsEmpty() || !wxFileExists( passins[pi->id] ) )
passins[pi->id] = g_Conf->FullpathTo( pi->id );
@ -101,6 +101,9 @@ static void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] )
typedef void (AppPluginManager::*FnPtr_AppPluginManager)();
typedef void (AppPluginManager::*FnPtr_AppPluginPid)( PluginsEnum_t pid );
// --------------------------------------------------------------------------------------
// SysExecEvent_AppPluginManager
// --------------------------------------------------------------------------------------
class SysExecEvent_AppPluginManager : public SysExecEvent
{
protected:
@ -122,6 +125,9 @@ protected:
}
};
// --------------------------------------------------------------------------------------
// LoadSinglePluginEvent
// --------------------------------------------------------------------------------------
class LoadSinglePluginEvent : public pxInvokeActionEvent
{
typedef pxInvokeActionEvent _parent;

View File

@ -28,11 +28,6 @@
using namespace pxSizerFlags;
static bool m_ForceWizard = false;
static bool m_UseGUI = false;
static bool m_NoFastBoot = false;
static bool m_DisableSpeedhacks = false;
static void CpuCheckSSE2()
{
if( x86caps.hasStreamingSIMD2Extensions ) return;
@ -110,7 +105,7 @@ void Pcsx2App::ReadUserModeSettings()
wxString groupname( wxsFormat( L"CWD.%08x", hashres ) );
bool hasGroup = conf_usermode->HasGroup( groupname );
bool forceWiz = m_ForceWizard || !hasGroup;
bool forceWiz = Startup.ForceWizard || !hasGroup;
if( !forceWiz )
{
@ -208,26 +203,28 @@ void Pcsx2App::OpenMainFrame()
MainEmuFrame* mainFrame = new MainEmuFrame( NULL, L"PCSX2" );
m_id_MainFrame = mainFrame->GetId();
if( wxWindow* deleteme = GetProgramLog() )
{
deleteme->Destroy();
g_Conf->ProgLogBox.Visible = true;
m_id_ProgramLogBox = wxID_ANY;
PostIdleAppMethod( &Pcsx2App::OpenProgramLog );
}
PostAppMethod( &Pcsx2App::OpenProgramLog );
SetTopWindow( mainFrame ); // not really needed...
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
SetExitOnFrameDelete( false ); // but being explicit doesn't hurt...
mainFrame->Show();
}
void Pcsx2App::OpenProgramLog()
{
if( GetProgramLog() != NULL ) return;
if( ConsoleLogFrame* frame = GetProgramLog() )
{
//pxAssume( );
return;
}
wxWindow* m_current_focus = wxGetActiveWindow();
m_id_ProgramLogBox = (new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox ))->GetId();
ScopedLock lock( m_mtx_ProgramLog );
m_ptr_ProgramLog = new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox );
m_id_ProgramLogBox = m_ptr_ProgramLog->GetId();
EnableAllLogging();
if( m_current_focus ) m_current_focus->SetFocus();
}
@ -330,21 +327,29 @@ void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser )
_("All options are for the current session only and will not be saved.\n")
);
wxString fixlist( L" " );
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
{
if( i != GamefixId_FIRST ) fixlist += L",";
fixlist += EnumToString(i);
}
parser.AddParam( _("IsoFile"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL );
parser.AddSwitch( L"h", L"help", _("displays this list of command line options"), wxCMD_LINE_OPTION_HELP );
parser.AddSwitch( wxEmptyString,L"console", _("forces the program log/console to be visible") );
parser.AddSwitch( L"h", L"help", _("displays this list of command line options"), wxCMD_LINE_OPTION_HELP );
parser.AddSwitch( wxEmptyString,L"nogui", _("disables display of the gui while running games") );
parser.AddOption( wxEmptyString,L"elf", _("executes an ELF image"), wxCMD_LINE_VAL_STRING );
parser.AddSwitch( wxEmptyString,L"nodisc", _("boots an empty dvd tray; use to enter the PS2 system menu") );
parser.AddSwitch( wxEmptyString,L"usecd", _("boots from the CDVD plugin (overrides IsoFile parameter)") );
parser.AddSwitch( wxEmptyString,L"nogui", _("disables display of the gui while running games") );
parser.AddOption( wxEmptyString,L"elf", _("executes an ELF image"), wxCMD_LINE_VAL_STRING );
parser.AddSwitch( wxEmptyString,L"nodisc", _("boots an empty dvd tray; use to enter the PS2 system menu") );
parser.AddSwitch( wxEmptyString,L"usecd", _("boots from the CDVD plugin (overrides IsoFile parameter)") );
parser.AddSwitch( wxEmptyString,L"fullboot", _("disables fast booting") );
parser.AddSwitch( wxEmptyString,L"nohacks", _("disables all speedhacks") );
parser.AddSwitch( wxEmptyString,L"gamefixes", _("use the specified comma or pipe-delimited list of gamefixes.") + fixlist );
parser.AddSwitch( wxEmptyString,L"fullboot",_("disables fast booting") );
parser.AddSwitch( wxEmptyString,L"nohacks", _("disables all speedhacks") );
parser.AddOption( wxEmptyString,L"cfgpath", _("changes the configuration file path"), wxCMD_LINE_VAL_STRING );
parser.AddOption( wxEmptyString,L"cfg", _("specifies the PCSX2 configuration file to use"), wxCMD_LINE_VAL_STRING );
parser.AddSwitch( wxEmptyString,L"forcewiz",_("forces PCSX2 to start the First-time Wizard") );
parser.AddOption( wxEmptyString,L"cfgpath", _("changes the configuration file path"), wxCMD_LINE_VAL_STRING );
parser.AddOption( wxEmptyString,L"cfg", _("specifies the PCSX2 configuration file to use"), wxCMD_LINE_VAL_STRING );
parser.AddSwitch( wxEmptyString,L"forcewiz", _("forces PCSX2 to start the First-time Wizard") );
const PluginInfo* pi = tbl_PluginInfo; do {
parser.AddOption( wxEmptyString, pi->GetShortname().Lower(),
@ -361,50 +366,85 @@ bool Pcsx2App::OnCmdLineError( wxCmdLineParser& parser )
return false;
}
bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser )
{
if( parser.GetParamCount() >= 1 )
wxString dest;
if( parser.Found( L"cfgpath", &dest ) && !dest.IsEmpty() )
{
// [TODO] : Unnamed parameter is taken as an "autorun" option for a cdvd/iso.
parser.GetParam( 0 );
Console.Warning( L"Config path override: " + dest );
Overrides.SettingsFolder = dest;
}
// Suppress wxWidgets automatic options parsing since none of them pertain to PCSX2 needs.
//wxApp::OnCmdLineParsed( parser );
m_UseGUI = !parser.Found(L"nogui");
m_DisableSpeedhacks = parser.Found(L"nohacks");
m_NoFastBoot = parser.Found(L"fullboot");
m_ForceWizard = parser.Found( L"forcewiz" );
wxString cfgPathOverride;
//if( parser.Found(L"cfgpath", cfgPathOverride ) )
if( parser.Found( L"cfg", &dest ) && !dest.IsEmpty() )
{
Console.Warning( L"Config file override: " + dest );
Overrides.SettingsFile = dest;
}
Overrides.DisableSpeedhacks = parser.Found(L"nohacks");
const PluginInfo* pi = tbl_PluginInfo; do
{
wxString dest;
if( !parser.Found( pi->GetShortname().Lower(), &dest ) ) continue;
OverrideOptions.Filenames.Plugins[pi->id] = dest;
if( wxFileExists( dest ) )
Console.Warning( pi->GetShortname() + L" override: " + dest );
else
{
bool result = Msgbox::OkCancel(
wxsFormat( _("Plugin Override Error! Specified %s plugin does not exist:\n\n"), pi->GetShortname().c_str() ) +
dest +
_("Press OK to use the default configured plugin, or Cancel to close."),
_("Plugin Override Error - PCSX2"), wxICON_ERROR
);
wxDialogWithHelpers okcan( NULL, _("Plugin Override Error - PCSX2") );
if( !result ) return false;
okcan += okcan.Heading( wxsFormat(
_("%s Plugin Override Error! The following file does not exist or is not a valid %s plugin:\n\n"),
pi->GetShortname().c_str(), pi->GetShortname().c_str()
) );
okcan += okcan.GetCharHeight();
okcan += okcan.Text(dest);
okcan += okcan.GetCharHeight();
okcan += okcan.Heading(_("Press OK to use the default configured plugin, or Cancel to close PCSX2."));
if( wxID_CANCEL == pxIssueConfirmation( okcan, MsgButtons().OKCancel() ) ) return false;
}
} while( ++pi, pi->shortname != NULL );
Overrides.Filenames.Plugins[pi->id] = dest;
parser.Found( L"cfgpath", &OverrideOptions.SettingsFolder );
} while( ++pi, pi->shortname != NULL );
return true;
}
bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
{
if( parser.Found(L"console") )
{
Startup.ForceConsole = true;
OpenProgramLog();
}
// Suppress wxWidgets automatic options parsing since none of them pertain to PCSX2 needs.
//wxApp::OnCmdLineParsed( parser );
m_UseGUI = !parser.Found(L"nogui");
if( !ParseOverrides(parser) ) return false;
// --- Parse Startup/Autoboot options ---
Startup.NoFastBoot = parser.Found(L"fullboot");
Startup.ForceWizard = parser.Found(L"forcewiz");
if( parser.GetParamCount() >= 1 )
{
Startup.IsoFile = parser.GetParam( 0 );
Startup.SysAutoRun = true;
}
if( parser.Found(L"usecd") )
{
Startup.CdvdSource = CDVDsrc_Plugin;
Startup.SysAutoRun = true;
}
return true;
}
@ -458,8 +498,23 @@ bool Pcsx2App::OnInit()
SysExecutorThread.Start();
DetectCpuAndUserMode();
PostAppMethod( &Pcsx2App::OpenMainFrame );
PostAppMethod( &Pcsx2App::OpenProgramLog );
if( Startup.ForceConsole ) g_Conf->ProgLogBox.Visible = true;
// Set Manual Exit Handling
// ----------------------------
// PCSX2 has a lot of event handling logistics, so we *cannot* depend on wxWidgets automatic event
// loop termination code. We have a much safer system in place that continues to process messages
// until all "important" threads are closed out -- not just until the main frame is closed(-ish).
m_timer_Termination = new wxTimer( this, wxID_ANY );
Connect( m_timer_Termination->GetId(), wxEVT_TIMER, wxTimerEventHandler(Pcsx2App::OnScheduledTermination) );
SetExitOnFrameDelete( false );
// Start GUI and/or Direct Emulation
// -------------------------------------
if( m_UseGUI )
PostAppMethod( &Pcsx2App::OpenMainFrame );
PostAppMethod( &Pcsx2App::AllocateCoreStuffs );
}
// ----------------------------------------------------------------------------
@ -491,6 +546,54 @@ bool Pcsx2App::OnInit()
return true;
}
static int m_term_threshold = 20;
void Pcsx2App::OnScheduledTermination( wxTimerEvent& evt )
{
if( !pxAssertDev( m_ScheduledTermination, "Scheduled Termination check is inconsistent with ScheduledTermination status." ) )
{
m_timer_Termination->Stop();
return;
}
if( m_PendingSaves != 0 )
{
if( --m_term_threshold > 0 )
{
Console.WriteLn( "(App) %d saves are still pending; exit postponed...", m_PendingSaves );
return;
}
Console.Error( "(App) %s pending saves have exceeded OnExit threshold and are being prematurely terminated!", m_PendingSaves );
}
m_timer_Termination->Stop();
Exit();
}
// Common exit handler which can be called from any event (though really it should
// be called only from CloseWindow handlers since that's the more appropriate way
// to handle cancelable window closures)
//
// returns true if the app can close, or false if the close event was canceled by
// the glorious user, whomever (s)he-it might be.
void Pcsx2App::PrepForExit()
{
if( m_ScheduledTermination ) return;
m_ScheduledTermination = true;
SysExecutorThread.ShutdownQueue();
DispatchEvent( AppStatus_Exiting );
m_timer_Termination->Start( 500 );
// This should be called by OnExit(), but sometimes wxWidgets fails to call OnExit(), so
// do it here just in case (no harm anyway -- OnExit is the next logical step after
// CloseWindow returns true from the TopLevel window).
//CleanupRestartable();
}
// This cleanup procedure can only be called when the App message pump is still active.
// OnExit() must use CleanupOnExit instead.
void Pcsx2App::CleanupRestartable()
@ -499,13 +602,9 @@ void Pcsx2App::CleanupRestartable()
ShutdownPlugins();
SysExecutorThread.ShutdownQueue();
//PingDispatcher( "Cleanup" );
//DeletionDispatcher();
IdleEventDispatcher( L"Cleanup" );
if( g_Conf )
AppSaveSettings();
if( g_Conf ) AppSaveSettings();
}
// This cleanup handler can be called from OnExit (it doesn't need a running message pump),
@ -561,7 +660,6 @@ void Pcsx2App::CleanupResources()
int Pcsx2App::OnExit()
{
CleanupOnExit();
return wxApp::OnExit();
}
@ -610,6 +708,7 @@ Pcsx2App::Pcsx2App()
m_id_MainFrame = wxID_ANY;
m_id_GsFrame = wxID_ANY;
m_id_ProgramLogBox = wxID_ANY;
m_ptr_ProgramLog = NULL;
SetAppName( L"pcsx2" );
BuildCommandHash();

View File

@ -47,7 +47,6 @@ wxDirName Logs;
bool UseDefaultLogs = true;
ScopedPtr<AppConfig> g_Conf;
ConfigOverrides OverrideOptions;
template<typename DialogType>
int AppOpenModalDialog( wxWindow* parent=NULL )
@ -488,12 +487,18 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
}
}
// A call to this method informs the app that there is a pending save operation that must be
// finished prior to exiting the app, or else data loss will occur. Any call to this method
// should be matched by a call to ClearPendingSave().
void Pcsx2App::StartPendingSave()
{
if( PostAppMethodMyself(&Pcsx2App::StartPendingSave) ) return;
++m_PendingSaves;
}
// If this method is called inappropriately then the entire pending save system will become
// unreliable and data loss can occur on app exit. Devel and debug builds will assert if
// such calls are detected (though the detection is far from fool-proof).
void Pcsx2App::ClearPendingSave()
{
if( PostAppMethodMyself(&Pcsx2App::ClearPendingSave) ) return;
@ -508,38 +513,6 @@ void Pcsx2App::ClearPendingSave()
}
}
// Common exit handler which can be called from any event (though really it should
// be called only from CloseWindow handlers since that's the more appropriate way
// to handle cancelable window closures)
//
// returns true if the app can close, or false if the close event was canceled by
// the glorious user, whomever (s)he-it might be.
void Pcsx2App::PrepForExit()
{
SysExecutorThread.ShutdownQueue();
//SysExecutorThread.Cancel();
DispatchEvent( AppStatus_Exiting );
if( m_PendingSaves != 0 )
{
// When the thread finishes, it will call ClearPendingSave, which in turn will
// exit the app once all pending saves have "logged out." (if one does not track
// itself using our PendingSaves feature, it would be lost -- too bad!)
Console.WriteLn( "App: Saves are pending; exit postponed..." );
SetExitOnFrameDelete( false );
m_ScheduledTermination = true;
return;
}
// This should be called by OnExit(), but sometimes wxWidgets fails to call OnExit(), so
// do it here just in case (no harm anyway -- OnExit is the next logical step after
// CloseWindow returns true from the TopLevel window).
CleanupRestartable();
}
// This method generates debug assertions if the MainFrame handle is NULL (typically
// indicating that PCSX2 is running in NoGUI mode, or that the main frame has been
// closed). In most cases you'll want to use HasMainFrame() to test for thread
@ -1013,3 +986,17 @@ SysCoreAllocations& GetSysCoreAlloc()
{
return *wxGetApp().m_CoreAllocs;
}
DataBase_Loader* Pcsx2App::GetGameDatabase()
{
pxAppResources& res( GetResourceCache() );
ScopedLock lock( m_mtx_LoadingGameDB );
if( !res.GameDB ) res.GameDB = new DataBase_Loader();
return res.GameDB;
}
DataBase_Loader* AppHost_GetGameDatabase()
{
return wxGetApp().GetGameDatabase();
}

View File

@ -89,6 +89,7 @@ RecentIsoManager& Pcsx2App::GetRecentIsoManager()
pxAppResources& Pcsx2App::GetResourceCache()
{
ScopedLock lock( m_mtx_Resources );
if( !m_Resources )
m_Resources = new pxAppResources();

View File

@ -141,12 +141,15 @@ static bool OpenLogFile(wxFile& file, wxString& filename, wxWindow *parent)
return file.Create(filename);
}
// ------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
// ConsoleLogFrame::ColorArray (implementations)
// --------------------------------------------------------------------------------------
// fontsize - size of the font specified in points.
// (actual font used is the system-selected fixed-width font)
//
ConsoleLogFrame::ColorArray::ColorArray( int fontsize ) :
m_table( ConsoleColors_Count )
ConsoleLogFrame::ColorArray::ColorArray( int fontsize )
: m_table( ConsoleColors_Count )
{
Create( fontsize );
}
@ -225,7 +228,37 @@ enum MenuIDs_t
MenuID_FontSize_Huge,
};
// ------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
// ScopedLogLock (implementations)
// --------------------------------------------------------------------------------------
class ScopedLogLock : ScopedLock
{
public:
ConsoleLogFrame* WindowPtr;
public:
ScopedLogLock()
: ScopedLock( ((Pcsx2App&)*wxTheApp).GetProgramLogLock() )
{
WindowPtr = ((Pcsx2App&)*wxTheApp).m_ptr_ProgramLog;
}
virtual ~ScopedLogLock() throw() {}
bool HasWindow() const
{
return WindowPtr != NULL;
}
ConsoleLogFrame& GetWindow() const
{
return *WindowPtr;
}
};
// --------------------------------------------------------------------------------------
// ConsoleLogFrame (implementations)
// --------------------------------------------------------------------------------------
ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, AppConfig::ConsoleLogOptions& options )
: wxFrame(parent, wxID_ANY, title)
, m_conf( options )
@ -333,6 +366,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
ConsoleLogFrame::~ConsoleLogFrame()
{
ScopedLogLock locker;
wxGetApp().OnProgramLogClosed( GetId() );
}
@ -776,6 +810,11 @@ const IConsoleWriter ConsoleWriter_File =
ConsoleToFile_SetTitle,
};
Mutex& Pcsx2App::GetProgramLogLock()
{
return m_mtx_ProgramLog;
}
// --------------------------------------------------------------------------------------
// ConsoleToWindow Implementations
// --------------------------------------------------------------------------------------
@ -798,7 +837,8 @@ template< const IConsoleWriter& secondary >
static void __concall ConsoleToWindow_Newline()
{
secondary.Newline();
((Pcsx2App&)*wxTheApp).GetProgramLog()->Newline();
ScopedLogLock locker;
if( locker.WindowPtr ) locker.WindowPtr->Newline();
}
template< const IConsoleWriter& secondary >
@ -806,7 +846,9 @@ static void __concall ConsoleToWindow_DoWrite( const wxString& fmt )
{
if( secondary.DoWrite != NULL )
secondary.DoWrite( fmt );
((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( Console.GetColor(), fmt );
ScopedLogLock locker;
if( locker.WindowPtr ) locker.WindowPtr->Write( Console.GetColor(), fmt );
}
template< const IConsoleWriter& secondary >
@ -814,7 +856,9 @@ static void __concall ConsoleToWindow_DoWriteLn( const wxString& fmt )
{
if( secondary.DoWriteLn != NULL )
secondary.DoWriteLn( fmt );
((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( Console.GetColor(), fmt + L"\n" );
ScopedLogLock locker;
if( locker.WindowPtr ) locker.WindowPtr->Write( Console.GetColor(), fmt + L'\n' );
}
typedef void __concall DoWriteFn(const wxString&);
@ -843,7 +887,9 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile =
void Pcsx2App::EnableAllLogging()
{
const bool logBoxOpen = (GetProgramLog() != NULL);
ScopedLock lock( m_mtx_ProgramLog );
const bool logBoxOpen = (m_ptr_ProgramLog != NULL);
const IConsoleWriter* newHandler = NULL;
if( emuLog )
@ -888,6 +934,7 @@ void Pcsx2App::DisableDiskLogging() const
void Pcsx2App::DisableWindowLogging() const
{
ScopedLock lock( m_mtx_ProgramLog );
Console_SetActiveHandler( (emuLog!=NULL) ? (IConsoleWriter&)ConsoleWriter_File : (IConsoleWriter&)ConsoleWriter_Stdout );
Threading::Sleep( 5 );
//Threading::Sleep( 5 );
}

View File

@ -94,13 +94,13 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
}
wxGetApp().PrepForExit();
sApp.OnMainFrameClosed( GetId() );
if( m_menubar.FindItem(MenuId_IsoSelector) )
m_menuCDVD.Remove(MenuId_IsoSelector);
RemoveEventHandler( &wxGetApp().GetRecentIsoManager() );
wxGetApp().PostIdleAppMethod( &Pcsx2App::PrepForExit );
evt.Skip();
}

View File

@ -330,7 +330,7 @@ namespace Panels
class GameFixesPanel : public BaseApplicableConfigPanel
{
protected:
pxCheckBox* m_checkbox[NUM_OF_GAME_FIXES];
pxCheckBox* m_checkbox[GamefixId_COUNT];
pxCheckBox* m_check_Enable;
public:
@ -358,7 +358,7 @@ namespace Panels
wxTextCtrl* compatBox;
wxTextCtrl* commentBox;
wxTextCtrl* patchesBox;
pxCheckBox* gameFixes[NUM_OF_GAME_FIXES];
pxCheckBox* gameFixes[GamefixId_COUNT];
public:
GameDatabasePanel( wxWindow* parent );

View File

@ -42,7 +42,10 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags =
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent )
{
if (!GameDB) GameDB = new DataBase_Loader();
//if (!GameDB) GameDB = new DataBase_Loader();
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
pxAssume( GameDB != NULL );
searchBtn = new wxButton (this, wxID_DEFAULT, L"Search");
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
@ -52,15 +55,8 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
gameFixes[0] = new pxCheckBox(this, L"VuAddSubHack");
gameFixes[1] = new pxCheckBox(this, L"VuClipFlagHack");
gameFixes[2] = new pxCheckBox(this, L"FpuCompareHack");
gameFixes[3] = new pxCheckBox(this, L"FpuMulHack");
gameFixes[4] = new pxCheckBox(this, L"FpuNegDivHack");
gameFixes[5] = new pxCheckBox(this, L"XgKickHack");
gameFixes[6] = new pxCheckBox(this, L"IPUWaitHack");
gameFixes[7] = new pxCheckBox(this, L"EETimingHack");
gameFixes[8] = new pxCheckBox(this, L"SkipMPEGHack");
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
gameFixes[i] = new pxCheckBox(this, EnumToString(i));
*this += Heading(_("Game Database Editor")).Bold() | StdExpand();
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
@ -84,14 +80,13 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
blankLine();
wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("PCSX2 Gamefixes"));
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3));
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4));
sizer3.AddGrowableCol(0);
for (int i = 0; i < NUM_OF_GAME_FIXES; i++) {
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
sizer3 += gameFixes[i];
}
sizer2 += sizer3 | pxCenter;
sizer2 += sizer3 | StdCenter();
*this += sizer1 | pxCenter;
*this += sizer2 | pxCenter;
@ -101,6 +96,8 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
}
void Panels::GameDatabasePanel::PopulateFields() {
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
if (GameDB->gameLoaded()) {
serialBox ->SetLabel(GameDB->getString("Serial"));
nameBox ->SetLabel(GameDB->getString("Name"));
@ -108,15 +105,9 @@ void Panels::GameDatabasePanel::PopulateFields() {
compatBox ->SetLabel(GameDB->getString("Compat"));
commentBox->SetLabel(GameDB->getString("[comments]"));
patchesBox->SetLabel(GameDB->getString("[patches]"));
gameFixes[0]->SetValue(GameDB->getBool("VuAddSubHack"));
gameFixes[1]->SetValue(GameDB->getBool("VuClipFlagHack"));
gameFixes[2]->SetValue(GameDB->getBool("FpuCompareHack"));
gameFixes[3]->SetValue(GameDB->getBool("FpuMulHack"));
gameFixes[4]->SetValue(GameDB->getBool("FpuNegDivHack"));
gameFixes[5]->SetValue(GameDB->getBool("XgKickHack"));
gameFixes[6]->SetValue(GameDB->getBool("IPUWaitHack"));
gameFixes[7]->SetValue(GameDB->getBool("EETimingHack"));
gameFixes[8]->SetValue(GameDB->getBool("SkipMPEGHack"));
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
gameFixes[i]->SetValue(GameDB->getBool(EnumToString(i)+wxString(L"Hack")));
}
else {
serialBox ->SetLabel(L"");
@ -125,7 +116,7 @@ void Panels::GameDatabasePanel::PopulateFields() {
compatBox ->SetLabel(L"");
commentBox->SetLabel(L"");
patchesBox->SetLabel(L"");
for (int i = 0; i < NUM_OF_GAME_FIXES; i++) {
for (int i = 0; i < GamefixId_COUNT; i++) {
gameFixes[i]->SetValue(0);
}
}
@ -136,15 +127,11 @@ void Panels::GameDatabasePanel::PopulateFields() {
else GameDB->writeString(wxT(_key), _value); \
}
#define writeGameFixToDB(_key, _value) { \
if (!_value) GameDB->deleteKey(wxT(_key)); \
else GameDB->writeBool(wxT(_key), _value); \
}
// 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() );
if (wxStr.IsEmpty()) return false;
if (wxStr != GameDB->getString("Serial")) {
GameDB->addGame(wxStr);
@ -155,19 +142,18 @@ bool Panels::GameDatabasePanel::WriteFieldsToDB() {
writeTextBoxToDB("Compat", compatBox->GetValue());
writeTextBoxToDB("[comments]", commentBox->GetValue());
writeTextBoxToDB("[patches]", patchesBox->GetValue());
writeGameFixToDB("VuAddSubHack", gameFixes[0]->GetValue());
writeGameFixToDB("VuClipFlagHack", gameFixes[1]->GetValue());
writeGameFixToDB("FpuCompareHack", gameFixes[2]->GetValue());
writeGameFixToDB("FpuMulHack", gameFixes[3]->GetValue());
writeGameFixToDB("FpuNegDivHack", gameFixes[4]->GetValue());
writeGameFixToDB("XgKickHack", gameFixes[5]->GetValue());
writeGameFixToDB("IPUWaitHack", gameFixes[6]->GetValue());
writeGameFixToDB("EETimingHack", gameFixes[7]->GetValue());
writeGameFixToDB("SkipMPEGHack", gameFixes[8]->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);
}
return true;
}
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
wxString wxStr = serialBox->GetValue();
if( wxStr.IsEmpty() ) wxStr = DiscID;
@ -180,6 +166,7 @@ void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
}
void Panels::GameDatabasePanel::Apply() {
DataBase_Loader* GameDB = AppHost_GetGameDatabase();
if( WriteFieldsToDB() )
{
Console.WriteLn("Saving changes to Game Database...");

View File

@ -31,7 +31,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent )
wxString label, tooltip;
};
const CheckTextMess check_text[NUM_OF_GAME_FIXES] =
const CheckTextMess check_text[GamefixId_COUNT] =
{
{
_("VU Add Hack - Fixes Tri-Ace games boot crash."),
@ -71,12 +71,12 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent )
)
},
{
_("Skip MPEG hack - Skips videos/FMV's in games to avoid game hanging/freezes."),
_("Skip MPEG hack - Skips videos/FMVs in games to avoid game hanging/freezes."),
wxEmptyString
}
};
for( int i=0; i<NUM_OF_GAME_FIXES; ++i )
for( int i=0; i<GamefixId_COUNT; ++i )
{
groupSizer += (m_checkbox[i] = new pxCheckBox( this, check_text[i].label ));
m_checkbox[i]->SetToolTip( check_text[i].tooltip );
@ -102,31 +102,19 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent )
EnableStuff();
}
// I could still probably get rid of the for loop, but I think this is clearer.
void Panels::GameFixesPanel::Apply()
{
g_Conf->EnableGameFixes = m_check_Enable->GetValue();
Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes );
for (int i = 0; i < NUM_OF_GAME_FIXES; i++)
{
if (m_checkbox[i]->GetValue())
{
opts.bitset |= (1 << i);
}
else
{
opts.bitset &= ~(1 << i);
}
}
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
opts.Set((GamefixId)i, m_checkbox[i]->GetValue());
}
void Panels::GameFixesPanel::EnableStuff()
{
for (int i = 0; i < NUM_OF_GAME_FIXES; i++)
{
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
m_checkbox[i]->Enable(m_check_Enable->GetValue());
}
}
void Panels::GameFixesPanel::OnEnable_Toggled( wxCommandEvent& evt )
@ -138,8 +126,6 @@ void Panels::GameFixesPanel::OnEnable_Toggled( wxCommandEvent& evt )
void Panels::GameFixesPanel::AppStatusEvent_OnSettingsApplied()
{
const Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes );
for( int i=0; i<NUM_OF_GAME_FIXES; ++i )
{
m_checkbox[i]->SetValue( !!(opts.bitset & (1 << i)) );
}
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
m_checkbox[i]->SetValue( opts.Get((GamefixId)i) );
}