Concept: World State & Identity

World-actor state is stored in slabs - one UCrimsonSaveWorldData per level - held at UCrimsonSaveGameManagerSubsystem (GameInstance) scope, so they outlive any single level or UWorldSubsystem and survive streaming and seamless travel. Each slab is a TMap<FGuid, FCrimsonSaveWorldActorData>. An actor opts in by implementing ICrimsonSaveableActor; on every save the world subsystem scans loaded levels and captures each one automatically.

What "automatic" means
Capture and restore are automatic once the interface is implemented. OnActorStateChanged / OnActorDestroyed are optional incremental hooks, not a requirement. bSaveWorldStateAfterEveryChange only changes when the disk flush happens, not whether your actor is captured.

What is captured automatically

CapturedNotes
TransformMovable actors only (root mobility != Static).
Actor UPROPERTY(SaveGame) fieldsThe actor's own tagged properties, via the engine proxy archive.
Component UPROPERTY(SaveGame) fieldsCascades into every component - state on health / inventory / movement components persists with no extra code.
Non-property stateHidden flag, physics & movement velocities, and pawn controller rotation - no SaveGame flag needed.
Cross-object referencesSaveGame AActor* / TWeakObjectPtr<AActor> pointers are stored as stable GUIDs and re-resolved to live instances after load (same level or persistent level).
Custom payloadOptional FInstancedStruct from GatherActorSaveData for anything beyond the above.

Identity

Every saveable actor is keyed by a stable GUID so it can be matched across sessions:

Actor kindIdentity key
Level-placedThe engine-assigned ActorGuid (set in the editor, stable across runs).
Runtime-spawnedA session FGuid assigned by the subsystem; the actor's class (TSoftClassPtr) is recorded so it can be re-spawned on load.

Capture and restore flow

  1. Save - the subsystem scans loaded levels for ICrimsonSaveableActor actors and writes each into its level slab: transform, the actor's SaveGame blob, per-component SaveGame blobs, non-property state, and cross-object reference GUIDs.
  2. Flush - slabs are written to WorldSlab_<Level>.sav in the active slot (as part of the main save, or via SaveWorldState).
  3. Load - slabs are read back into memory when the slot loads; each level's slab is applied when the level is present (LoadWorldState, or automatically as sublevels stream in).
  4. Resolve - after every actor in a level is restored / re-spawned, a deferred pass rewrites SaveGame actor-pointer properties from their stored GUIDs to the live instances.
Cross-object references
Because resolution runs after all actors in a level exist, references between actors in the same level (or to the persistent level) round-trip. References into a different streamed sublevel that is not loaded at restore time cannot be guaranteed, and are left null and logged. See How-To: Save Cross-Object References.

Deletion

Destruction is recorded from the engine's actor-destroyed event on the server, so only a real Destroy() removes an actor from the save - an actor simply being absent does not.

Actor kindOn destroySave-file cost
Runtime-spawnedIts slab entry is removed entirely - it simply stops being saved.None - a removed entry means nothing to re-spawn.
Placed (level)A minimal GUID-only tombstone is written; the copy reloaded from the level is destroyed on load.A few bytes, bounded by how many map actors you actually delete.
Opt into respawning
Override ShouldRespawnAfterDestroyed() (default false) and return true to skip the tombstone for a placed actor, so it respawns from the level on the next load. Runtime actors ignore this flag. See How-To: Persist a Level Actor.

ICrimsonSaveableActor overrides

All interface methods are optional BlueprintNativeEvents. Implement the interface and you are done; override these only for custom state or lifecycle handling.

OverrideWhen used
GatherActorSaveData()Return an FInstancedStruct for data that cannot be expressed as UPROPERTY(SaveGame). Empty (default) means only auto-captured state is saved.
RestoreFromSaveData(ActorData)Receives the FInstancedStruct. Transform, SaveGame fields, and component state are already restored before this runs.
OnPreRestoreState()Before any restoration. Disable physics, clear containers.
OnPostRestoreState()After all restoration. Re-enable physics, broadcast events.
ShouldRespawnAfterDestroyed()Return true so a destroyed placed actor respawns from the level instead of staying deleted. Default false. Runtime actors ignore it.

Streaming & World Partition

A sublevel's slab is applied when it streams in and its actors are re-captured just before it streams out, so revisiting a region restores it. World Partition runtime cells stream as levels through the same path, gated by bSupportWorldPartition (default on).

Server authority
All capture, restore, and runtime respawn happen on the server. Restore forces a net update; clients receive restored state through normal replication and never spawn replicated actors themselves. A SaveGame-only property never reaches clients unless it is also Replicated - see Concept: Multiplayer & Player Scoping.

Driving world state manually (optional)

With bIncludeWorldStateInMainSave (default), a normal save persists world actors too. To drive world state on its own:

Reach the subsystem with **Get World Subsystem** (class `Crimson Save World Manager Subsystem`), then call **Save World State** / **Load World State** off it. **On Actor State Changed** (shown) is the optional incremental capture of a single actor.