9.9 KiB
SS_SaveManager — GameInstance Subsystem
File: Content/Framework/Save/SS_SaveManager
⚡ C++ Status: Full Implementation —
Source/PG_Framework/Public/Save/SS_SaveManager.hprovides the complete save/load subsystem: slot manifest, save/load/delete, quick-save/load, checkpoint management, backup, FArchive binary serialization. Auto-created by UE's subsystem system whenGI_GameFrameworkinitializes — no BP child, no spawning needed. Access from any BP:Get Game Instance → Get Subsystem(SS_SaveManager). Seedocs/developer/cpp-integration-guide.md.
Purpose: The single authority for all serialisation and deserialisation of game state to disk. Supports multiple save slots, checkpoint saves, hard saves, auto-saves, and world object persistence.
Depends On: GI_GameFramework, I_Persistable
Used By: BPC_CheckpointSystem, WBP_SaveLoadMenu, BPC_PlayerRespawnSystem
Enums
// E_SaveType — Categorizes the trigger that initiated a save
E_SaveType
{
Checkpoint, // Auto-triggered by crossing a checkpoint volume
HardSave, // Player-initiated manual save
AutoSave, // Periodic or event-triggered auto save
DeathStateSave // Snapshot created when the player dies (for death loop continuity)
}
Structs
// S_SaveSlotInfo — Metadata entry for one save slot in the manifest
S_SaveSlotInfo
{
SlotIndex: Integer // 0-based slot number
DisplayName: FText // Player-chosen or auto-generated name
Timestamp: FDateTime // UTC timestamp of last save
ChapterTag: GameplayTag // Which chapter/level was active
ThumbnailBytes: Byte Array // Compressed screenshot for UI preview
PlaytimeSeconds: Float // Total playtime from GI_GameFramework
}
// S_WorldObjectState — Delta record for one persistent world actor
S_WorldObjectState
{
ObjectTag: GameplayTag // Unique identifier matching the actor's tag
bDestroyed: Bool // Was the actor destroyed?
CustomData: Map (Name → String) // Generic key-value store for any component state
}
// S_PlayerSnapshot — Complete capture of player state at save time
S_PlayerSnapshot
{
// Core vitals
Health: Float // Current HP
Stress: Float // Current stress level
Stamina: Float // Current stamina pool
// Transform
Position: Vector // World location
Rotation: Rotator // World rotation
// Inventory
InventoryData: Array of S_InventorySlot // From BPC_InventorySystem
QuickSlotData: Array of S_QuickSlotEntry // From BPC_InventoryQuickSlot
EquipmentData: Map (GameplayTag → S_EquipmentSlot) // From BPC_EquipmentSystem
// Narrative
NarrativeFlags: Map (GameplayTag → Bool) // From BPC_NarrativeStateSystem
NarrativeValues: Map (GameplayTag → Float)
// Metrics
DeathCount: Integer // From BPC_PlayerMetricsTracker
ItemsCollected: Integer
DistanceTravelled: Float
// Additional
ActiveObjectiveTags: Array of GameplayTag // From BPC_ObjectiveSystem
HidingState: Bool // Was player hiding?
CurrentHidingSpotTag: GameplayTag
AltDeathSpaceEnterCount: Integer
}
Variables
| Name | Type | Description |
|---|---|---|
SlotManifest |
Array of S_SaveSlotInfo |
Cached metadata for all available save slots |
ActiveSaveObject |
SaveGame Object Reference | The currently loaded save data object in memory |
bIsSaving |
Bool | Prevents concurrent save operations |
bIsLoading |
Bool | Prevents concurrent load operations |
SaveVersion |
Integer | Current schema version for migration detection |
WorldStateDelta |
Map (Name → S_WorldObjectState) |
Live delta of changed world objects since last save |
PersistentActors |
Array of Actor Reference | All registered I_Persistable actors in the current level |
Functions / Events
| Name | Inputs | Outputs | Description |
|---|---|---|---|
SaveToSlot |
SlotIndex: Int, SaveType: E_SaveType | Bool Success | Orchestrates full save: collects all state, writes SaveGame to disk, updates manifest |
LoadFromSlot |
SlotIndex: Int | Bool Success | Reads SaveGame from disk, migrates if needed, distributes state to all systems |
DeleteSlot |
SlotIndex: Int | — | Removes save file and manifest entry |
GetSlotManifest |
— | Array of S_SaveSlotInfo |
Returns all slot metadata for UI display |
GetSaveFileSize |
SlotIndex: Int | Int64 Bytes | Returns the on-disk file size for the given slot |
RegisterPersistableActor |
Actor: Actor Reference | — | Adds an I_Persistable actor to the tracked list |
UnregisterPersistableActor |
Actor: Actor Reference | — | Removes an I_Persistable actor from the tracked list |
CollectWorldState |
— | — | Iterates all registered I_Persistable actors and calls CollectState() |
DistributeWorldState |
— | — | Iterates all registered I_Persistable actors and calls RestoreState() |
CollectPlayerSnapshot |
— | S_PlayerSnapshot |
Gathers player state from all relevant components |
DistributePlayerSnapshot |
Snapshot: S_PlayerSnapshot | — | Restores player state to all relevant components |
MigrateSaveVersion |
OldVersion: Int, Data: SaveGame Object | SaveGame Object | Upgrades old save schema to current version |
SaveCheckpoint |
CheckpointTag: GameplayTag | — | Saves checkpoint data to the active slot without prompting the player |
SaveDeathState |
— | — | Saves a special death-state snapshot for death loop continuity |
LoadDeathState |
— | Bool Success | Loads the death-state snapshot |
HasSaveData |
SlotIndex: Int | Bool | Returns whether a save file exists for the slot |
GetActiveSaveSizeInfo |
— | FText | Formatted string with playtime, chapter, timestamp for HUD |
Event Dispatchers
| Name | Parameters | Fired When |
|---|---|---|
OnSaveComplete |
SlotIndex: Int, SaveType: E_SaveType | Save operation finishes successfully |
OnLoadComplete |
SlotIndex: Int | Load operation finishes successfully |
OnSaveFailed |
SlotIndex: Int, ErrorCode: Int | Save fails (disk full, write error, etc.) |
OnLoadFailed |
SlotIndex: Int, ErrorCode: Int | Load fails (corrupt file, version mismatch, etc.) |
OnWorldStateCollected |
ActorCount: Int | After all I_Persistable actors collected state |
OnWorldStateDistributed |
ActorCount: Int | After all I_Persistable actors restored state |
OnSaveVersionMigration |
OldVersion: Int, NewVersion: Int | When a save file is migrated to a newer schema |
Blueprint Flow Diagram
flowchart TD
A[SaveToSlot called] --> B{bIsSaving?}
B -->|Yes| C[Return False]
B -->|No| D[Set bIsSaving = true]
D --> E[CollectPlayerSnapshot]
E --> F[CollectWorldState]
F --> G[Write SaveGame to disk]
G --> H[Update SlotManifest]
H --> I[Set bIsSaving = false]
I --> J[Broadcast OnSaveComplete]
J --> K[Return True]
L[LoadFromSlot called] --> M{bIsLoading?}
M -->|Yes| N[Return False]
M -->|No| O[Set bIsLoading = true]
O --> P[Read SaveGame from disk]
P --> Q{File valid?}
Q -->|No| R[Broadcast OnLoadFailed]
R --> S[Set bIsLoading = false]
S --> T[Return False]
Q -->|Yes| U[Check SaveVersion]
U --> V{Needs migration?}
V -->|Yes| W[MigrateSaveVersion]
W --> X[DistributePlayerSnapshot]
V -->|No| X
X --> Y[DistributeWorldState]
Y --> Z[Set bIsLoading = false]
Z --> AA[Broadcast OnLoadComplete]
AA --> AB[Return True]
Save File Structure
SaveGame Object (USaveGame-derived)
├── Header
│ ├── SaveVersion: Integer
│ └── SlotInfo: S_SaveSlotInfo
├── Player Snapshot
│ └── S_PlayerSnapshot
├── World State
│ └── WorldStateDelta: Map (Name → S_WorldObjectState)
└── Death State
└── DeathStateData: S_PlayerSnapshot (optional, only in DeathStateSave)
Communication Matrix
| Target System | Method | Why |
|---|---|---|
All I_Persistable actors |
Interface call (CollectState, RestoreState) |
World object persistence |
BPC_HealthSystem / Stress / Stamina |
Via S_PlayerSnapshot |
Restore player vitals |
BPC_InventorySystem |
Via S_PlayerSnapshot |
Restore inventory state |
BPC_NarrativeStateSystem |
Via S_PlayerSnapshot |
Restore narrative flags |
BPC_PlayerMetricsTracker |
Via S_PlayerSnapshot |
Restore session metrics |
BPC_ObjectiveSystem |
Via S_PlayerSnapshot |
Restore objective state |
BPC_EquipmentSystem |
Via S_PlayerSnapshot |
Restore equipment state |
BPC_InventoryQuickSlot |
Via S_PlayerSnapshot |
Restore quick slot layout |
BPC_CheckpointSystem |
Dispatcher OnLoadComplete |
Notify checkpoint system to reset |
WBP_SaveLoadMenu |
Dispatcher OnSaveComplete/OnLoadComplete |
UI refresh after operation |
GI_GameFramework |
Direct (owned by) | Access active slot index, update phase |
BPC_DeathHandlingSystem |
Direct call SaveDeathState/LoadDeathState |
Death loop continuity |
Reuse Notes
- Add new fields to
S_PlayerSnapshotper project without breaking existing saves (migration handles missing fields) - The
WorldStateDeltamap handles anyI_Persistableactor generically — no per-actor serialisation code needed - Save file naming convention:
SaveSlot_{SlotIndex}.sav - All disk I/O uses UE5's
UGameplayStatics::SaveGameToSlot/LoadGameFromSlot - Register/unregister
I_Persistableactors inBeginPlay/EndPlayof the actor - For multiplayer, the
GM_CoreGameModeshould be the Server-authorised caller ofSaveToSlot/LoadFromSlot