Skip to content

01 — Attributes Save

Goal: Watch a save capture an owner's attributes, change something afterwards, and see the restore put the owner back to where it was — including removing an attribute that did not exist when the save was taken.


What This Scene Demonstrates

Attributes' save participant is the smallest of the six and takes no dependencies at all: it finds every owner carrying both an AttributeSet and a StableId, captures each one's base values, and hands the coordinator a section. Constructing it is new AttributesSaveParticipant() and nothing else.

Two behaviours are worth the scene rather than a paragraph:

Only base values are saved. Not effective values, not bounds. A restore rewinds. It does not merge.

Most restores in this framework apply onto existing state, so anything the save does not mention is left alone. This one re-seeds the authored rows and applies the saved values on top — so the owner ends up as it was at capture time rather than as a blend of then and now.


What Is In The Scene

Object What it is
Main Camera, Directional Light, Plane Ordinary scene furniture
Characters ▸ Player (Visual Only) A capsule carrying a StableId (Player) and the AttributeSet
Teaching Panel ▸ AttributesSavePanel Bound to the player's AttributeSet

The StableId and the AttributeSet share a GameObject, and that is the load-bearing detail. A capture matches them on the same object, so a StableId on a parent with the container on a child finds nothing at all — the panel would report a successful capture of zero owners, which is the failure that misleads rather than the one that stops you. The panel warns on screen if the owner it is bound to has no StableId.

The rows are the same three the quickstart uses, and Moved Id is set to strength so the rewind has a bounded attribute to move.

Nothing here writes to disk. The payload is held in memory so it can be read on screen, which is also what makes the scene safe to re-run.


What To Look For

Capture, then break it on purpose. On the Rewind tab, create created_after_save at 99 and add 100 to strength. Then restore. The created attribute is gone entirely rather than left at 99 — at the moment the save was taken it did not exist — and strength is back where it was. An apply-onto-existing-state restore would have left both.

Watch the event log stay empty. Clear it, then restore: nothing appears, however many values moved. Restores here are silent by design — state is written directly and presentation reconciles from RevSaveManager.LoadCompleted. Clear it again and press the step-1 buttons instead and entries do appear, because those are ordinary writes. That contrast is the lesson: a UI that only redraws on the change event will show the pre-load numbers until something else happens to move them.

Read the payload tab. It is the exact string the coordinator would write to disk. Note what is absent: no effective values, and no bounds. Effective values are functions of contributions owned by other systems, and bounds are authoring-time configuration — storing either here would write the same fact twice and let one copy win silently on load.