add blueprints
This commit is contained in:
103
docs/blueprints/05-saveload/36_I_Persistable.md
Normal file
103
docs/blueprints/05-saveload/36_I_Persistable.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# I_Persistable — Blueprint Interface
|
||||
|
||||
**File:** [`Content/Framework/Save/I_Persistable`](Content/Framework/Save/I_Persistable.uasset)
|
||||
|
||||
**Purpose:** Interface for any Actor or Component in the world that needs to save or restore per-instance state. Implemented by doors, containers, lootable objects, hidden collectibles, puzzle elements, destructibles, and any other persistent world actor.
|
||||
|
||||
**Depends On:** None
|
||||
**Used By:** [`SS_SaveManager`](35_SS_SaveManager.md), All persistent world actors
|
||||
|
||||
---
|
||||
|
||||
## Interface Functions
|
||||
|
||||
| Function | Inputs | Outputs | Description |
|
||||
|----------|--------|---------|-------------|
|
||||
| `CollectState` | — | `S_WorldObjectState` | The implementer packs its current state into a generic key-value struct |
|
||||
| `RestoreState` | StateData: `S_WorldObjectState` | — | The implementer unpacks the struct and reapplies its state |
|
||||
| `GetPersistenceTag` | — | GameplayTag | Returns the unique gameplay tag that identifies this instance in the save manifest |
|
||||
| `ShouldPersist` | — | Bool | Returns whether this actor should be serialised (e.g., false for temporary actors spawned via FX) |
|
||||
| `OnPreSave` | — | — | Called before the save operation begins; used to flush transient state |
|
||||
| `OnPostLoad` | — | — | Called after all state has been distributed; used to trigger animations, re-enable physics, etc. |
|
||||
|
||||
---
|
||||
|
||||
## Required Variable (on implementer)
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `PersistenceTag` | GameplayTag | Set in Construction Script or Defaults. Must be unique within the level. Convention: `Save.<LevelName>.<ActorClassName>.<Index>` |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Pattern
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[SS_SaveManager.CollectWorldState] --> B[Iterate registered I_Persistable actors]
|
||||
B --> C[Call actor.ShouldPersist]
|
||||
C --> D{Should persist?}
|
||||
D -->|No| E[Skip]
|
||||
D -->|Yes| F[Call actor.OnPreSave]
|
||||
F --> G[Call actor.CollectState]
|
||||
G --> H[Store in WorldStateDelta map]
|
||||
H --> I[Save to disk]
|
||||
|
||||
J[SS_SaveManager.DistributeWorldState] --> K[Iterate WorldStateDelta entries]
|
||||
K --> L[Find actor by ObjectTag]
|
||||
L --> M{Found?}
|
||||
M -->|No| N[Log warning]
|
||||
M -->|Yes| O[Call actor.RestoreState]
|
||||
O --> P[Call actor.OnPostLoad]
|
||||
P --> Q[Continue]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: BP_DoorWithState implements I_Persistable
|
||||
|
||||
```cpp
|
||||
// On CollectState
|
||||
State.bDestroyed = bIsDestroyed;
|
||||
State.CustomData.Add("bOpen", bIsOpen);
|
||||
State.CustomData.Add("bLocked", bIsLocked);
|
||||
State.CustomData.Add("Health", Health);
|
||||
State.CustomData.Add("PuzzleSolved", bPuzzleSolved);
|
||||
return State;
|
||||
|
||||
// On RestoreState(State)
|
||||
bIsDestroyed = State.bDestroyed;
|
||||
bIsOpen = State.CustomData["bOpen"].AsBool();
|
||||
bIsLocked = State.CustomData["bLocked"].AsBool();
|
||||
Health = State.CustomData["Health"].AsFloat();
|
||||
bPuzzleSolved = State.CustomData["PuzzleSolved"].AsBool();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PersistenceTag Convention
|
||||
|
||||
| Tag Pattern | Example | Used For |
|
||||
|-------------|---------|----------|
|
||||
| `Save.LevelName.ActorClass.Index` | `Save.Hospital.DoorHeavy.03` | Level-dense unique ID |
|
||||
| `Save.Persistent.ActorName` | `Save.Persistent.MansionKey` | Unique collectibles that span levels |
|
||||
| `Save.Global.FlagName` | `Save.Global.EndingUnlocked` | Cross-save narrative flags |
|
||||
|
||||
---
|
||||
|
||||
## Communication Matrix
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|------|
|
||||
| `SS_SaveManager` | Interface call | State collection and distribution |
|
||||
| `SS_SaveManager` | Register/Unregister | Lifecycle tracking (BeginPlay/EndPlay) |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
|
||||
- Keep `CustomData` entries simple: only Bool, Float, Int, String, or Name values
|
||||
- For complex state (arrays of structs), serialise to a Json string and store as a single `CustomData` entry
|
||||
- Use `OnPostLoad` to re-trigger timelines or timelines that drive animations (e.g., door opening animation after restoring closed state)
|
||||
- Implement `ShouldPersist` to return `false` for actors that are editor-placed but runtime-destroyed without state significance (e.g., particle emitters)
|
||||
- All interface functions are BlueprintImplementableEvent — no logic required in the interface itself
|
||||
Reference in New Issue
Block a user