mirror of
https://github.com/libretro/ppsspp.git
synced 2025-03-03 22:17:08 +00:00
Merge pull request #10737 from unknownbrackets/savestate
SaveState: Keep an undo for each slot by default
This commit is contained in:
commit
198d921a9b
@ -325,6 +325,14 @@ static bool DefaultCodeGen() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool DefaultEnableStateUndo() {
|
||||
#ifdef MOBILE_DEVICE
|
||||
// Off on mobile to save disk space.
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ConfigSectionSettings {
|
||||
const char *section;
|
||||
ConfigSetting *settings;
|
||||
@ -354,6 +362,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, &DefaultEnableStateUndo, true, true),
|
||||
ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true),
|
||||
|
||||
ConfigSetting("GridView1", &g_Config.bGridView1, true),
|
||||
|
@ -199,6 +199,7 @@ public:
|
||||
int iMaxRecent;
|
||||
int iCurrentStateSlot;
|
||||
int iRewindFlipFrequency;
|
||||
bool bEnableStateUndo;
|
||||
bool bEnableAutoLoad;
|
||||
bool bEnableCheats;
|
||||
bool bReloadCheats;
|
||||
|
@ -324,30 +324,46 @@ namespace SaveState
|
||||
// Slot utilities
|
||||
|
||||
std::string AppendSlotTitle(const std::string &filename, const std::string &title) {
|
||||
if (!endsWith(filename, std::string(".") + STATE_EXTENSION)) {
|
||||
return title + " (" + filename + ")";
|
||||
char slotChar = 0;
|
||||
auto detectSlot = [&](const std::string &ext) {
|
||||
if (!endsWith(filename, std::string(".") + ext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Usually these are slots, let's check the slot # after the last '_'.
|
||||
size_t slotNumPos = filename.find_last_of('_');
|
||||
if (slotNumPos == filename.npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t extLength = ext.length() + 1;
|
||||
// If we take out the extension, '_', etc. we should be left with only a single digit.
|
||||
if (slotNumPos + 1 + extLength != filename.length() - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
slotChar = filename[slotNumPos + 1];
|
||||
if (slotChar < '0' || slotChar > '8') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change from zero indexed to human friendly.
|
||||
slotChar++;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (detectSlot(STATE_EXTENSION)) {
|
||||
return StringFromFormat("%s (%c)", title.c_str(), slotChar);
|
||||
}
|
||||
if (detectSlot(UNDO_STATE_EXTENSION)) {
|
||||
I18NCategory *sy = GetI18NCategory("System");
|
||||
// Allow the number to be positioned where it makes sense.
|
||||
std::string undo = sy->T("undo %c");
|
||||
return title + " (" + StringFromFormat(undo.c_str(), slotChar) + ")";
|
||||
}
|
||||
|
||||
// Usually these are slots, let's check the slot # after the last '_'.
|
||||
size_t slotNumPos = filename.find_last_of('_');
|
||||
if (slotNumPos == filename.npos) {
|
||||
return title + " (" + filename + ")";
|
||||
}
|
||||
|
||||
const size_t extLength = strlen(STATE_EXTENSION) + 1;
|
||||
// If we take out the extension, '_', etc. we should be left with only a single digit.
|
||||
if (slotNumPos + 1 + extLength != filename.length() - 1) {
|
||||
return title + " (" + filename + ")";
|
||||
}
|
||||
|
||||
std::string slot = filename.substr(slotNumPos + 1, 1);
|
||||
if (slot[0] < '0' || slot[0] > '8') {
|
||||
return title + " (" + filename + ")";
|
||||
}
|
||||
|
||||
// Change from zero indexed to human friendly.
|
||||
slot[0]++;
|
||||
return title + " (" + slot + ")";
|
||||
// Couldn't detect, use the filename.
|
||||
return title + " (" + filename + ")";
|
||||
}
|
||||
|
||||
std::string GetTitle(const std::string &filename) {
|
||||
@ -411,11 +427,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 +445,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 +457,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);
|
||||
|
@ -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();
|
||||
|
@ -684,6 +684,7 @@ void GameSettingsScreen::CreateViews() {
|
||||
}
|
||||
|
||||
systemSettings->Add(new Choice(sy->T("Restore Default Settings")))->OnClick.Handle(this, &GameSettingsScreen::OnRestoreDefaultSettings);
|
||||
systemSettings->Add(new CheckBox(&g_Config.bEnableStateUndo, sy->T("Savestate slot backups")));
|
||||
systemSettings->Add(new CheckBox(&g_Config.bEnableAutoLoad, sy->T("Auto Load Newest Savestate")));
|
||||
|
||||
#if defined(USING_WIN_UI)
|
||||
|
Loading…
x
Reference in New Issue
Block a user