Loading a state from the pause menu closed it right away, and the game
ran a few frames from where it was (seen and heard) before the state
was applied. Now savestate operations run while the game is paused under
the menu, and the menu closes once the load (or rewind, or load undo) is
done. Rewind snapshots aren't taken while paused.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- 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>
libretro declared its own, which no longer matched once SaveStart got a
member, so serializing read an uninitialized byte. It's in SaveState.h
now.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The boot spinner, in the same corner without the background, while a
save, load or rewind is queued or in progress. Only after a quarter of a
second, so it doesn't flash up on every quick save; on desktop that's
rarely reached, but slow devices get some feedback.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Saving and loading stalled the emu thread for 30-75 ms, long enough to
glitch audio. Now only the snapshot and the apply run there; compression
and file I/O run on a savestate worker thread, in order.
- Save: snapshot in Process(), then compress, write and (for a slot) move
the old state to its undo name on the worker. The callback runs once the
file is written. Saving again to a path with a save pending is a repeat
key press, and gets that save's result without a message.
- Load: read and decompress on the worker while the game runs, then apply.
A slot load keeps the state it replaces for load undo at that point,
rather than saving it in full before starting.
- Rewind: compression and decoding are worker jobs, and the deltas get
zstd level 1 on top, which makes them about a third of the size.
- At most two save snapshots are in memory at once, and buffers are freed
when their operation is done.
- Shutdown waits for pending writes, and drops callbacks as before.
On desktop, a save now costs the emu thread 2-3 ms, a load or rewind
12-15 ms.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rewind:
- first_ never wrapped, so after about 40 snapshots rewinding past the
oldest state jumped back to the newest ones. Track a count instead.
- States whose base had been replaced stayed in the ring, and each one
failed a rewind with an empty error. Drop them when the base goes.
- Rewinding after pausing for longer than the snapshot interval restored a
snapshot taken just before the rewind ran.
- Rewind snapshots (and verification) counted as saves for IsStale().
Slots:
- Loading an empty slot replaced the load undo backup before failing.
- A refused save (hardcore mode) rotated the slot's screenshots first.
- Refused or dropped operations never called their callback, so auto-load
didn't notice it had failed.
- The slot listing went stale after a save until something rescanned.
Also: Verify always failed (its write pass never set the buffer start),
and corrupt or truncated files were reported as being from an older
version.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SaveState::Load and Save silently drop the operation when the network or
achievements hardcore mode forbids it, but the debugger still answered as if
it had been queued. Return whether it was, and check the boot state in the
same CPU-thread call.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Deleting a savestate from the savedata screen goes through GameInfo::Delete,
not SaveState::DeleteSlot, and it only knew about the .jpg - so the slot's
.name.txt was left behind with nothing to belong to.
Rather than teach the UI the naming scheme a third time, SaveState now answers
what sits beside a state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
If you load a save state from before you created savedata (or from a
different path of savedata), some games will refuse to save. This shows a
warning since it can be a confusing situation.
We could potentially add an undo for loading state, to give an option for
getting back after this warning.
Using save states instead of in game saves causes bugs in games, and
preserves bugs from bad settings and old PPSSPP versions.
This tells users when they might be affected.