08 — Save¶
Goal¶
Learn what a save file actually holds about health, what it deliberately leaves out, and why a restore is silent.
What This Scene Demonstrates¶
The participant flow:
Scene health systems → StableId lookup → HealthSnapshot per owner → one labelled section → coordinator → save payload
Three enemies carry a HealthSystem and a StableId. HealthSaveParticipant finds all three on its own — nothing in this scene points it at any of them.
A second participant defined inside the panel's own file writes an encounter counter into the same payload, so health is visibly not privileged: the coordinator cannot tell the two apart.
Why This Scene Was Built On The Death FX Scene¶
Because the most important thing here is something that does not happen, and you cannot see an absence in a scene that had no effect to begin with.
Kill an enemy with the panel and the real death path runs: the handler fires, the FX plays, the Died counter ticks. Now restore a save taken while it was alive. The enemy comes back at full health with nothing playing at all, and Revived still reads zero.
That silence is correct. RestoreSnapshot writes the fields directly rather than going through the kill or revive paths, and firing death events during a load would spawn VFX and drop loot every time a save was read. But it means an in-place restore leaves presentation to you.
What To Look For¶
- Who Gets Saved lists the three enemies with their ids and live health. A
HealthSystemwithout aStableIdis skipped — there would be no way to find it again on load - What The Snapshot Holds is the short list:
Max,Current,Dead. Read the payload and confirm there is nothing else in it - NOT saved and not restored: shields, regen timers and cooldowns, i-frame state, combat state, damage locks, and any state your own rules hold. An enemy saved mid-fight behind an
OverhealShieldcomes back with the right health and no shield - The Events That Do Not Fire counts
DiedandRevivedon the watched enemy. Only the Kill button moves them. Restoring — in either direction — moves neither - A Save That Cannot Be True captures a real save and forces
Maxto0, a state no capture can produce. The participant refuses that entry, names the owner, leaves the object alone, and the encounter section still loads
The three Debug Panel — Enemy … Health overlays are kept from the original scene on purpose: they show current/max live for all three enemies, so a restore is visible across the whole scene rather than only on the one the save panel is watching.
Scene Setup¶
- Three enemies, each with
HealthSystemandStableId - The death FX handlers from
07, left intact — they are the point, see above - The per-enemy health debug panels, left intact
HealthSavePanelin place ofDeathFXHandlersPanel, with Event Watch Target assigned explicitly rather than left to auto-resolve, so the same enemy is watched every run
The participant needs no configuration. Unlike Inventory's it takes no constructor arguments — health snapshots resolve nothing through a database, so there is nothing to hand it.
Sample Scope¶
This scene focuses only on:
- Capturing every scene
HealthSystemthrough one participant - The exact contents of
HealthSnapshot, and the far longer list of what is absent - Event silence on restore, in both directions
- Refusing a snapshot that describes no state the system could have been in
This scene does NOT cover:
- Writing the payload to disk — nothing here does any file I/O, on purpose
- Restoring shields, regen, i-frames, combat state or rule state, none of which are in the snapshot
- Reconstructing presentation after an in-place restore
- Save slots, versioning beyond the participant's own guard, or networking
If shields matter to your game, restore them through whatever granted them — a status effect via the Status Effects participant, or a participant of your own. The snapshot type belongs to Health's contract assembly, and a second definition of "health state" is not something this layer should invent.
Authority Note¶
This scene may include a permissive sample authority setup. If no authority is resolved, mutations are allowed for demonstration purposes.
Networking Reminder¶
No networking is included. Multiplayer authority and synchronization are the developer's responsibility.
How To Use¶
- Press Capture while all three enemies are healthy, and read the payload
- Press Damage a few times, then Restore. Health returns, on the watched enemy and on the others
- Press Reset Counters, then Kill. The FX plays and
Diedreads 1 - Press Restore. The enemy is alive again,
Revivedstill reads 0, and nothing played - Press Clear A Wave, capture again, and watch both sections move together
- Press Load A Save With Max 0. The health entry is refused by name; the encounter section still loads
- Read Last Result after each action
Step 4 is the one worth watching twice. Everything the death handler did in step 3 is still done — the enemy is upright and undamaged with its death FX having played and no revive having happened.
Failure Behaviour¶
Failures are reported through RevSaveReport rather than thrown. A load that throws is how a game ends up stuck on its main menu.
Common patterns:
-
No eligible health systems → nothing in the scene has both
HealthSystemandStableId→ Add aStableId; the capture would otherwise write no health section at all -
The section fails naming every owner → the ids in the save are not the ids in the scene → Usually the loaded scene is not the one the save was taken in. An object spawned at runtime gets a fresh id every launch unless
StableId.AssignIdis called with one of your own -
An entry is refused for an impossible snapshot →
Maxat or below zero, orCurrentoutside0..Max→ No capture produces these, so the file was edited or truncated. An entry carrying no snapshot at all deserialises to exactly this, which is why the two cases behave the same -
A restore reports a partial → some owners restored and others were refused → That section is no longer a description of anything. Do not carry it into a later save
-
Damage is refused → a rule, an i-frame, a damage lock or authority said no → Not a save concern; the panel reports it so you can tell it apart from a save problem
Note what is not checked: Dead is never validated against Current. Whether an object at zero health is dead belongs to its death rules, which RestoreSnapshot restores nothing of — rejecting that pairing would refuse real saves in order to catch tampered ones.
Behind The Scenes¶
This panel uses public save and health APIs only:
HealthSaveParticipantRevSaveCoordinator.Capture(...)/RevSaveCoordinator.Restore(...)RevSaveReportRevSaveEnvelope/RevSaveSectionIRevSaveParticipantStableId/StableIdOwners.Find<T>(...)HealthSystem.TryTakeDamage(...)/TryHeal(...)/Kill()HealthSystem.Died/RevivedHealthSnapshot
The participant is a translator, not a store. It adapts Health's existing CaptureSnapshot / RestoreSnapshot pair and widens nothing, which is why it lives in a define-gated integration assembly rather than in the Health package.
Key Takeaway¶
A save holds three numbers about a character, and a great deal of what makes that character feel alive is not among them.
The restore is deliberately silent, so nothing downstream of death or revival happens when a file is read. That is the right default and it is not a complete answer: after an in-place restore, read IsDead and put the object into the matching state yourself. Reloading the scene sidesteps the whole problem, which is why most games do exactly that.