Changelog
What shipped, what's planned. SaveStack follows semver — breaking changes get a major bump, additive features bump minor, fixes bump patch.
v1.1.0 — 2026-05-14
Mega-update: 16 new features across security, performance, UX, and testing. No breaking changes — all v1.0 code compiles and runs unchanged.
Security & Anti-Cheat
- HMAC-SHA256 Save-Signatures (Z.1) — tamper-evident format byte
0x07;HmacVerificationFailedExceptionon mismatch - Machine-Bound Key-Derivation (Z.2) — HKDF-SHA256 +
IMachineIdentityProvider; files non-transferable between devices - Save-File-Repair Tool (Z.3) — EditorWindow + headless CLI with 5 repair checks (header / HMAC / encryption / migration version / slot meta)
Performance
- Streaming Save/Load (P.1) — chunked I/O for 100 MB+ payloads;
IProgress<StreamProgress>pattern for loading-bar integration - Save-Batching / Transactions (P.2) — atomic multi-slot writes via 2-phase commit;
SaveBatch/TrySaveBatch/SaveBatchAsync - In-Memory LRU Cache (V.3) — configurable
maxEntries+maxByteSizewith hit-rate statistics
Foundation
- UnityEngine.Object References (V.1) — JsonConverter chain for assets, scene-objects, and sub-assets
- [Save] Attribute (V.2) — opt-in field marker with auto-discovery via
AutoSaveAttributeSaver - Backup Auto-Schedule (B.1) — count-triggered rolling FIFO snapshots with configurable retention depth
Testing & Quality
- Migration TestBed (M.1) — fluent
Given/When/Thenwith handler chains; JSON-path assertions - Stress-Test Suite (Q.1) — 10 000+ iteration framework with P50/P95/P99/StdDev latency metrics
- Fuzz-Test Suite (Q.2) — 5 modular mutators (BitFlip / ByteDeletion / RandomInjection / HeaderCorruption / Truncation)
UX & Onboarding
- Genre Recipes (R.1) — 4 drop-in schemas: RPG, Roguelike, Open-World, Arcade
- Code Snippets (R.2) — 7 ready-to-use templates: Settings, SaveSlotUI, AutoSave, QuickSave, Migration, LoadingScreen, BackupRestore
- i18n for Error Messages (L.1) — opt-in
ILocalizationProviderwith 22 message keys across en / de / ja / zh - DocFX API Docs Pipeline (D.1) — docfx.json config + 6 handwritten articles; ready for
tools.avanatro.com/savestack/api
Stats
- +245 tests (493 → 738 total, all green)
- 16 features across 4 fulldev sessions
- 0 new NuGet dependencies — pure C# stack
- 0 breaking changes to public API surface
v1.0.0 — pre-submit, 2026 Q2
The shipping foundation. Engineering complete; pending Asset Store submission after an in-house dogfood pilot and a 2-week external beta.
Core save & load
- Static facade
SaveSystem—Save/Load/TryLoad/HasKey/HasValidSlotwith slot-based API - Async paths —
SaveAsync/LoadAsync/TryLoadAsyncwithCancellationToken; native async I/O viaIAsyncStorageProvider - Per-slot lock (
SemaphoreSlim) — concurrentSave/SaveAsyncon the same slot are safe; different slots run in parallel
Storage backends
FileStorage— atomic writes (tmp +File.Replace+.bakfallback). Async viaIAsyncStorageProvider.PlayerPrefsStorage— WebGL / mobile fallback when filesystem access is restricted- In-memory storage — for tests + transient slots
Encryption
AesEncryption— AES-256-CBC, per-encrypt IV. Production default for Mono + IL2CPP.AesGcmEncryption— AES-256-GCM with format-version byte (0x01). IL2CPP-only in v1.0; Backwards-Compat with un-prefixed legacy bytes.NoEncryption— opt-out pass-through
Versioning & migration
MigrationHandler— opt-in envelope (__sspVersion/__sspData) with registeredIMigrationsteps- Pre-migration backups — every stale-version
Loadmirrors original cipher to<key>.premigration_v{N}.bakonce, idempotent RestoreBackup/ListBackupVersions— recovery API for migrations gone wrong- Legacy saves recognized as
VersionInfo.Unversioned— drop-in upgrade path from pre-versioning saves
Slot inventory & metadata
SlotMeta—SlotIndex/LastScene/SavedAt/Description/CustomFields/TotalPlaytimeTicksGetAllSlots/GetSlotInfo— load-game-menu listings without full-decrypt of each valueSetSlotDescription/SetSlotMetaField— atomic Read-Modify-Write on__metaPlaytimeTracker— monotonicStopwatch.GetTimestamp+ 24h sanity cap
Game systems
QuestStore(sub-namespace, separate asmdef) — start / advance / complete / fail with counters + variables; persists under__quests- Flag store —
SetFlag/GetFlag/HasFlag/ClearFlag/GetAllFlags; persists under__flags; corrupt-store-tolerant SettingsSystem— parallel facade, separate storage root, exception-freeGet, thread-safe
Saver components
Saverabstract base —GetUniqueKey= scene+hierarchy+type oroverrideKey; auto-register viaAwake- 6 built-in savers — Position / Rotation / Active / Enabled / AnimatorParameters / Rigidbody
SaveSystemSceneController— staticDictionary<Saver, byte>registry,OnSceneLoadedauto-restore, DontDestroyOnLoad-safe via build-index filter- Cross-scene state bucket —
__scene_<sceneName>;SaveSystem.GetSceneState/SetSceneState AutoSaver— periodic +OnApplicationQuit+OnApplicationPause+OnDisablesave triggersSlotSave/SlotLoad— one-call high-level scene capture / restore
Production hardening
- Path-traversal validation —
SaveSlot.ValidateUserKeypublic for caller pre-validation - Concurrent-save lock + 5+ regression tests
- IOException + corrupt-JSON recovery suites — 8 + 6 tests respectively
- Performance benchmarks — 1 MB ~22 ms, 10 MB ~80 ms, 50 MB ~350–660 ms (Win11, NVMe)
- Build test matrix — Standalone Win/Mac/Linux + WebGL + Android + iOS-IL2CPP (pre-submit checklist)
- Unity 6000 minimum — modern
Rigidbody.linearVelocityAPI + UPM Samples~ convention
Editor tools
SaveSystemWindow— slot inspector with JSON preview, delete, export (testableSaveSystemWindowViewModel)SaveWizard— bulk-add savers to Selection, ToggleRow preserves state, overrideKey applied only to newly-added components
Tests
- 300+ dotnet NUnit tests — Concurrent-Save, IOException-Recovery, CorruptJsonRecovery, PathTraversal, Async, Performance benchmarks
- 17 Unity Test Runner tests — EditMode (PlayerPrefs + AES-GCM smoke) + PlayMode (AutoSaver, PlaytimeTracker)
- Test code shipped separately via
UNITY_INCLUDE_TESTSconstraint — Asset Store package excludes test sources
Stabilization pass (2026-05-11)
- Export-crash fix in
SaveSystemWindowViewModel(JSON > 300 chars) - Lost-update race fixes:
SetSlotDescription,SetSlotMetaField,SaveAsync,QuestStoreactive-check +Persistbypass PlaytimeTrackermoved to monotonic clockFileStorage.bakfallback on 0-byte primary (mid-File.Replacecrash recovery)SaveSystemSceneControllerDontDestroyOnLoad fix + dead-entry sweepGetSlotInfoviaIStorageSizeProvider(no full read + decrypt)- UPM refactor →
Packages/com.avanatrotools.savestack/embedded package - One-call
SlotSave/SlotLoadhigh-level API + trigger MonoBehaviours - Stabilization follow-ups —
SettingsSystemstatic-lock hygiene + 7 concurrency tests;Loadbackup side-effect explicitly documented in user-facing XML-doc
v1.2 — planned
Additive features. No breaking changes. Public-API surface from v1.1 keeps working.
- Compression —
ICompressionProvider+GzipCompressiondefault. Pre-encryption gzip squeezes JSON to ~25–35% on typical RPG saves. - Screenshot preview per slot —
SnapshotCamera+SetSlotPreviewfor thumbnails in the load menu - AES-GCM on Mono — BouncyCastle-backed implementation, finally usable in non-IL2CPP builds. Format-version byte already in place; existing IL2CPP saves keep loading.
- Inspector bundle — custom Inspectors for every
Savercomponent (live preview, status badges), expandedSaveSystemWindow(Quest / Flag tabs, slot diff), optionalReflectionSaverwith field-picker for explicit auto-capture
Not planned for v1.2
Cloud-sync hooks. Shipping just an
ICloudProvider interface without a working implementation would be misleading marketing. If cloud-sync ships, it will be with a concrete Steam Cloud / iCloud / Google Play Saves integration in a v2.0 — not a stub.