A Unity persistence framework for predictable save/load and deterministic scene travel.
CrowSave is built around explicit capture/apply, scoped identity, and stable orchestration — designed to eliminate the class of bugs caused by implicit serialization, unscoped IDs, and non-deterministic apply order.
- Explicit Capture/Apply — entities own their blob format; no magic
- Scoped identity — state keyed by
(ScopeKey, EntityId)prevents cross-scene and cross-instance collisions - Two storage layers — RAM layer for in-session travel; disk layer for saves, checkpoints, and load-game
- Deterministic orchestration — stable apply order with a barrier step before every Apply phase
- Tombstones — destroyed entities stay destroyed across loads and transitions
- DirtyOnly capture — skip unchanged entities for efficient saves
- Checkpoint ring — rolling in-memory snapshots for rewind flows
- Scene GUID identity — stable scope keys that survive scene renames and moves
Option A — Unity Package (.unitypackage)
- Download the latest
.unitypackagefrom the releases page. - Double click on the file and import all assets.
Option B — Unity Package Manager (Git URL)
In Unity, open Window > Package Manager, click + → Add package from git URL, and enter:
https://github.com/Luci0n/CrowSave-Unity-Persistence.git?path=CrowSave
| Doc | Contents |
|---|---|
| Overview | Architecture, core concepts, modules |
| Getting Started | Bootstrap, SaveConfig, first entity, operations |
| Persistence | Capture/Apply authoring, versioning, DirtyOnly, policies |
| Architecture | End-to-end pipeline maps for all operations |
[RequireComponent(typeof(PersistentId))]
public sealed class Health : PersistentMonoBehaviour
{
[SerializeField] private int value = 100;
public void Damage(int amount)
{
value = Mathf.Max(0, value - amount);
MarkDirty();
}
public override void Capture(IStateWriter w)
{
w.WriteVersion(1);
w.WriteInt(value);
}
public override void Apply(IStateReader r)
{
r.ReadVersion(min: 1, max: 1);
value = r.ReadInt();
}
}SaveOrchestrator.Instance.SaveSlot(1);
SaveOrchestrator.Instance.LoadSlot(1);
SaveOrchestrator.Instance.TransitionToScene("Level02");
SaveOrchestrator.Instance.Checkpoint("boss_defeated");