add architecture
This commit is contained in:
367
docs/architecture/CLEAN_SLATE_PLAN.md
Normal file
367
docs/architecture/CLEAN_SLATE_PLAN.md
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
# Clean Slate Refactoring Plan
|
||||||
|
|
||||||
|
**Date:** 2026-05-18
|
||||||
|
**Source:** `docs/blueprints/AUDIT_REPORT.md`
|
||||||
|
**Master:** `UE5_Modular_Game_Framework.md`
|
||||||
|
**Goal:** Every Master-defined system has exactly 1 blueprint spec file with matching name. No bundled files. Consistent directory structure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Problem Statement
|
||||||
|
|
||||||
|
The current `docs/blueprints/` tree has 83 files covering ~131 Master systems via bundling, renaming, and relocation. This makes blueprint authoring ambiguous: an implementer cannot find a Master system by its name because the file is renamed, bundled inside another file, or in the wrong directory. Clean Slate makes the mapping 1:1.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Proposed Solution
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[AUDIT_REPORT.md] --> B[Step 1: Rename 18 files to match Master]
|
||||||
|
B --> C[Step 2: Split 2 bundled files into 12 individual files]
|
||||||
|
C --> D[Step 3: Create 12 new Data Asset spec files in 12-data/]
|
||||||
|
D --> E[Step 4: Create 30 new runtime system spec files in existing directories]
|
||||||
|
E --> F[Step 5: Reorganize 11-polish/ into 3 sub-directories]
|
||||||
|
F --> G[Step 6: Remove obsolete bundled umbrella files]
|
||||||
|
G --> H[Step 7: Renumber all files sequentially across all directories]
|
||||||
|
H --> I[Final: ~155 files, 1:1 master-to-file mapping]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Target Directory Structure (Final State)
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/blueprints/
|
||||||
|
├── TEMPLATE.md
|
||||||
|
├── AUDIT_REPORT.md
|
||||||
|
├── 01-core/ (12 files) — GameInstance, GameMode, GameState, Subsystems, Interfaces, FL, DataAssets
|
||||||
|
├── 02-player/ (9 files) — All BPC_ player components + contextual traversal
|
||||||
|
├── 03-interaction/ (11 files) — Interaction detection/execution, doors, puzzles, hiding spots, physics
|
||||||
|
├── 04-inventory/ (12 files) — Inventory, equipment, items, combine, documents, journal, collectibles
|
||||||
|
├── 05-saveload/ (9 files) — SaveManager, Persistable, Checkpoint, DeathOrchestrator, 4 death sub-systems
|
||||||
|
├── 06-ui/ (13 files) — HUD, menus (1 per widget), notifications, screen effects, menu flow
|
||||||
|
├── 07-narrative/ (11 files) — Narrative state, objectives, dialogue, choices, cutscenes, endings, lore
|
||||||
|
├── 08-weapons/ (12 files) — Weapons, melee, firearms, ammo, damage, recoil, reload, shield, reactions
|
||||||
|
├── 09-ai/ (9 files) — AI controller, perception, behavior trees, enemies, patrol, alert, state machine
|
||||||
|
├── 10-adaptive/ (9 files) — Atmosphere, lighting, audio, VFX, fear, pacing, procedural encounters
|
||||||
|
├── 11-meta/ (6 files) — Achievements, stats tracker, ending tracker, meta progression, run summary
|
||||||
|
├── 12-settings/ (5 files) — Settings system, accessibility, haptics, platform abstraction, settings UI
|
||||||
|
├── 13-polish/ (10 files) — Tutorial, loading, credits, splash, FPS, cheats, debug, analytics, error handler
|
||||||
|
└── 14-data-assets/ (13 files) — 1 Data Asset Architecture overview + 12 individual DA_ specs
|
||||||
|
```
|
||||||
|
|
||||||
|
**Total files: ~155 (including TEMPLATE.md and AUDIT_REPORT.md)**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Operation Details
|
||||||
|
|
||||||
|
### 4.1 RENAME Operations (18 files)
|
||||||
|
|
||||||
|
Each rename changes the filename to match the Master document system name exactly.
|
||||||
|
|
||||||
|
| Current File | Directory | New Name | Master Ref | Reason |
|
||||||
|
|-------------|-----------|----------|------------|--------|
|
||||||
|
| `22_BPC_InventoryComponent.md` | 04-inventory | `BPC_InventorySystem.md` | Sec 4.1 | Master name |
|
||||||
|
| `25_BPC_EquipmentSystem.md` | 04-inventory | `BPC_EquipmentSlotSystem.md` | Sec 4.2 | Master name |
|
||||||
|
| `50_BP_RangedWeapon.md` | 08-weapons | `BPC_FirearmSystem.md` | Sec 5.2 | Wrong prefix + Master name |
|
||||||
|
| `51_BP_MeleeWeapon.md` | 08-weapons | `BPC_MeleeSystem.md` | Sec 5.1 | Wrong prefix + Master name |
|
||||||
|
| `53_BPC_DamageHandlerComponent.md` | 08-weapons | `BPC_DamageReceptionSystem.md` | Sec 5.6 | Master name |
|
||||||
|
| `33_WBP_HUD.md` | 06-ui | `WBP_HUDController.md` | Sec 6.1 | Master name |
|
||||||
|
| `35_WBP_InteractionUI.md` | 06-ui | `WBP_InteractionPromptDisplay.md` | Sec 6.3 | Master name |
|
||||||
|
| `34_WBP_InventoryUI.md` | 06-ui | `WBP_InventoryMenu.md` | Sec 6.4 | Master name |
|
||||||
|
| `45_BPC_EndingAccumulatorSystem.md` | 07-narrative | `BPC_EndingAccumulator.md` | Sec 7.8 | Drop System suffix |
|
||||||
|
| `47_BPC_NarrativeTriggerVolume.md` | 07-narrative | `BP_NarrativeTriggerVolume.md` | Sec 7.10 | Component→Actor |
|
||||||
|
| `55_BPC_AIControllerBase.md` | 09-ai | `AI_BaseAgentController.md` | Sec 10.1 | Master type prefix |
|
||||||
|
| `56_BPC_PerceptionComponent.md` | 09-ai | `BPC_AIPerceptionSystem.md` | Sec 10.3 | Master name |
|
||||||
|
| `64_BPC_AtmosphereController.md` | 10-adaptive | `BPC_AtmosphereStateController.md` | Sec 9.4 | Master name |
|
||||||
|
| `65_BPC_LightingManager.md` | 10-adaptive | `BPC_LightEventController.md` | Sec 9.6 | Master name |
|
||||||
|
| `66_BPC_AudioManager.md` | 10-adaptive | `BPC_AudioAtmosphereController.md` | Sec 9.7 | Master name |
|
||||||
|
| `20_BPC_InteractableDoorComponent.md` | 03-interaction | `BP_DoorActor.md` | Sec 3.5 | Master type + name |
|
||||||
|
| `30_BPC_CheckpointSystem.md` | 05-saveload | `BP_Checkpoint.md` | Sec 8.1 | Verify master name |
|
||||||
|
| `28_SS_SaveManager.md` | 05-saveload | Keep as-is | Sec 1.2 | Master uses SS_SaveSystem; file content is the save manager. Decision: keep SS_SaveManager as it accurately describes the subsystem. |
|
||||||
|
|
||||||
|
**Note on file 28:** Master Section 1 calls it `SS_SaveSystem` but the file is named `SS_SaveManager` and contains full save management logic. The Master Section 8 may use `SS_SaveManager`. For Clean Slate consistency, the file stays as `SS_SaveManager` since that's what the detailed system definition calls it.
|
||||||
|
|
||||||
|
### 4.2 SPLIT Operations (2 bundled files → 12 individual files)
|
||||||
|
|
||||||
|
#### 4.2.1 Split `31_BPC_DeathHandlingSystem.md` → 5 files
|
||||||
|
|
||||||
|
The existing file (311 lines) contains the orchestrator component plus 4 sub-systems each with purpose, variables, functions, and event dispatchers. Each sub-system becomes a standalone file. The orchestrator keeps the parent-level enums, structs, core component variables, core functions, the flow diagram, and the communication matrix.
|
||||||
|
|
||||||
|
| # | New File | Source Lines | System Name |
|
||||||
|
|---|----------|-------------|-------------|
|
||||||
|
| 1 | `BPC_DeathHandlingSystem.md` | 1-64, 206-311 | Orchestrator (enums, structs, core vars, core fns, flow, matrix) |
|
||||||
|
| 2 | `BPC_AltDeathSpaceSystem.md` | 65-99 | Alt death space management |
|
||||||
|
| 3 | `BPC_PersistentCorpseSystem.md` | 102-132 | Corpse spawning and persistence |
|
||||||
|
| 4 | `BPC_PlayerRespawnSystem.md` | 136-167 | Respawn mechanics |
|
||||||
|
| 5 | `BPC_RunHistoryTracker.md` | 171-203 | Run-level death tracking |
|
||||||
|
|
||||||
|
**Mapping:** Master Section 8 lists `BPC_AltDeathSpaceSystem`, `BPC_PlayerRespawnSystem`, `BPC_RunHistoryTracker` as separate systems (8.5–8.7). The split matches the Master's structure.
|
||||||
|
|
||||||
|
#### 4.2.2 Split `36_WBP_MenuWidgets.md` → 7 files
|
||||||
|
|
||||||
|
The existing file (353 lines) bundles 6 widgets under one umbrella. Each widget has its own purpose, variables, functions, and in one case an enum. Split each into a standalone file.
|
||||||
|
|
||||||
|
| # | New File | Source Lines | Widget Name |
|
||||||
|
|---|----------|-------------|-------------|
|
||||||
|
| 1 | `WBP_MainMenu.md` | 15-48 | Title screen with New/Continue/Load/Settings/Credits/Quit |
|
||||||
|
| 2 | `WBP_PauseMenu.md` | 51-94 | In-game pause overlay |
|
||||||
|
| 3 | `WBP_SettingsMenu.md` | 99-188 | Full settings screen with 5 tabs |
|
||||||
|
| 4 | `WBP_NotificationToast.md` | 191-230 | Non-blocking toast notification |
|
||||||
|
| 5 | `WBP_ScreenEffectController.md` | 233-261 | Damage vignettes, jump scare flash, stress distortion |
|
||||||
|
| 6 | `WBP_MenuFlowController.md` | 264-353 | Menu state transitions, fades, level loading |
|
||||||
|
| 7 | *(Extra)* `WBP_ObjectiveDisplay.md` | — | Not in bundled file; master lists it as 6.6 |
|
||||||
|
|
||||||
|
**Mapping:** Master Section 6 lists all 6 widgets plus `WBP_ObjectiveDisplay` (Sec 6.6), `WBP_SubtitleDisplay` (Sec 6.7), `WBP_JournalDocumentViewer` (Sec 6.5), and `WBP_DiegeticHUDFrame` (Sec 6.2). The existing `37_WBP_AccessibilityUI.md` already covers subtitles. Two widgets remain missing (`WBP_JournalDocumentViewer`, `WBP_DiegeticHUDFrame` — addressed in section 4.4).
|
||||||
|
|
||||||
|
**Original umbrella file `36_WBP_MenuWidgets.md` is DELETED after splits.**
|
||||||
|
|
||||||
|
### 4.3 CREATE Operations — 12 Data Asset Specs (new `14-data-assets/` directory)
|
||||||
|
|
||||||
|
Master Section 13 defines 20 Data Asset types. 8 are already covered (`07_DA_ItemData.md`, `48_DA_NarrativeDataAssets.md` covers 5, `49_BP_WeaponBase.md` covers `DA_WeaponData`, `74_BPC_AchievementManager.md` implicitly covers `DA_AchievementData`). 12 have no spec.
|
||||||
|
|
||||||
|
Create these 13 files in a new `docs/blueprints/14-data-assets/` directory:
|
||||||
|
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `DA_DataAssetArchitecture.md` | Sec 13 overview | All 20 DA types, naming conventions, dependency rules, build order |
|
||||||
|
| 2 | `DA_InteractionData.md` | Sec 13 | Interaction prompt types, requirements, target filters |
|
||||||
|
| 3 | `DA_ObjectiveData.md` | Sec 13 | Objective definitions, states, rewards |
|
||||||
|
| 4 | `DA_EncounterData.md` | Sec 13 | Enemy encounter configurations |
|
||||||
|
| 5 | `DA_AtmosphereProfile.md` | Sec 13 | Lighting, audio, fog, post-process presets |
|
||||||
|
| 6 | `DA_ScareEvent.md` | Sec 13 | Scare trigger definitions, jump scares, ambient horror |
|
||||||
|
| 7 | `DA_RoomMutation.md` | Sec 13 | Environmental mutation content, memory drift |
|
||||||
|
| 8 | `DA_BehaviourVariant.md` | Sec 13 | AI behavior variant stats, aggression, patrol patterns |
|
||||||
|
| 9 | `DA_HapticProfile.md` | Sec 13 | DualSense/DualShock haptic patterns |
|
||||||
|
| 10 | `DA_AdaptationRule.md` | Sec 13 | Adaptive director rule sets |
|
||||||
|
| 11 | `DA_EquipmentConfig.md` | Sec 13 | Equipment slot configurations |
|
||||||
|
| 12 | `DA_PuzzleData.md` | Sec 13 | Puzzle solution definitions, input/output mappings |
|
||||||
|
| 13 | `DA_RareEvent.md` | Sec 13 | Rare world event definitions |
|
||||||
|
|
||||||
|
**Each Data Asset spec must include:** Parent Class (`UDataAsset`), Gameplay Tags namespace, struct definition for rows, example data rows, validation rules, and which systems consume it.
|
||||||
|
|
||||||
|
### 4.4 CREATE Operations — 30 Runtime System Specs (in existing directories)
|
||||||
|
|
||||||
|
#### 03-interaction/ (add 4 files)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_PhysicsDragSystem.md` | Sec 3.4 | Physics grab, drag, throw |
|
||||||
|
| 2 | `BPC_ContextualTraversalSystem.md` | Sec 3.8 | Vault, climb, ledge grab |
|
||||||
|
| 3 | `BP_PuzzleDeviceActor.md` | Sec 3.9 | Generic puzzle with input/output |
|
||||||
|
| 4 | `BPC_UsableWorldObjectSystem.md` | Sec 3.10 | Light switches, levers, simple on/off objects |
|
||||||
|
|
||||||
|
#### 04-inventory/ (add 7 files)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_ActiveItemSystem.md` | Sec 4.3 | Active hand item, raise/lower animations |
|
||||||
|
| 2 | `BPC_ItemCombineSystem.md` | Sec 4.5 | Item combination mechanic |
|
||||||
|
| 3 | `BPC_DocumentArchiveSystem.md` | Sec 4.6 | Document/note storage and reading |
|
||||||
|
| 4 | `BPC_JournalSystem.md` | Sec 4.7 | Player journal with entries |
|
||||||
|
| 5 | `BPC_CollectibleTracker.md` | Sec 4.8 | Collectible discovery tracking |
|
||||||
|
| 6 | `BPC_ConsumableSystem.md` | Sec 4.9 | Consumable item usage logic |
|
||||||
|
| 7 | `BPC_KeyItemSystem.md` | Sec 4.11 | Key item management and protection |
|
||||||
|
|
||||||
|
#### 05-saveload/ (add 1 file)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_PersistentWorldStateRecorder.md` | Sec 8.2 | World state recording for save (currently bundled in SS_SaveManager) |
|
||||||
|
|
||||||
|
#### 06-ui/ (add 3 files)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `WBP_DiegeticHUDFrame.md` | Sec 6.2 | Swappable diegetic HUD skin |
|
||||||
|
| 2 | `WBP_JournalDocumentViewer.md` | Sec 6.5 | Document and journal display widget |
|
||||||
|
| 3 | `WBP_ObjectiveDisplay.md` | Sec 6.6 | Objective overlay widget |
|
||||||
|
|
||||||
|
#### 08-weapons/ (add 5 files)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_RecoilSystem.md` | Sec 5.3 | Procedural recoil |
|
||||||
|
| 2 | `BPC_ReloadSystem.md` | Sec 5.4 | Weapon reload management |
|
||||||
|
| 3 | `BPC_ShieldDefenseSystem.md` | Sec 5.5 | Blocking and parrying |
|
||||||
|
| 4 | `BPC_HitReactionSystem.md` | Sec 5.7 | Hit reaction behaviour |
|
||||||
|
| 5 | `BPC_DeathCauseTracker.md` | Sec 5.8 | Death cause logging |
|
||||||
|
|
||||||
|
**Note:** `BPC_AmmoResourceSystem` (Sec 4.10) is handled by moving/renaming `52_BPC_AmmoComponent.md` from 08-weapons to 04-inventory.
|
||||||
|
|
||||||
|
#### 09-ai/ (add 3 files + relocate 1)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BB_AgentBoard.md` | Sec 10.2 | Blackboard asset for AI agents |
|
||||||
|
| 2 | `BPC_AIMemorySystem.md` | Sec 10.4 | AI memory of player actions |
|
||||||
|
| 3 | `BPC_BehaviourVariantSelector.md` | Sec 10.5 | Behaviour variant selection |
|
||||||
|
| 4 | `BPC_EncounterDirector.md` | Sec 10.6 | Relocated from 10-adaptive (currently `70_BPC_ProceduralEncounter.md`) |
|
||||||
|
|
||||||
|
#### 10-adaptive/ (add 5 files)
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_PlaystyleClassifier.md` | Sec 9.1 | Player playstyle analysis |
|
||||||
|
| 2 | `BPC_AdaptiveEnvironmentDirector.md` | Sec 9.2 | Master adaptive controller |
|
||||||
|
| 3 | `BPC_MemoryDriftSystem.md` | Sec 9.3 | Room mutation / environmental drift |
|
||||||
|
| 4 | `BPC_ScareEventSystem.md` | Sec 9.5 | Scare event scheduling and triggering |
|
||||||
|
| 5 | `BPC_PacingDirector.md` | Sec 9.8 | Tension and pacing control |
|
||||||
|
| 6 | `BPC_RareEventSystem.md` | Sec 9.9 | Rare world events |
|
||||||
|
|
||||||
|
#### New 11-meta/ directory (move 3 from 11-polish + add 3 new)
|
||||||
|
Existing files to move from 11-polish:
|
||||||
|
- `74_BPC_AchievementManager.md` → `SS_AchievementSystem.md`
|
||||||
|
- `75_BPC_StatsTracker.md` → `BPC_ProgressStatTracker.md`
|
||||||
|
|
||||||
|
New files:
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_EndingCompletionTracker.md` | Sec 11.4 | Ending tracking across save files |
|
||||||
|
| 2 | `BPC_MetaProgressionSystem.md` | Sec 11.5 | NG+ unlock system |
|
||||||
|
| 3 | `BPC_RunSummarySystem.md` | Sec 11.6 | End-of-run summary generation |
|
||||||
|
|
||||||
|
#### New 12-settings/ directory (move 2 from 11-polish + add 2 new)
|
||||||
|
Existing files to move from 11-polish:
|
||||||
|
- `71_SS_SettingsManager.md` → `SS_SettingsSystem.md`
|
||||||
|
- `72_BPC_AccessibilitySettings.md`
|
||||||
|
|
||||||
|
New files:
|
||||||
|
| # | File | Master Ref | Purpose |
|
||||||
|
|---|------|------------|---------|
|
||||||
|
| 1 | `BPC_HapticsController.md` | Sec 12.2 | Haptic feedback (DualSense) |
|
||||||
|
| 2 | `BPC_PlatformServiceAbstraction.md` | Sec 12.3 | Platform API abstraction layer |
|
||||||
|
|
||||||
|
### 4.5 REORGANIZE Operations — 11-polish/ split into 3 directories
|
||||||
|
|
||||||
|
The current `11-polish/` directory has 13 files spanning 3 different Master sections plus extras. Split into:
|
||||||
|
|
||||||
|
**11-meta/** (6 files) — Achievement, progression, meta systems:
|
||||||
|
- `SS_AchievementSystem.md` (from `74_BPC_AchievementManager.md`)
|
||||||
|
- `DA_AchievementData.md` (extracted from achievement manager or optionally kept bundled)
|
||||||
|
- `BPC_ProgressStatTracker.md` (from `75_BPC_StatsTracker.md`)
|
||||||
|
- `BPC_EndingCompletionTracker.md` (new)
|
||||||
|
- `BPC_MetaProgressionSystem.md` (new)
|
||||||
|
- `BPC_RunSummarySystem.md` (new)
|
||||||
|
|
||||||
|
**12-settings/** (5 files) — Settings, accessibility, platform:
|
||||||
|
- `SS_SettingsSystem.md` (from `71_SS_SettingsManager.md`)
|
||||||
|
- `BPC_AccessibilitySettings.md` (from `72_BPC_AccessibilitySettings.md`)
|
||||||
|
- `BPC_HapticsController.md` (new)
|
||||||
|
- `BPC_PlatformServiceAbstraction.md` (new)
|
||||||
|
- `WBP_SettingsMenu.md` (from 06-ui after menu split — it's the settings widget)
|
||||||
|
|
||||||
|
**13-polish/** (10 files) — Remaining polish/extras:
|
||||||
|
- `BPC_TutorialSystem.md` (from `73_BPC_TutorialSystem.md`)
|
||||||
|
- `BPC_LoadingScreen.md` (from `76_BPC_LoadingScreen.md`)
|
||||||
|
- `WBP_CreditsScreen.md` (from `77_WBP_CreditsScreen.md`)
|
||||||
|
- `WBP_SplashScreen.md` (from `78_WBP_SplashScreen.md`)
|
||||||
|
- `BPC_FPSCounter.md` (from `79_BPC_FPSCounter.md`)
|
||||||
|
- `BPC_DevCheatManager.md` (from `80_BPC_DevCheatManager.md`)
|
||||||
|
- `WBP_DebugMenu.md` (from `81_WBP_DebugMenu.md`)
|
||||||
|
- `BPC_AnalyticsTracker.md` (from `82_BPC_AnalyticsTracker.md`)
|
||||||
|
- `BPC_ErrorHandler.md` (from `83_BPC_ErrorHandler.md`)
|
||||||
|
- `WBP_NotificationToast.md` (relocated from 06-ui after menu split — it's a global toast, not menu-specific)
|
||||||
|
|
||||||
|
### 4.6 RENUMBER Operations
|
||||||
|
|
||||||
|
After all renames, splits, creates, and reorganizations, assign sequential numbering starting from 01. Numbering is global across all directories (keeps the current convention).
|
||||||
|
|
||||||
|
**Numbering Priority Order:**
|
||||||
|
1. 01-core/ → 1–12
|
||||||
|
2. 02-player/ → 13–21
|
||||||
|
3. 03-interaction/ → 22–32
|
||||||
|
4. 04-inventory/ → 33–44
|
||||||
|
5. 05-saveload/ → 45–53
|
||||||
|
6. 06-ui/ → 54–66
|
||||||
|
7. 07-narrative/ → 67–77
|
||||||
|
8. 08-weapons/ → 78–89
|
||||||
|
9. 09-ai/ → 90–98
|
||||||
|
10. 10-adaptive/ → 99–107
|
||||||
|
11. 11-meta/ → 108–113
|
||||||
|
12. 12-settings/ → 114–118
|
||||||
|
13. 13-polish/ → 119–128
|
||||||
|
14. 14-data-assets/ → 129–141
|
||||||
|
|
||||||
|
**Total: ~141 numbered files + TEMPLATE.md + AUDIT_REPORT.md = ~143 total**
|
||||||
|
|
||||||
|
### 4.7 DELETE Operations
|
||||||
|
|
||||||
|
| File to Delete | Reason |
|
||||||
|
|---------------|--------|
|
||||||
|
| `06-ui/36_WBP_MenuWidgets.md` | Split into 7 individual widget files |
|
||||||
|
| `05-saveload/31_BPC_DeathHandlingSystem.md` (original) | Replaced by 5 split files |
|
||||||
|
| `03-interaction/17_BPC_PickupComponent.md` | Not in Master; functionality covered by InteractionExecutor + ItemPickup |
|
||||||
|
| `03-interaction/19_BPC_LeverPuzzleComponent.md` | Not in Master; covered by `BP_PuzzleDeviceActor` |
|
||||||
|
| `04-inventory/23_BPC_InventoryWeightSystem.md` | Not in Master; weight is a sub-feature of InventorySystem |
|
||||||
|
| `04-inventory/24_BPC_InventoryQuickSlot.md` | Not in Master; quick slots are sub-feature of ActiveItemSystem |
|
||||||
|
| `09-ai/57_BPC_BehaviorTreeManager.md` | Not in Master; covered by `BB_AgentBoard` + `BPC_BehaviourVariantSelector` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. File Count Summary
|
||||||
|
|
||||||
|
| Phase | Operation | Count |
|
||||||
|
|-------|-----------|-------|
|
||||||
|
| **Start** | Existing files (including TEMPLATE + AUDIT) | 85 |
|
||||||
|
| | Rename (in-place, no net change) | 18 |
|
||||||
|
| | Split 2 bundled → 12 individual (-2 +12) | +10 |
|
||||||
|
| | Create new runtime specs | +30 |
|
||||||
|
| | Create new Data Asset specs | +13 |
|
||||||
|
| | Reorganize (move across dirs, no net change) | 0 |
|
||||||
|
| | Delete extra/unmatched files | -7 |
|
||||||
|
| **End** | **Final file count** | **~141** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Dependencies and Rules
|
||||||
|
|
||||||
|
### Content Creation Rules (for Execution Agent)
|
||||||
|
1. Every new file MUST follow [`TEMPLATE.md`](../blueprints/TEMPLATE.md) format
|
||||||
|
2. Parent Class, Dependencies, Purpose are mandatory sections
|
||||||
|
3. Variables must have Name, Type, Description columns
|
||||||
|
4. Functions must have Name, Inputs, Outputs, Description columns
|
||||||
|
5. Event Dispatchers must have Name, Parameters, "Fired When" columns
|
||||||
|
6. Every spec must include a Blueprint Flow Diagram (Mermaid)
|
||||||
|
7. Every spec must include a Communication Matrix
|
||||||
|
8. Every spec must include Reuse Notes
|
||||||
|
|
||||||
|
### Master Document Authority
|
||||||
|
- The Master document (`UE5_Modular_Game_Framework.md`) is the single source of truth for system names, types, and dependencies
|
||||||
|
- When in doubt about a variable or function name, consult the Master document section for that system
|
||||||
|
- If the Master document does not specify a detail, use the naming conventions defined in Section 13 of the Master
|
||||||
|
|
||||||
|
### Naming Conventions (from Master Section 13)
|
||||||
|
| Prefix | Asset Type |
|
||||||
|
|--------|-----------|
|
||||||
|
| `BP_` | Blueprint Actor |
|
||||||
|
| `BPC_` | Blueprint Actor Component |
|
||||||
|
| `WBP_` | Widget Blueprint |
|
||||||
|
| `I_` | Blueprint Interface |
|
||||||
|
| `DA_` | Data Asset |
|
||||||
|
| `E_` | Enumeration |
|
||||||
|
| `S_` | Structure |
|
||||||
|
| `GI_` | Game Instance |
|
||||||
|
| `GM_` | Game Mode |
|
||||||
|
| `GS_` | Game State |
|
||||||
|
| `SS_` | Subsystem |
|
||||||
|
| `FL_` | Function Library |
|
||||||
|
| `AI_` | AI Controller |
|
||||||
|
| `BB_` | Blackboard |
|
||||||
|
| `BTT_` | Behavior Tree Task |
|
||||||
|
| `BTS_` | Behavior Tree Service |
|
||||||
|
| `BTD_` | Behavior Tree Decorator |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Success Criteria
|
||||||
|
|
||||||
|
1. Every system in the Master document (Sections 1–13) has exactly 1 blueprint spec file
|
||||||
|
2. Every blueprint spec file name matches the Master system name exactly (including prefix)
|
||||||
|
3. No file bundles multiple Master-defined systems
|
||||||
|
4. Directory structure maps cleanly to Master sections
|
||||||
|
5. All markdown cross-references (`[link](file.md)`) are valid
|
||||||
|
6. All files follow TEMPLATE.md format
|
||||||
|
7. Sequential file numbering is contiguous from 01 to ~141
|
||||||
|
8. AUDIT_REPORT.md is updated to reflect final state (all ✅)
|
||||||
|
9. CONTEXT.md is updated with final directory structure and file count
|
||||||
|
10. `git status` shows clean, logical file operations (renames detected as renames, not delete+create)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*End of Clean Slate Plan*
|
||||||
282
docs/architecture/animation-catalog.md
Normal file
282
docs/architecture/animation-catalog.md
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
# Animation Requirements Catalog — Modular Game Framework
|
||||||
|
|
||||||
|
**For: Animator / Technical Animator | UE 5.5–5.7 | GASP-Based**
|
||||||
|
|
||||||
|
This catalog lists every animation asset needed across all 135 blueprint systems, organized by system category, with trigger, type, body region, and GASP integration notes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Use This Catalog
|
||||||
|
|
||||||
|
1. **Montages** = Root motion or in-place split into sections with notifies
|
||||||
|
2. **BlendSpaces** = Parameter-driven blending (speed, direction, strafe angle)
|
||||||
|
3. **PoseAssets** = Single-frame poses for IK targets or overlay blending
|
||||||
|
4. **IK Rigs** = Procedural arm/leg positioning
|
||||||
|
|
||||||
|
**GASP Integration Rule:** All full-body locomotion animations route through [`ABP_GASP`](../CONTEXT.md:9). Systems notify GASP via dispatchers; GASP reads state variables and selects the correct animation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Locomotion System (GASP Core — Extended, Not Replaced)
|
||||||
|
|
||||||
|
| Trigger | Asset Type | Body | Notes |
|
||||||
|
|---------|-----------|------|-------|
|
||||||
|
| `Idle` → `Walking` → `Jogging` → `Sprinting` | **BlendSpace** | Full | GASP core locomotion blend. Speed + direction + strafe angle as params. Extended by framework: extra sprint variant for exhaustion, injured walk variant |
|
||||||
|
| `Crouching` + moving | **BlendSpace** | Full | Crouch locomotion. Speed as param. Separate from standing blendspace |
|
||||||
|
| `Prone` / `Crawling` | **BlendSpace** or **Montage** | Full | Prone crawl. Slow. Forward only initially, with strafe variants |
|
||||||
|
| `Jump Start` / `Jump Loop` / `Jump Land` | **Montage** (3 sections) | Full | Jump with velocity-based land (soft/hard). Motion matching picks jump type |
|
||||||
|
| `Fall Loop` | **BlendSpace** | Full | Falling animation based on vertical velocity |
|
||||||
|
| `Land Soft` / `Land Hard` / `Land Roll` | **Montage** | Full | Velocity threshold determines land type. `OnLanded` dispatcher drives selection |
|
||||||
|
| `Turn In Place` (90°, 180°) | **Montage** | Full | Root motion turn. Triggered by GASP when exceeding rotation threshold |
|
||||||
|
| `Start Walk` / `Stop Walk` | **BlendSpace** (inertialization) | Full | GASP handles via motion matching — no separate asset needed |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Player Vital States
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_HealthSystem` (08) | `OnDeath` | **Montage** (4 sections) | Full | `E_DeathAnimationStage`: PreDeath (stagger), DeathAnim (fall), PostDeath (dark), RespawnTransition (fade-up). Directional death variants (front/back/left/right) |
|
||||||
|
| `BPC_HealthSystem` (08) | `OnDamageTaken` (minor) | **Montage** (upper overlay) | Upper | Flinch reaction, brief |
|
||||||
|
| `BPC_StaminaSystem` (09) | `OnExhaustionStateChanged` → Exhausted | **Montage** (loop) | Upper | Heavy breathing + hunched posture. `ABP_GASP` reads `bExhausted` |
|
||||||
|
| `BPC_StaminaSystem` (09) | Exhausted → Sprint attempt | **Montage** | Full | Failed sprint start — stumble |
|
||||||
|
| `BPC_StressSystem` (10) | `OnStressTierChanged` → Panicked | **PoseAsset** | Full | Shaky hands, rapid breathing chest rise. Blend weight scales with stress |
|
||||||
|
| `BPC_StressSystem` (10) | `OnStressTierChanged` → Catatonic | **Montage** | Full | Freeze in place, stumble, collapse |
|
||||||
|
| `BPC_StressSystem` (10) | `OnHallucinationTriggered` | **Montage** (upper) | Upper | Flinch at hallucination, head whip |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Hiding & Stealth
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_HidingSystem` (12) | `EnterHideSpot` (Locker) | **Montage** | Full | Open locker, step in, close door. Notify: `OnAnimationHideEnterComplete` |
|
||||||
|
| `BPC_HidingSystem` (12) | `EnterHideSpot` (BehindCover) | **Montage** | Full | Crouch behind cover, settle |
|
||||||
|
| `BPC_HidingSystem` (12) | `EnterHideSpot` (Under) | **Montage** | Full | Crawl under bed/table |
|
||||||
|
| `BPC_HidingSystem` (12) | `EnterHideSpot` (InShadow) | **Montage** | Full | Step into shadow, blend with darkness |
|
||||||
|
| `BPC_HidingSystem` (12) | `EnterHideSpot` (TallGrass) | **BlendSpace** (crouch) | Full | Crouch-walk through vegetation (locomotion, not one-shot) |
|
||||||
|
| `BPC_HidingSystem` (12) | `ExitHideSpot` (all types) | **Montage** | Full | Reverse of enter. `bForceExit` skips animation |
|
||||||
|
| `BPC_HidingSystem` (12) | `ExitHideSpot` (forced — enemy discovered) | **Montage** | Full | Burst out stumbling |
|
||||||
|
| `BPC_HidingSystem` (12) | `StartPeek` (Left/Right/Over) | **PoseAsset** (blend) | Upper | Lean/peek pose. Not full-body — camera shifts |
|
||||||
|
| `BPC_HidingSystem` (12) | `HoldBreath Start` / `HoldBreath End` | **Montage** (upper) | Upper | Hand over mouth, exhale |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Interaction & World Manipulation
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BP_DoorActor` (19) | `Open` / `Close` | **Timeline** (world) | — | Door mesh rotation — not a character anim |
|
||||||
|
| `BP_ItemPickup` (25) | `BeingPickedUp` | **Montage** | Arms | Reach down, grab item, pocket. Notify: `OnPickupAnimationComplete` |
|
||||||
|
| `BP_ItemPickup` (25) | `Idle Bob` / `Rotate` | **Timeline** (world) | — | Item floating bobbing/rotating — not character |
|
||||||
|
| `BPC_ContextualTraversalSystem` (21) | `Vault` | **Montage** (root motion) | Full | Hands on obstacle, vault over. Motion Warping to obstacle edge |
|
||||||
|
| `BPC_ContextualTraversalSystem` (21) | `Mantle` | **Montage** (root motion) | Full | Grab ledge, pull up, step over. Motion Warping to ledge top |
|
||||||
|
| `BPC_ContextualTraversalSystem` (21) | `Slide` | **Montage** (root motion) | Full | Slide under low obstacle |
|
||||||
|
| `BPC_ContextualTraversalSystem` (21) | `Squeeze` | **Montage** (root motion) | Full | Side-step through narrow gap |
|
||||||
|
| `BPC_ContextualTraversalSystem` (21) | `LedgeGrab` / `LedgeHang` | **Montage** (loop) + **PoseAsset** | Full | Hanging from ledge. Motion Warping to ledge edge |
|
||||||
|
| `BPC_PhysicsDragSystem` (22) | `GrabObject` | **PoseAsset** (IK) | Arms | Hand IK target to grab socket |
|
||||||
|
| `BPC_PhysicsDragSystem` (22) | `DragObject` (moving) | **BlendSpace** (upper overlay) | Upper | Walking while dragging. IK hand stays locked |
|
||||||
|
| `BPC_UsableWorldObjectSystem` (23) | `UseLever` / `UsePanel` / `UseValve` | **Montage** (upper) | Upper | Hand reaches to interaction point. IK to target socket |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Weapon & Combat — General
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BP_WeaponBase` (69) | `Equip` (from holster) | **Montage** | Upper | Draw weapon animation. `E_EquipAnimationType.Equip` |
|
||||||
|
| `BP_WeaponBase` (69) | `Holster` (to holster) | **Montage** | Upper | Holster animation. `E_EquipAnimationType.Holster` |
|
||||||
|
| `BP_WeaponBase` (69) | `Unequip` (drop/switch) | **Montage** | Upper | Reverse of equip |
|
||||||
|
| `BPC_EquipmentSlotSystem` (30) | `InstantEquip` | None | — | No animation — weapon appears instantly |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Firearm Combat
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_FirearmSystem` (74) | `Fire` (Pistol) | **Montage** (single) | Upper | Recoil + slide cycle. Notify: `OnAmmoConsumed` |
|
||||||
|
| `BPC_FirearmSystem` (74) | `Fire` (Shotgun) | **Montage** | Upper | Pump action. Heavier recoil |
|
||||||
|
| `BPC_FirearmSystem` (74) | `Fire` (Rifle Auto) | **Montage** (loop) | Upper | Automatic fire loop until trigger released |
|
||||||
|
| `BPC_ReloadSystem` (78) | `TacticalReload` (ammo > 0) | **Montage** | Upper | Mag out, mag in. Notify: `OnMagOut`, `OnMagIn`, `OnReloadComplete` |
|
||||||
|
| `BPC_ReloadSystem` (78) | `EmptyReload` (ammo = 0) | **Montage** | Upper | Mag out, mag in, bolt cycle. Longer. Same notifies |
|
||||||
|
| `BPC_ReloadSystem` (78) | `ReloadInterrupt` | **Blend** | Upper | Blend back to idle from any reload notify point |
|
||||||
|
| `BPC_FirearmSystem` (74) | `ChamberCheck` | **Montage** (upper) | Upper | Quick chamber check animation |
|
||||||
|
| `BPC_RecoilSystem` (77) | `Recoil` (per shot) | **Procedural** (spring arm) | — | Camera recoil + hand animation via spring arm offset. Not a montage |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Melee Combat
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_MeleeSystem` (76) | `LightAttack` (Combo 1/2/3) | **Montage** | Upper | 3-hit combo. Sections: Combo_1, Combo_2, Combo_3. Notify: `Notify_Windup`, `Notify_Active`, `Notify_Recovery`, `Notify_CanCombo` |
|
||||||
|
| `BPC_MeleeSystem` (76) | `HeavyAttack` | **Montage** | Upper | Slow windup, high damage. `E_AttackType.HeavyAttack` |
|
||||||
|
| `BPC_MeleeSystem` (76) | `ChargeAttack` | **Montage** | Upper | Hold to charge, release to strike. Charge duration tracked |
|
||||||
|
| `BPC_MeleeSystem` (76) | `SprintAttack` | **Montage** | Upper | Running melee attack |
|
||||||
|
| `BPC_MeleeSystem` (76) | `Block Start` / `Block Loop` / `Block End` | **Montage** (loop) | Upper | Block stance loop. Owner movement speed reduced |
|
||||||
|
| `BPC_MeleeSystem` (76) | `Parry` | **Montage** | Upper | Quick parry deflection. Active window via `Notify_ParryWindow` |
|
||||||
|
| `BPC_MeleeSystem` (76) | `ParryRiposte` | **Montage** | Upper | Counter-attack after successful parry |
|
||||||
|
| `BPC_ShieldDefenseSystem` (79) | `ShieldRaise` / `ShieldLower` | **Montage** | Upper | Raise/lower shield |
|
||||||
|
| `BPC_ShieldDefenseSystem` (79) | `Block Impact` (shield hit) | **Montage** (additive) | Upper | Additive shake on shield hit |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Hit Reactions & Damage
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_HitReactionSystem` (75) | `OnDamageTaken` (Light) | **Montage** (additive) | Full | Flinch. Directional: front/back/left/right |
|
||||||
|
| `BPC_HitReactionSystem` (75) | `OnDamageTaken` (Heavy) | **Montage** | Full | Stagger backward. Directional |
|
||||||
|
| `BPC_HitReactionSystem` (75) | `OnDamageTaken` (Knockdown) | **Montage** | Full | Fall to ground |
|
||||||
|
| `BPC_HitReactionSystem` (75) | `GetUp` (from knockdown) | **Montage** | Full | Stand up from ground |
|
||||||
|
| `BPC_HitReactionSystem` (75) | `Stagger Loop` | **PoseAsset** (loop) | Full | Dazed swaying while standing |
|
||||||
|
| `BPC_DamageReceptionSystem` (72) | `Death` (instant, no death loop) | **Montage** | Full | Ragdoll-triggered death |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Death & Respawn
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_DeathHandlingSystem` (39) | `DeathAnim` (standard) | **Montage** | Full | See HealthSystem death — same asset, called via `E_DeathAnimationStage.DeathAnim` |
|
||||||
|
| `BPC_DeathHandlingSystem` (39) | `PreDeath` (camera lock) | **PoseAsset** (freeze) | Full | Freeze frame-like pose on killing blow |
|
||||||
|
| `BPC_DeathHandlingSystem` (39) | `RespawnTransition` | **PostProcess** (fade) | — | Screen fade-up — no skeletal anim |
|
||||||
|
| `BPC_AltDeathSpaceSystem` (38) | `EnterAltDeathSpace` | **Montage** | Full | Being pulled into void/portal |
|
||||||
|
| `BPC_AltDeathSpaceSystem` (38) | `Void Walk` | **BlendSpace** | Full | Walking in alt death space — slow, floating feel |
|
||||||
|
| `BPC_AltDeathSpaceSystem` (38) | `ExitAltDeathSpace` | **Montage** | Full | Emerging from void/portal back to world |
|
||||||
|
| `BPC_AltDeathSpaceSystem` (38) | `Void Idle` | **PoseAsset** | Full | Floating idle in void |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Narrative & Dialogue
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_DialoguePlaybackSystem` (60) | `OnLineStarted` | None | — | VO audio only. Lip-sync handled by audio waveform, not animation |
|
||||||
|
| `BPC_DialoguePlaybackSystem` (60) | `Dialogue Idle` | **PoseAsset** (upper) | Upper | Subtle hand gestures, head nods during dialogue. Blend by line intensity |
|
||||||
|
| `BPC_CutsceneBridge` (64) | Cutscene animation | **Level Sequence** | Full | All cutscene animation authored in Sequencer, not as montages |
|
||||||
|
| `BPC_CutsceneBridge` (64) | `Transition` (Fade/HardCut/Letterbox) | **PostProcess** (UWidget) | — | Black bars, fade overlay — UI animation |
|
||||||
|
| `BPC_NarrativeStateSystem` (58) | `OnMilestoneReached` (major) | None | — | May trigger cutscene or audio stinger |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. AI Enemy
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BP_EnemyBase` (80) | `Patrol Walk` | **BlendSpace** | Full | Slow patrol locomotion. Speed + direction params |
|
||||||
|
| `BP_EnemyBase` (80) | `Search Walk` | **BlendSpace** | Full | Faster search locomotion |
|
||||||
|
| `BP_EnemyBase` (80) | `Combat Strafe` | **BlendSpace** | Full | Strafing combat locomotion. Direction angle param |
|
||||||
|
| `BP_EnemyBase` (80) | `Flee Sprint` | **BlendSpace** | Full | Sprinting away |
|
||||||
|
| `BP_EnemyBase` (80) | `Attack` (melee) | **Montage** | Upper | Enemy-specific attack montage |
|
||||||
|
| `BP_EnemyBase` (80) | `Attack` (ranged) | **Montage** | Upper | Enemy-specific ranged attack |
|
||||||
|
| `BP_EnemyBase` (80) | `Hit Reaction` (light/heavy) | **Montage** | Full | Enemy hit reactions — same as player but different skeleton |
|
||||||
|
| `BP_EnemyBase` (80) | `Death` | **Montage** → **Ragdoll** | Full | Death animation blending to ragdoll |
|
||||||
|
| `BPC_AlertSystem` (82) | `Suspicious` (head turn) | **Montage** (additive) | Upper | Head snap toward sound. Body turn |
|
||||||
|
| `BPC_AlertSystem` (82) | `Alerted` (weapon raise) | **Montage** | Full | Raise weapon, enter combat stance |
|
||||||
|
| `BPC_AlertSystem` (82) | `Combat → Search` (weapon lower) | **Montage** | Full | Lower weapon, start searching |
|
||||||
|
| `BPC_BehaviourVariantSelector` (88) | Variant-specific attacks | **Montage** | Upper | Chooses from multiple variant attack sets |
|
||||||
|
| `BPC_FearSystem` (90) | `Fearful` (enemy) | **PoseAsset** | Full | Cowering, whimpering pose |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Embodiment & IK
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_EmbodimentSystem` (13) | `CheckWallProximity` | **IK Rig** (arms) | Arms | Arm IK offset when near walls. Notifies `ABP_Arms` |
|
||||||
|
| `BPC_EmbodimentSystem` (13) | `SetVisibilityMode` (ArmsOnly/FullBody/Hidden) | Mesh visibility toggle | — | Not an animation — mesh component visibility |
|
||||||
|
| `BPC_EmbodimentSystem` (13) | `OnOverlayChanged` (blood/water/dirt) | Material parameter | — | Overlay material swap on body mesh |
|
||||||
|
| `BPC_ConsumableSystem` (28) | `UseConsumable` (bandage, syringe) | **Montage** | Upper | Use item animation. IK hand to item |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Atmosphere & Environment (Non-Character)
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Notes |
|
||||||
|
|--------|---------|-----------|-------|
|
||||||
|
| `BPC_LightEventController` (96) | `OnLightEvent` | **Timeline** (light intensity/color) | Light flicker, dim, color shift via timeline |
|
||||||
|
| `BPC_AudioAtmosphereController` (95) | `OnAtmosphereChanged` | Audio fade (not anim) | Sound only |
|
||||||
|
| `BPC_MemoryDriftSystem` (97) | Memory distortion active | **PostProcess** | Screen distortion — not skeletal |
|
||||||
|
| `BPC_ScareEventSystem` (101) | `OnScareTriggered` | **Camera Shake** | Camera whip/shake |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. UI Widget Animations (Non-Skeletal)
|
||||||
|
|
||||||
|
| System | Trigger | Animation Type |
|
||||||
|
|--------|---------|---------------|
|
||||||
|
| All `WBP_` widgets | Open/Close/Show/Hide | `UWidgetAnimation` (fade, slide, pulse, scale) |
|
||||||
|
| `WBP_ScreenEffectController` (56) | Damage vignette, stress vignette | `UWidgetAnimation` (pulse, fade, color shift) |
|
||||||
|
| `WBP_NotificationToast` (53) | Show/Hide | `UWidgetAnimation` (slide in, auto-dismiss) |
|
||||||
|
| `WBP_InteractionPromptDisplay` (48) | Show/Hide | `UWidgetAnimation` (fade in/out) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary — Asset Count by Type
|
||||||
|
|
||||||
|
| Asset Type | Count (Approx) | Systems Served |
|
||||||
|
|-----------|----------------|----------------|
|
||||||
|
| **BlendSpaces** (locomotion) | 8–12 | Movement, AI, Hiding |
|
||||||
|
| **Montages** (action/reaction) | 40–55 | Weapons, Melee, Hiding, Death, Traversal, HitReaction, Enemy |
|
||||||
|
| **PoseAssets** | 8–12 | Stress, Peek, Embodiment, Idle |
|
||||||
|
| **IK Rigs** | 2–4 | Embodiment, Physics Drag |
|
||||||
|
| **Timelines** (non-skeletal) | 8–12 | Doors, Pickups, Lights, UI |
|
||||||
|
| **Procedural** (recoil, camera) | 2–4 | Recoil, Camera Shake |
|
||||||
|
| **Level Sequences** (cutscenes) | Per-content | Cutscene Bridge |
|
||||||
|
|
||||||
|
**Grand Total: ~70–100 skeletal animation assets + per-cutscene Level Sequences**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GASP Animation Notify Contract
|
||||||
|
|
||||||
|
The following animation notifies must be present in montages for the framework to function:
|
||||||
|
|
||||||
|
| Notify Name | Used By | Purpose |
|
||||||
|
|-------------|---------|---------|
|
||||||
|
| `Notify_Windup` | `BPC_MeleeSystem` | Begin melee hit detection window |
|
||||||
|
| `Notify_Active` | `BPC_MeleeSystem` | Enable hit collision overlap |
|
||||||
|
| `Notify_Recovery` | `BPC_MeleeSystem` | Disable hit collision, start combo window |
|
||||||
|
| `Notify_CanCombo` | `BPC_MeleeSystem` | Window during which next combo input is accepted |
|
||||||
|
| `Notify_ParryWindow` | `BPC_MeleeSystem` | Parry-active frames |
|
||||||
|
| `Notify_OnAnimationHideEnterComplete` | `BPC_HidingSystem` | Hide spot enter animation finished |
|
||||||
|
| `Notify_OnAnimationHideExitComplete` | `BPC_HidingSystem` | Hide spot exit animation finished |
|
||||||
|
| `Notify_OnMagOut` | `BPC_ReloadSystem` | Magazine removed from weapon |
|
||||||
|
| `Notify_OnMagIn` | `BPC_ReloadSystem` | Magazine inserted into weapon |
|
||||||
|
| `Notify_OnReloadComplete` | `BPC_ReloadSystem` | Reload finished, ammo refilled |
|
||||||
|
| `Notify_OnPickupAnimationComplete` | `BP_ItemPickup` | Pickup animation finished, item collected |
|
||||||
|
| `Notify_OnAmmoConsumed` | `BPC_FirearmSystem` | Ammo consumed during fire animation |
|
||||||
|
| `Notify_TraversalEnd` | `BPC_ContextualTraversalSystem` | Traversal animation complete, return to locomotion |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Priority Order for Animation Production
|
||||||
|
|
||||||
|
1. **GASP Locomotion Base** (Idle, Walk, Jog, Sprint, Crouch, Jump, Land, Turn) — required for any movement
|
||||||
|
2. **Hiding Enter/Exit** (Locker, BehindCover, Under) — core stealth mechanic
|
||||||
|
3. **Traversal** (Vault, Mantle, Slide, Squeeze, LedgeGrab) — level navigation
|
||||||
|
4. **Weapon Equip/Holster** (Pistol, Shotgun, Rifle, Melee, Shield) — combat foundation
|
||||||
|
5. **Weapon Fire/Reload/Melee** — combat moment-to-moment
|
||||||
|
6. **Hit Reactions** (Light/Heavy/Knockdown per direction) — combat feedback
|
||||||
|
7. **Death & Respawn** — game loop completion
|
||||||
|
8. **Interaction** (Pickup, Lever, Valve, Panel) — world interaction
|
||||||
|
9. **Stress/Fear/Exhaustion Poses** — atmosphere and tension
|
||||||
|
10. **AI Locomotion + Combat** — enemy behaviors
|
||||||
|
11. **Alt Death Space** — optional deep feature
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Animation Catalog v1.0 — Aligned with Modular Game Framework Blueprint Specs. Handoff-ready for Animator.*
|
||||||
|
## 16. New States — Sitting, Injured, Heart Rate (Breathing)
|
||||||
|
|
||||||
|
| System | Trigger | Asset Type | Body | Notes |
|
||||||
|
|--------|---------|-----------|------|-------|
|
||||||
|
| `BPC_StateManager` (NEW) | `Sitting` (entered via world interaction point) | **Montage** | Full | Sit down transition. Loop pose for idle sitting. Camera limited to head freelook |
|
||||||
|
| `BPC_StateManager` (NEW) | `StandUp` (from Sitting) | **Montage** | Full | Stand up transition |
|
||||||
|
| `BPC_StateManager` (NEW) | `Injured` (health ≤ 30%) | **BlendSpace** (locomotion overlay) | Full | Limping walk animation. Reduced speed. One arm favoring (visible on overlay) |
|
||||||
|
| `BPC_StateManager` (NEW) | `Injured` idle | **PoseAsset** | Full | Injured idle stance — favoring one side, shallow breathing |
|
||||||
|
| `BPC_StateManager` (NEW) | Heart rate breathing | **Blend** (additive on torso) | Upper | Breathing amplitude increases with `ABP_GASP.HeartRate` parameter. 60 BPM = shallow, 150+ BPM = heavy chest heaving |
|
||||||
|
| `BPC_StateManager` (NEW) | Heart rate — Erratic | **Blend** (additive, random variation) | Upper | Irregular breathing rhythm when `E_PlayerVitalSignals.Erratic`. Random amplitude jumps |
|
||||||
|
| `BPC_StateManager` (NEW) | `E_OverlayState.Injured` | **PoseAsset** (upper) | Upper | Injured arm lowered, favoring — applied via overlay system to GASP |
|
||||||
943
docs/architecture/bpc-statemanager.md
Normal file
943
docs/architecture/bpc-statemanager.md
Normal file
@@ -0,0 +1,943 @@
|
|||||||
|
# BPC_StateManager — Central Nervous System for the Modular Game Framework
|
||||||
|
|
||||||
|
**Architecture Document | UE 5.5–5.7 | GASP Compatible**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Problem Statement
|
||||||
|
|
||||||
|
The framework has 129 systems, each maintaining its own state machine with 36+ state-gated actions. Without a central authority, systems must hardcode knowledge of every other system's state to know whether an action is permitted. This creates tight coupling and makes adding new states (e.g., a new traversal type or weapon mode) a cascade-change across dozens of files. **BPC_StateManager** solves this by being the single source of truth for "what can the player do right now?"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Proposed Solution
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[Any System: Request Action] --> B[BPC_StateManager.RequestStateChange]
|
||||||
|
B --> C{Check Gating Rules}
|
||||||
|
C -->|Permitted| D[Set NewState + Fire OnStateChanged]
|
||||||
|
D --> E[Notify: ABP_GASP via SetOverlayState]
|
||||||
|
D --> F[Notify: BPC_MovementStateSystem]
|
||||||
|
D --> G[Notify: SS_EnhancedInputManager - context switch]
|
||||||
|
D --> H[Notify: All bound listeners]
|
||||||
|
C -->|Blocked| I[Return false + Reason]
|
||||||
|
I --> J[Requester handles rejection - show prompt, play denied sound]
|
||||||
|
```
|
||||||
|
|
||||||
|
BPC_StateManager sits on the Player Character. It does NOT control GASP's Motion Matching, Camera Manager, or AnimBP. It communicates with GASP exclusively through overlay states and animation notify events. Every other system queries `IsActionPermitted(Tag)` before executing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
Content/Framework/Player/
|
||||||
|
BPC_StateManager.uasset # NEW — Central state authority
|
||||||
|
|
||||||
|
Content/Framework/Core/
|
||||||
|
E_PlayerActionState.uasset # NEW — Exclusive action state enum
|
||||||
|
E_OverlayState.uasset # NEW — Upper-body overlay state enum
|
||||||
|
E_ActionRequestResult.uasset # NEW — Result enum for RequestStateChange
|
||||||
|
S_StateChangeRequest.uasset # NEW — Struct for state change request
|
||||||
|
S_StateGatingRule.uasset # NEW — Struct for gating rule
|
||||||
|
DA_StateGatingTable.uasset # NEW — Data Asset: all gating rules
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Enums
|
||||||
|
|
||||||
|
### 4.1 E_PlayerActionState — Exclusive Action States
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enum Name: E_PlayerActionState
|
||||||
|
(DisplayName = "Player Action State")
|
||||||
|
|
||||||
|
Values:
|
||||||
|
Idle = 0 // Standing, not performing any action
|
||||||
|
Walking = 1 // Moving at walk speed
|
||||||
|
Jogging = 2 // Moving at jog speed
|
||||||
|
Sprinting = 3 // Moving at sprint speed (stamina draining)
|
||||||
|
Crouching = 4 // Crouched posture, possibly moving
|
||||||
|
Crawling = 5 // Prone, crawling
|
||||||
|
Sitting = 6 // Sitting on surface — immobile, can look around
|
||||||
|
Vaulting = 7 // Transient — vaulting over obstacle
|
||||||
|
Climbing = 8 // Ledge or ladder climbing
|
||||||
|
Sliding = 9 // Transient — sliding under or down
|
||||||
|
Interacting = 10 // Performing a hold/press interaction
|
||||||
|
Inspecting = 11 // Inspecting an item in close-up view
|
||||||
|
InInventory = 12 // Inventory menu is open
|
||||||
|
InJournal = 13 // Journal/document viewer is open
|
||||||
|
InPauseMenu = 14 // Pause menu is open
|
||||||
|
InDialogue = 15 // In dialogue with an NPC
|
||||||
|
InCutscene = 16 // Pre-authored cutscene playing
|
||||||
|
SwingMelee = 17 // Performing a melee attack
|
||||||
|
AimingFirearm = 18 // Aiming a firearm
|
||||||
|
FiringFirearm = 19 // Firing a firearm (transient)
|
||||||
|
Reloading = 20 // Reloading a firearm
|
||||||
|
DeployingShield = 21 // Raising a shield
|
||||||
|
Hiding = 22 // Inside a hiding spot (enclosed/behind/under/shadow)
|
||||||
|
Peeking = 23 // Peeking from behind cover
|
||||||
|
GrabbingObject = 24 // Holding a physics object
|
||||||
|
UsingObject = 25 // Using a world object (lever, panel, etc.)
|
||||||
|
Dead = 26 // Dead — death animation playing or death loop active
|
||||||
|
InVoidSpace = 27 // In alt death / void space
|
||||||
|
InPuzzle = 28 // Using a puzzle device
|
||||||
|
InTrialScenario = 29 // In a timed trial scenario
|
||||||
|
InMainMenu = 30 // At main menu (no gameplay)
|
||||||
|
Loading = 31 // Loading screen active
|
||||||
|
DraggingCorpse = 32 // Dragging a physics body
|
||||||
|
HoldingBreath = 33 // Holding breath while hiding
|
||||||
|
Injured = 34 // Health ≤ threshold — reduced speed, limp anim, restricted actions
|
||||||
|
Staggered = 35 // Transient — hit reaction / stagger
|
||||||
|
KnockedDown = 36 // Knocked to ground
|
||||||
|
Exhausted = 37 // Stamina fully depleted — panting/immobile
|
||||||
|
Panicked = 38 // Stress at catatonic tier — stumble/freeze
|
||||||
|
PushingObject = 39 // Pushing a movable object
|
||||||
|
AimingThrowable = 40 // Aiming a throwable item
|
||||||
|
ThrowingItem = 41 // Throwing an item (transient)
|
||||||
|
UsingConsumable = 42 // Using a consumable (heal, inject, etc.)
|
||||||
|
InPhotoMode = 43 // Photo mode active — free cam, no gameplay input
|
||||||
|
CustomAction = 44 // Reserved for mod/expansion actions
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 E_PlayerVitalSignals — Vital Signal Enum for HeartRate / Breathing
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enum Name: E_PlayerVitalSignals
|
||||||
|
(DisplayName = "Player Vital Signals")
|
||||||
|
|
||||||
|
Values:
|
||||||
|
Normal = 0 // Heart rate 60-80 BPM — resting/exploring
|
||||||
|
Elevated = 1 // Heart rate 80-110 BPM — sprinting, light combat
|
||||||
|
High = 2 // Heart rate 110-150 BPM — heavy combat, chased
|
||||||
|
Critical = 3 // Heart rate 150+ BPM — near death, terrified
|
||||||
|
Erratic = 4 // Irregular rhythm — panic state, hallucinating
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 E_OverlayState — Upper-Body Overlay for GASP AnimBP
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enum Name: E_OverlayState
|
||||||
|
(DisplayName = "Upper Body Overlay State")
|
||||||
|
|
||||||
|
Values:
|
||||||
|
Empty = 0 // No overlay — default locomotion
|
||||||
|
Flashlight = 1 // Holding flashlight
|
||||||
|
Melee_OneHanded = 2 // One-handed melee weapon (knife, baton)
|
||||||
|
Melee_TwoHanded = 3 // Two-handed melee weapon (axe, pipe)
|
||||||
|
Pistol = 4 // Pistol / handgun
|
||||||
|
Shotgun = 5 // Shotgun
|
||||||
|
Rifle = 6 // Rifle / carbine
|
||||||
|
Shield = 7 // Shield only
|
||||||
|
Shield_And_Melee = 8 // Shield + one-handed melee
|
||||||
|
Shield_And_Pistol = 9 // Shield + pistol
|
||||||
|
DualWield = 10 // Dual-wielding one-handed weapons
|
||||||
|
Inspect = 11 // Inspecting an object
|
||||||
|
DualHand_Flashlight_Melee = 12 // Flashlight + melee
|
||||||
|
Injured = 13 // Injured arm (lowered, favoring)
|
||||||
|
Throwable = 14 // Holding a throwable (grenade, bottle)
|
||||||
|
Consumable = 15 // Using consumable (syringe, bandage)
|
||||||
|
TwoHanded_Heavy = 16 // Heavy two-handed (sledgehammer, chainsaw)
|
||||||
|
EmptyHands_Raised = 17 // Empty hands raised (surrender, blocking bare)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 E_ActionRequestResult
|
||||||
|
|
||||||
|
```text
|
||||||
|
Enum Name: E_ActionRequestResult
|
||||||
|
|
||||||
|
Values:
|
||||||
|
Permitted = 0 // State change approved
|
||||||
|
Blocked_CurrentState = 1 // Blocked because player is in an incompatible state
|
||||||
|
Blocked_GamePhase = 2 // Blocked by game phase (menu, cutscene, loading)
|
||||||
|
Blocked_Dead = 3 // Player is dead
|
||||||
|
Blocked_Stamina = 4 // Insufficient stamina
|
||||||
|
Blocked_Equipment = 5 // Missing required equipment
|
||||||
|
Blocked_Cooldown = 6 // Action on cooldown
|
||||||
|
Blocked_Custom = 7 // Blocked by a custom gating rule
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Structs
|
||||||
|
|
||||||
|
### 5.1 S_StateChangeRequest
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `RequestedState` | `E_PlayerActionState` | The state the requester wants to enter |
|
||||||
|
| `RequesterTag` | `GameplayTag` | Identifies which system is requesting |
|
||||||
|
| `Priority` | `Integer` | 0=Normal, 50=High, 100=Force (bypasses all gating) |
|
||||||
|
| `OverrideReason` | `Text` | Human-readable reason for override/force |
|
||||||
|
|
||||||
|
### 5.2 S_StateGatingRule
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `ActionTag` | `GameplayTag` | The action being gated |
|
||||||
|
| `BlockedStates` | `Array<E_PlayerActionState>` | States that block this action |
|
||||||
|
| `BlockedGamePhases` | `Array<E_GamePhase>` | Game phases that block this |
|
||||||
|
| `RequiredTags` | `GameplayTagContainer` | Tags the player must have |
|
||||||
|
| `BlockedTags` | `GameplayTagContainer` | Tags the player must NOT have |
|
||||||
|
| `BlockReason` | `Text` | Reason shown to player when blocked |
|
||||||
|
| `Priority` | `Integer` | Rule evaluation order (lower = checked first) |
|
||||||
|
|
||||||
|
### 5.3 S_ActionPermissionResult
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `bPermitted` | `Boolean` | Whether the action is allowed |
|
||||||
|
| `BlockReason` | `Text` | Why it was blocked (if not permitted) |
|
||||||
|
| `ResultCode` | `E_ActionRequestResult` | Machine-readable result code |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Variables
|
||||||
|
|
||||||
|
### Configuration (Instance Editable, Expose On Spawn)
|
||||||
|
|
||||||
|
| Variable | Type | Default | Category | Description |
|
||||||
|
|----------|------|---------|----------|-------------|
|
||||||
|
| `GatingRules` | `Array<S_StateGatingRule>` | `DefaultRules` | `State Config` | All gating rules defined in blueprint |
|
||||||
|
| `DefaultState` | `E_PlayerActionState` | `Idle` | `State Config` | State to initialize on BeginPlay |
|
||||||
|
| `bLogStateTransitions` | `Boolean` | `false` | `Debug` | Log all state transitions to console |
|
||||||
|
| `StateTransitionDelay` | `Float` | `0.0` | `State Config` | Minimum time between state changes (anti-spam) |
|
||||||
|
| `DefaultOverlay` | `E_OverlayState` | `Empty` | `State Config` | Default overlay state |
|
||||||
|
| `InjuryHealthThreshold` | `Float` | `0.30` | `State Config` | Health ratio (0-1) below which player becomes Injured |
|
||||||
|
| `HeartRateBase` | `Float` | `70.0` | `State Config` | Base heart rate in BPM when calm |
|
||||||
|
| `HeartRateMax` | `Float` | `180.0` | `State Config` | Maximum heart rate in BPM |
|
||||||
|
|
||||||
|
### Internal (Private / Protected)
|
||||||
|
|
||||||
|
| Variable | Type | Default | Category | Description |
|
||||||
|
|----------|------|---------|----------|-------------|
|
||||||
|
| `CurrentState` | `E_PlayerActionState` | `Idle` | `State` | Current exclusive action state |
|
||||||
|
| `PreviousState` | `E_PlayerActionState` | `Idle` | `State` | Previous state for transitions |
|
||||||
|
| `CurrentOverlay` | `E_OverlayState` | `Empty` | `State` | Current upper-body overlay state |
|
||||||
|
| `LastStateChangeTime` | `Float` | `0.0` | `State` | Game time of last state change |
|
||||||
|
| `StateHistory` | `Array<E_PlayerActionState>` | `Empty` | `State` | History of last N states for debugging |
|
||||||
|
| `ForceStack` | `Array<E_PlayerActionState>` | `Empty` | `State` | Stack of forced states for nested overrides |
|
||||||
|
| `bIsTransitioning` | `Boolean` | `false` | `State` | True during a state transition |
|
||||||
|
| `PendingRequests` | `Array<S_StateChangeRequest>` | `Empty` | `State` | Queued requests during transition |
|
||||||
|
| `CachedABPRef` | `ABP_GASP` (soft ref) | `None` | `State` | Cached reference to GASP AnimBP |
|
||||||
|
| `CurrentActionFlags` | `Map<GameplayTag, Float>` | `Empty` | `State` | Active action tags with duration/timestamp |
|
||||||
|
| `CurrentHeartRate` | `Float` | `70.0` | `Vital Signs` | Current heart rate in BPM (recalculated each tick) |
|
||||||
|
| `CurrentVitalSignal` | `E_PlayerVitalSignals` | `Normal` | `Vital Signs` | Current vital signal category |
|
||||||
|
| `bIsInjured` | `Boolean` | `false` | `Vital Signs` | True when health ≤ InjuryHealthThreshold |
|
||||||
|
| `InjurySpeedMultiplier` | `Float` | `0.65` | `Vital Signs` | Walk speed multiplier when injured |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Functions / Custom Events
|
||||||
|
|
||||||
|
### 7.1 RequestStateChange
|
||||||
|
|
||||||
|
```
|
||||||
|
RequestStateChange(NewState: E_PlayerActionState, RequesterTag: GameplayTag, Priority: Integer = 0) → E_ActionRequestResult
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** The primary entry point. Any system requests to transition the player to a new exclusive action state. State Manager checks all gating rules and returns the result.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. If Priority == 100 (Force): bypass gating, go directly to step 6
|
||||||
|
2. If `bIsTransitioning`: queue the request on `PendingRequests`, return `Blocked_CurrentState`
|
||||||
|
3. Check time since `LastStateChangeTime` — if < `StateTransitionDelay`: return `Blocked_Cooldown`
|
||||||
|
4. If `CurrentState` == `Dead` and `NewState` != `Idle` (respawn): return `Blocked_Dead`
|
||||||
|
5. Iterate `GatingRules` matching `RequesterTag`:
|
||||||
|
- If `NewState` is in `BlockedStates` for any rule: return `Blocked_CurrentState` with `BlockReason`
|
||||||
|
- If `CurrentGamePhase` is in `BlockedGamePhases`: return `Blocked_GamePhase`
|
||||||
|
- If required tags missing or blocked tags present: return appropriate result
|
||||||
|
6. Execute state transition (see 7.7)
|
||||||
|
7. Return `Permitted`
|
||||||
|
|
||||||
|
### 7.2 ForceStateChange
|
||||||
|
|
||||||
|
```
|
||||||
|
ForceStateChange(NewState: E_PlayerActionState, Reason: Text) → void
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Bypasses ALL gating. Used by death system, cutscene bridge, void space entry, and developer cheats. Pushes current state onto `ForceStack`.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. If `ForceStack` already has `NewState` at top: return (prevents double-force)
|
||||||
|
2. Push `CurrentState` onto `ForceStack`
|
||||||
|
3. Execute state transition with `NewState`
|
||||||
|
4. Log reason to console if `bLogStateTransitions`
|
||||||
|
|
||||||
|
### 7.3 RestorePreviousState
|
||||||
|
|
||||||
|
```
|
||||||
|
RestorePreviousState() → void
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Pops the force stack. Used when exiting cutscenes, void space, or force-override states.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. If `ForceStack` is empty:
|
||||||
|
- Set to `Idle` or previously known normal state
|
||||||
|
- Return
|
||||||
|
2. Pop top of `ForceStack`
|
||||||
|
3. Execute state transition to popped state
|
||||||
|
|
||||||
|
### 7.4 GetCurrentState
|
||||||
|
|
||||||
|
```
|
||||||
|
GetCurrentState() → E_PlayerActionState
|
||||||
|
```
|
||||||
|
|
||||||
|
Pure getter — returns `CurrentState`.
|
||||||
|
|
||||||
|
### 7.5 GetPreviousState
|
||||||
|
|
||||||
|
```
|
||||||
|
GetPreviousState() → E_PlayerActionState
|
||||||
|
```
|
||||||
|
|
||||||
|
Pure getter — returns `PreviousState`.
|
||||||
|
|
||||||
|
### 7.6 IsActionPermitted
|
||||||
|
|
||||||
|
```
|
||||||
|
IsActionPermitted(ActionTag: GameplayTag) → S_ActionPermissionResult
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Non-mutating query. Does NOT change state. Any system can ask "can I do this right now?"
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. Find all `GatingRules` where `ActionTag` matches
|
||||||
|
2. Check `CurrentState` against `BlockedStates`
|
||||||
|
3. Check `GI_GameFramework.CurrentGamePhase` against `BlockedGamePhases`
|
||||||
|
4. Check `RequiredTags` and `BlockedTags`
|
||||||
|
5. Return `S_ActionPermissionResult` with `bPermitted`, `BlockReason`, `ResultCode`
|
||||||
|
|
||||||
|
### 7.7 SetOverlayState
|
||||||
|
|
||||||
|
```
|
||||||
|
SetOverlayState(Overlay: E_OverlayState) → void
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Tells GASP AnimBP which upper-body overlay to use. Does not change `E_PlayerActionState`. Called by equipment system, weapon system, and inspection.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. If `Overlay` == `CurrentOverlay`: return
|
||||||
|
2. Set `CurrentOverlay` = `Overlay`
|
||||||
|
3. If `CachedABPRef` is valid: set `ABP_GASP.OverlayState` = `Overlay` (via `I_AnimNotifyInterface` or direct variable set)
|
||||||
|
4. Fire `OnOverlayStateChanged`
|
||||||
|
5. Update visible first-person arm mesh if applicable (via `BPC_EmbodimentSystem`)
|
||||||
|
|
||||||
|
### 7.8 CanTransitionTo
|
||||||
|
|
||||||
|
```
|
||||||
|
CanTransitionTo(TargetState: E_PlayerActionState) → S_ActionPermissionResult
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Pre-flight check without executing. Used by UI to enable/disable buttons.
|
||||||
|
|
||||||
|
### 7.9 UpdateHeartRate (Tick-Driven)
|
||||||
|
|
||||||
|
```
|
||||||
|
UpdateHeartRate() → void
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Recalculates heart rate each tick based on current state, stress, stamina, and health. Evaluates `E_PlayerVitalSignals` thresholds. Called automatically from Tick.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. Calculate base rate:
|
||||||
|
- Idle/Walking/Sitting → `HeartRateBase` (60-80)
|
||||||
|
- Jogging → Base + 15
|
||||||
|
- Sprinting → Base + 30
|
||||||
|
- Combat (any weapon state) → Base + 40
|
||||||
|
- Hiding/Peeking → Base + 5 (suppressed by stealth)
|
||||||
|
- Panicked → Base + 50
|
||||||
|
- Dead → 0
|
||||||
|
2. Apply health modifier: (1.0 - HealthRatio) * 20 added
|
||||||
|
3. Apply stress modifier: StressRatio * 30 added
|
||||||
|
4. Apply stamina modifier: if Exhausted → +25
|
||||||
|
5. Clamp to `HeartRateMax`
|
||||||
|
6. Smooth interpolation: `CurrentHeartRate = FMath::FInterpTo(CurrentHeartRate, Target, DeltaTime, 3.0)`
|
||||||
|
7. Evaluate `E_PlayerVitalSignals` from `CurrentHeartRate`:
|
||||||
|
- ≤ 80 → Normal
|
||||||
|
- ≤ 110 → Elevated
|
||||||
|
- ≤ 150 → High
|
||||||
|
- ≤ 180 → Critical
|
||||||
|
- If Panicked state OR FearSystem active → Erratic (overrides BPM threshold)
|
||||||
|
8. If `CurrentVitalSignal` changed, fire `OnVitalSignalChanged`
|
||||||
|
9. Write `CurrentHeartRate` to `ABP_GASP.HeartRate` for breathing animation blend
|
||||||
|
|
||||||
|
### 7.10 EvaluateInjuryState
|
||||||
|
|
||||||
|
```
|
||||||
|
EvaluateInjuryState() → void
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Called when health changes. Sets `bIsInjured` flag and auto-transitions to/from `Injured` state if health crosses threshold.
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. Get `HealthRatio` from `BPC_HealthSystem.CurrentHealth / MaxHealth`
|
||||||
|
2. If `HealthRatio <= InjuryHealthThreshold` AND `!bIsInjured`:
|
||||||
|
- Set `bIsInjured = true`
|
||||||
|
- If CurrentState is Idle/Walking/Jogging/Sprinting/Crouching: `RequestStateChange(Injured, Tag.Health)`
|
||||||
|
- Apply `InjurySpeedMultiplier` to movement
|
||||||
|
3. If `HealthRatio > InjuryHealthThreshold` AND `bIsInjured`:
|
||||||
|
- Set `bIsInjured = false`
|
||||||
|
- If CurrentState == Injured: `RequestStateChange(Idle, Tag.Health)`
|
||||||
|
- Restore movement speed
|
||||||
|
|
||||||
|
### 7.11 IsInCombat
|
||||||
|
|
||||||
|
```
|
||||||
|
IsInCombat() → Boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Convenience — returns true if `CurrentState` is `SwingMelee`, `AimingFirearm`, `FiringFirearm`, `Reloading`, or `DeployingShield`.
|
||||||
|
|
||||||
|
### 7.12 IsMovementBlocked
|
||||||
|
|
||||||
|
```
|
||||||
|
IsMovementBlocked() → Boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Convenience — returns true if player cannot move. True when `CurrentState` is `Dead`, `InCutscene`, `InDialogue`, `InInventory`, `InJournal`, `InPauseMenu`, `InMainMenu`, `UsingObject`, `Sitting`, `KnockedDown`, `Panicked`, `Staggered`, `Exhausted`, `Loading`, `InPhotoMode`.
|
||||||
|
|
||||||
|
### 7.13 IsMovementRestricted
|
||||||
|
|
||||||
|
```
|
||||||
|
IsMovementRestricted() → Boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Convenience — returns true if movement is partially restricted (slowed/impaired but not fully blocked). True when `CurrentState` is `Injured`, `Crouching`, `Crawling`, `HoldingBreath`, `AimingFirearm`, `DeployingShield`, `Hiding`, `Peeking`, `GrabbingObject`, `PushingObject`, `UsingConsumable`.
|
||||||
|
|
||||||
|
### 7.14 GetHeartRate
|
||||||
|
|
||||||
|
```
|
||||||
|
GetHeartRate() → Float
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Returns `CurrentHeartRate` in BPM. Used by audio system for heartbeat SFX tempo, by UI for vitals display, by haptic system for controller pulse rate.
|
||||||
|
|
||||||
|
### 7.15 GetVitalSignal
|
||||||
|
|
||||||
|
```
|
||||||
|
GetVitalSignal() → E_PlayerVitalSignals
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Returns `CurrentVitalSignal`. Used by atmosphere system (audio tension layers), camera (breathing sway), and narrative system (dialogue conditionals).
|
||||||
|
|
||||||
|
### 7.16 CanEquipWeapon
|
||||||
|
|
||||||
|
```
|
||||||
|
CanEquipWeapon() → Boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Checks if weapon equip is permitted in current state.
|
||||||
|
|
||||||
|
### 7.17 RegisterActionFlag / UnregisterActionFlag / HasActionFlag
|
||||||
|
|
||||||
|
```
|
||||||
|
RegisterActionFlag(Tag: GameplayTag, Duration: Float = -1.0) → void
|
||||||
|
UnregisterActionFlag(Tag: GameplayTag) → void
|
||||||
|
HasActionFlag(Tag: GameplayTag) → Boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
**Description:** Lightweight flag system for transient action permissions. Duration of -1 = permanent until unregistered. Used by systems to mark "I am currently in cooldown" or "I am currently active."
|
||||||
|
|
||||||
|
### 7.18 Initialize (BeginPlay override)
|
||||||
|
|
||||||
|
**Flow:**
|
||||||
|
1. Get owner as Character
|
||||||
|
2. Cache reference to `ABP_GASP` from character's skeletal mesh
|
||||||
|
3. Set `CurrentState` = `DefaultState`, `CurrentOverlay` = `DefaultOverlay`
|
||||||
|
4. Populate default `GatingRules` from `DA_StateGatingTable` if assigned
|
||||||
|
5. Bind to `GI_GameFramework.OnGamePhaseChanged` (for game-phase-gated rules)
|
||||||
|
6. Bind to `BPC_HealthSystem.OnDeath` (auto-call `ForceStateChange(Dead)`)
|
||||||
|
7. Register with `GI_GameTagRegistry` for tag-based queries
|
||||||
|
8. Bind to `BPC_HealthSystem.OnHealthChanged` → call `EvaluateInjuryState()`
|
||||||
|
9. Bind to `BPC_StressSystem.OnStressTierChanged` → recalculate heart rate
|
||||||
|
10. Bind to `BPC_StaminaSystem.OnExhaustionStateChanged` → recalculate heart rate
|
||||||
|
11. Enable component tick (required for heart rate smoothing)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Event Dispatchers
|
||||||
|
|
||||||
|
| Dispatcher | Parameters | Bind Access | Description |
|
||||||
|
|------------|-----------|-------------|-------------|
|
||||||
|
| `OnStateChanged` | `OldState: E_PlayerActionState`, `NewState: E_PlayerActionState` | `Public` | Fired on any state transition |
|
||||||
|
| `OnStateChangeRequested` | `Request: S_StateChangeRequest` | `Public` | Fired when request is made (before evaluation) |
|
||||||
|
| `OnStateChangeDenied` | `Request: S_StateChangeRequest`, `Result: E_ActionRequestResult`, `Reason: Text` | `Public` | Fired when a request is denied |
|
||||||
|
| `OnOverlayStateChanged` | `OldOverlay: E_OverlayState`, `NewOverlay: E_OverlayState` | `Public` | Fired on overlay change |
|
||||||
|
| `OnActionFlagRegistered` | `Tag: GameplayTag`, `Duration: Float` | `Public` | Fired when a flag is registered |
|
||||||
|
| `OnActionFlagExpired` | `Tag: GameplayTag` | `Public` | Fired when a timed flag expires |
|
||||||
|
| `OnForceOverridePushed` | `ForcedState: E_PlayerActionState`, `PoppedState: E_PlayerActionState` | `Public` | Fired when force stack is pushed |
|
||||||
|
| `OnForceOverridePopped` | `RestoredState: E_PlayerActionState` | `Public` | Fired when force stack is popped |
|
||||||
|
| `OnVitalSignalChanged` | `OldSignal: E_PlayerVitalSignals`, `NewSignal: E_PlayerVitalSignals` | `Public` | Fired when vital signal tier changes |
|
||||||
|
| `OnHeartRateChanged` | `NewBPM: Float` | `Public` | Fired when heart rate changes significantly (±5 BPM) |
|
||||||
|
| `OnInjuryStateChanged` | `bIsInjured: Boolean`, `HealthRatio: Float` | `Public` | Fired when injury state toggles |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. State Gating Function Table
|
||||||
|
|
||||||
|
### Complete Action → Blocking State Matrix
|
||||||
|
|
||||||
|
| Requested Action (Tag) | Blocked If CurrentState Is | Reason |
|
||||||
|
|------------------------|----------------------------|--------|
|
||||||
|
| `Action.Move.Walk` | Dead, InCutscene, InDialogue, KnockedDown, Panicked, Exhausted, Sitting, InInventory, InJournal, InPauseMenu, UsingObject, GrabbingObject, InPhotoMode | Movement disabled |
|
||||||
|
| `Action.Move.Sprint` | Dead, InCutscene, InDialogue, Crouching, Crawling, Hiding, Peeking, Sitting, KnockedDown, Exhausted, Panicked, Reloading, UsingConsumable, Injured | Sprint requires standing + uninjured |
|
||||||
|
| `Action.Move.Crouch` | Dead, Vaulting, Climbing, Sliding, InCutscene, InDialogue, Sitting, KnockedDown, Exhausted, Panicked | Cannot crouch during traversal |
|
||||||
|
| `Action.Move.Crawl` | Dead, Standing required states, Vaulting, Climbing, InCutscene, Sitting, KnockedDown | Must be prone first |
|
||||||
|
| `Action.Move.Jump` | Dead, Hiding, Peeking, Crouching (maybe), Crawling, InCutscene, InDialogue, Sitting, KnockedDown, Panicked, Exhausted, UsingObject, InInventory, InPauseMenu | Jump blocked |
|
||||||
|
| `Action.Move.Sit` | Dead, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory, InCutscene, InDialogue | Sit requires neutral standing state |
|
||||||
|
| `Action.Move.StandUp` | Must be Sitting state | Must be sitting first |
|
||||||
|
| `Action.Traversal.Vault` | Dead, Hiding, Peeking, InCutscene, InDialogue, Reloading, SwingMelee, FiringFirearm, KnockedDown, Panicked | Traversal requires free hands |
|
||||||
|
| `Action.Traversal.Climb` | Dead, InCutscene, InDialogue, Reloading, SwingMelee, KnockedDown, Panicked | Climbing requires free hands |
|
||||||
|
| `Action.Traversal.Slide` | Dead, InCutscene, InDialogue, Reloading, SwingMelee, KnockedDown, Panicked | Slide requires two hands |
|
||||||
|
| `Action.Hide.Enter` | Dead, InCutscene, InDialogue, SwingMelee, FiringFirearm, Reloading, Vaulting, Climbing, KnockedDown, Panicked, Exhausted, GrabbingObject | Hide requires exposed state |
|
||||||
|
| `Action.Hide.Peek` | Dead, SwingMelee, FiringFirearm, Reloading | Peek only from hidden |
|
||||||
|
| `Action.Hide.Exit` | InCutscene, Dead (if not force-exit) | Forced exit allowed |
|
||||||
|
| `Action.Interact.Hold` | Dead, InCutscene, SwingMelee, FiringFirearm, Reloading, Hiding, Peeking, Vaulting, Climbing, KnockedDown, Panicked, InInventory, InPauseMenu, InDialogue, UsingObject | Interaction requires free state |
|
||||||
|
| `Action.Interact.Instant` | Dead, InCutscene, KnockedDown, Panicked | Instant interaction only blocked by critical |
|
||||||
|
| `Action.Inventory.Open` | Dead, InCutscene, Vaulting, Climbing, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, Hiding, GrabbingObject, InDialogue, InPuzzle, InTrialScenario | Inventory blocked during actions |
|
||||||
|
| `Action.Inventory.Close` | (always permitted — but may not open if blocked) | Close always works |
|
||||||
|
| `Action.Inventory.Equip` | Dead, InCutscene, Vaulting, Climbing, KnockedDown, Panicked | Equip requires stability |
|
||||||
|
| `Action.Inventory.UseItem` | Dead, InCutscene, Vaulting, Climbing, KnockedDown, Panicked, Hiding | Use requires stable state |
|
||||||
|
| `Action.Weapon.Fire` | Dead, Hiding, Peeking, Reloading, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, UsingConsumable, GrabbingObject | Cannot fire in these states |
|
||||||
|
| `Action.Weapon.Aim` | Dead, Hiding, Peeking, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, GrabbingObject | Cannot aim |
|
||||||
|
| `Action.Weapon.Reload` | Dead, Hiding, Peeking, Vaulting, Climbing, SwingMelee, InCutscene, InDialogue, KnockedDown, Panicked, InPauseMenu, GrabbingObject | Cannot reload |
|
||||||
|
| `Action.Weapon.Melee` | Dead, Hiding, Peeking, Reloading, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, GrabbingObject, UsingConsumable | Cannot melee |
|
||||||
|
| `Action.Weapon.Block` | Dead, Reloading, Vaulting, Climbing, InCutscene, KnockedDown, Panicked, Hiding, InInventory, InPauseMenu | Cannot block |
|
||||||
|
| `Action.Dialogue.Start` | Dead, InCutscene, Vaulting, Climbing, SwingMelee, FiringFirearm, Hiding, InInventory, InPauseMenu, Reloading, KnockedDown, Panicked | Dialogue requires neutral state |
|
||||||
|
| `Action.Dialogue.Choose` | Must be InDialogue state | Must be in dialogue |
|
||||||
|
| `Action.Cutscene.Play` | (handled by GI_GameFramework game phase, not action state) | Cutscene overrides via Force |
|
||||||
|
| `Action.Cutscene.Skip` | Must be InCutscene, bCanSkip | Must be in cutscene |
|
||||||
|
| `Action.HoldBreath` | Hiding state only, not Peeking | Breath hold only while hidden |
|
||||||
|
| `Action.Grab.PhysicsObject` | Dead, InCutscene, Hiding, Vaulting, Climbing, Reloading, SwingMelee, FiringFirearm, KnockedDown, Panicked, InInventory, InPauseMenu | Grab requires free hands |
|
||||||
|
| `Action.Puzzle.Use` | Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked | Puzzle requires focus |
|
||||||
|
| `Action.Consumable.Use` | Dead, InCutscene, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory | Consumable requires free hands |
|
||||||
|
| `Action.Pause.Open` | InCutscene, Dead, InMainMenu, Loading | Cannot pause in cutscene/death |
|
||||||
|
| `Action.Pause.Close` | (always permitted) | Close always works |
|
||||||
|
| `Action.Journal.Open` | Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory, InPuzzle, InTrialScenario | Journal requires neutral state |
|
||||||
|
| `Action.Settings.Open` | InCutscene, Loading | Settings limited during cutscene |
|
||||||
|
| `Action.MainMenu.Return` | (always permitted) | Return to menu always works |
|
||||||
|
| `Action.QuestLog.Open` | Same as Journal | Same blocking states |
|
||||||
|
| `Action.Map.Open` | Dead, InCutscene, Vaulting, Climbing, Hiding, InInventory, InPauseMenu | Map in neutral/explore states |
|
||||||
|
| `Action.Throwable.Aim` | Dead, Hiding, Peeking, Vaulting, Climbing, InCutscene, InDialogue, Reloading, KnockedDown, Panicked, InInventory, InPauseMenu | Throw requires free hands |
|
||||||
|
| `Action.Throwable.Throw` | Same as Aim + must be in AimingThrowable state | Must be aiming first |
|
||||||
|
| `Action.PhotoMode.Enter` | Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, KnockedDown, Panicked | Photo mode requires neutral state |
|
||||||
|
| `Action.PhotoMode.Exit` | Must be InPhotoMode | Must be in photo mode |
|
||||||
|
|
||||||
|
### Restricted Movement States (Enclosed Spaces / Injured)
|
||||||
|
|
||||||
|
The following states impose movement restrictions beyond simply blocked/unblocked:
|
||||||
|
|
||||||
|
| State | Walk Allowed | Sprint Allowed | Jump Allowed | Crouch Allowed | Camera Freelook | Notes |
|
||||||
|
|-------|-------------|----------------|-------------|----------------|-----------------|-------|
|
||||||
|
| `Sitting` | **No** | No | No | No | Yes (head only) | Must StandUp to move. Enter via world interaction point (bench, chair, floor) |
|
||||||
|
| `Injured` | **Slowed** (×0.65) | No | No | Yes | Yes | Limp animation. Heals above threshold. Sprint/jump blocked |
|
||||||
|
| `Hiding` (Locker/Under) | **No** | No | No | No | No (fixed cam) | Fully enclosed — zero movement |
|
||||||
|
| `Hiding` (BehindCover) | **No** | No | No | N/A (already crouched) | Limited (peek) | Can peek but cannot leave cover position |
|
||||||
|
| `Hiding` (InShadow) | **Yes** (slow) | No | No | Yes | Yes | Standing in shadow — can move but sprint blocked |
|
||||||
|
| `Hiding` (TallGrass) | **Yes** (crouch-walk) | No | No | Yes | Yes | Crouch-moving through vegetation |
|
||||||
|
| `Staggered` | **No** | No | No | No | Locked | Forced animation — no input |
|
||||||
|
| `KnockedDown` | **No** | No | No | No | Locked (ground view) | Must GetUp animation first |
|
||||||
|
| `Exhausted` | **No** | No | No | No | Yes | Heavy breathing — must wait for stamina regen |
|
||||||
|
| `Panicked` | **Stumble** | No | No | No | Random jerks | Camera shakes, movement impaired |
|
||||||
|
| `HoldingBreath` | **No** | No | No | No | Yes | Must release breath before moving |
|
||||||
|
| `InPhotoMode` | **No** (free cam only) | No | No | No | Full (free cam) | Gameplay input disabled, camera only |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. GASP Integration Notes
|
||||||
|
|
||||||
|
### 10.1 What the State Manager READS from GASP
|
||||||
|
|
||||||
|
| GASP Variable / Event | How Used |
|
||||||
|
|----------------------|----------|
|
||||||
|
| `ABP_GASP.bStrafing` | Read to detect if GASP is in strafing mode — informs combat state eligibility |
|
||||||
|
| `ABP_GASP.bSprinting` | Read to confirm sprint state when `BPC_MovementStateSystem` reports sprint |
|
||||||
|
| `ABP_GASP.MovementMode` | Read to cross-validate `BPC_MovementStateSystem.CurrentMovementMode` |
|
||||||
|
| `ABP_GASP.GroundState` | Read to know if airborne (blocks certain actions) |
|
||||||
|
| `AnimNotify_StateEnter` | Any GASP notify received via `I_AnimNotifyInterface` is forwarded to listeners |
|
||||||
|
|
||||||
|
### 10.2 What the State Manager WRITES to GASP
|
||||||
|
|
||||||
|
| GASP Variable / Event | How Written |
|
||||||
|
|----------------------|-------------|
|
||||||
|
| `ABP_GASP.OverlayState` | Set via `SetOverlayState(E_OverlayState)` — direct enum value set on cached AnimBP reference |
|
||||||
|
| `ABP_GASP.bIsInAction` | Set to `true` when `CurrentState` is any action state (not Idle/Walking/Jogging/Sprinting/Crouching) |
|
||||||
|
| `ABP_GASP.ActionIntensity` | Float 0.0–1.0 set based on action type: 0.0=Idle, 0.3=Interacting, 0.7=SwingMelee, 1.0=FiringFirearm |
|
||||||
|
| `AnimNotify_OverlayChanged` | Fired when overlay changes — GASP blends to new upper-body pose |
|
||||||
|
|
||||||
|
### 10.3 What the State Manager NEVER Touches
|
||||||
|
|
||||||
|
- **Motion Matching Database** — GASP's motion matching is sacred, never modified
|
||||||
|
- **Camera Manager** — Camera blends, FOV, and offsets belong to `BPC_CameraStateLayer`
|
||||||
|
- **GASP's Internal State Machine** — Ground/air transitions, rotation mode, strafing logic
|
||||||
|
- **Animation Blueprint Graph Logic** — Only sets variables, never modifies graph nodes
|
||||||
|
- **GASP's Root Motion** — Root motion extraction is GASP's domain
|
||||||
|
|
||||||
|
### 10.4 Overlay State Pipeline
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant ES as EquipmentSystem
|
||||||
|
participant SM as BPC_StateManager
|
||||||
|
participant GASP as ABP_GASP
|
||||||
|
participant AP as AnimPose
|
||||||
|
|
||||||
|
ES->>SM: SetOverlayState(Pistol)
|
||||||
|
SM->>SM: CurrentOverlay = Pistol
|
||||||
|
SM->>GASP: ABP_GASP.OverlayState = Pistol
|
||||||
|
GASP->>GASP: Blend upper body to Pistol pose
|
||||||
|
GASP->>AP: Apply overlay pose
|
||||||
|
SM->>SM: Fire OnOverlayStateChanged
|
||||||
|
SM->>ES: Confirm overlay set
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Blueprint Flow Diagram — RequestStateChange
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[System calls RequestStateChange] --> B{Priority == 100?}
|
||||||
|
B -->|Yes Force| C[ExecuteStateTransition]
|
||||||
|
B -->|No| D{bIsTransitioning?}
|
||||||
|
D -->|Yes| E[Queue on PendingRequests - return Blocked_CurrentState]
|
||||||
|
D -->|No| F{Within StateTransitionDelay?}
|
||||||
|
F -->|Yes| G[Return Blocked_Cooldown]
|
||||||
|
F -->|No| H{CurrentState == Dead?}
|
||||||
|
H -->|Yes and NewState != Idle| I[Return Blocked_Dead]
|
||||||
|
H -->|No| J[Fire OnStateChangeRequested]
|
||||||
|
J --> K[Evaluate GatingRules for RequesterTag]
|
||||||
|
K --> L{NewState in BlockedStates?}
|
||||||
|
L -->|Yes| M[Fire OnStateChangeDenied - return Blocked_CurrentState]
|
||||||
|
L -->|No| N{GamePhase blocks?}
|
||||||
|
N -->|Yes| O[Fire OnStateChangeDenied - return Blocked_GamePhase]
|
||||||
|
N -->|No| P{Required tags missing?}
|
||||||
|
P -->|Yes| Q[Fire OnStateChangeDenied - return reason]
|
||||||
|
P -->|No| R{Blocked tags present?}
|
||||||
|
R -->|Yes| Q
|
||||||
|
R -->|No| C
|
||||||
|
C --> S[PreviousState = CurrentState]
|
||||||
|
S --> T[CurrentState = NewState]
|
||||||
|
T --> U[Update bIsInAction on GASP]
|
||||||
|
U --> V[Update ActionIntensity on GASP]
|
||||||
|
V --> W[Fire OnStateChanged - OldState, NewState]
|
||||||
|
W --> X[Notify SS_EnhancedInputManager - context change]
|
||||||
|
X --> Y[Return Permitted]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Communication Matrix
|
||||||
|
|
||||||
|
| Who Talks | How | What Is Sent |
|
||||||
|
|-----------|-----|-------------|
|
||||||
|
| Any System | `RequestStateChange()` | `E_PlayerActionState`, `RequesterTag: GameplayTag`, `Priority: Int` |
|
||||||
|
| Any System | `IsActionPermitted()` | `GameplayTag` → `S_ActionPermissionResult` |
|
||||||
|
| BPC_StateManager | `ABP_GASP` (Direct variable set) | `OverlayState`, `bIsInAction`, `ActionIntensity` |
|
||||||
|
| BPC_StateManager | `Dispatcher: OnStateChanged` | `OldState`, `NewState` to all bound listeners |
|
||||||
|
| BPC_StateManager | `Dispatcher: OnOverlayStateChanged` | `OldOverlay`, `NewOverlay` to `BPC_EmbodimentSystem`, `WBP_HUDController` |
|
||||||
|
| BPC_StateManager | `Dispatcher: OnStateChangeDenied` | Request, Result, Reason to `WBP_InteractionPromptDisplay`, `WBP_NotificationToast` |
|
||||||
|
| BPC_StateManager | `SS_EnhancedInputManager` (Direct) | Context change notification when state changes |
|
||||||
|
| BPC_StateManager | `BPC_MovementStateSystem` (Direct) | Receives `OnMovementModeChanged` to track walking/sprinting |
|
||||||
|
| BPC_StateManager | `BPC_HealthSystem` (Listener on OnDeath) | Auto-transitions to Dead state |
|
||||||
|
| `GI_GameFramework` | `Dispatcher: OnGamePhaseChanged` | Notifies StateManager of phase changes for gating |
|
||||||
|
| `BPC_CameraStateLayer` | `Dispatcher: OnStateChanged` | Adjusts camera based on state (e.g., combat FOV) |
|
||||||
|
| `BPC_StressSystem` | `Direct: IsActionPermitted` | Checks if stress effects are currently permitted |
|
||||||
|
| `WBP_InteractionPromptDisplay` | `Listener on OnStateChanged` | Shows/hides interaction prompts based on state |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Testing Checklist
|
||||||
|
|
||||||
|
- [ ] `RequestStateChange` with valid state returns `Permitted` and fires `OnStateChanged`
|
||||||
|
- [ ] `RequestStateChange` while Dead (except to Idle) returns `Blocked_Dead`
|
||||||
|
- [ ] `RequestStateChange` during transition queues and returns `Blocked_CurrentState`
|
||||||
|
- [ ] `ForceStateChange` bypasses all gating and pushes to ForceStack
|
||||||
|
- [ ] `RestorePreviousState` pops ForceStack and restores correct state
|
||||||
|
- [ ] `IsActionPermitted` returns correct `S_ActionPermissionResult` for all 35+ actions
|
||||||
|
- [ ] `SetOverlayState` correctly writes to `ABP_GASP.OverlayState`
|
||||||
|
- [ ] Overlay change fires `OnOverlayStateChanged` dispatcher
|
||||||
|
- [ ] Game phase change (MainMenu → InGame → Cutscene) correctly gates actions
|
||||||
|
- [ ] Death auto-transitions to Dead state via `BPC_HealthSystem.OnDeath` binding
|
||||||
|
- [ ] Respawn restores previous state from ForceStack
|
||||||
|
- [ ] Rapid state change requests are throttled by `StateTransitionDelay`
|
||||||
|
- [ ] `IsInCombat()` returns true for `SwingMelee`, `AimingFirearm`, `FiringFirearm`, `Reloading`, `DeployingShield`
|
||||||
|
- [ ] `IsMovementBlocked()` returns true for all blocking states
|
||||||
|
- [ ] Edge case: `ForceStateChange` called twice with same state — second call is no-op
|
||||||
|
- [ ] Edge case: `RestorePreviousState` with empty ForceStack defaults to Idle
|
||||||
|
- [ ] Edge case: State Manager handles owner destruction gracefully (null checks on cached ABP ref)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Reuse Notes
|
||||||
|
|
||||||
|
- BPC_StateManager replaces the need for every system to check every other system's state. Systems call `IsActionPermitted(Tag)` instead of `IsPlayerInState(X) && !IsPlayerInState(Y) && ...`
|
||||||
|
- New states can be added to `E_PlayerActionState` and `DA_StateGatingTable` without modifying the State Manager blueprint logic.
|
||||||
|
- The `DA_StateGatingTable` Data Asset allows designers to tune gating rules without opening blueprints.
|
||||||
|
- Force stack pattern supports nested force overrides (e.g., Death → Cutscene flashback → Respawn).
|
||||||
|
- GASP variables `bIsInAction` and `ActionIntensity` allow AnimBP to blend differently during action vs exploration without the AnimBP knowing about game logic.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part B — Chooser Table Candidate Audit
|
||||||
|
|
||||||
|
### Complete Chooser Table Candidate Catalog (32 identified)
|
||||||
|
|
||||||
|
| # | Chooser Table Name | Input Columns (Name + Type) | Output Type | Row Logic Summary | Used By |
|
||||||
|
|---|-------------------|----------------------------|-------------|-------------------|---------|
|
||||||
|
| 1 | **Damage Resistance Lookup** | `E_DamageType` (enum), `bIsStackable` (bool) | `Float` (multiplier) | Map DamageType → resistance multiplier; accumulate if stackable | `BPC_HealthSystem` (08) |
|
||||||
|
| 2 | **Exhaustion Tier** | `CurrentStamina/MaxStamina` (float ratio) | `E_ExhaustionState` | ≤ ExhaustedThreshold → Exhausted; ≤ LowThreshold → Low; else Normal | `BPC_StaminaSystem` (09) |
|
||||||
|
| 3 | **Stress Tier** | `CurrentStress` (float) | `E_StressTier` | Descending threshold check: highest exceeded → assign tier | `BPC_StressSystem` (10) |
|
||||||
|
| 4 | **Movement Settings** | `E_MovementMode` (enum) | `S_MovementSettings` | Map[Mode] → speed/accel/friction/stamina drain | `BPC_MovementStateSystem` (11) |
|
||||||
|
| 5 | **Footstep Profile** | `EPhysicalSurface` (enum), `CurrentSpeed` (float vs threshold) | `S_FootstepProfile` (SoundSoft/SoundHard) | Trace surface → lookup profile → compare velocity to threshold | `BPC_MovementStateSystem` (11) |
|
||||||
|
| 6 | **Stance Transition** | `E_StanceTransition` (enum) | `Float` (blend time) | Instant→0s, Smooth→TransitionBlendTime, Forced→0s + impulse | `BPC_MovementStateSystem` (11) |
|
||||||
|
| 7 | **Hide Detectability** | `E_HideType` (enum), `Distance` (float), `LOS trace result` | `Boolean` (detectable) | Not hidden→true; trace hits cover first→false; hits player→true | `BPC_HidingSystem` (12) |
|
||||||
|
| 8 | **Hide Spot Quality** | `E_HideSpotQuality` (enum) | `DetectionRangeModifier`, `DetectionSpeedModifier` (floats 0-1) | Better quality → lower detection modifiers | `I_HidingSpot` / `BP_HidingSpotBase` (17) |
|
||||||
|
| 9 | **Door Interaction Outcome** | `EDoorState` (enum), `ELockState` (enum), `bHasKey` (bool) | `E_DoorActionResult` | Locked→check key; Closed→open; Open→close | `BP_DoorActor` (19) |
|
||||||
|
| 10 | **Traversal Type** | `ObstacleHeight` (float) vs thresholds (Low/Medium/High) | `E_TraversalType` | ≤Low→step; ≤Medium→vault; ≤High→mantle; >High→climb | `BPC_ContextualTraversalSystem` (21) |
|
||||||
|
| 11 | **Container Fill Method** | `E_ContainerFillMethod` (enum) | `LootTable` or `FixedList` or `Empty` | Switch on FillMethod → generate appropriate loot | `BPC_ContainerInventory` (24) |
|
||||||
|
| 12 | **Weighted Loot Selection** | `Weight` (float per entry), `bGuaranteed` (bool) | `DA_ItemData` + `quantity` | Roll random vs weight sum; guaranteed items always spawn | `BPC_ContainerInventory` (24) |
|
||||||
|
| 13 | **Pickup Visual State** | `Distance/Overlap` (enum state) | `E_PickupState` | Far→Idle; Near→Highlighted; Interact→BeingPickedUp; Timer→Respawning | `BP_ItemPickup` (25) |
|
||||||
|
| 14 | **Equip Result** | `SlotOccupied` (bool), `Category` (tag), `StateBlocked` (bool) | `E_EquipResult` | Cascading validation: slot→category→state→Success | `BPC_EquipmentSlotSystem` (30) |
|
||||||
|
| 15 | **Equip Animation** | `E_EquipAnimationType` (enum) | `UAnimMontage` | Instant→none; Holster→holster; Equip→equip; Unequip→reverse equip | `BPC_EquipmentSlotSystem` (30) |
|
||||||
|
| 16 | **Inventory Sort Mode** | `E_SortMode` (enum) | Reordered `Array<S_InventorySlot>` | Switch: ByName, ByCategory, ByRarity, ByWeight, ByQuantity, ByRecent | `BPC_InventorySystem` (31) |
|
||||||
|
| 17 | **Add Item Outcome** | `HasSpace` (bool), `HasStack` (bool), `WeightCapacity` (float) | `E_AddItemResult` | Find stack→increment; else find slot→new; else→Full/Overweight | `BPC_InventorySystem` (31) |
|
||||||
|
| 18 | **Alt Death Space** | `GameplayTag` (context) | `TSoftObjectPtr<UWorld>` | Map lookup by context tag → level reference | `BPC_AltDeathSpaceSystem` (38) |
|
||||||
|
| 19 | **Death Outcome** | `S_DeathOutcomeRules` (struct), `S_DeathContext` (struct) | `E_DeathOutcome` | Check: max deaths→GameOver; has alt space→AltDeathSpace; else→StandardRespawn | `BPC_DeathHandlingSystem` (39) |
|
||||||
|
| 20 | **Document Font** | `E_DocumentFontStyle` (enum) | `UFont` + color | Handwritten/Typewritten/Digital/BloodScrawled → font asset + color tint | `WBP_JournalDocumentViewer` (50) |
|
||||||
|
| 21 | **Narrative Flag Query** | `Array<GameplayTag>`, `bUseAndLogic` (bool) | `Boolean` | AND query: all must be true; OR query: any must be true | `BPC_NarrativeStateSystem` (58) |
|
||||||
|
| 22 | **Dialogue Choice Filter** | `RequiredFlagTag` (GameplayTag) per choice | Filtered `Array<FDialogueChoice>` | If RequiredFlagTag set AND not in narrative state → hide choice | `BPC_DialogueChoiceSystem` (61) |
|
||||||
|
| 23 | **Consequence Action** | `EConsequenceActionType` (enum) | System call | Switch: PlayDialogue, UpdateObjective, SetWorldState, TriggerCutscene, GiveItem, etc. | `BPC_BranchingConsequenceSystem` (62) |
|
||||||
|
| 24 | **Scenario Outcome** | `bAllObjectivesComplete` (bool), `bFailureConditionMet` (bool) | `EScenarioOutcome` | All complete→Success; failure→Failure; else→InProgress | `BPC_TrialScenarioSystem` (63) |
|
||||||
|
| 25 | **Fire Mode** | `E_FireMode` (enum) | `FireRate`, `AmmoPerShot` | Single→1 shot, long delay; Burst→3 shots, medium; Auto→continuous, short | `BPC_FirearmSystem` (74) |
|
||||||
|
| 26 | **Reload Type** | `CurrentAmmo` (int) == 0 vs > 0 | `EReloadType` | Ammo=0→EmptyReload montage; else→TacticalReload montage | `BPC_ReloadSystem` (78) |
|
||||||
|
| 27 | **AI State Transition** | `PerceptionStatus` (enum), `AlertLevel` (float), `HealthRatio` (float) | `E_AIState` | HasTarget+HighAlert→Combat; LostTarget→Search; LowHealth→Flee; else→Patrol | `BPC_AIStateMachine` (83) |
|
||||||
|
| 28 | **Behaviour Variant** | `DA_BehaviourVariant` (Data Asset entries with weights) | `S_BehaviourVariant` | Weighted random selection from variant set | `BPC_BehaviourVariantSelector` (88) |
|
||||||
|
| 29 | **Difficulty Scaling** | `PlayerMetrics` (struct) vs thresholds | `DamageMultiplier`, `SpawnRate`, `ResourceAmount` | Metrics-to-difficulty mapping: Easy/Normal/Hard/Adaptive | `BPC_DifficultyManager` (89) |
|
||||||
|
| 30 | **Memory Drift** | `StressTier` (enum), `RandomRoll` (float) | `E_DriftEffectType` | Random selection weighted by stress tier → Visual/Audio/Dialogue | `BPC_MemoryDriftSystem` (97) |
|
||||||
|
| 31 | **Pacing Intensity** | `Stress` (float), `CombatTime` (float), `ExploreTime` (float) | `E_IntensityBand` + Music/Spawn settings | Composite score → Low/Medium/High/VeryHigh | `BPC_PacingDirector` (98) |
|
||||||
|
| 32 | **Rare Event** | `DA_RareEvent` weight table | `DA_RareEvent` entry | Weighted random selection from configured events | `BPC_RareEventSystem` (100) |
|
||||||
|
|
||||||
|
### Top 5 Most Impactful Chooser Tables — Full Specs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### TOP 1 — Death Outcome Chooser
|
||||||
|
|
||||||
|
**Table Name:** `CT_DeathOutcome`
|
||||||
|
|
||||||
|
**Blueprint:** [`BPC_DeathHandlingSystem`](../blueprints/05-saveload/39_BPC_DeathHandlingSystem.md:88)
|
||||||
|
|
||||||
|
**Input Columns:**
|
||||||
|
|
||||||
|
| Column | Type | Value Range | Source |
|
||||||
|
|--------|------|-------------|--------|
|
||||||
|
| `StandardDeathsUsed` | `Integer` | 0–MaxStandardDeaths | `BPC_RunHistoryTracker.GetDeathCount()` |
|
||||||
|
| `MaxStandardDeaths` | `Integer` | 1–99 | `S_DeathOutcomeRules.MaxStandardDeaths` |
|
||||||
|
| `AltSpaceEntrancesUsed` | `Integer` | 0–MaxAltDeathSpaceEntrances | `BPC_RunHistoryTracker.GetAltSpaceEntranceCount()` |
|
||||||
|
| `MaxAltDeathSpaceEntrances` | `Integer` | 0–99 | `S_DeathOutcomeRules.MaxAltDeathSpaceEntrances` |
|
||||||
|
| `bHasAltDeathSpace` | `Boolean` | true/false | `S_DeathContext.bHasAltDeathSpace` |
|
||||||
|
| `bEnableAltDeathSpace` | `Boolean` | true/false | `S_DeathOutcomeRules.bEnableAltDeathSpace` |
|
||||||
|
| `bIsBossDeath` | `Boolean` | true/false | `S_DeathContext.KillerTag` matches boss tag |
|
||||||
|
| `bGameOverOnBossDeath` | `Boolean` | true/false | `S_DeathOutcomeRules.bGameOverOnBossDeath` |
|
||||||
|
| `bIsNarrativeClimax` | `Boolean` | true/false | `BPC_NarrativeStateSystem.HasFlag(ClimaxFlag)` |
|
||||||
|
| `bGameOverInNarrativeClimax` | `Boolean` | true/false | `S_DeathOutcomeRules.bGameOverInNarrativeClimax` |
|
||||||
|
|
||||||
|
**Output Column:** `E_DeathOutcome` (StandardRespawn / GameOver / AltDeathSpace)
|
||||||
|
|
||||||
|
**All Rows:**
|
||||||
|
|
||||||
|
| Row | Conditions | Outcome |
|
||||||
|
|-----|-----------|---------|
|
||||||
|
| 1 | `bIsBossDeath == true AND bGameOverOnBossDeath == true` | `GameOver` |
|
||||||
|
| 2 | `bIsNarrativeClimax == true AND bGameOverInNarrativeClimax == true` | `GameOver` |
|
||||||
|
| 3 | `StandardDeathsUsed >= MaxStandardDeaths` | `GameOver` |
|
||||||
|
| 4 | `AltSpaceEntrancesUsed >= MaxAltDeathSpaceEntrances AND !bHasAltDeathSpace` | `GameOver` |
|
||||||
|
| 5 | `bEnableAltDeathSpace == true AND bHasAltDeathSpace == true AND AltSpaceEntrancesUsed < MaxAltDeathSpaceEntrances` | `AltDeathSpace` |
|
||||||
|
| 6 | (default — none of above) | `StandardRespawn` |
|
||||||
|
|
||||||
|
**Reuse Notes:** Rules are externalized to `S_DeathOutcomeRules`, configurable per level/chapter. The chooser evaluates rows in priority order (1→6). First match wins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### TOP 2 — Traversal Type Chooser
|
||||||
|
|
||||||
|
**Table Name:** `CT_TraversalType`
|
||||||
|
|
||||||
|
**Blueprint:** [`BPC_ContextualTraversalSystem`](../blueprints/03-interaction/21_BPC_ContextualTraversalSystem.md:224)
|
||||||
|
|
||||||
|
**Input Columns:**
|
||||||
|
|
||||||
|
| Column | Type | Value Range | Source |
|
||||||
|
|--------|------|-------------|--------|
|
||||||
|
| `ObstacleHeight` | `Float` | 0–400 cm | Line trace from player location upward |
|
||||||
|
| `ObstacleDepth` | `Float` | 0–200 cm | Line trace from player location forward |
|
||||||
|
| `ClearanceAbove` | `Float` | 0–300 cm | Ceiling check trace above obstacle |
|
||||||
|
| `bIsGrounded` | `Boolean` | true/false | `BPC_MovementStateSystem.bIsOnGround` |
|
||||||
|
| `CurrentSpeed` | `Float` | 0–SprintSpeed | `BPC_MovementStateSystem.CurrentSpeed` |
|
||||||
|
|
||||||
|
**Output Column:** `E_TraversalType` (Step / Vault / Mantle / Slide / Squeeze / Climb / Blocked)
|
||||||
|
|
||||||
|
**All Rows:**
|
||||||
|
|
||||||
|
| Row | Conditions | Outcome |
|
||||||
|
|-----|-----------|---------|
|
||||||
|
| 1 | `!bIsGrounded` | `Blocked` (cannot traverse in air) |
|
||||||
|
| 2 | `ObstacleHeight <= 15` | `Step` |
|
||||||
|
| 3 | `ObstacleHeight <= 60 AND CurrentSpeed >= JogSpeed` | `Vault` |
|
||||||
|
| 4 | `ObstacleHeight <= 150 AND ClearanceAbove >= 180` | `Mantle` |
|
||||||
|
| 5 | `ObstacleHeight <= 80 AND ClearanceAbove <= 90 AND ClearanceAbove > 40` | `Slide` |
|
||||||
|
| 6 | `ObstacleDepth >= 60 AND ClearanceAbove <= 80 AND ClearanceAbove >= 30` | `Squeeze` |
|
||||||
|
| 7 | `ObstacleHeight > 150 AND ClearanceAbove >= 200` | `Climb` |
|
||||||
|
| 8 | (default) | `Blocked` |
|
||||||
|
|
||||||
|
**Reuse Notes:** Thresholds should be in a `DA_TraversalConfig` Data Asset for easy tuning. Root motion montages selected by traversal type from a map: `Map<E_TraversalType, UAnimMontage>`. Motion Warping targets set from obstacle edge location.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### TOP 3 — AI State Transition Chooser
|
||||||
|
|
||||||
|
**Table Name:** `CT_AIState`
|
||||||
|
|
||||||
|
**Blueprint:** [`BPC_AIStateMachine`](../blueprints/09-ai/83_BPC_AIStateMachine.md:241)
|
||||||
|
|
||||||
|
**Input Columns:**
|
||||||
|
|
||||||
|
| Column | Type | Value Range | Source |
|
||||||
|
|--------|------|-------------|--------|
|
||||||
|
| `CurrentState` | `E_AIState` | Patrol/Search/Combat/Flee/Idle | Self |
|
||||||
|
| `bHasTarget` | `Boolean` | true/false | `BPC_AIPerceptionSystem.HasCurrentTarget()` |
|
||||||
|
| `bTargetVisible` | `Boolean` | true/false | `BPC_AIPerceptionSystem.IsTargetVisible()` |
|
||||||
|
| `AlertLevel` | `Float` | 0.0–1.0 | `BPC_AlertSystem.AlertLevel` |
|
||||||
|
| `HealthRatio` | `Float` | 0.0–1.0 | `BPC_HealthSystem (enemy).CurrentHealth/MaxHealth` |
|
||||||
|
| `bFearActive` | `Boolean` | true/false | `BPC_FearSystem.IsFeared()` |
|
||||||
|
| `LastKnownTargetLocation` | `Vector` | world position | `BPC_AIMemorySystem.LastKnownLocation` |
|
||||||
|
| `DistanceToTarget` | `Float` | 0–MaxPerceptionRange | Distance calc |
|
||||||
|
| `TimeSinceLastSighting` | `Float` | 0–∞ seconds | `BPC_AIMemorySystem.TimeSinceLastSighting` |
|
||||||
|
|
||||||
|
**Output Column:** `E_AIState` (new target state)
|
||||||
|
|
||||||
|
**All Rows:**
|
||||||
|
|
||||||
|
| Row | Conditions | Outcome |
|
||||||
|
|-----|-----------|---------|
|
||||||
|
| 1 | `bFearActive == true AND HealthRatio <= 0.3` | `Flee` |
|
||||||
|
| 2 | `CurrentState == Combat AND HealthRatio <= 0.15` | `Flee` |
|
||||||
|
| 3 | `bHasTarget == true AND bTargetVisible == true AND AlertLevel >= 0.7` | `Combat` |
|
||||||
|
| 4 | `bHasTarget == true AND bTargetVisible == true AND AlertLevel < 0.7 AND AlertLevel >= 0.3` | `Search` (advance to last known) |
|
||||||
|
| 5 | `bHasTarget == false AND AlertLevel >= 0.5 AND TimeSinceLastSighting <= 15` | `Search` |
|
||||||
|
| 6 | `AlertLevel < 0.3 AND TimeSinceLastSighting > 30` | `Patrol` |
|
||||||
|
| 7 | (default — same as current) | `CurrentState` |
|
||||||
|
|
||||||
|
**Reuse Notes:** Transition animations (alert→combat raise weapon, combat→search lower weapon) triggered by state change. BlendSpace selection per state: Patrol uses slow walk, Search uses jog, Combat uses strafing blendspace, Flee uses sprint.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### TOP 4 — Dialogue Choice Filter Chooser
|
||||||
|
|
||||||
|
**Table Name:** `CT_DialogueChoices`
|
||||||
|
|
||||||
|
**Blueprint:** [`BPC_DialogueChoiceSystem`](../blueprints/07-narrative/61_BPC_DialogueChoiceSystem.md:236)
|
||||||
|
|
||||||
|
**Input Columns:**
|
||||||
|
|
||||||
|
| Column | Type | Value Range | Source |
|
||||||
|
|--------|------|-------------|--------|
|
||||||
|
| `Choice.RequiredFlagTag` | `GameplayTag` | any valid narrative tag | `DA_DialogueData.ChoiceDefinitions[i].RequiredFlag` |
|
||||||
|
| `Choice.BlockedFlagTag` | `GameplayTag` | any valid narrative tag | `DA_DialogueData.ChoiceDefinitions[i].BlockedFlag` |
|
||||||
|
| `Choice.RequiredItemTag` | `GameplayTag` | any valid item tag | `DA_DialogueData.ChoiceDefinitions[i].RequiredItem` |
|
||||||
|
| `Choice.MinStressTier` | `E_StressTier` | Calm–Catatonic | `DA_DialogueData.ChoiceDefinitions[i].MinStressTier` |
|
||||||
|
| `CurrentNarrativeFlags` | `GameplayTagContainer` | accumulated flags | `BPC_NarrativeStateSystem.GetActiveFlags()` |
|
||||||
|
| `CurrentInventoryTags` | `GameplayTagContainer` | possessed item tags | `BPC_InventorySystem.GetAllItemTags()` |
|
||||||
|
| `CurrentStressTier` | `E_StressTier` | Calm–Catatonic | `BPC_StressSystem.CurrentTier` |
|
||||||
|
|
||||||
|
**Output Column:** Filtered `Array<S_DialogueChoice>` (visible choices)
|
||||||
|
|
||||||
|
**All Rows (per choice):**
|
||||||
|
|
||||||
|
| Row | Conditions | Action |
|
||||||
|
|-----|-----------|--------|
|
||||||
|
| 1 | `RequiredFlagTag.IsValid() AND !CurrentNarrativeFlags.HasTag(RequiredFlagTag)` | HIDE choice |
|
||||||
|
| 2 | `BlockedFlagTag.IsValid() AND CurrentNarrativeFlags.HasTag(BlockedFlagTag)` | HIDE choice |
|
||||||
|
| 3 | `RequiredItemTag.IsValid() AND !CurrentInventoryTags.HasTag(RequiredItemTag)` | HIDE choice |
|
||||||
|
| 4 | `MinStressTier > CurrentStressTier` | HIDE choice |
|
||||||
|
| 5 | (all conditions pass) | SHOW choice |
|
||||||
|
|
||||||
|
**Reuse Notes:** Maximum 6 visible choices at once. If more than 6 pass, prioritize by `Priority` field in choice definition. Hidden choices still count for narrative branching — they were "considered" but not presented.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### TOP 5 — Difficulty Scaling Chooser
|
||||||
|
|
||||||
|
**Table Name:** `CT_DifficultyScaling`
|
||||||
|
|
||||||
|
**Blueprint:** [`BPC_DifficultyManager`](../blueprints/10-adaptive/89_BPC_DifficultyManager.md:243)
|
||||||
|
|
||||||
|
**Input Columns:**
|
||||||
|
|
||||||
|
| Column | Type | Value Range | Source |
|
||||||
|
|--------|------|-------------|--------|
|
||||||
|
| `PlayerDeathCount` | `Integer` | 0–∞ | `BPC_PlayerMetricsTracker.DeathCount` |
|
||||||
|
| `PlayerAccuracy` | `Float` | 0.0–1.0 | `BPC_PlayerMetricsTracker.HitAccuracy` |
|
||||||
|
| `AverageCombatTime` | `Float` | 0–∞ seconds | `BPC_PlayerMetricsTracker.AvgCombatDuration` |
|
||||||
|
| `HealthItemUsageRate` | `Float` | 0–∞ per hour | `BPC_PlayerMetricsTracker.ConsumableUsageRate` |
|
||||||
|
| `PlaystyleArchetype` | `E_PlaystyleArchetype` | Aggressive/Stealthy/Explorer/Balanced | `BPC_PlaystyleClassifier.CurrentArchetype` |
|
||||||
|
| `bIsBossCombat` | `Boolean` | true/false | `BPC_AlertSystem.IsBossCombat()` |
|
||||||
|
| `CurrentDifficulty` | `E_DifficultyLevel` | Easy/Normal/Hard/Nightmare | Self (current state) |
|
||||||
|
| `bAdaptiveEnabled` | `Boolean` | true/false | Config setting |
|
||||||
|
|
||||||
|
**Output Column Parameters:**
|
||||||
|
|
||||||
|
| Output | Type | Range |
|
||||||
|
|--------|------|-------|
|
||||||
|
| `EnemyDamageMultiplier` | `Float` | 0.5–3.0 |
|
||||||
|
| `EnemyHealthMultiplier` | `Float` | 0.5–3.0 |
|
||||||
|
| `SpawnGroupSize` | `Integer` | 1–8 |
|
||||||
|
| `ResourceScarcity` | `Float` | 0.2–2.0 (ammo/health items) |
|
||||||
|
| `EnemyPerceptionSpeed` | `Float` | 0.5–2.0 |
|
||||||
|
| `EnemyReactionTime` | `Float` | 0.2–2.0 seconds |
|
||||||
|
|
||||||
|
**All Rows (simplified — full table uses continuous interpolation):**
|
||||||
|
|
||||||
|
| Row | Conditions | Difficulty Band | Multipliers |
|
||||||
|
|-----|-----------|-----------------|-------------|
|
||||||
|
| 1 | `bIsBossCombat == true` | Fixed (no adaptive) | Damage=1.2, Health=1.5, Resources=1.0 |
|
||||||
|
| 2 | `PlayerDeathCount >= 5 AND bAdaptiveEnabled` | Easier | Damage=0.7, Health=0.8, Resources=1.5, Perception=0.7 |
|
||||||
|
| 3 | `PlayerDeathCount <= 1 AND PlayerAccuracy >= 0.7 AND bAdaptiveEnabled` | Harder | Damage=1.5, Health=1.3, Resources=0.7, Perception=1.3 |
|
||||||
|
| 4 | `PlaystyleArchetype == Stealthy` | Stealth-tuned | Perception=0.8, SpawnGroups=-2, ReactionTime=1.5 |
|
||||||
|
| 5 | `PlaystyleArchetype == Aggressive` | Combat-tuned | SpawnGroups=+2, Resources=1.3, Perception=1.0 |
|
||||||
|
| 6 | (default — Normal metrics) | Normal | All multipliers = 1.0 |
|
||||||
|
|
||||||
|
**Reuse Notes:** Continuous interpolation between rows rather than hard switches — avoids jarring difficulty changes. All thresholds and multipliers in `DA_DifficultyProfile` Data Asset. `PlaystyleArchetype` is a rolling average, not instant — prevents oscillation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Gating Rules Data Asset Specification
|
||||||
|
|
||||||
|
### DA_StateGatingTable
|
||||||
|
|
||||||
|
```
|
||||||
|
Class: UPrimaryDataAsset
|
||||||
|
Asset Path: Content/Framework/Core/DA_StateGatingTable
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
GatingRules: Array<S_StateGatingRule>
|
||||||
|
- ActionTag: GameplayTag // e.g., "Action.Weapon.Fire"
|
||||||
|
- BlockedStates: Array<E_PlayerActionState> // e.g., [Dead, Hiding, Reloading, ...]
|
||||||
|
- BlockedGamePhases: Array<E_GamePhase> // e.g., [MainMenu, Cutscene, Loading]
|
||||||
|
- RequiredTags: GameplayTagContainer // e.g., [State.CanFire, Status.Armed]
|
||||||
|
- BlockedTags: GameplayTagContainer // e.g., [Status.Disarmed, Status.Cuffed]
|
||||||
|
- BlockReason: Text // e.g., "Cannot fire while reloading"
|
||||||
|
- Priority: Integer // 0 = checked first
|
||||||
|
```
|
||||||
|
|
||||||
|
This Data Asset allows designers to add, remove, or modify gating rules without touching the State Manager blueprint. The blueprint reads the array and evaluates rules in priority order.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Architecture Document: BPC_StateManager. Conforms to the Modular Game Framework conventions. GASP is sacred. Ready for Code agent implementation.*
|
||||||
214
docs/architecture/enhanced-input-system.md
Normal file
214
docs/architecture/enhanced-input-system.md
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
# Enhanced Input System Architecture
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
The project has **no input system specification** despite 230+ cross-references to a non-existent [`BPC_InputManager`](../02-player/13_BPC_InputManager.md) across existing blueprint specs. UE5's Enhanced Input System must be architected into the framework using a centralized [`SS_EnhancedInputManager`](Game Instance Subsystem) that manages Input Mapping Context push/pop, priority, platform profiles, and input mode coordination with [`SS_UIManager`](docs/blueprints/06-ui/44_SS_UIManager.md).
|
||||||
|
|
||||||
|
## Proposed Solution
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[Game Boot / GI_GameFramework Init] --> B[SS_EnhancedInputManager.Initialize]
|
||||||
|
B --> C[Load DA_InputMappingProfile]
|
||||||
|
C --> D[Cache platform-specific IMCs]
|
||||||
|
|
||||||
|
E[GM_CoreGameMode.OnPlayerPossess] --> F[SS_EnhancedInputManager.PushDefaultContext]
|
||||||
|
F --> G[Add IMC_Default Priority 0 via EnhancedInputLocalPlayerSubsystem]
|
||||||
|
|
||||||
|
H[Gameplay Event] --> I{Context Switch?}
|
||||||
|
I -->|Open Inventory| J[PushContext IMC_WristwatchUI Priority 10]
|
||||||
|
I -->|Pick Up Item| K[PushContext IMC_Inspection Priority 20]
|
||||||
|
I -->|Enter Hiding| L[PushContext IMC_Hiding Priority 5]
|
||||||
|
I -->|Open Pause| M[SS_UIManager.ShowMenu + PushContext IMC_UI Priority 100]
|
||||||
|
|
||||||
|
N[Exit Context] --> O[SS_EnhancedInputManager.PopContext]
|
||||||
|
O --> P[Remove IMC, restore lower priority contexts]
|
||||||
|
|
||||||
|
Q[SS_SettingsSystem.ApplyControlSettings] --> R[SS_EnhancedInputManager.RebindKey]
|
||||||
|
R --> S[Update IMC mappings via DA_InputMappingProfile]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Architecture Decision: Centralized Subsystem (Option A)
|
||||||
|
`SS_EnhancedInputManager` is a **Game Instance Subsystem**, matching the project's existing [`SS_UIManager`](docs/blueprints/06-ui/44_SS_UIManager.md), [`SS_SettingsSystem`](docs/blueprints/12-settings/105_SS_SettingsSystem.md), and [`SS_SaveManager`](docs/blueprints/05-saveload/35_SS_SaveManager.md) pattern. It manages all Input Mapping Contexts globally, while individual systems request context pushes via a clean API (function calls + dispatchers).
|
||||||
|
|
||||||
|
### Context Priority Ladder
|
||||||
|
|
||||||
|
| Priority | Context | Trigger | Overrides |
|
||||||
|
|----------|---------|---------|-----------|
|
||||||
|
| 0 | `IMC_Default` | Persistent gameplay | Nothing |
|
||||||
|
| 5 | `IMC_Hiding` | Enter hiding spot | Movement, Interact |
|
||||||
|
| 10 | `IMC_WristwatchUI` | Open watch/inventory | Movement, Look |
|
||||||
|
| 20 | `IMC_Inspection` | Pick up 3D item | All below |
|
||||||
|
| 100 | `IMC_UI` | Pause/Settings/Journal | Everything |
|
||||||
|
|
||||||
|
Higher priority = takes precedence. Multiple contexts can be active simultaneously.
|
||||||
|
|
||||||
|
### Input Actions (IA_) Master Registry
|
||||||
|
|
||||||
|
#### Axis2D Inputs
|
||||||
|
| Action | Value Type | Used In | Description |
|
||||||
|
|--------|-----------|---------|-------------|
|
||||||
|
| `IA_Move` | Axis2D | IMC_Default | W/A/S/D + Left Stick → locomotion |
|
||||||
|
| `IA_Look` | Axis2D | IMC_Default | Mouse XY + Right Stick → camera |
|
||||||
|
| `IA_Inspect_Rotate` | Axis2D | IMC_Inspection | Mouse/Right Stick → rotate item |
|
||||||
|
| `IA_UI_Navigate` | Axis2D | IMC_WristwatchUI, IMC_UI | D-Pad/Arrows → menu navigation |
|
||||||
|
| `IA_Hide_Look` | Axis2D | IMC_Hiding | Mouse/Right Stick → look while hidden |
|
||||||
|
|
||||||
|
#### Axis1D Inputs
|
||||||
|
| Action | Value Type | Used In | Description |
|
||||||
|
|--------|-----------|---------|-------------|
|
||||||
|
| `IA_Inspect_Zoom` | Axis1D | IMC_Inspection | Scroll/LT-RT → zoom item |
|
||||||
|
| `IA_Hide_Peek` | Axis1D | IMC_Hiding | W/S → lean forward in hiding |
|
||||||
|
| `IA_QuickSlotScroll` | Axis1D | IMC_Default | Scroll wheel → cycle quick slots |
|
||||||
|
|
||||||
|
#### Digital (Bool) Inputs — Gameplay
|
||||||
|
| Action | Used In | PC Default | Gamepad Default | Description |
|
||||||
|
|--------|---------|------------|-----------------|-------------|
|
||||||
|
| `IA_Interact` | IMC_Default | E / Left Click | X / Square | Pick up, hold for physics-drag |
|
||||||
|
| `IA_PrimaryAction` | IMC_Default | LMB | RT / R2 | Fire weapon / Swing tool |
|
||||||
|
| `IA_SecondaryAction` | IMC_Default | RMB | LT / L2 | ADS / Shield |
|
||||||
|
| `IA_Sprint` | IMC_Default | L-Shift | L3 | Run (triggers stamina + stress) |
|
||||||
|
| `IA_Crouch` | IMC_Default | C / L-Ctrl | B / Circle | Sneak / crawl |
|
||||||
|
| `IA_Vault_Climb` | IMC_Default | Spacebar | A / Cross | Contextual parkour |
|
||||||
|
| `IA_Jump` | IMC_Default | Spacebar | A / Cross | Basic jump (coexists with Vault via context) |
|
||||||
|
| `IA_Flashlight` | IMC_Default | F | D-Pad Up | Toggle light |
|
||||||
|
| `IA_QuickHeal` | IMC_Default | Q / H | D-Pad Down | Consume health item |
|
||||||
|
| `IA_Reload` | IMC_Default | R | Y / Triangle | Reload weapon |
|
||||||
|
| `IA_OpenWatch` | IMC_Default | Tab / I | View / Touchpad | Wristwatch UI |
|
||||||
|
| `IA_PauseMenu` | IMC_Default | Esc / P | Menu / Options | Pause game |
|
||||||
|
| `IA_QuickSlot1`–`IA_QuickSlot8` | IMC_Default | 1–8 | None | Direct quick slot selection |
|
||||||
|
|
||||||
|
#### Digital (Bool) Inputs — Context-Specific
|
||||||
|
| Action | Used In | PC Default | Gamepad Default | Description |
|
||||||
|
|--------|---------|------------|-----------------|-------------|
|
||||||
|
| `IA_Inspect_Flip` | IMC_Inspection | F | Y / Triangle | Flip document |
|
||||||
|
| `IA_Cancel_Drop` | IMC_Inspection | RMB / Esc | B / Circle | Exit inspection |
|
||||||
|
| `IA_UI_Select` | IMC_WristwatchUI, IMC_UI | E / Enter | A / Cross | Confirm/equip |
|
||||||
|
| `IA_UI_Combine` | IMC_WristwatchUI | C | X / Square | Item combination |
|
||||||
|
| `IA_UI_DropItem` | IMC_WristwatchUI | X | Y / Triangle | Drop from inventory |
|
||||||
|
| `IA_CloseWatch` | IMC_WristwatchUI | Tab / Esc | B / Circle | Lower arm |
|
||||||
|
| `IA_UI_Back` | IMC_UI | Esc / Backspace | B / Circle | Back one menu level |
|
||||||
|
| `IA_Hide_HoldBreath` | IMC_Hiding | Spacebar (Hold) | LT+RT (Hold) | Suppress breathing |
|
||||||
|
| `IA_Exit_Hide` | IMC_Hiding | C / Esc | B / Circle | Leave hiding spot |
|
||||||
|
|
||||||
|
#### New Input Types Added (beyond user's original list)
|
||||||
|
| Action | Value Type | Used In | Description | Rationale |
|
||||||
|
|--------|-----------|---------|-------------|-----------|
|
||||||
|
| `IA_Jump` | Digital | IMC_Default | Separate from Vault for non-contextual jumps | Prevents accidental climbing when player just wants to jump |
|
||||||
|
| `IA_QuickSlotScroll` | Axis1D | IMC_Default | Cycle through 8 quick slots | Natural controller wheel support for inventory |
|
||||||
|
| `IA_QuickSlot1`–`IA_QuickSlot8` | Digital | IMC_Default | Direct slot access (KB only) | Quick weapon/item switching |
|
||||||
|
| `IA_UI_Back` | Digital | IMC_UI | Universal back navigation | Separates "back" from "cancel" semantics |
|
||||||
|
| `IA_ToggleAccessibility` | Digital | IMC_UI | Toggle accessibility features mid-game | Required by [`BPC_AccessibilitySettings`](../02-player/104_BPC_AccessibilitySettings.md) |
|
||||||
|
| `IA_SkipCutscene` | Digital | IMC_Default | Hold to skip (contextual) | Already referenced by [`BPC_CutsceneBridge`](../07-narrative/64_BPC_CutsceneBridge.md) |
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
blueprints/
|
||||||
|
15-input/ # NEW directory
|
||||||
|
128_SS_EnhancedInputManager.md # Central subsystem spec
|
||||||
|
14-data-assets/
|
||||||
|
129_DA_InputMappingProfile.md # Data Asset for platform profiles
|
||||||
|
|
||||||
|
Content/
|
||||||
|
Framework/
|
||||||
|
Input/ # NEW directory
|
||||||
|
Actions/ # IA_* Input Action assets
|
||||||
|
IA_Move.uasset
|
||||||
|
IA_Look.uasset
|
||||||
|
IA_Interact.uasset
|
||||||
|
... (all 30+ IA_ assets)
|
||||||
|
Contexts/ # IMC_* Input Mapping Context assets
|
||||||
|
IMC_Default.uasset
|
||||||
|
IMC_Inspection.uasset
|
||||||
|
IMC_WristwatchUI.uasset
|
||||||
|
IMC_Hiding.uasset
|
||||||
|
IMC_UI.uasset
|
||||||
|
DataAssets/
|
||||||
|
DA_InputMappingProfile.uasset # Platform profiles
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Contracts
|
||||||
|
|
||||||
|
### SS_EnhancedInputManager Interface
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// === Public Functions ===
|
||||||
|
|
||||||
|
// Initialize with a profile
|
||||||
|
void Initialize(DA_InputMappingProfile Profile);
|
||||||
|
|
||||||
|
// Context management (stack-based)
|
||||||
|
void PushContext(E_InputContext ContextType, int32 PriorityOverride = -1);
|
||||||
|
void PopContext(E_InputContext ContextType);
|
||||||
|
void SetContextPriority(E_InputContext ContextType, int32 NewPriority);
|
||||||
|
TArray<E_InputContext> GetActiveContexts() const;
|
||||||
|
bool IsContextActive(E_InputContext ContextType) const;
|
||||||
|
|
||||||
|
// Input state queries (read-only for other systems)
|
||||||
|
bool IsActionPressed(FName ActionName) const;
|
||||||
|
float GetActionValue1D(FName ActionName) const;
|
||||||
|
FVector2D GetActionValue2D(FName ActionName) const;
|
||||||
|
|
||||||
|
// Key rebinding (called by SS_SettingsSystem)
|
||||||
|
void RebindKey(FName ActionName, FKey NewKey, E_InputPlatform Platform);
|
||||||
|
void ResetToDefaultBindings(E_InputPlatform Platform);
|
||||||
|
TMap<FName, FKey> GetCurrentBindings(E_InputPlatform Platform) const;
|
||||||
|
|
||||||
|
// Input mode coordination with SS_UIManager
|
||||||
|
void SetInputModeUIOnly();
|
||||||
|
void SetInputModeGameOnly();
|
||||||
|
void SetInputModeGameAndUI();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enums
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum E_InputContext {
|
||||||
|
Default = 0,
|
||||||
|
Hiding = 1,
|
||||||
|
WristwatchUI = 2,
|
||||||
|
Inspection = 3,
|
||||||
|
UI = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum E_InputPlatform {
|
||||||
|
PC_KeyboardMouse = 0,
|
||||||
|
Xbox = 1,
|
||||||
|
PS5_DualSense = 2
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Dispatchers
|
||||||
|
|
||||||
|
| Dispatcher | Payload | Description |
|
||||||
|
|------------|---------|-------------|
|
||||||
|
| `OnContextPushed` | `E_InputContext Context, int32 Priority` | Fired when a new context is activated |
|
||||||
|
| `OnContextPopped` | `E_InputContext Context` | Fired when a context is removed |
|
||||||
|
| `OnInputModeChanged` | `E_InputMode NewMode` | Syncs with SS_UIManager for cursor visibility |
|
||||||
|
| `OnKeyRebound` | `FName ActionName, FKey NewKey` | Fired after rebinding for UI update |
|
||||||
|
| `OnPlatformChanged` | `E_InputPlatform NewPlatform` | Fired on input device hot-swap |
|
||||||
|
|
||||||
|
### Communication Matrix
|
||||||
|
|
||||||
|
| Source | Target | Method | Data |
|
||||||
|
|--------|--------|--------|------|
|
||||||
|
| SS_EnhancedInputManager | UEnhancedInputLocalPlayerSubsystem | Direct (UE5 API) | Add/Remove Mapping Context |
|
||||||
|
| SS_EnhancedInputManager | SS_UIManager | Direct | Input mode changes |
|
||||||
|
| SS_EnhancedInputManager | SS_SettingsSystem | Direct | Key rebinding requests |
|
||||||
|
| SS_EnhancedInputManager | WBP_InteractionPromptDisplay | Dispatcher | Current action key icons |
|
||||||
|
| BPC_InteractionDetector | SS_EnhancedInputManager | Function Call | IsActionPressed for interact |
|
||||||
|
| BPC_FirearmSystem | SS_EnhancedInputManager | Function Call | GetActionValue1D for trigger |
|
||||||
|
| BPC_CutsceneBridge | SS_EnhancedInputManager | Function Call | PushContext/PopContext |
|
||||||
|
| BP_PuzzleDeviceActor | SS_EnhancedInputManager | Function Call | PushContext(Inspection) |
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. All 30+ Input Actions are created and mapped across all 3 platforms (PC, Xbox, PS5)
|
||||||
|
2. Context switching is seamless: pushing a higher-priority context overrides lower ones without blocking
|
||||||
|
3. Key rebinding via SS_SettingsSystem persists across sessions
|
||||||
|
4. Input mode changes (GameOnly ↔ UIOnly) correctly show/hide cursor
|
||||||
|
5. All existing specs that reference `BPC_InputManager` are updated to reference `SS_EnhancedInputManager`
|
||||||
|
6. Quick slot scrolling and direct selection work on both KB+M and gamepad
|
||||||
|
7. Hold inputs (HoldBreath, physics-drag) correctly trigger on hold and cancel on early release
|
||||||
|
8. Cutscene skip works via hold-to-skip (not tap)
|
||||||
137
docs/architecture/hud-overview.md
Normal file
137
docs/architecture/hud-overview.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# HUD System Architecture — Modular Game Framework
|
||||||
|
|
||||||
|
**Architecture Overview | UE 5.5–5.7 | Widget Blueprint**
|
||||||
|
|
||||||
|
This document explains how the 14 UI widgets in `docs/blueprints/06-ui/` connect and interact. Use this as a wiring reference when implementing the HUD layer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Widget Hierarchy
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
WBP_HUDController[WBP_HUDController — Root HUD Container] --> Diegetic[WBP_DiegeticHUDFrame — Health, Stress, Stamina, Compass]
|
||||||
|
WBP_HUDController --> Prompt[WBP_InteractionPromptDisplay — Interaction cues]
|
||||||
|
WBP_HUDController --> Subtitle[WBP_AccessibilityUI — Subtitles, Accessibility overlays]
|
||||||
|
WBP_HUDController --> Toast[WBP_NotificationToast — Toast messages]
|
||||||
|
WBP_HUDController --> Objective[WBP_ObjectiveDisplay — Active objectives]
|
||||||
|
WBP_HUDController --> ScreenFX[WBP_ScreenEffectController — Damage, Stress, Flash]
|
||||||
|
|
||||||
|
SS_UIManager[SS_UIManager — Menu Stack Manager] --> MainMenu[WBP_MainMenu]
|
||||||
|
SS_UIManager --> PauseMenu[WBP_PauseMenu]
|
||||||
|
SS_UIManager --> Inventory[WBP_InventoryMenu]
|
||||||
|
SS_UIManager --> Journal[WBP_JournalDocumentViewer]
|
||||||
|
SS_UIManager --> Settings[WBP_SettingsMenu]
|
||||||
|
SS_UIManager --> MenuFlow[WBP_MenuFlowController — State Machine]
|
||||||
|
|
||||||
|
SS_UIManager -.->|Input Mode Sync| SS_EnhancedInputManager
|
||||||
|
SS_UIManager -.->|Visibility| WBP_HUDController
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Two-Layer Architecture
|
||||||
|
|
||||||
|
| Layer | Manager | Widgets | When Visible |
|
||||||
|
|-------|---------|---------|-------------|
|
||||||
|
| **HUD Layer** | `WBP_HUDController` | 45-48, 53-54, 56 | Gameplay only |
|
||||||
|
| **Menu Layer** | `SS_UIManager` (44) | 49-52, 55, 57 | On top of gameplay (pause, menu, inventory) |
|
||||||
|
|
||||||
|
**Rule:** `WBP_HUDController` hides when any full-screen menu opens. `SS_UIManager` handles the menu stack (push/pop). Only one layer is interactive at a time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Widget Quick Reference
|
||||||
|
|
||||||
|
| # | Widget | Lines | Role | Key Input | Key Output |
|
||||||
|
|---|--------|-------|------|-----------|------------|
|
||||||
|
| 44 | `SS_UIManager` | — | Menu stack subsystem | `PushMenu`/`PopMenu` | Input mode, cursor state |
|
||||||
|
| 45 | `WBP_AccessibilityUI` | 141 | Subtitles + accessibility | `OnDialogueLine` dispatcher | Subtitle text on screen |
|
||||||
|
| 46 | `WBP_DiegeticHUDFrame` | 89 | In-world HUD skin | Player state dispatchers | Health/stress/stamina display |
|
||||||
|
| 47 | `WBP_HUDController` | 114 | Root HUD container | Game phase changes | Child widget visibility |
|
||||||
|
| 48 | `WBP_InteractionPromptDisplay` | 135 | Interaction cues | `OnFocusGained`/`OnFocusLost` | Prompt text + progress ring |
|
||||||
|
| 49 | `WBP_InventoryMenu` | — | Inventory grid UI | `BPC_InventorySystem` data | Drag-drop, equip, drop |
|
||||||
|
| 50 | `WBP_JournalDocumentViewer` | — | Document/journal reader | `BPC_DocumentArchiveSystem` | Paged text with font styles |
|
||||||
|
| 51 | `WBP_MainMenu` | — | Main menu screen | Game start/load events | New game, continue, settings |
|
||||||
|
| 52 | `WBP_MenuFlowController` | — | Menu state machine | Menu transitions | Back navigation |
|
||||||
|
| 53 | `WBP_NotificationToast` | 52 | Toast notifications | Any system dispatcher | Slide-in text + icon |
|
||||||
|
| 54 | `WBP_ObjectiveDisplay` | 86 | Objective overlay | `BPC_ObjectiveSystem` events | Objective text + progress |
|
||||||
|
| 55 | `WBP_PauseMenu` | — | Pause menu | Pause input action | Resume, save, load, quit |
|
||||||
|
| 56 | `WBP_ScreenEffectController` | 43 | Full-screen effects | Health/stress events | Damage vignette, flash |
|
||||||
|
| 57 | `WBP_SettingsMenu` | — | Settings screen | `SS_SettingsSystem` | Audio/video/controls tabs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Flow: HUD Widgets
|
||||||
|
|
||||||
|
```
|
||||||
|
Player State Components HUD Layer
|
||||||
|
┌─────────────────────┐ ┌──────────────────────────┐
|
||||||
|
│ BPC_HealthSystem │─OnHealthChanged──→│ WBP_DiegeticHUDFrame │
|
||||||
|
│ BPC_StressSystem │─OnStressTierChanged→│ WBP_ScreenEffectController│
|
||||||
|
│ BPC_StaminaSystem │─OnStaminaChanged─→│ (via WBP_HUDController) │
|
||||||
|
│ BPC_InteractionDetector│─OnFocusGained───→│ WBP_InteractionPromptDisplay│
|
||||||
|
│ BPC_DialoguePlayback │─OnDialogueLine───→│ WBP_AccessibilityUI │
|
||||||
|
│ BPC_ObjectiveSystem │─OnObjectiveUpdate→│ WBP_ObjectiveDisplay │
|
||||||
|
│ Any System │─ShowToast───────→│ WBP_NotificationToast │
|
||||||
|
└─────────────────────┘ └──────────────────────────┘
|
||||||
|
|
||||||
|
Key: WBP_ widgets NEVER write to game state. They only read via dispatchers.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Flow: Menu Widgets
|
||||||
|
|
||||||
|
```
|
||||||
|
Input Event Menu Layer (SS_UIManager)
|
||||||
|
┌──────────────────┐ ┌─────────────────────────┐
|
||||||
|
│ IA_Pause │──→ │ PushMenu(PauseMenu) │
|
||||||
|
│ IA_Inventory │──→ │ PushMenu(InventoryMenu) │
|
||||||
|
│ IA_Journal │──→ │ PushMenu(JournalViewer) │
|
||||||
|
│ IA_Escape (back) │──→ │ PopMenu() — back nav │
|
||||||
|
│ │ │ │
|
||||||
|
│ WBP_SettingsMenu │──SetFloat→│ SS_SettingsSystem │
|
||||||
|
│ │ │ └→ SS_AudioManager.SetBusVolume│
|
||||||
|
│ │ │ └→ Save to persistent storage│
|
||||||
|
└──────────────────┘ └─────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Order (Dependency-Safe)
|
||||||
|
|
||||||
|
| Step | Widget | Depends On | Reason |
|
||||||
|
|------|--------|-----------|--------|
|
||||||
|
| 1 | `WBP_HUDController` (47) | *(none)* | Root container — must exist first |
|
||||||
|
| 2 | `WBP_DiegeticHUDFrame` (46) | 47 | Parented by HUDController |
|
||||||
|
| 3 | `WBP_InteractionPromptDisplay` (48) | 47, `BPC_InteractionDetector` (16) | Needs prompt data |
|
||||||
|
| 4 | `WBP_NotificationToast` (53) | 47 | Parented by HUDController |
|
||||||
|
| 5 | `WBP_ObjectiveDisplay` (54) | 47, `BPC_ObjectiveSystem` (59) | Needs objective data |
|
||||||
|
| 6 | `WBP_ScreenEffectController` (56) | 47 | Parented by HUDController |
|
||||||
|
| 7 | `WBP_AccessibilityUI` (45) | 47, `BPC_DialoguePlaybackSystem` (60) | Needs dialogue events |
|
||||||
|
| 8 | `SS_UIManager` (44) | *(none — subsystem)* | Menu stack manager |
|
||||||
|
| 9 | `WBP_MenuFlowController` (52) | 44 | Menu state machine |
|
||||||
|
| 10 | `WBP_MainMenu` (51) | 44, 52 | First menu pushed |
|
||||||
|
| 11 | `WBP_PauseMenu` (55) | 44, 52 | Push on pause |
|
||||||
|
| 12 | `WBP_SettingsMenu` (57) | 44, 52, `SS_SettingsSystem` (105) | Push from menus |
|
||||||
|
| 13 | `WBP_InventoryMenu` (49) | 44, `BPC_InventorySystem` (31) | Needs inventory data |
|
||||||
|
| 14 | `WBP_JournalDocumentViewer` (50) | 44, `BPC_DocumentArchiveSystem` (29) | Needs document data |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Integration Points with New Systems (130-135)
|
||||||
|
|
||||||
|
| Widget | Integration |
|
||||||
|
|--------|------------|
|
||||||
|
| `WBP_HUDController` | Reads `BPC_StateManager (130).OnStateChanged` — hides HUD during `InCutscene`, `InMainMenu`, `Loading` |
|
||||||
|
| `WBP_InteractionPromptDisplay` | Calls `BPC_StateManager.IsActionPermitted(ActionTag)` — shows "Blocked: [Reason]" when action denied |
|
||||||
|
| `WBP_InteractionPromptDisplay` | Reads `BPC_StateManager.OnStateChangeDenied` — displays `BlockReason` to player |
|
||||||
|
| `WBP_SettingsMenu` | Calls `SS_AudioManager (132).SetBusVolume()` for each volume slider |
|
||||||
|
| `WBP_SettingsMenu` | Calls `SS_AudioManager.GetBusVolume()` to populate slider defaults |
|
||||||
|
| `WBP_AccessibilityUI` | Reads `BPC_StateManager.GetHeartRate()` for visual heartbeat indicator (deaf accessibility) |
|
||||||
|
| `WBP_DiegeticHUDFrame` | Reads `BPC_StateManager.GetVitalSignal()` to show heart rate tier indicator |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Architecture Overview: HUD System. See [`44_SS_UIManager.md`](../blueprints/06-ui/44_SS_UIManager.md) for the menu stack subsystem spec. See [`47_WBP_HUDController.md`](../blueprints/06-ui/47_WBP_HUDController.md) for the root HUD container spec.*
|
||||||
Reference in New Issue
Block a user