mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-15 11:48:50 +00:00
SaveState: Rework error handling when saving states
This commit is contained in:
parent
764875ddbf
commit
e8c2cfa843
@ -1266,6 +1266,51 @@ void MainWindow::reportStateLoadError(const QString& message, std::optional<s32>
|
||||
delete message_box;
|
||||
}
|
||||
|
||||
void MainWindow::reportStateSaveError(const QString& message, std::optional<s32> slot)
|
||||
{
|
||||
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||
if (!prompt_on_error)
|
||||
{
|
||||
SaveState_ReportSaveErrorOSD(message.toStdString(), slot);
|
||||
return;
|
||||
}
|
||||
|
||||
QString title;
|
||||
if (slot.has_value())
|
||||
title = tr("Failed to Save State To Slot %1").arg(*slot);
|
||||
else
|
||||
title = tr("Failed to Save State");
|
||||
|
||||
VMLock lock(pauseAndLockVM());
|
||||
|
||||
QCheckBox* do_not_show_again = new QCheckBox(tr("Do not show again"));
|
||||
|
||||
QPointer<QMessageBox> message_box = new QMessageBox(this);
|
||||
message_box->setWindowTitle(title);
|
||||
message_box->setText(message);
|
||||
message_box->setIcon(QMessageBox::Critical);
|
||||
message_box->addButton(QMessageBox::Ok);
|
||||
message_box->setDefaultButton(QMessageBox::Ok);
|
||||
message_box->setCheckBox(do_not_show_again);
|
||||
|
||||
message_box->exec();
|
||||
if (message_box.isNull())
|
||||
return;
|
||||
|
||||
if (do_not_show_again->isChecked())
|
||||
{
|
||||
Host::SetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", false);
|
||||
Host::CommitBaseSettingChanges();
|
||||
if (m_settings_window)
|
||||
{
|
||||
InterfaceSettingsWidget* interface_settings = m_settings_window->getInterfaceSettingsWidget();
|
||||
interface_settings->updatePromptOnStateLoadSaveFailureCheckbox(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
delete message_box;
|
||||
}
|
||||
|
||||
void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||
{
|
||||
func();
|
||||
|
||||
@ -121,6 +121,7 @@ public Q_SLOTS:
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
void onStatusMessage(const QString& message);
|
||||
void reportStateLoadError(const QString& message, std::optional<s32> slot, bool backup);
|
||||
void reportStateSaveError(const QString& message, std::optional<s32> slot);
|
||||
|
||||
void runOnUIThread(const std::function<void()>& func);
|
||||
void requestReset();
|
||||
|
||||
@ -337,11 +337,11 @@ void EmuThread::saveState(const QString& filename)
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
if (!VMManager::SaveState(filename.toUtf8().constData()))
|
||||
{
|
||||
// this one is usually the result of a user-chosen path, so we can display a message box safely here
|
||||
Console.Error("Failed to save state");
|
||||
}
|
||||
VMManager::SaveState(filename.toUtf8().constData(), true, false, [](const std::string& error) {
|
||||
QtHost::RunOnUIThread([message = QString::fromStdString(error)]() {
|
||||
g_main_window->reportStateSaveError(message, std::nullopt);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void EmuThread::saveStateToSlot(qint32 slot)
|
||||
@ -355,7 +355,11 @@ void EmuThread::saveStateToSlot(qint32 slot)
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
VMManager::SaveStateToSlot(slot);
|
||||
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||
QtHost::RunOnUIThread([message = QString::fromStdString(error), slot]() {
|
||||
g_main_window->reportStateSaveError(message, slot);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void EmuThread::run()
|
||||
|
||||
@ -112,7 +112,9 @@ static void HotkeyLoadStateSlot(s32 slot)
|
||||
|
||||
static void HotkeySaveStateSlot(s32 slot)
|
||||
{
|
||||
VMManager::SaveStateToSlot(slot);
|
||||
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||
FullscreenUI::ReportStateSaveError(error, slot);
|
||||
});
|
||||
}
|
||||
|
||||
static bool CanPause()
|
||||
|
||||
@ -671,6 +671,7 @@ namespace FullscreenUI
|
||||
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
|
||||
static void DrawResumeStateSelector();
|
||||
static void DoLoadState(std::string path, std::optional<s32> slot, bool backup);
|
||||
static void DoSaveState(s32 slot);
|
||||
|
||||
static std::vector<SaveStateListEntry> s_save_state_selector_slots;
|
||||
static std::string s_save_state_selector_game_path;
|
||||
@ -7349,7 +7350,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
||||
if (is_loading)
|
||||
DoLoadState(std::move(entry.path), entry.slot, false);
|
||||
else
|
||||
Host::RunOnCPUThread([slot = entry.slot]() { VMManager::SaveStateToSlot(slot); });
|
||||
DoSaveState(entry.slot);
|
||||
|
||||
CloseSaveStateSelector();
|
||||
ReturnToMainWindow();
|
||||
@ -7487,7 +7488,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
||||
if (is_loading)
|
||||
DoLoadState(entry.path, entry.slot, false);
|
||||
else
|
||||
Host::RunOnCPUThread([slot = entry.slot]() { VMManager::SaveStateToSlot(slot); });
|
||||
DoSaveState(entry.slot);
|
||||
|
||||
CloseSaveStateSelector();
|
||||
ReturnToMainWindow();
|
||||
@ -7667,6 +7668,15 @@ void FullscreenUI::DoLoadState(std::string path, std::optional<s32> slot, bool b
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::DoSaveState(s32 slot)
|
||||
{
|
||||
Host::RunOnCPUThread([slot]() {
|
||||
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||
ReportStateSaveError(error, slot);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::PopulateGameListEntryList()
|
||||
{
|
||||
const int sort = Host::GetBaseIntSettingValue("UI", "FullscreenUIGameSort", 0);
|
||||
@ -9168,9 +9178,9 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
|
||||
EndMenuButtons();
|
||||
}
|
||||
|
||||
void FullscreenUI::ReportStateLoadError(std::string message, std::optional<s32> slot, bool backup)
|
||||
void FullscreenUI::ReportStateLoadError(const std::string& message, std::optional<s32> slot, bool backup)
|
||||
{
|
||||
MTGS::RunOnGSThread([message = std::move(message), slot, backup]() {
|
||||
MTGS::RunOnGSThread([message, slot, backup]() {
|
||||
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||
if (!prompt_on_error || !ImGuiManager::InitializeFullscreenUI())
|
||||
{
|
||||
@ -9206,6 +9216,37 @@ void FullscreenUI::ReportStateLoadError(std::string message, std::optional<s32>
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::ReportStateSaveError(const std::string& message, std::optional<s32> slot)
|
||||
{
|
||||
MTGS::RunOnGSThread([message, slot]() {
|
||||
const bool prompt_on_error = Host::GetBaseBoolSettingValue("UI", "PromptOnStateLoadSaveFailure", true);
|
||||
if (!prompt_on_error || !ImGuiManager::InitializeFullscreenUI())
|
||||
{
|
||||
SaveState_ReportSaveErrorOSD(message, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string title;
|
||||
if (slot.has_value())
|
||||
title = fmt::format(FSUI_FSTR("Failed to Save State To Slot {}"), *slot);
|
||||
else
|
||||
title = FSUI_STR("Failed to Save State");
|
||||
|
||||
ImGuiFullscreen::InfoMessageDialogCallback callback;
|
||||
if (VMManager::GetState() == VMState::Running)
|
||||
{
|
||||
Host::RunOnCPUThread([]() { VMManager::SetPaused(true); });
|
||||
callback = []() {
|
||||
Host::RunOnCPUThread([]() { VMManager::SetPaused(false); });
|
||||
};
|
||||
}
|
||||
|
||||
ImGuiFullscreen::OpenInfoMessageDialog(
|
||||
fmt::format("{} {}", ICON_FA_TRIANGLE_EXCLAMATION, title),
|
||||
std::move(message), std::move(callback));
|
||||
});
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Translation String Area
|
||||
// To avoid having to type T_RANSLATE("FullscreenUI", ...) everywhere, we use the shorter macros at the top
|
||||
|
||||
@ -27,7 +27,8 @@ namespace FullscreenUI
|
||||
void OpenPauseMenu();
|
||||
bool OpenAchievementsWindow();
|
||||
bool OpenLeaderboardsWindow();
|
||||
void ReportStateLoadError(std::string message, std::optional<s32> slot, bool backup);
|
||||
void ReportStateLoadError(const std::string& message, std::optional<s32> slot, bool backup);
|
||||
void ReportStateSaveError(const std::string& message, std::optional<s32> slot);
|
||||
|
||||
// NOTE: Only call from GS thread.
|
||||
bool IsAchievementsWindowOpen();
|
||||
|
||||
@ -1400,7 +1400,9 @@ void SaveStateSelectorUI::LoadCurrentBackupSlot()
|
||||
void SaveStateSelectorUI::SaveCurrentSlot()
|
||||
{
|
||||
Host::RunOnCPUThread([slot = GetCurrentSlot()]() {
|
||||
VMManager::SaveStateToSlot(slot);
|
||||
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||
FullscreenUI::ReportStateSaveError(error, slot);
|
||||
});
|
||||
});
|
||||
Close();
|
||||
}
|
||||
|
||||
@ -646,7 +646,11 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size)) [[unlikely]]
|
||||
goto error;
|
||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] { VMManager::SaveStateToSlot(slot); });
|
||||
Host::RunOnCPUThread([slot = FromSpan<u8>(buf, buf_cnt)] {
|
||||
VMManager::SaveStateToSlot(slot, true, [slot](const std::string& error) {
|
||||
SaveState_ReportSaveErrorOSD(error, slot);
|
||||
});
|
||||
});
|
||||
buf_cnt += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -56,8 +56,9 @@ bool InputRecording::create(const std::string& fileName, const bool fromSaveStat
|
||||
m_initial_load_complete = true;
|
||||
m_watching_for_rerecords = true;
|
||||
setStartingFrame(g_FrameCount);
|
||||
// TODO - error handling
|
||||
VMManager::SaveState(savestatePath.c_str());
|
||||
VMManager::SaveState(savestatePath.c_str(), true, false, [](const std::string& error) {
|
||||
SaveState_ReportSaveErrorOSD(error, std::nullopt);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -395,8 +396,7 @@ void InputRecording::InformGSThread()
|
||||
TinyString frame_data_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Frame: {}/{} ({})"), g_InputRecording.getFrameCounter(), g_InputRecording.getData().getTotalFrames(), g_InputRecording.getFrameCounterStateless());
|
||||
TinyString undo_count_message = TinyString::from_format(TRANSLATE_FS("InputRecording", "Undo Count: {}"), g_InputRecording.getData().getUndoCount());
|
||||
|
||||
MTGS::RunOnGSThread([recording_active_message, frame_data_message, undo_count_message](bool is_recording = g_InputRecording.getControls().isRecording())
|
||||
{
|
||||
MTGS::RunOnGSThread([recording_active_message, frame_data_message, undo_count_message](bool is_recording = g_InputRecording.getControls().isRecording()) {
|
||||
g_InputRecordingData.is_recording = is_recording;
|
||||
g_InputRecordingData.recording_active_message = recording_active_message;
|
||||
g_InputRecordingData.frame_data_message = frame_data_message;
|
||||
|
||||
@ -1253,3 +1253,16 @@ void SaveState_ReportLoadErrorOSD(const std::string& message, std::optional<s32>
|
||||
Host::AddIconOSDMessage("LoadState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
full_message, Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
void SaveState_ReportSaveErrorOSD(const std::string& message, std::optional<s32> slot)
|
||||
{
|
||||
std::string full_message;
|
||||
if (slot.has_value())
|
||||
full_message = fmt::format(
|
||||
TRANSLATE_FS("SaveState", "Failed to save state to slot {}: {}"), *slot, message);
|
||||
else
|
||||
full_message = fmt::format(TRANSLATE_FS("SaveState", "Failed to save state: {}"), message);
|
||||
|
||||
Host::AddIconOSDMessage("SaveState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
full_message, Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
@ -356,3 +356,4 @@ public:
|
||||
};
|
||||
|
||||
void SaveState_ReportLoadErrorOSD(const std::string& message, std::optional<s32> slot, bool backup);
|
||||
void SaveState_ReportSaveErrorOSD(const std::string& message, std::optional<s32> slot);
|
||||
|
||||
@ -115,13 +115,13 @@ namespace VMManager
|
||||
|
||||
static std::string GetCurrentSaveStateFileName(s32 slot, bool backup = false);
|
||||
static bool DoLoadState(const char* filename, Error* error = nullptr);
|
||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
||||
static void DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback);
|
||||
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
||||
s32 slot_for_message);
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename,
|
||||
s32 slot_for_message, std::function<void(const std::string&)> error_callback);
|
||||
static void ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
||||
s32 slot_for_message);
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename,
|
||||
s32 slot_for_message, std::function<void(const std::string&)> error_callback);
|
||||
|
||||
static void LoadSettings();
|
||||
static void LoadCoreSettings(SettingsInterface& si);
|
||||
@ -1617,8 +1617,13 @@ 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, false))
|
||||
Console.Error("Failed to save resume state");
|
||||
if (!resume_file_name.empty())
|
||||
{
|
||||
DoSaveState(resume_file_name.c_str(), -1, true, false, [](const std::string& error) {
|
||||
Host::AddIconOSDMessage("SaveResumeState", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save resume state: {}"), error), Host::OSD_QUICK_DURATION);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// end input recording before clearing state
|
||||
@ -1829,7 +1834,7 @@ bool VMManager::DoLoadState(const char* filename, Error* error)
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
Error::SetString(error, TRANSLATE_STR("VMManager", "Cannot load save state while replaying GS dump."));
|
||||
Error::SetString(error, TRANSLATE_STR("VMManager", "Cannot load state while replaying GS dump."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1849,21 +1854,21 @@ bool VMManager::DoLoadState(const char* filename, Error* error)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state)
|
||||
void VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback)
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
return false;
|
||||
{
|
||||
error_callback(TRANSLATE_STR("VMManager", "Cannot save state while replaying GS dump."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string osd_key(fmt::format("SaveStateSlot{}", slot_for_message));
|
||||
Error error;
|
||||
|
||||
std::unique_ptr<ArchiveEntryList> elist = SaveState_DownloadState(&error);
|
||||
if (!elist)
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state: {}."), error.GetDescription()),
|
||||
Host::OSD_ERROR_DURATION);
|
||||
return false;
|
||||
error_callback(fmt::format(
|
||||
TRANSLATE_FS("VMManager", "Failed to save state: {}."), error.GetDescription()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot = SaveState_SaveScreenshot();
|
||||
@ -1874,10 +1879,10 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||
Console.WriteLn(fmt::format("Creating save state backup {}...", backup_filename));
|
||||
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
||||
{
|
||||
Host::AddIconOSDMessage(osd_key, ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(
|
||||
TRANSLATE_FS("VMManager", "Failed to back up old save state {}."), Path::GetFileName(filename)),
|
||||
Host::OSD_ERROR_DURATION);
|
||||
error_callback(fmt::format(
|
||||
TRANSLATE_FS("VMManager", "Cannot back up old save state '{}'."),
|
||||
Path::GetFileName(filename)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1886,21 +1891,22 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||
// lock order here is important; the thread could exit before we resume here.
|
||||
std::unique_lock lock(s_save_state_threads_mutex);
|
||||
s_save_state_threads.emplace_back(&VMManager::ZipSaveStateOnThread, std::move(elist), std::move(screenshot),
|
||||
std::move(osd_key), std::string(filename), slot_for_message);
|
||||
std::string(filename), slot_for_message, std::move(error_callback));
|
||||
}
|
||||
else
|
||||
{
|
||||
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename, slot_for_message);
|
||||
ZipSaveState(
|
||||
std::move(elist), std::move(screenshot), filename, slot_for_message, std::move(error_callback));
|
||||
}
|
||||
|
||||
Host::OnSaveStateSaved(filename);
|
||||
MemcardBusy::CheckSaveStateDependency();
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
||||
s32 slot_for_message)
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, const char* filename,
|
||||
s32 slot_for_message, std::function<void(const std::string&)> error_callback)
|
||||
{
|
||||
Common::Timer timer;
|
||||
|
||||
@ -1908,26 +1914,26 @@ void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||
{
|
||||
if (slot_for_message >= 0 && VMManager::HasValidVM())
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_FLOPPY_DISK,
|
||||
Host::AddIconOSDMessage("SaveState", ICON_FA_FLOPPY_DISK,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "State saved to slot {}."), slot_for_message),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {}."), slot_for_message,
|
||||
Host::OSD_ERROR_DURATION));
|
||||
error_callback(fmt::format(
|
||||
TRANSLATE_FS("VMManager", "Failed to save state to slot {}."), slot_for_message));
|
||||
}
|
||||
|
||||
DevCon.WriteLn("Zipping save state to '%s' took %.2f ms", filename, timer.GetTimeMilliseconds());
|
||||
}
|
||||
|
||||
void VMManager::ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
||||
s32 slot_for_message)
|
||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename,
|
||||
s32 slot_for_message, std::function<void(const std::string&)> error_callback)
|
||||
{
|
||||
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename.c_str(), slot_for_message);
|
||||
ZipSaveState(
|
||||
std::move(elist), std::move(screenshot), filename.c_str(), slot_for_message, std::move(error_callback));
|
||||
|
||||
// remove ourselves from the thread list. if we're joining, we might not be in there.
|
||||
const auto this_id = std::this_thread::get_id();
|
||||
@ -2046,37 +2052,45 @@ bool VMManager::LoadStateFromSlot(s32 slot, bool backup, Error* error)
|
||||
return DoLoadState(filename.c_str(), error);
|
||||
}
|
||||
|
||||
bool VMManager::SaveState(const char* filename, bool zip_on_thread, bool backup_old_state)
|
||||
void VMManager::SaveState(
|
||||
const char* filename, bool zip_on_thread, bool backup_old_state, std::function<void(const std::string&)> error_callback)
|
||||
{
|
||||
if (MemcardBusy::IsBusy())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state (Memory card is busy)")),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
return false;
|
||||
error_callback(TRANSLATE_STR("VMManager", "Failed to save state (memory card is busy)."));
|
||||
return;
|
||||
}
|
||||
|
||||
return DoSaveState(filename, -1, zip_on_thread, backup_old_state);
|
||||
DoSaveState(filename, -1, zip_on_thread, backup_old_state, std::move(error_callback));
|
||||
}
|
||||
|
||||
bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
|
||||
void VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread, std::function<void(const std::string&)> error_callback)
|
||||
{
|
||||
const std::string filename(GetCurrentSaveStateFileName(slot));
|
||||
if (filename.empty())
|
||||
return false;
|
||||
{
|
||||
error_callback(TRANSLATE_STR("VMManager", "Failed to generate filename for save state."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MemcardBusy::IsBusy())
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {} (Memory card is busy)"), slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
return false;
|
||||
error_callback(fmt::format(
|
||||
TRANSLATE_FS("VMManager", "Failed to save state to slot {} (Memory card is busy)"), slot));
|
||||
return;
|
||||
}
|
||||
|
||||
// if it takes more than a minute.. well.. wtf.
|
||||
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_FLOPPY_DISK,
|
||||
fmt::format(TRANSLATE_FS("VMManager", "Saving state to slot {}..."), slot), 60.0f);
|
||||
return DoSaveState(filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate);
|
||||
|
||||
auto callback = [error_callback = std::move(error_callback), slot](const std::string& error) {
|
||||
Host::RemoveKeyedOSDMessage(fmt::format("SaveStateSlot{}", slot));
|
||||
error_callback(error);
|
||||
};
|
||||
|
||||
return DoSaveState(
|
||||
filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate, std::move(callback));
|
||||
}
|
||||
|
||||
LimiterModeType VMManager::GetLimiterMode()
|
||||
|
||||
@ -165,10 +165,11 @@ namespace VMManager
|
||||
bool LoadStateFromSlot(s32 slot, bool backup = false, Error* error = nullptr);
|
||||
|
||||
/// Saves state to the specified filename.
|
||||
bool SaveState(const char* filename, bool zip_on_thread = true, bool backup_old_state = false);
|
||||
void SaveState(const char* filename, bool zip_on_thread, bool backup_old_state,
|
||||
std::function<void(const std::string&)> error_callback);
|
||||
|
||||
/// Saves state to the specified slot.
|
||||
bool SaveStateToSlot(s32 slot, bool zip_on_thread = true);
|
||||
void SaveStateToSlot(s32 slot, bool zip_on_thread, std::function<void(const std::string&)> error_callback);
|
||||
|
||||
/// Waits until all compressing save states have finished saving to disk.
|
||||
void WaitForSaveStateFlush();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user