# SS_SaveManager — GameInstance Subsystem **File:** [`Content/Framework/Save/SS_SaveManager`](Content/Framework/Save/SS_SaveManager.uasset) > **⚡ C++ Status: Full Implementation** — `Source/PG_Framework/Public/Save/SS_SaveManager.h` provides 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 when `GI_GameFramework` initializes — no BP child, no spawning needed. Access from any BP: `Get Game Instance → Get Subsystem(SS_SaveManager)`. See `docs/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`](../01-core/04_GI_GameFramework.md), [`I_Persistable`](30_I_Persistable.md) **Used By:** [`BPC_CheckpointSystem`](31_BPC_CheckpointSystem.md), [`WBP_SaveLoadMenu`](../06-ui/), [`BPC_PlayerRespawnSystem`](31_BPC_CheckpointSystem.md) --- ## Enums ```cpp // 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 ```cpp // 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 ```mermaid 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_PlayerSnapshot` per project without breaking existing saves (migration handles missing fields) - The `WorldStateDelta` map handles any `I_Persistable` actor 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_Persistable` actors in `BeginPlay` / `EndPlay` of the actor - For multiplayer, the `GM_CoreGameMode` should be the Server-authorised caller of `SaveToSlot` / `LoadFromSlot`