Simple Save: Save & Load Toolkit for Unity w/ 4 Playable Demos & Auto-Save


A simple yet agnostic save & load toolkit for Unity. JSON / Binary / AES-encrypted / PlayerPrefs / Cloud, multi-profile, autosave, version migration, async, ScriptableObject support. 4 demos.


by Living Failure


Price History +

Still rolling your own save/load every project?


Stop. Save systems are a solved problem.


SimpleSave is a complete, system-agnostic save/load framework that hides the boring parts (file IO, atomic writes, threading, version migration, encryption) behind a one-line static API. It scales from "I just need to save a high score" to "I have multi-profile cloud-synced AES-encrypted saves with offline-progress reconciliation" — without changing a single Save() call site.


THE FACADE — ONE LINE PER OPERATION


   SimpleSave.Save("player", playerData);

   var loaded = SimpleSave.Load<PlayerData>("player");


That's the whole hello-world. No setup. No bootstrap manager to drag into your scene.


The static facade auto-bootstraps on first call with sensible defaults (JSON files in Application.persistentDataPath/SimpleSave/, JsonUtility serializer).


FIVE PLUGGABLE BACKENDS


JsonFileBackend — Default. Plain JSON files. Human-readable. The .json files genuinely parse as JSON (the SSV2 envelope wraps payload in a clean JSON document).


BinaryFileBackend — Same envelope, gzip-compressed. 30-70% smaller for typical save payloads. Drop-in replacement.


EncryptedFileBackend — AES-256-CBC + HMAC-SHA256 + per-save salt + PBKDF2-SHA256 (100,000 iterations default, configurable, embedded in the wire format so you can re-tune without breaking back-compat). Encrypt-then-MAC ordering — tampered files fail HMAC before decryption is attempted, no padding-oracle vector.


PlayerPrefsBackend — Wraps the envelope as base64 inside Unity's PlayerPrefs. For settings, keybindings, and tutorial-seen flags only — emits a warning above 8KB per slot.


CloudBackend (abstract base) — Implement five async methods (Upload / Download / RemoteExists / DeleteRemote / ListRemoteKeys) for your provider (PlayFab, Unity Cloud, Steam Cloud, your own server). The base handles the entire ISaveBackend contract, local cache, conflict resolution hooks, and a persistent retry queue for failed background uploads. Bring the SDK calls; SimpleSave brings the architecture.


Switch backends with one line: SimpleSave.SetBackend(new EncryptedFileBackend("passphrase"));


TWO SERIALIZERS, AUTO-DETECTED


JsonUtilitySerializer — Default. Always available. Zero dependencies. Handles [Serializable] classes, structs, Vector3/Quaternion/Color, lists, primitive arrays.


NewtonsoftSerializer — Reflection-bridged (no hard reference to Newtonsoft.Json). Drop in com.unity.nuget.newtonsoft-json via Package Manager and the bridge lights up automatically — no scripting defines, no menu toggles. Handles dictionaries, polymorphism, top-level lists, custom converters, contract resolvers, properties.


Format-mismatch detection: every save stamps the serializer name in metadata. Loading a Newtonsoft save with the JsonUtility serializer (or vice versa) throws a clean SaveFormatMismatchException before deserialization.


MULTI-PROFILE GAMES (SaveContext)


For couch co-op, Renegade vs Paragon parallel playthroughs, NG+ runs, family-shared installs:


   var profileA = new SaveContext(new JsonFileBackend(folderA), label: "Profile A");

   var profileB = new SaveContext(new JsonFileBackend(folderB), label: "Profile B");

   profileA.Save("player", a);

   profileB.Save("player", b); // same key, different folder, no collision


Each SaveContext owns its own backend, serializer, autosave timer, migration registry, and event subscriptions. Zero cross-contamination. The static SimpleSave.* facade is just a wrapper around SaveContext.Default — single-profile games never need to think about contexts.


AUTOSAVE — ONE CALL, FRAMEWORK-MANAGED LIFECYCLE


   SimpleSave.EnableAutoSave(snapshotFactory: () => BuildCurrentSnapshot(), intervalSeconds: 30f);


Periodic background saves with platform-aware lifecycle hooks (defaults to AutoSaveOnApplicationPause = true on Android/iOS where the OS reaps backgrounded apps). Returning null from the snapshot factory skips a tick — cheap "no changes since last save" guard. Pause / resume / force-save-now / events for spinner UI. One driver per SaveContext, so multi-profile games run independent timers.


VERSION MIGRATION — RENAME FIELDS WITHOUT BREAKING LIVE SAVES


You shipped v1 with playerName. v2 renames it to displayName. Old saves still need to load:


   SimpleSave.SetCurrentVersion<PlayerData>(2);

   SimpleSave.RegisterMigration<PlayerData>(fromVersion: 1, toVersion: 2, upgrade: json => json.Replace(""playerName"", ""displayName""));


Migrations operate on the JSON payload string (the old class shape may not even exist in your project anymore). Chain walker prefers +1 hops over longer hops, with longest-as-fallback. Cycle protection. Failed chains throw MigrationFailedException with the path walked so far.


SCRIPTABLEOBJECT SUPPORT


For game state already living on a ScriptableObject (currency wallet, settings, achievements, idle-game stats):


   SimpleSave.SaveAll("game", wallet, achievements, settings);

   SimpleSave.LoadAll("game", new ScriptableObject[] { wallet, achievements, settings });


Optional SaveableScriptableObject base class adds:

- SaveKey override for stable identity across asset renames

- OnBeforeSave hook to flush volatile/cached state into [SerializeField] fields

- OnAfterLoad hook to rebuild derived caches


Schema-evolution pattern (schemaVersion field + OnAfterLoad remap) documented in Recipe 16. Duplicate SaveKeys throw DuplicateSaveKeyException — fail-fast prevents silent overwrites.


ASYNC API — NO FRAME HITCH


   await SimpleSave.SaveAsync("autosave", BuildSnapshot());

   var data = await SimpleSave.LoadAsync<PlayerData>("player");


Every facade method has an async equivalent. Backends that implement IAsyncSaveBackend (CloudBackend, PlayerPrefs) dispatch natively. Sync-only backends (file backends) wrap their thread-safe sync methods in Task.Run via the IThreadSafeBackend marker — the main thread never sees the IO cost. Cancellation tokens supported throughout.


ATOMIC WRITES + .BAK CRASH RECOVERY


All three file backends inherit a robust write path from FileBackendBase:

- Write to .tmp, atomic-rename over the final, brief .bak preserves the previous version

- If the process dies mid-rename and only .bak survives, the next Load auto-recovers it and emits one Debug.Log line

- Either the new file is in place or the previous file is recoverable — no half-written corrupt state


EDITOR TOOLING


Window > Living Failure > SimpleSave gives you four editor windows:


Save Inspector — Open any save file (.json / .sav / .enc) by path or active-backend slot. Auto-detects format by first bytes ('{' = JSON envelope, '1F 8B' = gzip, otherwise prompts for AES passphrase). Decode the envelope, edit metadata + payload as plain JSON, write back. The killer support tool.


Slot Browser — Lists every slot in the active backend with size + last-modified. Per-row: Inspect, Delete (confirm), Copy, Rename, Reveal in Explorer, Export to JSON. Search filter, refresh, backend status row.


Export Slot to JSON — Decode + decrypt + decompress + unwrap into a plain readable JSON file. Player sends you a save? Drop it on your machine, repro the bug. Strict UTF-8 round-trip with base64 fallback for binary serializer payloads — never lossy.


Import Slot from JSON — The other half of the export flow. Reads any v2 export file back into a slot.


SaveConfig ScriptableObject — Right-click in Project > Create > SimpleSave > Config. Pick backend, serializer, custom directory, encryption passphrase, autosave defaults from the inspector. Drop in a Resources/ folder, tick Apply on Startup, and SimpleSave auto-bootstraps via [RuntimeInitializeOnLoadMethod] before the first scene loads. Zero code.


FOUR PLAYABLE DEMO SCENES


Not tech demos. Each exercises a different slice of the framework as a working reference you can read end-to-end.


Save Sandbox — Every facade method on one screen. Slot picker, save/load/delete buttons, raw inspector, edit field rows, GetSlots enumeration. The API surface tour.


Multi-Profile — Two SaveContext instances side-by-side with isolated folders under persistentDataPath/Profiles/A/ and /B/. Per-profile event log proves isolation. Use-case card lists the real-world patterns this unlocks.


Synthwave Tycoon — Idle clicker built on a SaveableScriptableObject (ClickerStats). Three generator tiers, 5-second async autosave, sync save on quit/focus/scene-unload, "WELCOME BACK" offline-progress modal that fires on resume. Showcases the patterns idle games actually need.


World Builder — 3D scene with editable Actor MonoBehaviours. Spawn Player / Enemy / Prop, edit name / level / HP / damage / AI / transform / tint via a left-list-right-inspector UI, save the entire scene to one slot. List of complex objects + transforms, all round-tripped.


DOCUMENTATION


- 17-page HTML documentation site (multi-page + single-page concatenation, neumorphic indigo theme): index, installation, quick-start, backends, serializers, autosave, profiles, ScriptableObjects, encryption, migrations, editor tools, API reference, recipes, demos, troubleshooting, about

- Recipes.md with 24 copy-paste solutions for the situations you'll actually run into — RPG progress, idle clicker offline progress, multi-profile, encrypted mobile, slot browser UI, version migration, custom cloud backend, SIdF pairing