diff --git a/Core/Config.cpp b/Core/Config.cpp index f89d75f738..b985a7ba62 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -354,6 +354,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("DumpAudio", &g_Config.bDumpAudio, false), ConfigSetting("SaveLoadResetsAVdumping", &g_Config.bSaveLoadResetsAVdumping, false), ConfigSetting("StateSlot", &g_Config.iCurrentStateSlot, 0, true, true), + ConfigSetting("EnableStateUndo", &g_Config.bEnableStateUndo, true, true, true), ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true), ConfigSetting("GridView1", &g_Config.bGridView1, true), diff --git a/Core/Config.h b/Core/Config.h index 43751c9a79..edc88e4a19 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -199,6 +199,7 @@ public: int iMaxRecent; int iCurrentStateSlot; int iRewindFlipFrequency; + bool bEnableStateUndo; bool bEnableAutoLoad; bool bEnableCheats; bool bReloadCheats; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 1f79ebc143..29190c6497 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -411,11 +411,16 @@ namespace SaveState { std::string fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); std::string shot = GenerateSaveSlotFilename(gameFilename, slot, SCREENSHOT_EXTENSION); + std::string fnUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_STATE_EXTENSION); + std::string shotUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_SCREENSHOT_EXTENSION); if (!fn.empty()) { auto renameCallback = [=](bool status, const std::string &message, void *data) { if (status) { - if (File::Exists(fn)) { - File::Delete(fn); + if (File::Exists(fnUndo) && g_Config.bEnableStateUndo) { + File::Delete(fnUndo); + } + if (File::Exists(fn) && g_Config.bEnableStateUndo) { + File::Rename(fn, fnUndo); } File::Rename(fn + ".tmp", fn); } @@ -424,6 +429,9 @@ namespace SaveState } }; // Let's also create a screenshot. + if (File::Exists(shot) && g_Config.bEnableStateUndo) { + File::Rename(shot, shotUndo); + } SaveScreenshot(shot, Callback(), 0); Save(fn + ".tmp", renameCallback, cbUserData); } else { @@ -433,12 +441,43 @@ namespace SaveState } } + bool UndoSaveSlot(const std::string &gameFilename, int slot) { + std::string fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); + std::string shot = GenerateSaveSlotFilename(gameFilename, slot, SCREENSHOT_EXTENSION); + std::string fnUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_STATE_EXTENSION); + std::string shotUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_SCREENSHOT_EXTENSION); + + // Do nothing if there's no undo. + if (File::Exists(fnUndo)) { + // Swap them so they can undo again to redo. Mistakes happen. + if (File::Exists(shotUndo)) { + File::Rename(shot, shot + ".tmp"); + File::Rename(shotUndo, shot); + File::Rename(shot + ".tmp", shotUndo); + } + + File::Rename(fn, fn + ".tmp"); + File::Rename(fnUndo, fn); + File::Rename(fn + ".tmp", fnUndo); + + return true; + } + + return false; + } + bool HasSaveInSlot(const std::string &gameFilename, int slot) { std::string fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); return File::Exists(fn); } + bool HasUndoSaveInSlot(const std::string &gameFilename, int slot) + { + std::string fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); + return File::Exists(fn + ".undo"); + } + bool HasScreenshotInSlot(const std::string &gameFilename, int slot) { std::string fn = GenerateSaveSlotFilename(gameFilename, slot, SCREENSHOT_EXTENSION); diff --git a/Core/SaveState.h b/Core/SaveState.h index a4719103af..64c4dbe0c7 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -28,6 +28,8 @@ namespace SaveState static const int NUM_SLOTS = 5; static const char *STATE_EXTENSION = "ppst"; static const char *SCREENSHOT_EXTENSION = "jpg"; + static const char *UNDO_STATE_EXTENSION = "undo.ppst"; + static const char *UNDO_SCREENSHOT_EXTENSION = "undo.jpg"; void Init(); void Shutdown(); @@ -36,8 +38,10 @@ namespace SaveState void NextSlot(); void SaveSlot(const std::string &gameFilename, int slot, Callback callback, void *cbUserData = 0); void LoadSlot(const std::string &gameFilename, int slot, Callback callback, void *cbUserData = 0); + bool UndoSaveSlot(const std::string &gameFilename, int slot); // Checks whether there's an existing save in the specified slot. bool HasSaveInSlot(const std::string &gameFilename, int slot); + bool HasUndoSaveInSlot(const std::string &gameFilename, int slot); bool HasScreenshotInSlot(const std::string &gameFilename, int slot); int GetCurrentSlot();