Skip to content

State & Save

Capture and restore object state — positions, rotations, physics, UI — in topic-typed slices. Saving the whole scene to a file and loading it back comes with Magpile, through SceneState.

Overview

Need to reset an object to its starting position after a player dies? Want to save game progress to a file and load it back later? The State package handles both, at two levels:

  • Per-object state via ObjectStateHolder and topic state holders — pick the slice you want to save (Transform, Rigidbody, GameObject, …) and add operations to it.
  • Whole-scene saves via SceneState, which comes with Magpile — capture every registered scene object and pool-spawned instance, with cross-references resolved automatically and an optional async settle phase on restore.

Both layers are data-driven: configure what to save in the Inspector using class selection, and trigger save/restore through commands or SceneState's API.

Per-object state ships with every Jungle plugin. Without Magpile you can capture and restore objects in memory, for example to reset a level, but not write the scene to a file.


Topic-typed state holders

State is decomposed by topic — a topic holder targets a specific component type (or GameObject) and only accepts operations valid for that type. The structure mirrors Jungle's targeted commands: a TransformStateHolder works on a Transform and only accepts ITransformStateOperations, a RigidbodyStateHolder works on a Rigidbody and only accepts IRigidbodyStateOperations, and so on.

This means: - The picker only shows operations relevant to the current topic — no scrolling through a flat list of every state class in the project. - The target is resolved once on the holder (via a SmartX value), not per-operation. - New aspects of an existing topic can be added simply by writing one more operation class implementing the topic's marker interface.

For the catalog of built-in topic holders and their operations, see Topic State Holders. Each holder picks its own target via its SmartX value — no parent composite is required.


ObjectStateHolder

The MonoBehaviour you drop on a saveable GameObject. It hosts a list of StateHolderBase entries — topic holders chosen per-aspect, each with its own smart target. See ObjectStateHolder for details.

ObjectStateHolder (component on a saveable GameObject)
├─ Holders:
│   ├─ Transform State
│   │   ├─ Target: SmartGameObject (Self by default)
│   │   └─ Operations: Position, Rotation
│   ├─ Rigidbody State
│   │   ├─ Target: SmartRigidbody (sibling by default)
│   │   └─ Operations: Velocity
│   └─ GameObject State
│       ├─ Target: GameObject (Self by default)
│       └─ Operations: Active
└─ Capture On Begin / End Action  (optional automation)

Authoring a custom operation

Plugin authors implement one of the topic interfaces (ITransformStateOperation, IRigidbodyStateOperation, etc.) — typically by extending StateOperation<T>:

[Serializable]
[JungleClassInfo("Renderer Color", "Saves the renderer material color.", null, "Audio & Visuals")]
public class RendererColorStateOperation : StateOperation<Renderer>, IRendererStateOperation
{
    [SerializeField, HideInInspector] private Color color;
    protected override void OnCapture(Renderer t) => color = t.material.color;
    protected override void OnRestore(Renderer t) => t.material.color = color;
}

The base class handles the HasCapturedData flag (so the state survives JSON round-trip) and gates Restore on it. Cross-references to other GameObjects go through SavedRef — the scene state encodes and decodes them transparently.


Commands

Command Description
Capture State Calls CaptureAll() on the target Object State Holder.
Restore State Calls RestoreAll() (optionally clearing afterwards).
Clear State Calls ClearAll().

To save to a file, use Magpile's SceneState: the Scene State Command with Save To File and Load From File, or SaveToFile / RestoreFromFile from code.

Collision matrix

Magpile can also keep Unity's layer collision matrix (Project Settings > Physics). The Collision Matrix State holder saves and restores it, and the Apply Collision Matrix operation in the Physics Settings Command applies a matrix you set in the Inspector.


Practical Examples

Resettable Object

Save a transform on level start, restore it on death.

  1. Add ObjectStateHolder to the object.
  2. Add a Transform State entry. Inside it, add a Full operation.
  3. Set the holder's execution frame to your lifecycle (e.g. Mono Lifecycle Frame: EnableDisable), enable Capture On Begin, set End Action to Restore And Clear.

The transform is captured automatically when the holder enables, restored when it disables.

Save the Whole Scene

For scenes mixing static GameObjects with pool-spawned items (typical for Octoputs scenes with attachment points + attachable pools). Needs Magpile.

  1. Drop a SceneState component in the scene.
  2. Register every persistent scene object in Permanent Refs (Key + GameObject) and every runtime pool/factory in Creators (Key + creator).
  3. Add an ObjectStateHolder to each saveable object (and each pool prefab) with the topic holders and operations you want.
  4. Optionally add settle conditions like Time Delay or Rigidbodies At Rest so restore waits for physics/animation before reporting done.
  5. Call sceneState.SaveToFile(path) and sceneState.RestoreFromFile(path, onComplete) from your save UI or commands.

Cross-object references (e.g. "this AttachmentPoint was holding that AttachableObject") are handled by SavedRef inside individual operations — plugin authors put SavedRef fields in their operations, end users never see them.


Architecture

flowchart TD
    subgraph SceneState
        SS[Permanent Refs + Creators registries]
    end

    subgraph ObjectStateHolder
        OSH[List of StateHolderBase]
    end

    subgraph "Topic Holders"
        TH1[TransformStateHolder]
        TH2[RigidbodyStateHolder]
        TH3[GameObjectStateHolder]
        THN[…]
    end

    subgraph Operations
        OP1[ITransformStateOperation impls]
        OP2[IRigidbodyStateOperation impls]
        OP3[IGameObjectStateOperation impls]
    end

    SS -->|CaptureAll / RestoreAll| OSH
    OSH --> TH1
    OSH --> TH2
    OSH --> TH3
    OSH --> THN
    TH1 --> OP1
    TH2 --> OP2
    TH3 --> OP3