Qt: Implement save state backups option

This commit is contained in:
Connor McLaughlin 2022-10-01 23:46:53 +10:00 committed by lightningterror
parent 4907003d3c
commit bebad5127c
4 changed files with 47 additions and 26 deletions

View File

@ -59,6 +59,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnShutdown, "EmuCore", "SaveStateOnShutdown", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnStart, "UI", "StartPaused", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.backupSaveStates, "EmuCore", "BackupSavestate", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.startFullscreen, "UI", "StartFullscreen", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.doubleClickTogglesFullscreen, "UI", "DoubleClickTogglesFullscreen",
@ -115,6 +116,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
dialog->registerWidgetHelp(m_ui.pauseOnFocusLoss, tr("Pause On Focus Loss"), tr("Unchecked"),
tr("Pauses the emulator when you minimize the window or switch to another application, "
"and unpauses when you switch back."));
dialog->registerWidgetHelp(m_ui.backupSaveStates, tr("Create Save State Backups"), tr("Unchecked"),
tr("Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix."));
dialog->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
tr("Automatically switches to fullscreen mode when a game is started."));
dialog->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Checked"),

View File

@ -32,31 +32,17 @@
<string>Behaviour</string>
</property>
<layout class="QGridLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="pauseOnStart">
<property name="text">
<string>Pause On Start</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="3" column="1">
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
<string>Pause On Focus Loss</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="confirmShutdown">
<item row="0" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Confirm Shutdown</string>
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
@ -67,7 +53,28 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="3" column="0">
<widget class="QCheckBox" name="pauseOnStart">
<property name="text">
<string>Pause On Start</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="confirmShutdown">
<property name="text">
<string>Confirm Shutdown</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="backupSaveStates">
<property name="text">
<string>Create Save State Backups</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="discordPresence">
<property name="text">
<string>Enable Discord Presence</string>

View File

@ -93,7 +93,7 @@ namespace VMManager
static std::string GetCurrentSaveStateFileName(s32 slot);
static bool DoLoadState(const char* filename);
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread);
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key,
const char* filename, s32 slot_for_message);
@ -1028,7 +1028,7 @@ void VMManager::Shutdown(bool save_resume_state)
if (!GSDumpReplayer::IsReplayingDump() && save_resume_state)
{
std::string resume_file_name(GetCurrentSaveStateFileName(-1));
if (!resume_file_name.empty() && !DoSaveState(resume_file_name.c_str(), -1, true))
if (!resume_file_name.empty() && !DoSaveState(resume_file_name.c_str(), -1, true, false))
Console.Error("Failed to save resume state");
}
else if (GSDumpReplayer::IsReplayingDump())
@ -1185,7 +1185,7 @@ bool VMManager::DoLoadState(const char* filename)
}
}
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread)
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state)
{
if (GSDumpReplayer::IsReplayingDump())
return false;
@ -1197,6 +1197,17 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
std::unique_ptr<ArchiveEntryList> elist(SaveState_DownloadState());
std::unique_ptr<SaveStateScreenshotData> screenshot(SaveState_SaveScreenshot());
if (FileSystem::FileExists(filename) && backup_old_state)
{
const std::string backup_filename(fmt::format("{}.backup", filename));
Console.WriteLn(fmt::format("Creating save state backup {}...", backup_filename));
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
{
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format("Failed to back up old save state {}.", Path::GetFileName(filename)));
}
}
if (zip_on_thread)
{
// lock order here is important; the thread could exit before we resume here.
@ -1336,9 +1347,9 @@ bool VMManager::LoadStateFromSlot(s32 slot)
return DoLoadState(filename.c_str());
}
bool VMManager::SaveState(const char* filename, bool zip_on_thread)
bool VMManager::SaveState(const char* filename, bool zip_on_thread, bool backup_old_state)
{
return DoSaveState(filename, -1, zip_on_thread);
return DoSaveState(filename, -1, zip_on_thread, backup_old_state);
}
bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
@ -1349,7 +1360,7 @@ bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
// if it takes more than a minute.. well.. wtf.
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_SAVE, fmt::format("Saving state to slot {}...", slot), 60.0f);
return DoSaveState(filename.c_str(), slot, zip_on_thread);
return DoSaveState(filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate);
}
LimiterModeType VMManager::GetLimiterMode()

View File

@ -122,7 +122,7 @@ namespace VMManager
bool LoadStateFromSlot(s32 slot);
/// Saves state to the specified filename.
bool SaveState(const char* filename, bool zip_on_thread = true);
bool SaveState(const char* filename, bool zip_on_thread = true, bool backup_old_state = false);
/// Saves state to the specified slot.
bool SaveStateToSlot(s32 slot, bool zip_on_thread = true);