mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
Save States: 1. Added "Undo Load State" which... undoes load state :)
2. Implemented saving/loading to memory buffers (very fast) for temporal states such as for "undo load state" git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3585 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
e341985003
commit
fd47eb7b44
@ -895,12 +895,10 @@ void Callback_KeyPress(int key, bool shift, bool control)
|
|||||||
// 0x7a == VK_F12
|
// 0x7a == VK_F12
|
||||||
if (key == 0x7b)
|
if (key == 0x7b)
|
||||||
{
|
{
|
||||||
// TODO: Move to memory buffer, implement last state before loading
|
|
||||||
if(shift)
|
if(shift)
|
||||||
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav");
|
State_UndoSaveState();
|
||||||
/*else
|
else
|
||||||
State_LoadAs(FULL_STATESAVES_DIR "tempState.sav");
|
State_UndoLoadState();
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +53,15 @@ static int ev_Save, ev_BufferSave;
|
|||||||
static int ev_Load, ev_BufferLoad;
|
static int ev_Load, ev_BufferLoad;
|
||||||
|
|
||||||
static std::string cur_filename, lastFilename;
|
static std::string cur_filename, lastFilename;
|
||||||
|
static u8 **cur_buffer = NULL;
|
||||||
|
|
||||||
|
// Temporary undo state buffers
|
||||||
|
static u8 *undoLoad = NULL;
|
||||||
|
|
||||||
static bool const bCompressed = true;
|
static bool const bCompressed = true;
|
||||||
|
|
||||||
|
static Common::Thread *saveThread = NULL;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
version = 1,
|
version = 1,
|
||||||
@ -79,6 +85,49 @@ void DoState(PointerWrap &p)
|
|||||||
CoreTiming::DoState(p);
|
CoreTiming::DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadBufferStateCallback(u64 userdata, int cyclesLate)
|
||||||
|
{
|
||||||
|
if(!cur_buffer || !*cur_buffer) {
|
||||||
|
Core::DisplayMessage("State does not exist", 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jit.ClearCache();
|
||||||
|
|
||||||
|
u8 *ptr = *cur_buffer;
|
||||||
|
PointerWrap p(&ptr, PointerWrap::MODE_READ);
|
||||||
|
DoState(p);
|
||||||
|
|
||||||
|
cur_buffer = NULL;
|
||||||
|
|
||||||
|
Core::DisplayMessage("Loaded state", 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveBufferStateCallback(u64 userdata, int cyclesLate)
|
||||||
|
{
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
if(!cur_buffer) {
|
||||||
|
Core::DisplayMessage("Error saving state", 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jit.ClearCache();
|
||||||
|
|
||||||
|
u8 *ptr = NULL;
|
||||||
|
|
||||||
|
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
|
||||||
|
DoState(p);
|
||||||
|
sz = (size_t)ptr;
|
||||||
|
|
||||||
|
*cur_buffer = new u8[sz];
|
||||||
|
ptr = *cur_buffer;
|
||||||
|
p.SetMode(PointerWrap::MODE_WRITE);
|
||||||
|
DoState(p);
|
||||||
|
|
||||||
|
cur_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
THREAD_RETURN CompressAndDumpState(void *pArgs)
|
THREAD_RETURN CompressAndDumpState(void *pArgs)
|
||||||
{
|
{
|
||||||
saveStruct *saveArg = (saveStruct *)pArgs;
|
saveStruct *saveArg = (saveStruct *)pArgs;
|
||||||
@ -149,8 +198,6 @@ THREAD_RETURN CompressAndDumpState(void *pArgs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Thread *saveThread = NULL;
|
|
||||||
|
|
||||||
void SaveStateCallback(u64 userdata, int cyclesLate)
|
void SaveStateCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
// If already saving state, wait for it to finish
|
// If already saving state, wait for it to finish
|
||||||
@ -193,6 +240,10 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
|
|||||||
saveThread = NULL;
|
saveThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save temp buffer for undo load state
|
||||||
|
cur_buffer = &undoLoad;
|
||||||
|
SaveBufferStateCallback(userdata, cyclesLate);
|
||||||
|
|
||||||
FILE *f = fopen(cur_filename.c_str(), "rb");
|
FILE *f = fopen(cur_filename.c_str(), "rb");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
Core::DisplayMessage("State not found", 2000);
|
Core::DisplayMessage("State not found", 2000);
|
||||||
@ -270,6 +321,8 @@ void State_Init()
|
|||||||
{
|
{
|
||||||
ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback);
|
ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback);
|
||||||
ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback);
|
ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback);
|
||||||
|
ev_BufferLoad = CoreTiming::RegisterEvent("LoadBufferState", &LoadBufferStateCallback);
|
||||||
|
ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void State_Shutdown()
|
void State_Shutdown()
|
||||||
@ -279,6 +332,12 @@ void State_Shutdown()
|
|||||||
delete saveThread;
|
delete saveThread;
|
||||||
saveThread = NULL;
|
saveThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(undoLoad)
|
||||||
|
{
|
||||||
|
delete[] undoLoad;
|
||||||
|
undoLoad = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MakeStateFilename(int state_number)
|
std::string MakeStateFilename(int state_number)
|
||||||
@ -316,3 +375,27 @@ void State_LoadLastSaved()
|
|||||||
else
|
else
|
||||||
State_LoadAs(lastFilename);
|
State_LoadAs(lastFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void State_LoadFromBuffer(u8 **buffer)
|
||||||
|
{
|
||||||
|
cur_buffer = buffer;
|
||||||
|
CoreTiming::ScheduleEvent_Threadsafe(0, ev_BufferLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void State_SaveToBuffer(u8 **buffer)
|
||||||
|
{
|
||||||
|
cur_buffer = buffer;
|
||||||
|
CoreTiming::ScheduleEvent_Threadsafe(0, ev_BufferSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the last state before loading the state
|
||||||
|
void State_UndoLoadState()
|
||||||
|
{
|
||||||
|
State_LoadFromBuffer(&undoLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the state that the last save state overwritten on
|
||||||
|
void State_UndoSaveState()
|
||||||
|
{
|
||||||
|
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav");
|
||||||
|
}
|
||||||
|
@ -20,6 +20,12 @@
|
|||||||
#ifndef _STATE_H_
|
#ifndef _STATE_H_
|
||||||
#define _STATE_H_
|
#define _STATE_H_
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 *buffer;
|
||||||
|
size_t size;
|
||||||
|
} saveStruct;
|
||||||
|
|
||||||
void State_Init();
|
void State_Init();
|
||||||
void State_Shutdown();
|
void State_Shutdown();
|
||||||
|
|
||||||
@ -32,12 +38,11 @@ void State_SaveAs(const std::string &filename);
|
|||||||
void State_LoadAs(const std::string &filename);
|
void State_LoadAs(const std::string &filename);
|
||||||
|
|
||||||
void State_LoadLastSaved();
|
void State_LoadLastSaved();
|
||||||
|
void State_UndoSaveState();
|
||||||
|
void State_UndoLoadState();
|
||||||
|
|
||||||
typedef struct
|
void State_LoadFromBuffer(u8 **buffer);
|
||||||
{
|
void State_SaveToBuffer(u8 **buffer);
|
||||||
u8 *buffer;
|
|
||||||
size_t size;
|
|
||||||
} saveStruct;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -286,7 +286,8 @@ EVT_MENU(IDM_LISTUSA, CFrame::GameListChanged)
|
|||||||
EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged)
|
EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged)
|
||||||
|
|
||||||
EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState)
|
EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState)
|
||||||
EVT_MENU(IDM_UNDOSTATE, CFrame::OnUndoState)
|
EVT_MENU(IDM_UNDOLOADSTATE, CFrame::OnUndoLoadState)
|
||||||
|
EVT_MENU(IDM_UNDOSAVESTATE, CFrame::OnUndoSaveState)
|
||||||
EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile)
|
EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile)
|
||||||
EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile)
|
EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile)
|
||||||
|
|
||||||
|
@ -188,7 +188,8 @@ class CFrame : public wxFrame
|
|||||||
void OnLoadStateFromFile(wxCommandEvent& event);
|
void OnLoadStateFromFile(wxCommandEvent& event);
|
||||||
void OnSaveStateToFile(wxCommandEvent& event);
|
void OnSaveStateToFile(wxCommandEvent& event);
|
||||||
void OnLoadLastState(wxCommandEvent& event);
|
void OnLoadLastState(wxCommandEvent& event);
|
||||||
void OnUndoState(wxCommandEvent& event);
|
void OnUndoLoadState(wxCommandEvent& event);
|
||||||
|
void OnUndoSaveState(wxCommandEvent& event);
|
||||||
|
|
||||||
void OnConfigMain(wxCommandEvent& event); // Options
|
void OnConfigMain(wxCommandEvent& event); // Options
|
||||||
void OnPluginGFX(wxCommandEvent& event);
|
void OnPluginGFX(wxCommandEvent& event);
|
||||||
|
@ -137,11 +137,12 @@ void CFrame::CreateMenu()
|
|||||||
m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State"));
|
m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State"));
|
||||||
|
|
||||||
saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State..."));
|
saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State..."));
|
||||||
|
loadMenu->Append(IDM_UNDOSAVESTATE, _T("Last Overwritten State\tShift+F12"));
|
||||||
saveMenu->AppendSeparator();
|
saveMenu->AppendSeparator();
|
||||||
|
|
||||||
loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State..."));
|
loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State..."));
|
||||||
loadMenu->Append(IDM_LOADLASTSTATE, _T("Last Saved State\tF11"));
|
loadMenu->Append(IDM_LOADLASTSTATE, _T("Last Saved State\tF11"));
|
||||||
loadMenu->Append(IDM_UNDOSTATE, _T("Last Overwritten State\tF12"));
|
loadMenu->Append(IDM_UNDOLOADSTATE, _T("Undo Load State\tF12"));
|
||||||
loadMenu->AppendSeparator();
|
loadMenu->AppendSeparator();
|
||||||
|
|
||||||
for (int i = 1; i <= 8; i++) {
|
for (int i = 1; i <= 8; i++) {
|
||||||
@ -716,11 +717,17 @@ void CFrame::OnLoadLastState(wxCommandEvent& WXUNUSED (event))
|
|||||||
State_LoadLastSaved();
|
State_LoadLastSaved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrame::OnUndoState(wxCommandEvent& WXUNUSED (event))
|
void CFrame::OnUndoLoadState(wxCommandEvent& WXUNUSED (event))
|
||||||
{
|
{
|
||||||
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav");
|
State_UndoLoadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFrame::OnUndoSaveState(wxCommandEvent& WXUNUSED (event))
|
||||||
|
{
|
||||||
|
State_UndoSaveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CFrame::OnLoadState(wxCommandEvent& event)
|
void CFrame::OnLoadState(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
int id = event.GetId();
|
int id = event.GetId();
|
||||||
|
@ -32,7 +32,8 @@ enum
|
|||||||
IDM_LOADSTATE = 200, // File menu
|
IDM_LOADSTATE = 200, // File menu
|
||||||
IDM_SAVESTATE,
|
IDM_SAVESTATE,
|
||||||
IDM_LOADLASTSTATE,
|
IDM_LOADLASTSTATE,
|
||||||
IDM_UNDOSTATE,
|
IDM_UNDOLOADSTATE,
|
||||||
|
IDM_UNDOSAVESTATE,
|
||||||
IDM_LOADSTATEFILE,
|
IDM_LOADSTATEFILE,
|
||||||
IDM_SAVESTATEFILE,
|
IDM_SAVESTATEFILE,
|
||||||
IDM_SAVESLOT1,
|
IDM_SAVESLOT1,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user