Security
- HMAC-SHA256 Signatures — tamper-evident saves
- Machine-Bound Keys — HKDF-derived from device identity
- Save-File-Repair Tool — EditorWindow + headless CLI
Streaming saves, HMAC-SHA256 tamper detection, machine-bound keys, 16 new features, 738 passing tests, and 0 NuGet dependencies. Built for shipping games, not prototypes.
The Unity Asset Store has plenty of save loaders. SaveStack is opinionated about three things — each one a trade-off some other library doesn't make.
Every write is atomic: temp file + File.Replace + .bak-fallback. If the OS dies mid-save, the previous slot stays intact. Verified with simulated I/O failures (8 dedicated regression tests).
SaveStack does not silently serialize every field of your MonoBehaviour. You declare what's persistent — through the static API for game data, or with drop-in saver components for transforms and animator state. The benefit: you can read your save file. You can diff two slots. You can debug a migration. No reflection black box.
Every versioned load that crosses a schema boundary mirrors the original cipher bytes to <key>.premigration_v{N}.bak — exactly once, idempotently. If a migration step turns out broken, SaveSystem.RestoreBackup rolls back the player's slot. Live-service games update without burning save data.
Download the asset in Unity via Window → Package Manager → My Assets → SaveStack → Import. SaveStack registers as a Package Manager entry automatically. No manifest edits, no manual paths.
The static facade SaveSystem covers 80% of typical use. Defaults: JSON via Newtonsoft, no encryption, OS-appropriate save folder.
using AvanatroTools.SaveStack;
// Save
SaveSystem.Save("playerName", "Player One");
SaveSystem.Save("score", 1337, slot: 0);
// Load (returns default(T) if missing — use TryLoad for explicit handling)
string name = SaveSystem.Load<string>("playerName");
int score = SaveSystem.Load<int>("score", slot: 0);
Provider-pattern — swap any of ISerializer / IStorageProvider / IEncryptionProvider / IPathProvider independently.
var key = new byte[32]; // store + derive securely
SaveSystem.Configure(encryption: new AesEncryption(key));
// or production-default for v1.1+ IL2CPP builds:
// SaveSystem.Configure(encryption: new AesGcmEncryption(key));
AesGcmEncryption is IL2CPP-only — Unity's Mono runtime does not ship .NET 8's AesGcm. The production-default for both Mono and IL2CPP today is AesEncryption (AES-256-CBC). v1.1 swaps in a BouncyCastle-backed AES-GCM for full Mono support.
| Layer | What you get |
|---|---|
| Static facade | SaveSystem, SettingsSystem — save, load, async, try-load, has-key, delete |
| Storage providers | FileStorage (atomic), PlayerPrefsStorage (WebGL/mobile fallback), in-memory for tests |
| Encryption providers | NoEncryption, AesEncryption (CBC, prod default), AesGcmEncryption (GCM, IL2CPP) |
| Versioning | MigrationHandler, pre-migration backups, RestoreBackup |
| Slot ops | GetAllSlots, SlotMeta (description / custom fields / playtime), SlotSave / SlotLoad |
| Game systems | QuestStore (5c), SetFlag/GetFlag (5d.7), PlaytimeTracker |
| Saver components | PositionSaver, RotationSaver, ActiveSaver, EnabledSaver, AnimatorParametersSaver, RigidbodySaver + SaveSystemSceneController |
| Editor | SaveSystemWindow (inspect / delete / export), SaveWizard (bulk add savers) |
| Tests | 738 dotnet NUnit + 17 Unity Test Runner. Run them yourself — CI-friendly. |