Files
UE5-Modular-Game-Framework/docs/blueprints/05-saveload/36_I_Persistable.md

4.4 KiB

I_Persistable — Blueprint Interface

File: Content/Framework/Save/I_Persistable

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, 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

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

// 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