SaveState: Report failed writes, and call back on network refusals

- A failed final flush (a full disk) or a failed rename into place was
  reported as "Saved State". A failed load undo rename still pointed load
  undo at the current game, while the file was another game's state.
- Refusing a save or load for being online didn't call the callback,
  unlike every other refusal.
- A rewind dropped after its decode started stayed active, and stopped
  rewind snapshots until the next clear.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-19 20:18:46 +02:00
1 parent f45f4d5c85
commit 3cc61d3f8e
5 files changed
+33 -4

No files matched your search

+14 -2
View File
@@ -414,6 +414,7 @@ int g_screenshotFailures;
static bool QueueLoad(const Operation &op) {
if (NetworkWarnUserIfOnlineAndCantSavestate()) {
CallbackRefused(op.callback);
return false;
}
@@ -425,6 +426,7 @@ int g_screenshotFailures;
static bool QueueSave(const Operation &op) {
if (NetworkWarnUserIfOnlineAndCantSavestate()) {
CallbackRefused(op.callback);
return false;
}
if (AttachToPendingSave(op.path, op.callback)) {
@@ -646,6 +648,7 @@ int g_screenshotFailures;
bool UndoLoad(std::string_view gamePrefix, Callback callback) {
if (NetworkWarnUserIfOnlineAndCantSavestate()) {
CallbackRefused(callback);
return false;
}
@@ -1159,7 +1162,10 @@ int g_screenshotFailures;
} else {
DeleteIfExists(job.path);
}
File::Rename(job.writePath, job.path);
if (!File::Rename(job.writePath, job.path)) {
ERROR_LOG(Log::SaveState, "Failed to move '%s' into place", job.writePath.c_str());
result = CChunkFileReader::ERROR_BAD_FILE;
}
}
PostCompletion([job, result](bool callCallbacks) {
FinishSave(job, result, callCallbacks);
@@ -1193,7 +1199,10 @@ int g_screenshotFailures;
g_saveSnapshots--;
if (result == CChunkFileReader::ERROR_NONE) {
DeleteIfExists(backup);
File::Rename(temp, backup);
if (!File::Rename(temp, backup)) {
// The undo would load whatever was there before, maybe another game's state.
result = CChunkFileReader::ERROR_BAD_FILE;
}
}
// Not a callback, so it runs at shutdown too.
PostCompletion([result, gamePrefix](bool) {
@@ -1404,6 +1413,9 @@ int g_screenshotFailures;
needsProcess = false;
lock.unlock();
for (const Operation &op : operations) {
if (op.type == OperationType::Rewind && op.started) {
rewindStates.CancelRestore();
}
RefuseOperation(op);
}
return;