add blueprints
This commit is contained in:
216
docs/blueprints/05-saveload/35_SS_SaveManager.md
Normal file
216
docs/blueprints/05-saveload/35_SS_SaveManager.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# SS_SaveManager — GameInstance Subsystem
|
||||
|
||||
**File:** [`Content/Framework/Save/SS_SaveManager`](Content/Framework/Save/SS_SaveManager.uasset)
|
||||
|
||||
**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`
|
||||
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
|
||||
169
docs/blueprints/05-saveload/37_BP_Checkpoint.md
Normal file
169
docs/blueprints/05-saveload/37_BP_Checkpoint.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# BP_Checkpoint — Checkpoint Actor
|
||||
|
||||
**File:** [`Content/Framework/Save/BP_Checkpoint`](Content/Framework/Save/BP_Checkpoint.uasset)
|
||||
|
||||
**Purpose:** Manages checkpoint volumes in the world, tracks the most recent checkpoint crossed by the player, and triggers save operations via [`SS_SaveManager`](35_SS_SaveManager.md). Also stores respawn transform data for use by the death handling systems.
|
||||
|
||||
**Depends On:** [`SS_SaveManager`](35_SS_SaveManager.md), [`GM_CoreGameMode`](../01-core/05_GM_CoreGameMode.md)
|
||||
**Used By:** Player Controller or Game Mode (placed at game setup)
|
||||
|
||||
---
|
||||
|
||||
## Enums
|
||||
|
||||
```cpp
|
||||
// E_CheckpointActivationMode — Determines when a checkpoint triggers
|
||||
E_CheckpointActivationMode
|
||||
{
|
||||
OnOverlap, // Player overlaps the checkpoint volume
|
||||
OnInteract, // Player must press an interact key at the checkpoint
|
||||
Automated // Triggered by external event (e.g., completing a puzzle)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Structs
|
||||
|
||||
```cpp
|
||||
// S_CheckpointData — Runtime data for one checkpoint
|
||||
S_CheckpointData
|
||||
{
|
||||
CheckpointTag: GameplayTag // Unique identifier for this checkpoint
|
||||
DisplayName: FText // "Save Room - Floor 2", etc.
|
||||
RespawnLocation: Transform // Where the player spawns on reload
|
||||
CameraCutTransform: Transform // Optional camera cut point for respawn transition
|
||||
bHasBeenUsed: Bool // Has the player crossed this checkpoint?
|
||||
ActivationMode: E_CheckpointActivationMode
|
||||
bAutoSave: Bool // Does crossing this checkpoint trigger an auto-save?
|
||||
LinkedObjectives: Array of GameplayTag // Objectives to mark complete on activation
|
||||
}
|
||||
|
||||
// S_RespawnCache — Lightweight in-memory respawn data (not saved to disk)
|
||||
S_RespawnCache
|
||||
{
|
||||
LastCheckpointTag: GameplayTag
|
||||
LastCheckpointLocation: Transform
|
||||
bIsRespawnFromDeath: Bool // False = checkpoint load, True = death respawn
|
||||
DeathCountAtCheckpoint: Integer // Snapshot of death count for metrics
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `RegisteredCheckpoints` | Map (GameplayTag → `S_CheckpointData`) | All checkpoint volumes in the current level |
|
||||
| `ActiveCheckpoint` | `S_CheckpointData` | The most recently activated checkpoint |
|
||||
| `RespawnCache` | `S_RespawnCache` | Lightweight cache for respawn without full load |
|
||||
| `bCanCrossCheckpoint` | Bool | Cooldown guard to prevent double-trigger (reset after 0.5s) |
|
||||
| `DefaultRespawnTransform` | Transform | Fallback spawn point if no checkpoint exists (level start) |
|
||||
| `CheckpointCooldownTimer` | Float | Timer handle for cooldown (0.5s default) |
|
||||
|
||||
---
|
||||
|
||||
## Functions / Events
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `RegisterCheckpoint` | Data: `S_CheckpointData` | — | Adds a checkpoint to the registered map |
|
||||
| `UnregisterCheckpoint` | CheckpointTag: GameplayTag | — | Removes a checkpoint from the map |
|
||||
| `ActivateCheckpoint` | CheckpointTag: GameplayTag | — | Sets the given checkpoint as active; triggers save if `bAutoSave` is true |
|
||||
| `GetActiveCheckpoint` | — | `S_CheckpointData` | Returns the currently active checkpoint |
|
||||
| `GetRespawnTransform` | — | Transform | Returns the respawn location (active checkpoint or fallback) |
|
||||
| `HasActiveCheckpoint` | — | Bool | Returns whether a checkpoint has been crossed |
|
||||
| `GetCheckpointList` | — | Array of `S_CheckpointData` | Returns all registered checkpoints (for UI map / fast travel) |
|
||||
| `ClearCheckpointData` | — | — | Resets all checkpoint state (on new game) |
|
||||
| `SetDefaultRespawn` | Transform: Transform | — | Sets the fallback respawn point when no checkpoint exists |
|
||||
| `OnPlayerDeath` | — | — | Fired by GM_CoreGameMode; caches current checkpoint as death respawn point |
|
||||
| `OnPlayerRespawn` | — | — | Fired after respawn; clears death flags |
|
||||
|
||||
---
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired When |
|
||||
|------|-----------|------------|
|
||||
| `OnCheckpointActivated` | CheckpointTag: GameplayTag, DisplayName: FText | A checkpoint is crossed and becomes active |
|
||||
| `OnCheckpointSaveTriggered` | CheckpointTag: GameplayTag | An auto-save was triggered by this checkpoint |
|
||||
| `OnRespawnPointSet` | RespawnTransform: Transform | The respawn point has changed |
|
||||
| `OnCheckpointListChanged` | CheckpointCount: Int | A checkpoint was added or removed |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Player overlaps checkpoint volume] --> B{Volume implements\nI_CheckpointVolume?}
|
||||
B -->|No| C[Ignore]
|
||||
B -->|Yes| D[Get checkpoint GameplayTag]
|
||||
D --> E{Can cross?\nbCanCrossCheckpoint}
|
||||
E -->|No| F[Ignore]
|
||||
E -->|Yes| G[Set bCanCrossCheckpoint = false]
|
||||
G --> H[Lookup in RegisteredCheckpoints map]
|
||||
H --> I{Found?}
|
||||
I -->|No| J[Log warning: unregistered checkpoint]
|
||||
I -->|Yes| K[Set ActiveCheckpoint = found data]
|
||||
K --> L[Set RespawnCache.LastCheckpointTag]
|
||||
L --> M[Set RespawnCache.LastCheckpointLocation]
|
||||
M --> N[Broadcast OnCheckpointActivated]
|
||||
N --> O{bAutoSave?}
|
||||
O -->|Yes| P[SS_SaveManager.SaveCheckpoint\nCheckpointTag]
|
||||
P --> Q[Broadcast OnCheckpointSaveTriggered]
|
||||
O -->|No| R[Skip save]
|
||||
R --> S[Start cooldown timer 0.5s]
|
||||
Q --> S
|
||||
S --> T[Timer expires -> set bCanCrossCheckpoint = true]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communication Matrix
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| `SS_SaveManager` | Direct call `SaveCheckpoint` | Trigger checkpoint auto-save |
|
||||
| `SS_SaveManager` | Bind to `OnLoadComplete` | Restore active checkpoint tag after load |
|
||||
| `GM_CoreGameMode` | Bind to death/respawn events | Receive death and respawn notifications |
|
||||
| `BPC_PlayerRespawnSystem` | Provide `GetRespawnTransform` | Supply respawn location on death |
|
||||
| `BPC_DeathHandlingSystem` | Provide `RespawnCache` data | Death handling reads cache for appropriate flow |
|
||||
| Checkpoint Volume Actors | Interface call | Register/unregister via BeginPlay/EndPlay |
|
||||
| `WBP_CheckpointNotification` | Dispatcher `OnCheckpointActivated` | Show "Checkpoint Saved" HUD notification |
|
||||
| `WBP_MapWidget` | Function `GetCheckpointList` | Display discovered checkpoints on map |
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint Volume Setup
|
||||
|
||||
```
|
||||
BP_CheckpointVolume (Box Collision, Render CustomDepth)
|
||||
└── Collision: OverlapOnly (PlayerOnly)
|
||||
└── OnComponentBeginOverlap
|
||||
└── Get owner's CheckpointTag (GameplayTag)
|
||||
└── Call BP_Checkpoint.ActivateCheckpoint(Tag)
|
||||
```
|
||||
|
||||
**Checkpoint Volume Variables:**
|
||||
|
||||
| Variable | Type | Source |
|
||||
|----------|------|--------|
|
||||
| `CheckpointTag` | GameplayTag | Set per-instance in level |
|
||||
| `DisplayName` | FText | Set in defaults (e.g., "Hospital Lobby") |
|
||||
| `RespawnLocation` | Transform | Arrow component on the volume |
|
||||
| `CameraCutTransform` | Transform | Optional arrow component |
|
||||
| `ActivationMode` | E_CheckpointActivationMode | Overlap by default |
|
||||
| `bAutoSave` | Bool | True by default |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
|
||||
- Each checkpoint volume creates itself by calling `RegisterCheckpoint` in `BeginPlay` with its configured `S_CheckpointData`
|
||||
- Single-player only — multiplayer requires a server-authorised version with per-player checkpoint tracking
|
||||
- The 0.5s cooldown prevents double-activation from overlapping two volumes simultaneously
|
||||
- `DefaultRespawnTransform` should be set by `GM_CoreGameMode` on level start from the PlayerStart actor
|
||||
- `CheckpointTag` naming convention: `Checkpoint.<LevelName>.<AreaName>`
|
||||
- Renamed from `BPC_CheckpointSystem` to `BP_Checkpoint` per Master naming convention.
|
||||
95
docs/blueprints/05-saveload/38_BPC_AltDeathSpaceSystem.md
Normal file
95
docs/blueprints/05-saveload/38_BPC_AltDeathSpaceSystem.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# BPC_AltDeathSpaceSystem — Actor Component (Alt Death Space)
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_AltDeathSpaceSystem`](Content/Framework/Save/BPC_AltDeathSpaceSystem.uasset)
|
||||
|
||||
**Purpose:** Manages the limbo / between-world death space where the player can wander, find clues, or trigger special mechanics before being returned to the living world.
|
||||
|
||||
**Depends On:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md), [`BP_Checkpoint`](BP_Checkpoint.md), [`SS_SaveManager`](35_SS_SaveManager.md)
|
||||
**Used By:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) (orchestrator)
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `AltDeathSpaceMap` | Map (GameplayTag → Level Soft Reference) | Tag-to-level mapping for alt death space variants |
|
||||
| `CurrentAltDeathSpace` | Level Soft Reference | The active alt death space level |
|
||||
| `AltDeathSpaceEnterCount` | Integer | How many times the player has entered alt space this run |
|
||||
| `ExitPortalTransform` | Transform | Where the player emerges back into the living world |
|
||||
| `bIsInAltDeathSpace` | Bool | Is the player currently in the alt death space? |
|
||||
| `AltSpaceTimeline` | Float | Current time-in-alt-space (for atmosphere changes) |
|
||||
| `MaxTimeInAltSpace` | Float | Max seconds before forced exit (default 60.0) |
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `EnterAltDeathSpace` | Context: S_DeathContext | — | Loads the alt death space level, moves player |
|
||||
| `ExitAltDeathSpace` | — | — | Unloads alt space, returns player to ExitPortalTransform |
|
||||
| `GetCurrentAltDeathSpaceTag` | — | GameplayTag | Returns which variant of alt space the player is in |
|
||||
| `SetExitPortal` | Transform: Transform | — | Sets where the player exits alt space |
|
||||
| `IsInAltDeathSpace` | — | Bool | Public getter for bIsInAltDeathSpace |
|
||||
|
||||
---
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired When |
|
||||
|------|-----------|------------|
|
||||
| `OnEnteredAltDeathSpace` | SpaceTag: GameplayTag | Player enters alt death space |
|
||||
| `OnExitedAltDeathSpace` | — | Player exits alt death space back to living world |
|
||||
| `OnAltSpaceTimeLow` | RemainingSeconds: Float | 10s remaining before forced exit (every 1s tick) |
|
||||
| `OnAltSpaceForcedExit` | — | Timer expired, player forcibly returned |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow
|
||||
|
||||
```
|
||||
[EnterAltDeathSpace]
|
||||
└─► Set bIsInAltDeathSpace = true
|
||||
└─► Increment AltDeathSpaceEnterCount
|
||||
└─► Lookup CurrentAltDeathSpace from AltDeathSpaceMap by Context tag
|
||||
└─► Load stream level (CurrentAltDeathSpace)
|
||||
└─► Move player to level entry point
|
||||
└─► Set ExitPortalTransform to Context.CurrentCheckpoint respawn location
|
||||
└─► Start AltSpaceTimeline countdown
|
||||
└─► Broadcast OnEnteredAltDeathSpace
|
||||
|
||||
[ExitAltDeathSpace]
|
||||
└─► Unload alt death space stream level
|
||||
└─► Move player to ExitPortalTransform
|
||||
└─► Set bIsInAltDeathSpace = false
|
||||
└─► Broadcast OnExitedAltDeathSpace
|
||||
|
||||
[Tick: AltSpaceTimeline]
|
||||
└─► If TimeRemaining <= 10.0:
|
||||
Broadcast OnAltSpaceTimeLow(TimeRemaining)
|
||||
└─► If TimeRemaining <= 0:
|
||||
Broadcast OnAltSpaceForcedExit
|
||||
ExitAltDeathSpace()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communications With
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) | Direct call | Orchestrator triggers enter/exit |
|
||||
| [`BP_Checkpoint`](BP_Checkpoint.md) | Direct call | Get respawn transform for exit portal |
|
||||
| [`SS_SaveManager`](35_SS_SaveManager.md) | Direct call | Save alt space state |
|
||||
| [`BPC_AtmosphereStateController`](../10-adaptive/BPC_AtmosphereStateController.md) | Dispatcher | Atmosphere changes based on time in alt space |
|
||||
| [`SS_AudioManager`](../10-adaptive/132_SS_AudioManager.md) | Direct call | Audio ambience for alt space (`PlayAmbient()`, `SetRoomPreset()`) |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
- Alt death space levels are loaded via `UGameplayStatics::LoadStreamLevel` and must be in the persistent level's Streaming Levels list
|
||||
- The ExitPortalTransform is set to the last checkpoint location by default, but can be overridden by alt space mechanics
|
||||
- Alt space variants are data-driven via AltDeathSpaceMap — designers add new entries without code changes
|
||||
- The MaxTimeInAltSpace timer prevents the player from being stuck indefinitely
|
||||
- Split from original bundled `31_BPC_DeathHandlingSystem.md` per Clean Slate refactoring plan
|
||||
170
docs/blueprints/05-saveload/39_BPC_DeathHandlingSystem.md
Normal file
170
docs/blueprints/05-saveload/39_BPC_DeathHandlingSystem.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# BPC_DeathHandlingSystem — Actor Component (Death Orchestrator)
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_DeathHandlingSystem`](Content/Framework/Save/BPC_DeathHandlingSystem.uasset)
|
||||
|
||||
**Purpose:** The single authority for the player death flow. Determines the death outcome (standard respawn, game over, or alt death space), manages the death animation/camera sequence, coordinates corpse persistence, tracks run history, and triggers respawn. Sits on the Player Controller alongside four sub-systems that each handle one death-related concern.
|
||||
|
||||
**Depends On:** [`SS_SaveManager`](35_SS_SaveManager.md), [`BP_Checkpoint`](BP_Checkpoint.md), [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md), [`GM_CoreGameMode`](../01-core/05_GM_CoreGameMode.md), [`BPC_AltDeathSpaceSystem`](BPC_AltDeathSpaceSystem.md), [`BPC_PersistentCorpseSystem`](BPC_PersistentCorpseSystem.md), [`BPC_PlayerRespawnSystem`](BPC_PlayerRespawnSystem.md), [`BPC_RunHistoryTracker`](BPC_RunHistoryTracker.md)
|
||||
**Used By:** Player Controller (spawned by `GM_CoreGameMode`)
|
||||
|
||||
---
|
||||
|
||||
## Enums
|
||||
|
||||
```cpp
|
||||
// E_DeathOutcome — Determined by game rules + player state at death moment
|
||||
E_DeathOutcome
|
||||
{
|
||||
StandardRespawn, // Normal death at a checkpoint — full respawn
|
||||
GameOver, // No respawn possible — screen shows game over / main menu
|
||||
AltDeathSpace // Player enters the limbo / between-world death space
|
||||
}
|
||||
|
||||
// E_DeathAnimationStage — Controls the death anim sequence timeline
|
||||
E_DeathAnimationStage
|
||||
{
|
||||
PreDeath, // Brief pause before death anim (player can see the killer)
|
||||
DeathAnim, // Death animation playing (screen fade, camera pull back)
|
||||
PostDeath, // Screen fully dark, system state being evaluated
|
||||
RespawnTransition // Fade-up to respawn location
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Structs
|
||||
|
||||
```cpp
|
||||
// S_DeathContext — Captured at the moment of death for all sub-systems
|
||||
S_DeathContext
|
||||
{
|
||||
DeathLocation: Vector // World location where health hit 0
|
||||
KillerTag: GameplayTag // What caused the death (DamageType.Tag)
|
||||
bIsInHidingSpot: Bool // Was the player hiding when killed?
|
||||
bWasFearCritical: Bool // Was stress/fear at critical level?
|
||||
DeathTimestamp: FDateTime // UTC timestamp
|
||||
DeathCount: Integer // Running total (from BPC_PlayerMetricsTracker)
|
||||
CurrentCheckpoint: GameplayTag // Most recent checkpoint at death
|
||||
bHasAltDeathSpace: Bool // Can this death use alt death space?
|
||||
}
|
||||
|
||||
// S_DeathOutcomeRules — Configurable rules for determining death outcome
|
||||
S_DeathOutcomeRules
|
||||
{
|
||||
bEnableAltDeathSpace: Bool // Master toggle for alt death space feature
|
||||
MaxStandardDeaths: Integer // After X standard deaths, force GameOver
|
||||
MaxAltDeathSpaceEntrances: Integer // After Y alt space entrances, force GameOver
|
||||
AltDeathSpaceCheckpoint: GameplayTag // Which checkpoint to respawn to after alt space
|
||||
bGameOverOnBossDeath: Bool // Boss kills always trigger game over
|
||||
bGameOverInNarrativeClimax:Bool // Death at narrative climax = game over
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Component Variables (BPC_DeathHandlingSystem)
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `DeathContext` | `S_DeathContext` | Captured at death moment; used by all sub-systems |
|
||||
| `OutcomeRules` | `S_DeathOutcomeRules` | Configurable rules for outcome determination |
|
||||
| `CurrentOutcome` | `E_DeathOutcome` | The determined death outcome |
|
||||
| `AnimStage` | `E_DeathAnimationStage` | Current stage of the death animation sequence |
|
||||
| `bIsDying` | Bool | True from death trigger until full respawn |
|
||||
| `bIsRespawning` | Bool | True during the respawn process |
|
||||
| `ActiveAltDeathSpaceSystem` | BPC_AltDeathSpaceSystem | Reference to sub-system component (must be on same actor) |
|
||||
| `ActiveCorpseSystem` | BPC_PersistentCorpseSystem | Reference to sub-system component |
|
||||
| `ActiveRespawnSystem` | BPC_PlayerRespawnSystem | Reference to sub-system component |
|
||||
| `ActiveRunHistory` | BPC_RunHistoryTracker | Reference to sub-system component |
|
||||
|
||||
---
|
||||
|
||||
## Core Functions (BPC_DeathHandlingSystem)
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `OnPlayerDeath` | KillerTag: GameplayTag, DamageAmount: Float | — | Entry point — called by BPC_HealthSystem when HP reaches 0 |
|
||||
| `DetermineDeathOutcome` | Context: S_DeathContext | E_DeathOutcome | Evaluates rules to decide StandardRespawn / GameOver / AltDeathSpace |
|
||||
| `ExecuteDeathSequence` | Outcome: E_DeathOutcome | — | Drives the full death animation timeline |
|
||||
| `ExecuteStandardRespawn` | Context: S_DeathContext | — | Saves death state, runs respawn via BPC_PlayerRespawnSystem |
|
||||
| `ExecuteGameOver` | Context: S_DeathContext | — | Saves run history, triggers game over UI, disables input |
|
||||
| `ExecuteAltDeathSequence` | Context: S_DeathContext | — | Spawns corpse, enters alt death space via BPC_AltDeathSpaceSystem |
|
||||
| `AbortDeathSequence` | — | — | Cancels death flow (for debug / dev cheats) |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[BPC_HealthSystem: HP = 0] --> B[Capture S_DeathContext]
|
||||
B --> C[Broadcast OnPlayerDeath]
|
||||
C --> D[BPC_DeathHandlingSystem.OnPlayerDeath]
|
||||
D --> E[DetermineDeathOutcome]
|
||||
|
||||
E --> F{Outcome?}
|
||||
|
||||
F -->|StandardRespawn| G[DeathAnimStage = DeathAnim]
|
||||
G --> H[Spawn corpse via BPC_PersistentCorpseSystem]
|
||||
H --> I[SS_SaveManager.SaveDeathState]
|
||||
I --> J[DeathAnimStage = PostDeath]
|
||||
J --> K[Delay RespawnDelay seconds]
|
||||
K --> L[BPC_PlayerRespawnSystem.RespawnPlayer]
|
||||
L --> M[DeathAnimStage = RespawnTransition]
|
||||
M --> N[Fade in at checkpoint location]
|
||||
N --> O[ApplyRespawnState]
|
||||
O --> P[DeathAnimStage = null]
|
||||
P --> Q[Broadcast OnRespawnCompleted]
|
||||
|
||||
F -->|AltDeathSpace| R[DeathAnimStage = DeathAnim]
|
||||
R --> S[Spawn corpse via BPC_PersistentCorpseSystem]
|
||||
S --> T[SS_SaveManager.SaveDeathState]
|
||||
T --> U[BPC_AltDeathSpaceSystem.EnterAltDeathSpace]
|
||||
U --> V[Set exit portal to current checkpoint]
|
||||
V --> W[DeathAnimStage = null]
|
||||
W --> X[Player wanders alt space]
|
||||
X --> Y{Exit condition met?}
|
||||
Y -->|Optional: find exit portal| Z[BPC_AltDeathSpaceSystem.ExitAltDeathSpace]
|
||||
Y -->|Timer expired| AA[BPC_AltDeathSpaceSystem.ExitAltDeathSpace]
|
||||
Z --> AB[Respawn at exit portal transform]
|
||||
AA --> AB
|
||||
AB --> AC[ApplyRespawnState]
|
||||
AC --> AD[Broadcast OnRespawnCompleted]
|
||||
|
||||
F -->|GameOver| AE[DeathAnimStage = PostDeath]
|
||||
AE --> AF[BPC_RunHistoryTracker.EndRun]
|
||||
AF --> AG[Disable player input]
|
||||
AG --> AH[Show Game Over screen]
|
||||
AH --> AI[Offer: Load / Main Menu / Quit]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communication Matrix
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| `BPC_HealthSystem` | Dispatcher bind (HP reached 0) | Receives death trigger |
|
||||
| `SS_SaveManager` | Direct call `SaveDeathState` / `LoadDeathState` | Saves/loads death state for continuity |
|
||||
| `BP_Checkpoint` | Direct call `GetRespawnTransform` | Gets respawn location |
|
||||
| `BP_Checkpoint` | Direct call `OnPlayerDeath` / `OnPlayerRespawn` | Notifies checkpoint system of death cycle |
|
||||
| `GM_CoreGameMode` | Dispatcher `OnPlayerDeath` / `OnRespawnCompleted` | Game mode tracks death flow for game phase |
|
||||
| `GS_CoreGameState` | Direct set `CurrentGamePhase` = GameOver | Game state reflects game over condition |
|
||||
| `PC_PlayerController` | SetIgnoreMoveInput / SetIgnoreLookInput | Disable input during death sequence |
|
||||
| `WBP_GameOverScreen` | Dispatcher via GM or direct | Show game over UI |
|
||||
| `WBP_DeathScreen` | Dispatcher `OnPlayerDeath` | Show death animation overlay |
|
||||
| `WBP_RunSummary` | Function `GetRunSummary` | Display death recap on game over |
|
||||
| `BPC_PlayerMetricsTracker` | Read `DeathCount` | Include in death context |
|
||||
| `I_Persistable` corpse actors | Register/unregister with `SS_SaveManager` | Corpse persistence |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
|
||||
- All five sub-systems (DeathHandling, AltDeathSpace, Corpse, Respawn, RunHistory) sit on the same actor — the Player Controller
|
||||
- The death outcome determination (`S_DeathOutcomeRules`) can be swapped per-level or per-chapter via `DA_LevelConfig`
|
||||
- Corpse persistence across saves requires the corpse actor to implement `I_Persistable`
|
||||
- Alt death space levels are loaded via `UGameplayStatics::LoadStreamLevel` and must be in the persistent level's Streaming Levels list
|
||||
- Run history is session-only and NOT serialised — it resets on game restart
|
||||
- `AbortDeathSequence` is useful for debug cheats: `GodMode` or `RespawnNow` console commands
|
||||
- For multiplayer, the server must be the authority: all death trigger logic should run on the server via `HasAuthority()`
|
||||
88
docs/blueprints/05-saveload/40_BPC_PersistentCorpseSystem.md
Normal file
88
docs/blueprints/05-saveload/40_BPC_PersistentCorpseSystem.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# BPC_PersistentCorpseSystem — Actor Component (Persistent Corpse)
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_PersistentCorpseSystem`](Content/Framework/Save/BPC_PersistentCorpseSystem.uasset)
|
||||
|
||||
**Purpose:** Spawns a persistent corpse actor at the death location. The corpse remains in the world and can be interacted with (looted, examined) after respawn.
|
||||
|
||||
**Depends On:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md), [`SS_SaveManager`](35_SS_SaveManager.md), [`I_Persistable`](36_I_Persistable.md)
|
||||
**Used By:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) (orchestrator)
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `CorpseActorClass` | Actor Class Reference | Blueprint class for the corpse actor (e.g., BP_PlayerCorpse) |
|
||||
| `ActiveCorpse` | Actor Reference | The spawned corpse in the world |
|
||||
| `bSpawnCorpseOnDeath` | Bool | Toggle: should a corpse be spawned? |
|
||||
| `CorpseLifetime` | Float | Seconds before corpse auto-destroys (default 300.0) |
|
||||
| `bPersistCorpseAcrossSaves` | Bool | If true, corpse is saved via I_Persistable |
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `SpawnCorpse` | Context: S_DeathContext | Actor Reference | Spawns the corpse BP at DeathLocation |
|
||||
| `DestroyCorpse` | — | — | Removes the corpse from the world |
|
||||
| `GetCorpseLocation` | — | Vector | Returns the active corpse's world location |
|
||||
| `HasActiveCorpse` | — | Bool | Is there a corpse in the world? |
|
||||
|
||||
---
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired When |
|
||||
|------|-----------|------------|
|
||||
| `OnCorpseSpawned` | CorpseActor: Actor Reference | Corpse appears in the world |
|
||||
| `OnCorpseDestroyed` | — | Corpse is cleaned up |
|
||||
| `OnCorpseLooted` | CorpseActor: Actor Reference | Player loots the corpse |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow
|
||||
|
||||
```
|
||||
[SpawnCorpse: Context]
|
||||
└─► If !bSpawnCorpseOnDeath → return null
|
||||
└─► Spawn Actor of CorpseActorClass at Context.DeathLocation
|
||||
└─► Set corpse appearance based on DeathContext (pose, damage visuals)
|
||||
└─► Set ActiveCorpse = spawned actor
|
||||
└─► If bPersistCorpseAcrossSaves:
|
||||
Register corpse with SS_SaveManager via I_Persistable
|
||||
└─► Start CorpseLifetime auto-destroy timer
|
||||
└─► Broadcast OnCorpseSpawned
|
||||
|
||||
[DestroyCorpse]
|
||||
└─► If ActiveCorpse is valid:
|
||||
If bPersistCorpseAcrossSaves: Unregister from SS_SaveManager
|
||||
Destroy ActiveCorpse actor
|
||||
Set ActiveCorpse = null
|
||||
Broadcast OnCorpseDestroyed
|
||||
|
||||
[CorpseLifetime Timer]
|
||||
└─► When timer expires:
|
||||
DestroyCorpse()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communications With
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) | Direct call | Orchestrator triggers spawn/destroy |
|
||||
| [`SS_SaveManager`](35_SS_SaveManager.md) | Direct call | Persist corpse across save/load |
|
||||
| [`I_Persistable`](36_I_Persistable.md) | Interface | Corpse actor implements for serialization |
|
||||
| [`BPC_InteractionDetector`](../03-interaction/16_BPC_InteractionDetector.md) | Dispatcher | Player can interact with corpse (loot) |
|
||||
| [`BPC_InventorySystem`](../04-inventory/BPC_InventorySystem.md) | Direct call | Transfer loot items to player |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
- Corpse persistence across saves requires the corpse actor to implement `I_Persistable`
|
||||
- CorpseLifetime default of 300 seconds can be configured per level
|
||||
- Loot interaction routes through InteractionDetector and InventorySystem
|
||||
- Split from original bundled `31_BPC_DeathHandlingSystem.md` per Clean Slate refactoring plan
|
||||
@@ -0,0 +1,89 @@
|
||||
# BPC_PersistentWorldStateRecorder — Actor Component
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_PersistentWorldStateRecorder`](Content/Framework/Save/BPC_PersistentWorldStateRecorder.uasset)
|
||||
**Parent Class:** `UActorComponent`
|
||||
**Dependencies:** [`I_Persistable`](36_I_Persistable.md), [`SS_SaveManager`](35_SS_SaveManager.md)
|
||||
|
||||
**Purpose:** Tracks all world-object state changes throughout a session so they can be serialised on save and restored on load. Maintains the delta map of changed world objects and coordinates save/load with all registered `I_Persistable` actors.
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `PersistableActors` | Array of Actor Reference | All registered `I_Persistable` actors |
|
||||
| `WorldStateDelta` | Map (Name → `S_WorldObjectState`) | Changed state records since last save |
|
||||
| `bIsCollecting` | Bool | Prevent re-entrant collect operations |
|
||||
| `bIsDistributing` | Bool | Prevent re-entrant distribute operations |
|
||||
|
||||
## Structs
|
||||
|
||||
```cpp
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
## Functions / Events
|
||||
|
||||
| Name | Inputs | Outputs | What it does |
|
||||
|------|--------|---------|--------------|
|
||||
| `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 actors and calls `I_Persistable.CollectState()` |
|
||||
| `DistributeWorldState` | — | — | Iterates all registered actors and calls `I_Persistable.RestoreState()` |
|
||||
| `GetWorldStateDelta` | — | Map (Name → S_WorldObjectState) | Returns full delta map for serialisation |
|
||||
| `ClearWorldStateDelta` | — | — | Clears the delta after save |
|
||||
| `HasPersistableActor` | Actor: Actor Reference | Bool | Check if actor is registered |
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired when |
|
||||
|------|-----------|-----------|
|
||||
| `OnWorldStateCollected` | ActorCount: Integer | All registered actors collected |
|
||||
| `OnWorldStateDistributed` | ActorCount: Integer | All registered actors restored |
|
||||
|
||||
## Blueprint Flow Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[RegisterPersistableActor] --> B[Add to PersistableActors array]
|
||||
C[SS_SaveManager.SaveToSlot called] --> D[Call CollectWorldState]
|
||||
D --> E[bIsCollecting?]
|
||||
E -->|Yes| F[Return]
|
||||
E -->|No| G[Set bIsCollecting = true]
|
||||
G --> H[Iterate PersistableActors]
|
||||
H --> I[Call I_Persistable.CollectState on each]
|
||||
I --> J[Store in WorldStateDelta]
|
||||
J --> K[Set bIsCollecting = false]
|
||||
K --> L[Broadcast OnWorldStateCollected]
|
||||
|
||||
M[SS_SaveManager.LoadFromSlot called] --> N[Call DistributeWorldState]
|
||||
N --> O[bIsDistributing?]
|
||||
O -->|Yes| P[Return]
|
||||
O -->|No| Q[Set bIsDistributing = true]
|
||||
Q --> R[Iterate PersistableActors]
|
||||
R --> S[Call I_Persistable.RestoreState with WorldStateDelta entry]
|
||||
S --> T[Set bIsDistributing = false]
|
||||
T --> U[Broadcast OnWorldStateDistributed]
|
||||
```
|
||||
|
||||
## Communications With
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| All `I_Persistable` actors | Interface calls | Collect/restore world state |
|
||||
| `SS_SaveManager` | Direct | Provides world state delta for save |
|
||||
| `GI_GameFramework` | Direct | Lifecycle bindings |
|
||||
|
||||
## Reuse Notes
|
||||
|
||||
- Actors register themselves in `BeginPlay` and unregister in `EndPlay`
|
||||
- The `CustomData` map allows any component to store arbitrary state without modifying the struct
|
||||
- Adding new `I_Persistable` actor types requires zero changes to this system
|
||||
- For spawned/destroyed actors mid-session, register/unregister when the actor is created/destroyed
|
||||
- The `WorldStateDelta` is cleared after each save to track only changes since last save
|
||||
97
docs/blueprints/05-saveload/42_BPC_PlayerRespawnSystem.md
Normal file
97
docs/blueprints/05-saveload/42_BPC_PlayerRespawnSystem.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# BPC_PlayerRespawnSystem — Actor Component (Respawn)
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_PlayerRespawnSystem`](Content/Framework/Save/BPC_PlayerRespawnSystem.uasset)
|
||||
|
||||
**Purpose:** Handles the actual respawn mechanics after death outcome is determined. Reads respawn transform from `BP_Checkpoint`, applies state restoration from `SS_SaveManager`, and runs the respawn transition.
|
||||
|
||||
**Depends On:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md), [`BP_Checkpoint`](BP_Checkpoint.md), [`SS_SaveManager`](35_SS_SaveManager.md), [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md), [`BPC_StaminaSystem`](../02-player/09_BPC_StaminaSystem.md), [`BPC_StressSystem`](../02-player/10_BPC_StressSystem.md)
|
||||
**Used By:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) (orchestrator)
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `RespawnDelay` | Float | Seconds before respawn after death (default 2.0) |
|
||||
| `RespawnFadeDuration` | Float | Seconds for camera fade (default 1.0) |
|
||||
| `bRestoreHealthOnRespawn` | Bool | Should health be fully restored? (default true) |
|
||||
| `HealthRestorePercent` | Float | If bRestoreHealthOnRespawn is false, what % HP to restore (0.0-1.0) |
|
||||
| `bClearStressOnRespawn` | Bool | Reset stress to minimum on respawn? (default true) |
|
||||
| `bRestoreStaminaOnRespawn` | Bool | Reset stamina to maximum on respawn? (default true) |
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `RespawnPlayer` | Outcome: E_DeathOutcome, Context: S_DeathContext | — | Orchestrates the full respawn sequence |
|
||||
| `GetRespawnTransform` | — | Transform | Delegates to BP_Checkpoint |
|
||||
| `ApplyRespawnState` | — | — | Restores health, stamina, stress via their respective components |
|
||||
| `ResetPlayerAtTransform` | Transform: Transform | — | Moves the character to the respawn location |
|
||||
| `PlayRespawnTransition` | — | — | Camera fade-in, post-process effects |
|
||||
|
||||
---
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired When |
|
||||
|------|-----------|------------|
|
||||
| `OnRespawnStarted` | Outcome: E_DeathOutcome | Respawn sequence begins |
|
||||
| `OnRespawnCompleted` | — | Player is fully respawned and controllable |
|
||||
| `OnRespawnFailed` | Reason: FText | Respawn could not be completed |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow
|
||||
|
||||
```
|
||||
[RespawnPlayer: Outcome, Context]
|
||||
└─► Broadcast OnRespawnStarted(Outcome)
|
||||
└─► Delay RespawnDelay seconds
|
||||
└─► GetRespawnTransform() → RespawnLocation
|
||||
└─► If RespawnLocation is invalid:
|
||||
Broadcast OnRespawnFailed("No valid respawn point")
|
||||
return
|
||||
└─► ResetPlayerAtTransform(RespawnLocation)
|
||||
└─► ApplyRespawnState()
|
||||
└─► PlayRespawnTransition()
|
||||
└─► Re-enable player input
|
||||
└─► Broadcast OnRespawnCompleted
|
||||
|
||||
[ApplyRespawnState]
|
||||
└─► If bRestoreHealthOnRespawn:
|
||||
BPC_HealthSystem.SetHealth(MaxHealth)
|
||||
└─► Else:
|
||||
BPC_HealthSystem.SetHealth(MaxHealth * HealthRestorePercent)
|
||||
└─► If bClearStressOnRespawn:
|
||||
BPC_StressSystem.ResetStress()
|
||||
└─► If bRestoreStaminaOnRespawn:
|
||||
BPC_StaminaSystem.SetStamina(MaxStamina)
|
||||
|
||||
[GetRespawnTransform]
|
||||
└─► Get BP_Checkpoint from Owner
|
||||
└─► Return BP_Checkpoint.GetRespawnTransform()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communications With
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) | Direct call | Orchestrator triggers respawn |
|
||||
| [`BP_Checkpoint`](BP_Checkpoint.md) | Direct call | Get respawn transform |
|
||||
| [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) | Direct call | Restore health on respawn |
|
||||
| [`BPC_StaminaSystem`](../02-player/09_BPC_StaminaSystem.md) | Direct call | Restore stamina on respawn |
|
||||
| [`BPC_StressSystem`](../02-player/10_BPC_StressSystem.md) | Direct call | Reset stress on respawn |
|
||||
| [`SS_SaveManager`](35_SS_SaveManager.md) | Direct call | Load respawn state |
|
||||
| [`WBP_HUDController`](../06-ui/WBP_HUDController.md) | Dispatcher | Fade transitions |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
- RespawnDelay and RespawnFadeDuration are configurable per difficulty level
|
||||
- State restoration values (health %, stress reset, stamina) can be tuned via data assets
|
||||
- Split from original bundled `31_BPC_DeathHandlingSystem.md` per Clean Slate refactoring plan
|
||||
90
docs/blueprints/05-saveload/43_BPC_RunHistoryTracker.md
Normal file
90
docs/blueprints/05-saveload/43_BPC_RunHistoryTracker.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# BPC_RunHistoryTracker — Actor Component (Run History)
|
||||
|
||||
**File:** [`Content/Framework/Save/BPC_RunHistoryTracker`](Content/Framework/Save/BPC_RunHistoryTracker.uasset)
|
||||
|
||||
**Purpose:** Records session-level death and run data for the run summary screen (death recap, stats, journal entries tied to the run). Not saved to the main save file but stored per-session for display at game over.
|
||||
|
||||
**Depends On:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md)
|
||||
**Used By:** [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) (orchestrator), UI (Run Summary screen)
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `RunHistory` | Array of `S_DeathContext` | Every death this run, in order |
|
||||
| `RunStartTime` | FDateTime | When the current run started |
|
||||
| `RunEndTime` | FDateTime | When the run ended (game over or quit) |
|
||||
| `TotalDeathsThisRun` | Integer | Convenience counter |
|
||||
| `bIsNewRun` | Bool | True until the first death occurs |
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
| Name | Inputs | Outputs | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| `RecordDeath` | Context: S_DeathContext | — | Appends death to run history |
|
||||
| `GetRunHistory` | — | Array of S_DeathContext | Returns full death list |
|
||||
| `GetRunDuration` | — | FTimespan | RunStartTime to now |
|
||||
| `GetDeathCountThisRun` | — | Integer | Returns TotalDeathsThisRun |
|
||||
| `StartNewRun` | — | — | Clears history, sets RunStartTime to now |
|
||||
| `EndRun` | — | — | Sets RunEndTime to now |
|
||||
| `GetRunSummary` | — | FText | Formatted summary text for run recap UI |
|
||||
|
||||
---
|
||||
|
||||
## Event Dispatchers
|
||||
|
||||
| Name | Parameters | Fired When |
|
||||
|------|-----------|------------|
|
||||
| `OnDeathRecorded` | DeathIndex: Integer, Context: S_DeathContext | A death was added to history |
|
||||
| `OnRunStarted` | StartTime: FDateTime | StartNewRun was called |
|
||||
| `OnRunEnded` | Duration: FTimespan, DeathCount: Integer | EndRun was called |
|
||||
|
||||
---
|
||||
|
||||
## Blueprint Flow
|
||||
|
||||
```
|
||||
[RecordDeath: Context]
|
||||
└─► Append Context to RunHistory array
|
||||
└─► TotalDeathsThisRun = RunHistory.Length
|
||||
└─► bIsNewRun = false
|
||||
└─► Broadcast OnDeathRecorded(TotalDeathsThisRun - 1, Context)
|
||||
|
||||
[StartNewRun]
|
||||
└─► Clear RunHistory array
|
||||
└─► Set RunStartTime = CurrentDateTime
|
||||
└─► Set TotalDeathsThisRun = 0
|
||||
└─► Set bIsNewRun = true
|
||||
└─► Broadcast OnRunStarted(RunStartTime)
|
||||
|
||||
[EndRun]
|
||||
└─► Set RunEndTime = CurrentDateTime
|
||||
└─► Broadcast OnRunEnded(GetRunDuration(), TotalDeathsThisRun)
|
||||
|
||||
[GetRunSummary]
|
||||
└─► Format: "Run Duration: {duration}\nDeaths: {count}\nDeath 1: {context.KillerTag} at {context.DeathLocation}"
|
||||
└─► Return formatted FText
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communications With
|
||||
|
||||
| Target System | Method | Why |
|
||||
|---------------|--------|-----|
|
||||
| [`BPC_DeathHandlingSystem`](BPC_DeathHandlingSystem.md) | Direct call | Orchestrator records deaths and ends runs |
|
||||
| [`GM_CoreGameMode`](../01-core/05_GM_CoreGameMode.md) | Direct call | Start new run on game start |
|
||||
| UI (WBP_RunSummary) | Dispatcher / Function | Display run summary on game over |
|
||||
| [`BPC_EndingAccumulator`](../07-narrative/BPC_EndingAccumulator.md) | Direct call | Death count feeds into ending evaluation |
|
||||
|
||||
---
|
||||
|
||||
## Reuse Notes
|
||||
- Run history is session-only and NOT serialised — it resets on game restart
|
||||
- The RunHistory array grows unbounded within a session (typically < 20 entries)
|
||||
- RunSummary text formatting can be overridden per project for localization
|
||||
- Split from original bundled `31_BPC_DeathHandlingSystem.md` per Clean Slate refactoring plan
|
||||
Reference in New Issue
Block a user