diff --git a/Core/Debugger/WebSocket/GameSubscriber.cpp b/Core/Debugger/WebSocket/GameSubscriber.cpp index 4c1c223a7d..10739b20b9 100644 --- a/Core/Debugger/WebSocket/GameSubscriber.cpp +++ b/Core/Debugger/WebSocket/GameSubscriber.cpp @@ -136,24 +136,30 @@ void WebSocketGameStatus(DebuggerRequest &req) { // Parameters: // - path: string, path to the .ppst file. // -// Response (same event name) with no extra data, once queued. +// Response (same event name) with no extra data, once queued, or an error if the network or +// achievements hardcore mode refuses it. void WebSocketGameStateLoad(DebuggerRequest &req) { std::string path; if (!req.ParamString("path", &path)) return; bool running = false; + bool queued = false; Core_RunOnCPUThread([&] { running = PSP_GetBootState() == BootState::Complete; + if (running) { + queued = SaveState::Load(Path(path), -1, [](SaveState::Status status, std::string_view message, std::string_view) { + if (status == SaveState::Status::FAILURE) { + ERROR_LOG(Log::System, "game.state.load: %.*s", STR_VIEW(message)); + } + }); + } }); if (!running) return req.Fail("Game not running"); - - SaveState::Load(Path(path), -1, [](SaveState::Status status, std::string_view message, std::string_view) { - if (status == SaveState::Status::FAILURE) { - ERROR_LOG(Log::System, "game.state.load: %.*s", STR_VIEW(message)); - } - }); + if (!queued) { + return req.Fail("Could not queue savestate load"); + } req.Respond(); } @@ -164,24 +170,30 @@ void WebSocketGameStateLoad(DebuggerRequest &req) { // Parameters: // - path: string, path to write the .ppst file to. // -// Response (same event name) with no extra data, once queued. +// Response (same event name) with no extra data, once queued, or an error if the network or +// achievements hardcore mode refuses it. void WebSocketGameStateSave(DebuggerRequest &req) { std::string path; if (!req.ParamString("path", &path)) return; bool running = false; + bool queued = false; Core_RunOnCPUThread([&] { running = PSP_GetBootState() == BootState::Complete; + if (running) { + queued = SaveState::Save(Path(path), -1, [](SaveState::Status status, std::string_view message, std::string_view) { + if (status == SaveState::Status::FAILURE) { + ERROR_LOG(Log::System, "game.state.save: %.*s", STR_VIEW(message)); + } + }); + } }); if (!running) return req.Fail("Game not running"); - - SaveState::Save(Path(path), -1, [](SaveState::Status status, std::string_view message, std::string_view) { - if (status == SaveState::Status::FAILURE) { - ERROR_LOG(Log::System, "game.state.save: %.*s", STR_VIEW(message)); - } - }); + if (!queued) { + return req.Fail("Could not queue savestate save"); + } req.Respond(); } diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 6be636c0e7..630d231119 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -201,17 +201,17 @@ int g_screenshotFailures; pspFileSystem.DoState(p); } - void Enqueue(const SaveState::Operation &op) { + bool Enqueue(const SaveState::Operation &op) { // These two both refuse the operation, and both say so - dropping it silently just // looks like the hotkey didn't work. Callers that ask the same questions themselves // return before getting here, so nothing shows a message twice. if (NetworkWarnUserIfOnlineAndCantSavestate()) { - return; + return false; } // Hardcore mode bans loading savestates outright, and saving too unless the user opted // back into that. if (Achievements::WarnUserIfHardcoreModeActive(op.type == OperationType::Save)) { - return; + return false; } std::lock_guard guard(mutex); @@ -220,28 +220,29 @@ int g_screenshotFailures; // Don't actually run it until next frame. // It's possible there might be a duplicate but it won't hurt us. needsProcess = true; + return true; } - void Load(const Path &filename, int slot, Callback callback) { + bool Load(const Path &filename, int slot, Callback callback) { if (NetworkWarnUserIfOnlineAndCantSavestate()) { - return; + return false; } rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break(BreakReason::SavestateLoad, 0); - Enqueue(Operation(OperationType::Load, filename, slot, callback)); + return Enqueue(Operation(OperationType::Load, filename, slot, callback)); } - void Save(const Path &filename, int slot, Callback callback) { + bool Save(const Path &filename, int slot, Callback callback) { if (NetworkWarnUserIfOnlineAndCantSavestate()) { - return; + return false; } rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break(BreakReason::SavestateSave, 0); - Enqueue(Operation(OperationType::Save, filename, slot, callback)); + return Enqueue(Operation(OperationType::Save, filename, slot, callback)); } void Verify(Callback callback) { diff --git a/Core/SaveState.h b/Core/SaveState.h index 746c4c3f11..cfbda4ec1a 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -88,12 +88,12 @@ namespace SaveState { std::string GetTitle(const Path &filename); // Load the specified file into the current state (async.) - // Warning: callback will be called on a different thread. - void Load(const Path &filename, int slot, Callback callback = Callback()); + // Returns true if queued. The callback may run on a different thread. + bool Load(const Path &filename, int slot, Callback callback = Callback()); // Save the current state to the specified file (async.) - // Warning: callback will be called on a different thread. - void Save(const Path &filename, int slot, Callback callback = Callback()); + // Returns true if queued. The callback may run on a different thread. + bool Save(const Path &filename, int slot, Callback callback = Callback()); CChunkFileReader::Error SaveToRam(std::vector &state); CChunkFileReader::Error LoadFromRam(std::vector &state, std::string *errorString);