Save States:

1. Added a header, including the Game ID (old states are obsolete unless the gameid is appended to the beginning) so states from different games can't be cross-loaded
2. Added loading/saving from/to file
3. Added loading of last saved state (F11)
4. Added "Undo State": Load the backed up last overwritten state (if you press save instead of load) (F12)
5. State code cleanup

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3560 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
XTra.KrazzY 2009-06-28 01:11:35 +00:00
parent 2ea850f5a0
commit 7ea2bc5da9
7 changed files with 169 additions and 30 deletions

View File

@ -863,6 +863,14 @@ void Callback_KeyPress(int key, bool shift, bool control)
State_Load(slot_number);
}
}
// 0x7a == VK_F11
if (key == 0x7a)
State_LoadLastSaved();
// 0x7a == VK_F12
if (key == 0x7b)
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav");
}
// Callback_WiimoteLog

View File

@ -52,12 +52,13 @@ static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS);
static int ev_Save;
static int ev_Load;
static std::string cur_filename;
static std::string cur_filename, lastFilename;
static bool const bCompressed = true;
enum {
version = 1
enum
{
version = 1,
};
void DoState(PointerWrap &p)
@ -84,22 +85,31 @@ THREAD_RETURN CompressAndDumpState(void *pArgs)
u8 *buffer = saveArg->buffer;
size_t sz = saveArg->size;
lzo_uint out_len = 0;
state_header header;
std::string filename = cur_filename;
delete saveArg;
FILE *f = fopen(cur_filename.c_str(), "wb");
// Moving to last overwritten save-state
if(File::Exists(cur_filename.c_str())) {
if(File::Exists(FULL_STATESAVES_DIR "lastState.sav"))
File::Delete(FULL_STATESAVES_DIR "lastState.sav");
if(!File::Rename(cur_filename.c_str(), FULL_STATESAVES_DIR "lastState.sav"))
Core::DisplayMessage("Failed to move previous state to state undo backup", 1000);
}
FILE *f = fopen(filename.c_str(), "wb");
if(f == NULL) {
Core::DisplayMessage("Could not save state", 2000);
return 0;
}
if (bCompressed) {
fwrite(&sz, sizeof(int), 1, f);
} else {
int zero = 0;
fwrite(&zero, sizeof(int), 1, f);
}
// Setting up the header
memcpy(header.gameID, Core::GetStartupParameter().GetUniqueID().c_str(), 6);
header.sz = bCompressed ? sz : 0;
fwrite(&header, sizeof(state_header), 1, f);
if (bCompressed) {
if (lzo_init() != LZO_E_OK)
@ -134,7 +144,7 @@ THREAD_RETURN CompressAndDumpState(void *pArgs)
delete [] buffer;
Core::DisplayMessage(StringFromFormat("Saved State to %s",
cur_filename.c_str()).c_str(), 2000);
filename.c_str()).c_str(), 2000);
return 0;
}
@ -176,22 +186,43 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
bool bCompressedState;
// If saving state, wait for it to finish
if(saveThread)
{
delete saveThread;
saveThread = NULL;
}
FILE *f = fopen(cur_filename.c_str(), "rb");
if (!f) {
Core::DisplayMessage("State not found", 2000);
return;
}
jit.ClearCache();
u8 *buffer = NULL;
state_header header;
size_t sz;
int sz;
fread(&sz, sizeof(int), 1, f);
fread(&header, sizeof(state_header), 1, f);
if(memcmp(Core::GetStartupParameter().GetUniqueID().c_str(), header.gameID, 6))
{
char gameID[7] = {0};
memcpy(gameID, header.gameID, 6);
Core::DisplayMessage(StringFromFormat("State belongs to a different game (ID %s)",
gameID), 2000);
fclose(f);
return;
}
sz = header.sz;
bCompressedState = (sz != 0);
if (bCompressedState) {
Core::DisplayMessage("Decompressing State...", 500);
if (lzo_init() != LZO_E_OK)
PanicAlert("Internal LZO Error - lzo_init() failed");
else {
@ -225,6 +256,8 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
fclose(f);
jit.ClearCache();
u8 *ptr = buffer;
PointerWrap p(&ptr, PointerWrap::MODE_READ);
DoState(p);
@ -253,14 +286,33 @@ std::string MakeStateFilename(int state_number)
return StringFromFormat(FULL_STATESAVES_DIR "%s.s%02i", Core::GetStartupParameter().GetUniqueID().c_str(), state_number);
}
void State_SaveAs(const std::string &filename)
{
cur_filename = filename;
lastFilename = filename;
CoreTiming::ScheduleEvent_Threadsafe(0, ev_Save);
}
void State_Save(int slot)
{
cur_filename = MakeStateFilename(slot);
CoreTiming::ScheduleEvent_Threadsafe(0, ev_Save);
State_SaveAs(MakeStateFilename(slot));
}
void State_LoadAs(const std::string &filename)
{
cur_filename = filename;
CoreTiming::ScheduleEvent_Threadsafe(0, ev_Load);
}
void State_Load(int slot)
{
cur_filename = MakeStateFilename(slot);
CoreTiming::ScheduleEvent_Threadsafe(0, ev_Load);
State_LoadAs(MakeStateFilename(slot));
}
void State_LoadLastSaved()
{
if(lastFilename.empty())
Core::DisplayMessage("There is no last saved state", 2000);
else
State_LoadAs(lastFilename);
}

View File

@ -28,10 +28,22 @@ void State_Shutdown();
void State_Save(int slot);
void State_Load(int slot);
void State_SaveAs(const std::string &filename);
void State_LoadAs(const std::string &filename);
void State_LoadLastSaved();
typedef struct
{
u8 *buffer;
size_t size;
} saveStruct;
typedef struct
{
u8 gameID[6];
size_t sz;
} state_header;
#endif

View File

@ -285,6 +285,11 @@ EVT_MENU(IDM_LISTPAL, CFrame::GameListChanged)
EVT_MENU(IDM_LISTUSA, CFrame::GameListChanged)
EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged)
EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState)
EVT_MENU(IDM_UNDOSTATE, CFrame::OnUndoState)
EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile)
EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile)
EVT_MENU_RANGE(IDM_LOADSLOT1, IDM_LOADSLOT10, CFrame::OnLoadState)
EVT_MENU_RANGE(IDM_SAVESLOT1, IDM_SAVESLOT10, CFrame::OnSaveState)
EVT_MENU_RANGE(IDM_DRIVE1, IDM_DRIVE24, CFrame::OnBootDrive)

View File

@ -185,6 +185,10 @@ class CFrame : public wxFrame
void OnClose(wxCloseEvent &event);
void OnLoadState(wxCommandEvent& event);
void OnSaveState(wxCommandEvent& event);
void OnLoadStateFromFile(wxCommandEvent& event);
void OnSaveStateToFile(wxCommandEvent& event);
void OnLoadLastState(wxCommandEvent& event);
void OnUndoState(wxCommandEvent& event);
void OnConfigMain(wxCommandEvent& event); // Options
void OnPluginGFX(wxCommandEvent& event);

View File

@ -139,11 +139,20 @@ void CFrame::CreateMenu()
emulationMenu->AppendSeparator();
wxMenu *saveMenu = new wxMenu;
wxMenu *loadMenu = new wxMenu;
m_pSubMenuLoad = emulationMenu->AppendSubMenu(saveMenu, _T("&Load State"));
m_pSubMenuSave = emulationMenu->AppendSubMenu(loadMenu, _T("Sa&ve State"));
m_pSubMenuLoad = emulationMenu->AppendSubMenu(loadMenu, _T("&Load State"));
m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State"));
saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State..."));
saveMenu->AppendSeparator();
loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State..."));
loadMenu->Append(IDM_LOADLASTSTATE, _T("Last Saved State\tF11"));
loadMenu->Append(IDM_UNDOSTATE, _T("Last Overwritten State\tF12"));
loadMenu->AppendSeparator();
for (int i = 1; i < 10; i++) {
saveMenu->Append(IDM_LOADSLOT1 + i - 1, wxString::Format(_T("Slot %i\tF%i"), i, i));
loadMenu->Append(IDM_SAVESLOT1 + i - 1, wxString::Format(_T("Slot %i\tShift+F%i"), i, i));
loadMenu->Append(IDM_LOADSLOT1 + i - 1, wxString::Format(_T("Slot %i\tF%i"), i, i));
saveMenu->Append(IDM_SAVESLOT1 + i - 1, wxString::Format(_T("Slot %i\tShift+F%i"), i, i));
}
menuBar->Append(emulationMenu, _T("&Emulation"));
@ -717,6 +726,52 @@ void CFrame::OnToggleSkipIdle(wxCommandEvent& WXUNUSED (event))
SConfig::GetInstance().SaveSettings();
}
void CFrame::OnLoadStateFromFile(wxCommandEvent& WXUNUSED (event))
{
wxString path = wxFileSelector(
_T("Select the state to load"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxString::Format
(
_T("All Save States (sav, s##)|*.sav;*.s??|All files (%s)|%s"),
wxFileSelectorDefaultWildcardStr,
wxFileSelectorDefaultWildcardStr
),
wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST,
this);
if(path)
State_LoadAs(path.ToAscii());
}
void CFrame::OnSaveStateToFile(wxCommandEvent& WXUNUSED (event))
{
wxString path = wxFileSelector(
_T("Select the state to save"),
wxEmptyString, wxEmptyString, wxEmptyString,
wxString::Format
(
_T("All Save States (sav, s##)|*.sav;*.s??|All files (%s)|%s"),
wxFileSelectorDefaultWildcardStr,
wxFileSelectorDefaultWildcardStr
),
wxFD_SAVE,
this);
if(path)
State_SaveAs(path.ToAscii());
}
void CFrame::OnLoadLastState(wxCommandEvent& WXUNUSED (event))
{
State_LoadLastSaved();
}
void CFrame::OnUndoState(wxCommandEvent& WXUNUSED (event))
{
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav");
}
void CFrame::OnLoadState(wxCommandEvent& event)
{
int id = event.GetId();
@ -724,13 +779,6 @@ void CFrame::OnLoadState(wxCommandEvent& event)
State_Load(slot);
}
void CFrame::OnResize(wxSizeEvent& event)
{
FitInside();
DoMoveIcons(); // In FrameWiimote.cpp
event.Skip();
}
void CFrame::OnSaveState(wxCommandEvent& event)
{
int id = event.GetId();
@ -738,6 +786,12 @@ void CFrame::OnSaveState(wxCommandEvent& event)
State_Save(slot);
}
void CFrame::OnResize(wxSizeEvent& event)
{
FitInside();
DoMoveIcons(); // In FrameWiimote.cpp
event.Skip();
}
// Enable and disable the toolbar
void CFrame::OnToggleToolbar(wxCommandEvent& event)

View File

@ -31,6 +31,10 @@ enum
{
IDM_LOADSTATE = 200, // File menu
IDM_SAVESTATE,
IDM_LOADLASTSTATE,
IDM_UNDOSTATE,
IDM_LOADSTATEFILE,
IDM_SAVESTATEFILE,
IDM_SAVESLOT1,
IDM_SAVESLOT2,
IDM_SAVESLOT3,