Fixes to backup savestate system, starting of undo savestate implementation.

This commit is contained in:
adelikat 2008-12-23 20:29:27 +00:00
parent 20ef5a722c
commit 93c48afbb6
6 changed files with 128 additions and 37 deletions

View File

@ -336,6 +336,7 @@ BEGIN
MENUITEM "&Replay Movie", FCEUX_CONTEXT_REPLAYMOVIE
MENUITEM "Record Movie", FCEUX_CONTEXT_RECORDMOVIE
MENUITEM SEPARATOR
MENUITEM "Undo savestate", FCEUX_CONTEXT_UNDOSAVESTATE
MENUITEM "Undo loadstate", FCEUX_CONTEXT_UNDOLOADSTATE
MENUITEM "Rewind to last auto-save", FCEUX_CONTEXT_REWINDTOLASTAUTO
MENUITEM "Screenshot", FCEUX_CONTEXT_SCREENSHOT

View File

@ -381,7 +381,6 @@
#define MEMW_EDIT03RMADDRESS 1191
#define IDC_DEBUGGER_RESTORESIZE 1191
#define MEMW_EDIT04RMADDRESS 1192
#define IDC_MOVIE_CANCEL 1192
#define IDC_MOVIE_CLOSE 1192
#define EDIT00_RESULTS 1193
#define IDC_MOVIE_PAUSEAFTERPLAYBACK 1193
@ -636,6 +635,8 @@
#define FCEUX_CONTEXT_MAKEBACKUP 40320
#define ID_CONFIG_MOVIEOPTIONS 40321
#define MENU_MOVIEOPTIONS 40322
#define ID_GAME_UNDOSAVESTATE 40323
#define FCEUX_CONTEXT_UNDOSAVESTATE 40324
#define IDC_DEBUGGER_ICONTRAY 55535
#define MW_ValueLabel2 65423
#define MW_ValueLabel1 65426
@ -645,7 +646,7 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 125
#define _APS_NEXT_COMMAND_VALUE 40323
#define _APS_NEXT_COMMAND_VALUE 40325
#define _APS_NEXT_CONTROL_VALUE 1199
#define _APS_NEXT_SYMED_VALUE 101
#endif

View File

@ -93,8 +93,8 @@ char *md5_asciistr(uint8 digest[16]);
void ShowNetplayConsole(void); //mbg merge 7/17/06 YECH had to add
void MapInput(void);
extern BOOL CALLBACK ReplayMetadataDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); //Metadata dialog
extern bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
extern void SwapSaveState();
//AutoFire-----------------------------------------------
void SetAutoFirePattern(int onframes, int offframes);
@ -1301,6 +1301,11 @@ UpdateContextMenuItems(hfceuxcontextsub, whichContext);
CreateDialog(fceu_hInstance, "IDD_REPLAY_METADATA", hWnd, ReplayMetadataDialogProc);
break;
//Undo Savestate
case FCEUX_CONTEXT_UNDOSAVESTATE:
SwapSaveState();
break;
//Undo Loadstate
case FCEUX_CONTEXT_UNDOLOADSTATE:
if (CheckBackupSaveStateExist())

View File

@ -1301,10 +1301,10 @@ bool CheckFileExists(const char* filename)
{
//This function simply checks to see if the given filename exists
string checkFilename;
if (filename)
checkFilename = filename;
FCEUI_printf("Checking file %s\n",checkFilename.c_str());
//Check if this filename exists
fstream test;
test.open(checkFilename.c_str(),fstream::in);
@ -1312,11 +1312,11 @@ bool CheckFileExists(const char* filename)
if (test.fail())
{
test.close();
return false;
return false;
}
else
{
test.close();
return true;
return true;
}
}

View File

@ -59,6 +59,9 @@ static int StateShow;
//tells the save system innards that we're loading the old format
bool FCEU_state_loading_old_format;
char lastSavestateMade[2048]; //Stores the last savestate made (needed for UndoSavestate)
bool redoSS = false; //This will be true if UndoSaveState is run, will turn false when a new savestate is made
#define SFMDATA_SIZE (64)
static SFORMAT SFMDATA[SFMDATA_SIZE];
static int SFEXINDEX;
@ -425,17 +428,37 @@ void FCEUSS_Save(const char *fname)
return;
}
if(fname)
if(fname) //If filename is given use it.
{
//backup existing savestate first
if (CheckFileExists(fname))
{
CreateBackupSaveState(fname); //Make a backup of previous savestate before overwriting it
strcpy(lastSavestateMade,fname); //Remember what the last savestate filename was (for undoing later)
redoSS = true; //Backup was created so redo is possible
}
else
redoSS = false; //No backup was needed, so lastSavestateMade does not contain a file that has a backup
st =FCEUD_UTF8_fstream(fname, "wb");
else
}
else //Else, generate one
{
//FCEU_PrintError("daCurrentState=%d",CurrentState);
fn = strdup(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0).c_str());
st = FCEUD_UTF8_fstream(fn,"wb");
//backup existing savestate first
if (CheckFileExists(fn)) CreateBackupSaveState(fn);
if (CheckFileExists(fn))
{
CreateBackupSaveState(fn); //Make a backup of previous savestate before overwriting it
strcpy(lastSavestateMade,fn); //Remember what the last savestate filename was (for undoing later)
FCEUI_printf("Last save made: %s\n",lastSavestateMade);
redoSS = true; //Backup was created so redo is possible
}
else
redoSS = false; //No backup was needed, so lastSavestateMade does not contain a file that has a backup
st = FCEUD_UTF8_fstream(fn,"wb");
free(fn);
}
@ -848,6 +871,90 @@ void FCEU_DrawSaveStates(uint8 *XBuf)
StateShow--;
}
//*************************************************************************
//Savestate backup functions
//(Used when making savestates)
//*************************************************************************
string GenerateBackupSaveStateFn(const char *fname)
{
//This backup is for the backup "slot" for any savestate made. Example: smb.fc0 becomes smb-bak.fc0
string filename;
filename = fname; //Convert fname to a string object
int x = filename.find_last_of("."); //Find file extension
filename.insert(x,"-bak"); //add "-bak" before the dot.
FCEUI_printf("Generating filename of %s\n",filename.c_str());
return filename;
}
void CreateBackupSaveState(const char *fname)
{
string filename = GenerateBackupSaveStateFn(fname);
std::fstream* st = 0;
st = FCEUD_UTF8_fstream(filename.c_str(),"wb");
if(st == NULL)
{
FCEU_DispMessage("State %d save error.",filename.c_str());
return;
}
if(FCEUMOV_Mode(MOVIEMODE_INACTIVE))
FCEUSS_SaveMS(st,-1);
else
FCEUSS_SaveMS(st,0);
delete st;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------
//Logic - undo available until a new savestate is made,game is closed, or fcuex is closed
//What we need is a concept of if you are undoing or redoing as well
//Undo should know there is a bak file before making a decision. the main platform code should know this before calling it.
//Once it is undone, it should know this and call it a redo if called again on the same file. It should remember as long as it knows about undo.
//The undo redo is meaningless information for this function as it simply swaps.
//perhaps a combo of flag(s) and a function to handle flag situations is called for?
//This function would then simply swap the files, which means it is both undo and redo
//And extra function needs to be in charge of flags to keep up with which one is being done, but that is purely cosmetic
void SwapSaveState()
{
if (!lastSavestateMade) return; //If there is no last savestate, can't undo
string backup = GenerateBackupSaveStateFn(lastSavestateMade); //Get filename of backup state
if (!CheckFileExists(backup.c_str()))
{
FCEUI_printf("%s exists",backup.c_str());
return; //If no backup, can't undo
}
//--------------------------------------------------------------------------------------------
//So both exists, now swap the last savestate and its backup
//--------------------------------------------------------------------------------------------
string temp; //Create a temp string object
temp = backup; //Put backup filename in temp
temp.append("x"); //Add x
FILE* backupf = fopen(backup.c_str(),"r"); //Open backup file
FILE* currentf = fopen(lastSavestateMade,"w"); //create temp file
rename(backup.c_str(),temp.c_str()); //rename backup file to temp file
rename(lastSavestateMade,backup.c_str()); //rename current as backup
rename(temp.c_str(),lastSavestateMade); //rename backup as current
fclose(backupf); //Cleanup, close backup file
fclose(currentf); //Cleanup, close current file
FCEUI_DispMessage("%s restored",backup.c_str());
FCEUI_printf("%s restored\n",backup.c_str());
//TODO: deal with error handling if any of these files does/doesn't exist unexpectedly
}
//------------------------------------------------------------------------------------------------------------------------------------------------------
//*************************************************************************
//Loadstate backup functions
//(Used when Loading savestates)
//*************************************************************************
string GetBackupFileName()
{
//This backup savestate is a special one specifically made whenever a loadstate occurs so that the user's place in a movie/game is never lost
@ -863,30 +970,6 @@ string GetBackupFileName()
return filename;
}
void CreateBackupSaveState(const char *fname)
{
string filename;
filename = fname; //Convert fname to a string object
int x = filename.find_last_of("."); //Find file extension
filename.insert(x-1,"-bak"); //add "-bak" before the dot. Ex: smb.fc0 becomes smb-bak.fc0
std::fstream* st = 0;
st = FCEUD_UTF8_fstream(filename.c_str(),"wb");
if(st == NULL)
{
FCEU_DispMessage("State %d save error.",CurrentState);
return;
}
if(FCEUMOV_Mode(MOVIEMODE_INACTIVE))
FCEUSS_SaveMS(st,-1);
else
FCEUSS_SaveMS(st,0);
delete st;
}
void BackupLoadState()
{
string filename = GetBackupFileName();

View File

@ -63,4 +63,5 @@ void FCEU_DrawSaveStates(uint8 *XBuf);
void CreateBackupSaveState(const char *fname); //backsup a savestate before overwriting it with a new one
void BackupLoadState(); //Makes a backup savestate before any loadstate
void LoadBackup(); //Loads the backupsavestate
void LoadBackup(); //Loads the backupsavestate
void SwapSaveState(); //Swaps a savestate with its backup state