107 lines
4.4 KiB
Markdown
107 lines
4.4 KiB
Markdown
# I_Persistable — Blueprint Interface
|
|
|
|
**File:** [`Content/Framework/Save/I_Persistable`](Content/Framework/Save/I_Persistable.uasset)
|
|
|
|
> **⚡ C++ Status: Full Implementation** — Defined in `Source/PG_Framework/Public/Core/I_InterfaceLibrary.h` as `BlueprintNativeEvent`. **Do NOT create a Blueprint Interface asset.** On any actor that needs save/load: Class Settings → Interfaces → Add → `UPersistable`. Override `On Save`, `On Load`, `Get Save Tag`, `Needs Save`. See `docs/developer/cpp-integration-guide.md`.
|
|
>
|
|
> ---
|
|
|
|
**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 |