diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index a8300543d9..837ce22dea 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -414,7 +414,7 @@ int g_screenshotFailures; Path backup = GetSysDirectory(DIRECTORY_SAVESTATE) / LOAD_UNDO_NAME; std::string prefix(gamePrefix); - auto saveCallback = [prefix, fn, backup, slot, callback](Status status, std::string_view message) { + auto saveCallback = [prefix, fn, backup, slot, callback](Status status, std::string_view message, std::string_view metadata) { if (status != Status::FAILURE) { DeleteIfExists(backup); File::Rename(backup.WithExtraExtension(".tmp"), backup); @@ -438,7 +438,7 @@ int g_screenshotFailures; } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to load state. Error in the file system.")); + callback(Status::FAILURE, sy->T("Failed to load state. Error in the file system."), ""); } } } @@ -451,7 +451,7 @@ int g_screenshotFailures; if (g_Config.sStateLoadUndoGame != gamePrefix) { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Error: load undo state is from a different game")); + callback(Status::FAILURE, sy->T("Error: load undo state is from a different game"), ""); } return false; } @@ -463,7 +463,7 @@ int g_screenshotFailures; } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to load state for load undo. Error in the file system.")); + callback(Status::FAILURE, sy->T("Failed to load state for load undo. Error in the file system."), ""); } return false; } @@ -480,7 +480,7 @@ int g_screenshotFailures; Path shot = GenerateSaveSlotPath(gamePrefix, slot, SCREENSHOT_EXTENSION); std::string prefix(gamePrefix); - auto renameCallback = [fn, fnUndo, prefix, slot, callback](Status status, std::string_view message) { + auto renameCallback = [fn, fnUndo, prefix, slot, callback](Status status, std::string_view message, std::string_view metadata) { if (status != Status::FAILURE) { if (g_Config.bEnableStateUndo) { DeleteIfExists(fnUndo); @@ -494,7 +494,7 @@ int g_screenshotFailures; File::Rename(fn.WithExtraExtension(".tmp"), fn); } if (callback) { - callback(status, message); + callback(status, message, ""); } }; // Let's also create a screenshot. @@ -508,7 +508,7 @@ int g_screenshotFailures; } else { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); - callback(Status::FAILURE, sy->T("Failed to save state. Error in the file system.")); + callback(Status::FAILURE, sy->T("Failed to save state. Error in the file system."), ""); } } Rescan(gamePrefix); @@ -714,7 +714,7 @@ int g_screenshotFailures; return copy; } - bool HandleLoadFailure(bool wasRewinding) { + static bool HandleLoadFailure(bool wasRewinding, std::string *metadata) { if (wasRewinding) { WARN_LOG(Log::SaveState, "HandleLoadFailure - trying a rewind state."); // Okay, first, let's give the next rewind state a shot - maybe we can at least not reset entirely. @@ -722,7 +722,7 @@ int g_screenshotFailures; CChunkFileReader::Error result; do { std::string errorString; - result = rewindStates.Restore(&errorString); + result = rewindStates.Restore(&errorString, metadata); } while (result == CChunkFileReader::ERROR_BROKEN_STATE); if (result == CChunkFileReader::ERROR_NONE) { @@ -813,6 +813,7 @@ int g_screenshotFailures; CChunkFileReader::Error result; Status callbackResult; std::string callbackMessage; + std::string callbackMetadata; std::string title; auto sc = GetI18NCategory(I18NCat::SCREEN); @@ -849,7 +850,7 @@ int g_screenshotFailures; #endif g_lastSaveTime = time_now_d(); } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { - HandleLoadFailure(false); + HandleLoadFailure(false, &callbackMetadata); callbackMessage = std::string(i18nLoadFailure) + ": " + errorString; ERROR_LOG(Log::SaveState, "Load state failure: %s", errorString.c_str()); callbackResult = Status::FAILURE; @@ -909,7 +910,7 @@ int g_screenshotFailures; case OperationType::Rewind: INFO_LOG(Log::SaveState, "Rewinding to recent savestate snapshot"); - result = rewindStates.Restore(&errorString); + result = rewindStates.Restore(&errorString, &callbackMetadata); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Loaded State"); callbackResult = Status::SUCCESS; @@ -917,7 +918,7 @@ int g_screenshotFailures; Core_ResetException(); } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // Cripes. Good news is, we might have more. Let's try those too, better than a reset. - if (HandleLoadFailure(true)) { + if (HandleLoadFailure(true, &callbackMetadata)) { // Well, we did rewind, even if too much... callbackMessage = sc->T("Loaded State"); callbackResult = Status::SUCCESS; @@ -940,7 +941,7 @@ int g_screenshotFailures; } if (op.callback) { - op.callback(callbackResult, callbackMessage); + op.callback(callbackResult, callbackMessage, callbackMetadata); } } if (operations.size()) { diff --git a/Core/SaveState.h b/Core/SaveState.h index c8400bafe6..ba5ae44f0b 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -34,7 +34,7 @@ namespace SaveState { WARNING, SUCCESS, }; - typedef std::function Callback; + typedef std::function Callback; static const char * const SCREENSHOT_EXTENSION = "jpg"; diff --git a/Core/SaveStateRewind.cpp b/Core/SaveStateRewind.cpp index 414886d436..c61570bb40 100644 --- a/Core/SaveStateRewind.cpp +++ b/Core/SaveStateRewind.cpp @@ -1,4 +1,5 @@ #include "Common/Thread/ThreadUtil.h" +#include "Common/Data/Text/I18n.h" #include "Core/SaveState.h" #include "Core/SaveStateRewind.h" #include "Core/Core.h" @@ -42,7 +43,7 @@ CChunkFileReader::Error StateRingbuffer::Save() { return err; } -CChunkFileReader::Error StateRingbuffer::Restore(std::string *errorString) { +CChunkFileReader::Error StateRingbuffer::Restore(std::string *errorString, std::string *metadata) { std::lock_guard guard(lock_); // No valid states left. @@ -53,9 +54,12 @@ CChunkFileReader::Error StateRingbuffer::Restore(std::string *errorString) { if (states_[n].empty()) return CChunkFileReader::ERROR_BAD_FILE; + auto pa = GetI18NCategory(I18NCat::PAUSE); + static std::vector buffer; LockedDecompress(buffer, states_[n], bases_[baseMapping_[n]]); CChunkFileReader::Error error = LoadFromRam(buffer, errorString); + *metadata = pa->T("Rewind"); rewindLastTime_ = time_now_d(); return error; } diff --git a/Core/SaveStateRewind.h b/Core/SaveStateRewind.h index a20837ddd3..5c6cb3a83e 100644 --- a/Core/SaveStateRewind.h +++ b/Core/SaveStateRewind.h @@ -28,7 +28,7 @@ public: } CChunkFileReader::Error Save(); - CChunkFileReader::Error Restore(std::string *errorString); + CChunkFileReader::Error Restore(std::string *errorString, std::string *metadata); void ScheduleCompress(std::vector *result, const std::vector *state, const std::vector *base); void Compress(std::vector &result, const std::vector &state, const std::vector &base); void LockedDecompress(std::vector &result, const std::vector &compressed, const std::vector &base); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b294842044..67c25d9dac 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -74,7 +74,6 @@ using namespace std::placeholders; #include "Core/Screenshot.h" #include "UI/ImDebugger/ImDebugger.h" #include "Core/HLE/__sceAudio.h" -// #include "Core/HLE/proAdhoc.h" #include "Core/HW/Display.h" #include "UI/BackgroundAudio.h" @@ -533,12 +532,6 @@ void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) { lastImguiEnabled_ = false; } -static void AfterSaveStateAction(SaveState::Status status, std::string_view message) { - if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { - g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); - } -} - void EmuScreen::focusChanged(ScreenFocusChange focusChange) { Screen::focusChanged(focusChange); @@ -609,7 +602,7 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { if (newGamePath.GetFileExtension() == ".ppst") { // TODO: Should verify that it's for the correct game.... INFO_LOG(Log::Loader, "New game is a save state - just load it."); - SaveState::Load(newGamePath, -1, [](SaveState::Status status, std::string_view message) { + SaveState::Load(newGamePath, -1, [](SaveState::Status status, std::string_view message, std::string_view metadata) { Core_Resume(); System_Notify(SystemNotification::DISASSEMBLY); }); @@ -965,7 +958,7 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) { case VIRTKEY_REWIND: if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { if (SaveState::CanRewind()) { - SaveState::Rewind(&AfterSaveStateAction); + SaveState::Rewind(&ShowMessageAfterSaveStateAction); } else { g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("norewind", "No rewind save states available"), 2.0); } @@ -1058,12 +1051,12 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) { case VIRTKEY_SAVE_STATE: if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { - SaveState::SaveSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, &AfterSaveStateAction); + SaveState::SaveSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, &ShowMessageAfterSaveStateAction); } break; case VIRTKEY_LOAD_STATE: if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate() && !bootPending_) { - SaveState::LoadSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, &AfterSaveStateAction); + SaveState::LoadSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, &ShowMessageAfterSaveStateAction); } break; case VIRTKEY_PREVIOUS_SLOT: @@ -2053,8 +2046,8 @@ void EmuScreen::AutoLoadSaveState() { } if (g_Config.iAutoLoadSaveState && autoSlot != -1) { - SaveState::LoadSlot(gamePrefix, autoSlot, [this, autoSlot](SaveState::Status status, std::string_view message) { - AfterSaveStateAction(status, message); + SaveState::LoadSlot(gamePrefix, autoSlot, [this, autoSlot](SaveState::Status status, std::string_view message, std::string_view metadata) { + ShowMessageAfterSaveStateAction(status, message, metadata); auto sy = GetI18NCategory(I18NCat::SYSTEM); if (status == SaveState::Status::FAILURE) { autoLoadFailed_ = true; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 913068a782..ab3b410d3d 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -133,6 +133,7 @@ #include "UI/OnScreenDisplay.h" #include "UI/RemoteISOScreen.h" #include "UI/Theme.h" +#include "UI/PauseScreen.h" #include "UI/UIAtlas.h" #if PPSSPP_PLATFORM(UWP) @@ -693,12 +694,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch g_BackgroundAudio.SFX().Init(); if (!boot_filename.empty() && stateToLoad.Valid()) { - SaveState::Load(stateToLoad, -1, [](SaveState::Status status, std::string_view message) { - if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { - g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, - message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); - } - }); + SaveState::Load(stateToLoad, -1, &ShowMessageAfterSaveStateAction); } if (g_Config.bAchievementsEnable) { diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 12b9d00a02..802145d6c2 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -76,10 +76,10 @@ void copyDeepLinkForPath(std::string_view filePath); #endif -static void AfterSaveStateAction(SaveState::Status status, std::string_view message) { - if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { +void ShowMessageAfterSaveStateAction(SaveState::Status status, std::string_view message, std::string_view metadata) { + if (!message.empty()) { g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, - message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); + message, metadata, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); } } @@ -153,7 +153,7 @@ private: void ScreenshotViewScreen::OnSaveState(UI::EventParams &e) { if (!NetworkWarnUserIfOnlineAndCantSavestate()) { g_Config.iCurrentStateSlot = slot_; - SaveState::SaveSlot(saveStatePrefix_, slot_, &AfterSaveStateAction); + SaveState::SaveSlot(saveStatePrefix_, slot_, &ShowMessageAfterSaveStateAction); TriggerFinish(DR_OK); //OK will close the pause screen as well } } @@ -161,7 +161,7 @@ void ScreenshotViewScreen::OnSaveState(UI::EventParams &e) { void ScreenshotViewScreen::OnLoadState(UI::EventParams &e) { if (!NetworkWarnUserIfOnlineAndCantSavestate()) { g_Config.iCurrentStateSlot = slot_; - SaveState::LoadSlot(saveStatePrefix_, slot_, &AfterSaveStateAction); + SaveState::LoadSlot(saveStatePrefix_, slot_, &ShowMessageAfterSaveStateAction); TriggerFinish(DR_OK); } } @@ -303,7 +303,7 @@ void SaveSlotView::Draw(UIContext &dc) { void SaveSlotView::OnLoadState(UI::EventParams &e) { if (!NetworkWarnUserIfOnlineAndCantSavestate()) { g_Config.iCurrentStateSlot = slot_; - SaveState::LoadSlot(saveStatePrefix_, slot_, &AfterSaveStateAction); + SaveState::LoadSlot(saveStatePrefix_, slot_, &ShowMessageAfterSaveStateAction); UI::EventParams e2{}; e2.v = this; OnStateLoaded.Trigger(e2); @@ -313,7 +313,7 @@ void SaveSlotView::OnLoadState(UI::EventParams &e) { void SaveSlotView::OnSaveState(UI::EventParams &e) { if (!NetworkWarnUserIfOnlineAndCantSavestate()) { g_Config.iCurrentStateSlot = slot_; - SaveState::SaveSlot(saveStatePrefix_, slot_, &AfterSaveStateAction); + SaveState::SaveSlot(saveStatePrefix_, slot_, &ShowMessageAfterSaveStateAction); UI::EventParams e2{}; e2.v = this; OnStateSaved.Trigger(e2); @@ -426,7 +426,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems, UI::Choice *loadUndoButton = buttonRow->Add(new Choice(pa->T("Undo last load"), ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT))); loadUndoButton->SetEnabled(SaveState::HasUndoLoad(saveStatePrefix_)); loadUndoButton->OnClick.Add([this](UI::EventParams &e) { - SaveState::UndoLoad(saveStatePrefix_, &AfterSaveStateAction); + SaveState::UndoLoad(saveStatePrefix_, &ShowMessageAfterSaveStateAction); TriggerFinish(DR_CANCEL); }); } @@ -435,7 +435,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems, UI::Choice *rewindButton = buttonRow->Add(new Choice(pa->T("Rewind"), ImageID("I_REWIND"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT))); rewindButton->SetEnabled(SaveState::CanRewind()); rewindButton->OnClick.Add([this](UI::EventParams &e) { - SaveState::Rewind(&AfterSaveStateAction); + SaveState::Rewind(&ShowMessageAfterSaveStateAction); TriggerFinish(DR_CANCEL); }); } diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 5cf57ac5f3..e7115c4458 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -23,6 +23,7 @@ #include "Common/File/Path.h" #include "Common/UI/UIScreen.h" #include "Common/UI/ViewGroup.h" +#include "Core/SaveState.h" #include "Core/ControlMapper.h" #include "UI/BaseScreens.h" #include "UI/Screen.h" @@ -85,3 +86,4 @@ private: }; std::string GetConfirmExitMessage(); +void ShowMessageAfterSaveStateAction(SaveState::Status status, std::string_view message, std::string_view metadata); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 0c684163d0..89831211ca 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -45,6 +45,7 @@ #include "Core/SaveState.h" #include "Core/Core.h" #include "Core/RetroAchievements.h" +#include "UI/PauseScreen.h" #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION #include "ext/rcheevos/include/rc_client_raintegration.h" @@ -394,10 +395,9 @@ namespace MainWindow { }); } - static void SaveStateActionFinished(SaveState::Status status, std::string_view message) { - if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) { - g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0); - } + static void SaveStateActionFinished(SaveState::Status status, std::string_view message, std::string_view metadata) { + // Reuse the message from the pause screen. + ShowMessageAfterSaveStateAction(status, message, metadata); PostMessage(MainWindow::GetHWND(), WM_USER_SAVESTATE_FINISH, 0, 0); }