You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With the core engine snapshotting framework implemented in PR #5637 (Add versioned game state snapshots), the underlying simulation can now be serialized and restored at any tick boundary with zero turn re-simulation delays.
As noted in #5637, that PR provides the engine and worker APIs (WorkerClient.snapshot(), new WorkerClient(..., snapshotToRestore)) with "No UI".
This issue tracks the player-facing UI, platform save management, and runtime snapshot persistence to bring seamless singleplayer save and resume to users.
Resume Saved Match Card: When an in-progress solo save exists, displays a prominent resume card displaying map name and elapsed game time formatted as mm:ss (e.g. Resume Asia (03:45)).
Instantaneous $O(1)$ Load: Clicking "Resume" decompresses the gzip snapshot and passes the raw buffer into WorkerClient(startInfo, clientID, resumeSnapshot). The engine rehydrates in ~150 ms without any turn-replay catchup or battery/CPU drain.
Discard Action: Dedicated discard button with in-game confirmation modal (showInGameConfirm) to prevent accidental deletion.
2. Platform & Account Save Scoping (src/client/SinglePlayerSaveManager.ts)
Steam Integration: Isolates saves per 64-bit Steam ID (openfront_solo_save:steam:<steamId>:v1) via steamSDK.getSteamIdSync(), ensuring multiple Steam accounts on the same computer do not overwrite each other's games.
Web & CrazyGames Scoping: Keyed by persistent user identity.
Compression: Saves are compressed with gzip (CompressionStream / pako) to keep localStorage footprint light (~1.2 MB).
Legacy Migration: Automatically migrates any legacy un-scoped save keys on first boot.
Lifecycle Cleanup: Automatically clears the save state once a match is won or lost.
Periodic Background Snapshots: Takes non-blocking engine snapshots via WorkerClient.snapshot() every 50 ticks during singleplayer gameplay and writes compressed state to storage.
Snapshot Preservation: Preserves the binary snapshot when LocalServer syncs sparse turns or handles beforeunload.
Exit Teardown: Automatically cleans up and purges saves when a match is won or lost (SendWinnerEvent).
Summary
With the core engine snapshotting framework implemented in PR #5637 (
Add versioned game state snapshots), the underlying simulation can now be serialized and restored at any tick boundary with zero turn re-simulation delays.As noted in #5637, that PR provides the engine and worker APIs (
WorkerClient.snapshot(),new WorkerClient(..., snapshotToRestore)) with "No UI".This issue tracks the player-facing UI, platform save management, and runtime snapshot persistence to bring seamless singleplayer save and resume to users.
Scope of the UI & Client Save Layer
1. Singleplayer Modal UI (
src/client/SinglePlayerModal.ts)mm:ss(e.g.Resume Asia (03:45)).WorkerClient(startInfo, clientID, resumeSnapshot). The engine rehydrates in ~150 ms without any turn-replay catchup or battery/CPU drain.showInGameConfirm) to prevent accidental deletion.2. Platform & Account Save Scoping (
src/client/SinglePlayerSaveManager.ts)openfront_solo_save:steam:<steamId>:v1) viasteamSDK.getSteamIdSync(), ensuring multiple Steam accounts on the same computer do not overwrite each other's games.CompressionStream/ pako) to keeplocalStoragefootprint light (~1.2 MB).3. Auto-Save Lifecycle (
src/client/ClientGameRunner.ts/src/client/LocalServer.ts)WorkerClient.snapshot()every 50 ticks during singleplayer gameplay and writes compressed state to storage.LocalServersyncs sparse turns or handlesbeforeunload.SendWinnerEvent).Status & Companion Branch
feat/singleplayer-ui-snapshots(built directly on top of PR Add versioned game state snapshots #5637):tests/client/SinglePlayerSaveManager.test.ts(6/6 passed)tests/core/snapshot/CoreSnapshot.test.ts(2/2 passed)tests/client/SinglePlayerModalStart.test.ts(1/1 passed)tests/EnJsonSorted.test.ts(1/1 passed)tsc --noEmit,oxlint, andeslintclean (0 errors)