mirror of https://github.com/PCSX2/pcsx2.git
* Call PADupdate from MTGS thread when using legacy GSopen -- Should fix Linux Pad instabilities.
* Fixed a savestate loading bug, when loading states made with different sets/versions of plugins. DevNote: * Moved some old PS2E types to PS2Edefs, since the new v2 plugin API won't use them (freezeData, keyEvent). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2380 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
203979c16b
commit
408dbd7256
|
@ -48,6 +48,29 @@
|
|||
|
||||
#include "Pcsx2Defs.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
// freeze modes:
|
||||
#define FREEZE_LOAD 0
|
||||
#define FREEZE_SAVE 1
|
||||
#define FREEZE_SIZE 2
|
||||
|
||||
// event values:
|
||||
#define KEYPRESS 1
|
||||
#define KEYRELEASE 2
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
s8 *data;
|
||||
} freezeData;
|
||||
|
||||
typedef struct _keyEvent {
|
||||
u32 key;
|
||||
u32 evt;
|
||||
} keyEvent;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \
|
||||
defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \
|
||||
defined(USBdefs) || defined(FWdefs)
|
||||
|
@ -172,11 +195,6 @@ typedef int (*DEV9handler)(void);
|
|||
typedef void (*USBcallback)(int cycles);
|
||||
typedef int (*USBhandler)(void);
|
||||
|
||||
// freeze modes:
|
||||
#define FREEZE_LOAD 0
|
||||
#define FREEZE_SAVE 1
|
||||
#define FREEZE_SIZE 2
|
||||
|
||||
typedef struct _GSdriverInfo {
|
||||
char name[8];
|
||||
void *common;
|
||||
|
|
|
@ -287,20 +287,4 @@ static const int __pagesize = PCSX2_PAGESIZE;
|
|||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
s8 *data;
|
||||
} freezeData;
|
||||
|
||||
// event values:
|
||||
#define KEYPRESS 1
|
||||
#define KEYRELEASE 2
|
||||
|
||||
typedef struct _keyEvent {
|
||||
u32 key;
|
||||
u32 evt;
|
||||
} keyEvent;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -337,62 +337,4 @@ namespace Exception
|
|||
public:
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Savestate Exceptions:
|
||||
// BadSavedState / FreezePluginFailure / StateLoadError / UnsupportedStateVersion /
|
||||
// StateCrcMismatch
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
// Exception thrown when a corrupted or truncated savestate is encountered.
|
||||
//
|
||||
class BadSavedState : public virtual BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( BadSavedState, wxLt("Savestate data is corrupted or incomplete.") )
|
||||
};
|
||||
|
||||
// thrown when the savestate being loaded isn't supported.
|
||||
//
|
||||
class UnsupportedStateVersion : public virtual BadSavedState
|
||||
{
|
||||
public:
|
||||
u32 Version; // version number of the unsupported state.
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion )
|
||||
|
||||
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString )
|
||||
{
|
||||
StreamName = objname;
|
||||
Version = version;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// A recoverable exception thrown when the CRC of the savestate does not match the
|
||||
// CRC returned by the Cdvd driver.
|
||||
// [feature not implemented yet]
|
||||
//
|
||||
class StateCrcMismatch : public virtual BadSavedState
|
||||
{
|
||||
public:
|
||||
u32 Crc_Savestate;
|
||||
u32 Crc_Cdvd;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch )
|
||||
|
||||
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString )
|
||||
{
|
||||
StreamName = objname;
|
||||
Crc_Savestate = crc_save;
|
||||
Crc_Cdvd = crc_cdvd;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -190,41 +190,3 @@ wxString Exception::Stream::FormatDisplayMessage() const
|
|||
wxsFormat( _("Name: %s"), StreamName.c_str() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::UnsupportedStateVersion::FormatDiagnosticMessage() const
|
||||
{
|
||||
// Note: no stacktrace needed for this one...
|
||||
return wxsFormat( L"Unknown or unsupported savestate version: 0x%x", Version );
|
||||
}
|
||||
|
||||
wxString Exception::UnsupportedStateVersion::FormatDisplayMessage() const
|
||||
{
|
||||
// m_message_user contains a recoverable savestate error which is helpful to the user.
|
||||
return wxsFormat(
|
||||
m_message_user + L"\n\n" +
|
||||
wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version )
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::StateCrcMismatch::FormatDiagnosticMessage() const
|
||||
{
|
||||
// Note: no stacktrace needed for this one...
|
||||
return wxsFormat(
|
||||
L"Game/CDVD does not match the savestate CRC.\n"
|
||||
L"\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n",
|
||||
Crc_Savestate, Crc_Cdvd
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::StateCrcMismatch::FormatDisplayMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
m_message_user + L"\n\n" +
|
||||
wxsFormat(
|
||||
L"Savestate game/crc mismatch. Cdvd CRC: 0x%X Game CRC: 0x%X\n",
|
||||
Crc_Savestate, Crc_Cdvd
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -370,6 +370,11 @@ void SysMtgsThread::ExecuteTaskInThread()
|
|||
GSvsync(tag.data[0]);
|
||||
gsFrameSkip();
|
||||
|
||||
// if we're not using GSOpen2, then the GS window is on this thread (MTGS thread),
|
||||
// so we need to call PADupdate from here.
|
||||
if( (GSopen2 == NULL) && (PADupdate != NULL) )
|
||||
PADupdate(0);
|
||||
|
||||
StateCheckInThread();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -123,7 +123,12 @@ struct LegacyApi_OptMethod
|
|||
};
|
||||
|
||||
|
||||
static s32 CALLBACK fallback_freeze(int mode, freezeData *data) { data->size = 0; return 0; }
|
||||
static s32 CALLBACK fallback_freeze(int mode, freezeData *data)
|
||||
{
|
||||
if( mode == FREEZE_SIZE ) data->size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CALLBACK fallback_keyEvent(keyEvent *ev) {}
|
||||
static void CALLBACK fallback_setSettingsDir(const char* dir) {}
|
||||
static void CALLBACK fallback_configure() {}
|
||||
|
|
|
@ -23,6 +23,17 @@
|
|||
|
||||
#include <wx/dynlib.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// Disabling C4673: throwing 'Exception::Blah' the following types will not be considered at the catch site
|
||||
// The warning is bugged, and happens even though we're properly inheriting classes with
|
||||
// 'virtual' qualifiers. But since the warning is potentially useful elsewhere, I disable
|
||||
// it only for the scope of these exceptions.
|
||||
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4673)
|
||||
#endif
|
||||
|
||||
struct PluginInfo
|
||||
{
|
||||
const char* shortname;
|
||||
|
@ -36,22 +47,18 @@ struct PluginInfo
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// Disabling C4673: throwing 'Exception::Blah' the following types will not be considered at the catch site
|
||||
// The warning is bugged, and happens even though we're properly inheriting classes with
|
||||
// 'virtual' qualifiers. But since the warning is potentially useful elsewhere, I disable
|
||||
// it only for the scope of these exceptions.
|
||||
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4673)
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Plugin-related Exceptions
|
||||
// --------------------------------------------------------------------------------------
|
||||
namespace Exception
|
||||
{
|
||||
// Exception thrown when a corrupted or truncated savestate is encountered.
|
||||
class SaveStateLoadError : public virtual BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Savestate data is corrupted or incomplete.") )
|
||||
};
|
||||
|
||||
class PluginError : public virtual RuntimeError
|
||||
{
|
||||
public:
|
||||
|
@ -137,7 +144,7 @@ namespace Exception
|
|||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class ThawPluginFailure : public virtual PluginError, public virtual BadSavedState
|
||||
class ThawPluginFailure : public virtual PluginError, public virtual SaveStateLoadError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure )
|
||||
|
|
|
@ -37,6 +37,13 @@ int sys_resume_lock = 0;
|
|||
|
||||
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
|
||||
|
||||
static bool StateCopy_ForceClear()
|
||||
{
|
||||
sys_resume_lock = 0;
|
||||
state_buffer_lock.Release();
|
||||
state_buffer.Dispose();
|
||||
}
|
||||
|
||||
static void __evt_fastcall StateThread_OnAppStatus( void* thr, AppEventType& stat )
|
||||
{
|
||||
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
|
||||
|
@ -378,9 +385,17 @@ void StateCopy_FreezeToMem()
|
|||
(new StateThread_Freeze( OnFinished_Resume ))->Start();
|
||||
}
|
||||
|
||||
static void _acquire_and_block()
|
||||
class Acquire_And_Block
|
||||
{
|
||||
if( state_buffer_lock.TryAcquire() ) return;
|
||||
protected:
|
||||
bool m_DisposeWhenFinished;
|
||||
bool m_Acquired;
|
||||
|
||||
public:
|
||||
Acquire_And_Block( bool dispose )
|
||||
{
|
||||
m_DisposeWhenFinished = dispose;
|
||||
m_Acquired = false;
|
||||
|
||||
/*
|
||||
// If the state buffer is locked and we're being called from the main thread then we need
|
||||
|
@ -390,31 +405,38 @@ static void _acquire_and_block()
|
|||
if( wxThread::IsMain() )
|
||||
throw Exception::CancelEvent( "Blocking ThawFromMem canceled due to existing state buffer lock." );
|
||||
else*/
|
||||
|
||||
while ( !state_buffer_lock.TryAcquire() )
|
||||
{
|
||||
pxAssume( current_state_thread != NULL );
|
||||
do {
|
||||
current_state_thread->Block();
|
||||
wxGetApp().ProcessPendingEvents(); // Trying this for now, may or may not work due to recursive pitfalls (see above)
|
||||
} while ( !state_buffer_lock.TryAcquire() );
|
||||
};
|
||||
|
||||
m_Acquired = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Acquire_And_Block() throw()
|
||||
{
|
||||
if( m_DisposeWhenFinished )
|
||||
state_buffer.Dispose();
|
||||
|
||||
if( m_Acquired )
|
||||
state_buffer_lock.Release();
|
||||
}
|
||||
};
|
||||
|
||||
void StateCopy_FreezeToMem_Blocking()
|
||||
{
|
||||
_acquire_and_block();
|
||||
|
||||
Acquire_And_Block blocker( false );
|
||||
memSavingState( state_buffer ).FreezeAll();
|
||||
state_buffer_lock.Release();
|
||||
}
|
||||
|
||||
// Copies the saved state into the active VM, and automatically free's the saved state data.
|
||||
void StateCopy_ThawFromMem_Blocking()
|
||||
{
|
||||
_acquire_and_block();
|
||||
|
||||
Acquire_And_Block blocker( true );
|
||||
memLoadingState( state_buffer ).FreezeAll();
|
||||
state_buffer.Dispose();
|
||||
state_buffer_lock.Release();
|
||||
}
|
||||
|
||||
void StateCopy_Clear()
|
||||
|
@ -427,4 +449,3 @@ bool StateCopy_IsBusy()
|
|||
{
|
||||
return state_buffer_lock.IsLocked();
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
using namespace R5900;
|
||||
|
||||
|
||||
static void PreLoadPrep()
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
|
@ -45,14 +46,14 @@ wxString SaveStateBase::GetFilename( int slot )
|
|||
wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath();
|
||||
}
|
||||
|
||||
SaveStateBase::SaveStateBase( SafeArray<u8>& memblock ) :
|
||||
m_memory( memblock )
|
||||
, m_version( g_SaveVersion )
|
||||
, m_idx( 0 )
|
||||
, m_sectid( FreezeId_Unknown )
|
||||
, m_pid( PluginId_GS )
|
||||
, m_DidBios( false )
|
||||
SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
|
||||
: m_memory( memblock )
|
||||
{
|
||||
m_version = g_SaveVersion;
|
||||
m_idx = 0;
|
||||
m_sectid = FreezeId_Unknown;
|
||||
m_pid = PluginId_GS;
|
||||
m_DidBios = false;
|
||||
}
|
||||
|
||||
void SaveStateBase::PrepBlock( int size )
|
||||
|
@ -63,7 +64,7 @@ void SaveStateBase::PrepBlock( int size )
|
|||
else
|
||||
{
|
||||
if( m_memory.GetSizeInBytes() < end )
|
||||
throw Exception::BadSavedState();
|
||||
throw Exception::SaveStateLoadError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +80,7 @@ void SaveStateBase::FreezeTag( const char* src )
|
|||
if( strcmp( m_tagspace, src ) != 0 )
|
||||
{
|
||||
pxFail( "Savestate data corruption detected while reading tag" );
|
||||
throw Exception::BadSavedState(
|
||||
throw Exception::SaveStateLoadError(
|
||||
// Untranslated diagnostic msg (use default msg for translation)
|
||||
L"Savestate data corruption detected while reading tag: " + fromUTF8(src)
|
||||
);
|
||||
|
@ -205,7 +206,7 @@ void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxCh
|
|||
{
|
||||
if( sectlen != realsectsize ) // if they don't match then we have a problem, jim.
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
wxsFormat( L"Invalid size encountered on section '%s'.", sectname ),
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
|
@ -234,7 +235,7 @@ bool SaveStateBase::FreezeSection( int seek_section )
|
|||
|
||||
if( sectlen != 128 )
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
L"Invalid size encountered on BiosVersion section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
|
@ -257,7 +258,7 @@ bool SaveStateBase::FreezeSection( int seek_section )
|
|||
Freeze( sectlen );
|
||||
if( sectlen != MainMemorySizeInBytes )
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
L"Invalid size encountered on MainMemory section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
|
@ -302,7 +303,7 @@ bool SaveStateBase::FreezeSection( int seek_section )
|
|||
else
|
||||
g_plugins->Freeze( (PluginsEnum_t)m_pid, *this );
|
||||
|
||||
WritebackSectionLength( seekpos, sectlen, L"HardwareRegisters" );
|
||||
WritebackSectionLength( seekpos, sectlen, L"Plugins" );
|
||||
|
||||
// following increments only affect Saving mode, which needs to be sure to save all
|
||||
// plugins (order doesn't matter but sequential is easy enough. (ignored by Loading mode)
|
||||
|
@ -411,3 +412,42 @@ bool memLoadingState::SeekToSection( PluginsEnum_t pid )
|
|||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveState Exception Messages
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
wxString Exception::UnsupportedStateVersion::FormatDiagnosticMessage() const
|
||||
{
|
||||
// Note: no stacktrace needed for this one...
|
||||
return wxsFormat( L"Unknown or unsupported savestate version: 0x%x", Version );
|
||||
}
|
||||
|
||||
wxString Exception::UnsupportedStateVersion::FormatDisplayMessage() const
|
||||
{
|
||||
// m_message_user contains a recoverable savestate error which is helpful to the user.
|
||||
return wxsFormat(
|
||||
m_message_user + L"\n\n" +
|
||||
wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version )
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::StateCrcMismatch::FormatDiagnosticMessage() const
|
||||
{
|
||||
// Note: no stacktrace needed for this one...
|
||||
return wxsFormat(
|
||||
L"Game/CDVD does not match the savestate CRC.\n"
|
||||
L"\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n",
|
||||
Crc_Savestate, Crc_Cdvd
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::StateCrcMismatch::FormatDisplayMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
m_message_user + L"\n\n" +
|
||||
wxsFormat(
|
||||
L"Savestate game/crc mismatch. Cdvd CRC: 0x%X Game CRC: 0x%X\n",
|
||||
Crc_Savestate, Crc_Cdvd
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,58 @@ enum FreezeSectionId
|
|||
FreezeId_Unknown,
|
||||
};
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Savestate Exceptions:
|
||||
// UnsupportedStateVersion / StateCrcMismatch
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
// thrown when the savestate being loaded isn't supported.
|
||||
//
|
||||
class UnsupportedStateVersion : public virtual SaveStateLoadError
|
||||
{
|
||||
public:
|
||||
u32 Version; // version number of the unsupported state.
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion )
|
||||
|
||||
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString )
|
||||
{
|
||||
StreamName = objname;
|
||||
Version = version;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// A recoverable exception thrown when the CRC of the savestate does not match the
|
||||
// CRC returned by the Cdvd driver.
|
||||
// [feature not implemented yet]
|
||||
//
|
||||
class StateCrcMismatch : public virtual SaveStateLoadError
|
||||
{
|
||||
public:
|
||||
u32 Crc_Savestate;
|
||||
u32 Crc_Cdvd;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch )
|
||||
|
||||
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString )
|
||||
{
|
||||
StreamName = objname;
|
||||
Crc_Savestate = crc_save;
|
||||
Crc_Cdvd = crc_cdvd;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveStateBase class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -207,7 +207,11 @@ void Pcsx2App::OnLogicalVsync( wxCommandEvent& evt )
|
|||
{
|
||||
if( !SysHasValidState() || g_plugins == NULL ) return;
|
||||
|
||||
if( PADupdate != NULL ) PADupdate(0);
|
||||
// Only call PADupdate here if we're using GSopen2. Legacy GSopen plugins have the
|
||||
// GS window belonging to the MTGS thread.
|
||||
if( (PADupdate != NULL) && (GSopen2 != NULL) && (m_gsFrame != NULL) )
|
||||
PADupdate(0);
|
||||
|
||||
const keyEvent* ev = PADkeyEvent();
|
||||
|
||||
if( (ev != NULL) && (ev->key != 0) )
|
||||
|
@ -369,6 +373,12 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
Console.Warning( "User canceled BIOS configuration." );
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::SaveStateLoadError& ex)
|
||||
{
|
||||
// Saved state load failed.
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
CoreThread.Resume();
|
||||
}
|
||||
catch( Exception::PluginInitError& ex )
|
||||
{
|
||||
if( m_CorePlugins ) m_CorePlugins->Shutdown();
|
||||
|
@ -430,14 +440,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
{
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::BadSavedState& ex)
|
||||
{
|
||||
// Saved state load failed.
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
CoreThread.Resume();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
// Runtime errors which have been unhandled should still be safe to recover from,
|
||||
|
|
Loading…
Reference in New Issue