Add haptics example documentation for Project Void controller feedback

- Introduced comprehensive guide for setting up controller haptics and force feedback.
- Detailed directory structure for haptic profiles and creation steps for DA_HapticProfile instances.
- Included platform-specific configurations for Xbox and PS5 DualSense adaptive triggers.
- Outlined wiring of BPC_HapticsController to various gameplay systems and events.
- Provided accessibility integration options and testing checklist for haptic functionality.
This commit is contained in:
Lefteris Notas
2026-05-22 17:16:34 +03:00
parent 7c2e8df6b1
commit 14441c000c
16 changed files with 1213 additions and 46 deletions

View File

@@ -0,0 +1,577 @@
# 148 — Haptics Controller (`BPC_HapticsController`)
> **Blueprint-Only Implementation** — UE 5.55.7 fully supports controller haptics/force feedback from Blueprints. No C++ required. This component wraps UE5's `Play Force Feedback`, `Set Haptics By Value`, and DualSense adaptive trigger APIs behind a GameplayTag-driven event system.
---
## Purpose
Abstraction layer for all controller haptic feedback and force feedback effects. Gameplay systems trigger haptics by GameplayTag (e.g., `Haptic.Damage.Heavy`) rather than calling raw UE5 haptic APIs. This component handles platform detection (Xbox rumble vs PS5 DualSense adaptive triggers vs generic PC gamepad), respects accessibility settings (`BPC_AccessibilitySettings.bHapticsEnabled`), and manages effect priority/conflict resolution.
## Dependencies
- **Requires:** [`DA_HapticProfile`](docs/blueprints/14-data-assets/121_DA_HapticProfile.md) (effect definitions), [`BPC_AccessibilitySettings`](docs/blueprints/12-settings/104_BPC_AccessibilitySettings.md) (master toggle), [`BPC_StateManager`](docs/blueprints/16-state/130_BPC_StateManager.md) (heart rate for heartbeat haptic)
- **Required By:** `BPC_HealthSystem` (damage haptics), `BPC_FirearmSystem` (weapon fire kick), `BPC_MeleeSystem` (melee impact), `BPC_PhysicsDragSystem` (grab/release), `BPC_ScareEventSystem` (tension rumble), `BP_ItemPickup` (pickup pulse), `BPC_MovementStateSystem` (footstep rumble via GASP notifies)
- **Engine/Plugin Requirements:** Enhanced Input Plugin (controller detection), PlayStation 5 Controller Plugin (DualSense adaptive triggers — optional, graceful fallback)
## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `ActorComponent` |
| **Class Type** | Blueprint Component |
| **Asset Path** | `Content/Framework/Settings/BPC_HapticsController` |
| **Implements Interfaces** | None |
| **Attachment** | Player Controller (`PC_CoreController`) |
---
## 1. Enums
### `EHapticEvent`
| Value | Description |
|-------|-------------|
| `None = 0` | No haptic effect |
| `Damage = 1` | Player takes damage (intensity scales with amount) |
| `HeavyDamage = 2` | Critical/major damage hit |
| `Heartbeat = 3` | Heartbeat pulse (tempo from BPC_StateManager heart rate) |
| `WeaponFire = 4` | Weapon fire kick |
| `WeaponReload = 5` | Reload action feedback |
| `MeleeImpact = 6` | Melee weapon hit/kill |
| `Footstep = 7` | Footstep surface-dependent rumble |
| `Explosion = 8` | Nearby explosion or environmental blast |
| `PickupItem = 9` | Item picked up |
| `DropItem = 10` | Item dropped/discarded |
| `GrabObject = 11` | Physics object grabbed |
| `ReleaseObject = 12` | Physics object released/thrown |
| `ScareEvent = 13` | Jump scare / tension event |
| `AmbientPulse = 14` | Low-level ambient tension rumble |
| `UI_Confirm = 15` | Menu confirm/select haptic click |
| `UI_Navigate = 16` | Menu navigation tick |
| `LowHealth = 17` | Health-critical warning pulse |
| `StaminaExhausted = 18` | Stamina depleted heavy pulse |
| `Death = 19` | Player death rumble |
### `EHapticMotor`
| Value | Description |
|-------|-------------|
| `Left = 0` | Left (low-frequency) motor only |
| `Right = 1` | Right (high-frequency) motor only |
| `Both = 2` | Both motors simultaneously |
### `EControllerPlatform`
| Value | Description |
|-------|-------------|
| `Unknown = 0` | Platform not yet detected |
| `PC_Generic = 1` | PC with generic gamepad (XInput) |
| `Xbox = 2` | Xbox Series X\|S / Xbox One controller |
| `PS5_DualSense = 3` | PlayStation 5 DualSense controller |
| `PS4_DualShock = 4` | PlayStation 4 DualShock 4 controller |
---
## 2. Structs
### `S_HapticRequest`
| Field | Type | Description |
|-------|------|-------------|
| `ProfileTag` | `FGameplayTag` | Which DA_HapticProfile to use |
| `EventType` | `EHapticEvent` | Event category |
| `IntensityMultiplier` | `Float` | Scale intensity (0.02.0, 1.0 = default) |
| `DurationOverride` | `Float` | Override duration (-1 = use profile default) |
| `Priority` | `Int32` | Higher interrupts lower (0100) |
| `RequestTime` | `Float` | Game time when requested (for cooldown) |
---
## 3. Variables
### Configuration (Instance Editable)
| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `HapticProfileMap` | `TMap<FGameplayTag, DA_HapticProfile>` | `Empty` | `Config` | All haptic profiles loaded at startup |
| `bHapticsEnabled` | `Bool` | `true` | `Config` | Master toggle (synced from BPC_AccessibilitySettings) |
| `bEnableDualSenseTriggers` | `Bool` | `true` | `Config` | Enable adaptive trigger effects on PS5 |
| `bEnableSpeakerAudio` | `Bool` | `true` | `Config` | Enable controller speaker audio on PS5 |
| `MinTimeBetweenEffects` | `Float` | `0.05` | `Config` | Minimum seconds between any two effects (prevents rumble spam) |
| `HapticIntensityScale` | `Float` | `1.0` | `Config` | Global intensity multiplier (0.0 = off, 1.0 = full) |
| `HeartbeatMinBPM` | `Float` | `40.0` | `Config` | Minimum BPM for heartbeat haptic |
| `HeartbeatMaxBPM` | `Float` | `180.0` | `Config` | Maximum BPM for heartbeat haptic |
### Internal (Private)
| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `CurrentPlatform` | `EControllerPlatform` | `Unknown` | `State` | Detected controller platform |
| `bIsInitialized` | `Bool` | `false` | `State` | Whether Initialize has completed |
| `CachedPlayerController` | `APlayerController` | `None` | `Cache` | Cached owner PlayerController reference |
| `ActiveHapticEffect` | `UForceFeedbackEffect` | `None` | `State` | Currently playing effect asset |
| `LastPlayTime` | `Float` | `0.0` | `State` | Game time of last played effect |
| `PendingRequest` | `S_HapticRequest` | `Empty` | `State` | Currently queued request |
| `bHeartbeatActive` | `Bool` | `false` | `State` | Whether heartbeat loop is active |
---
## 4. Functions
### Public Functions
#### `Initialize` → `void`
- **Description:** Detects controller platform, loads all `DA_HapticProfile` instances into `HapticProfileMap`, caches PlayerController.
- **Parameters:** None
- **Blueprint Authority:** Local Client Only
- **Flow:**
1. Get Owner → Cast to `APlayerController` → Store as `CachedPlayerController`
2. Detect platform: Check `UGameplayStatics::GetPlatformName()` + connected input devices
3. Set `CurrentPlatform` (Xbox, PS5_DualSense, PS4_DualShock, or PC_Generic)
4. Load all `DA_HapticProfile` assets from `Content/Framework/DataAssets/Haptics/` into `HapticProfileMap`
5. If `BPC_AccessibilitySettings` exists on owner → bind to `OnHapticsToggleChanged`
6. Bind to `BPC_StateManager.OnHeartRateChanged` for heartbeat haptic
7. Set `bIsInitialized = true`
8. Broadcast `OnHapticsControllerInitialized`
#### `PlayHapticByTag` → `void`
- **Description:** Play a haptic effect by its GameplayTag. Main entry point for all gameplay systems.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `ProfileTag` | `FGameplayTag` | Tag matching a DA_HapticProfile |
| `IntensityMultiplier` | `Float` | Scale intensity (default 1.0) |
- **Blueprint Authority:** Local Client Only
- **Flow:**
1. Validate `bHapticsEnabled` and `bIsInitialized` — if disabled, return
2. Check `MinTimeBetweenEffects` cooldown — if too soon, queue or skip
3. Look up `DA_HapticProfile` from `HapticProfileMap` by `ProfileTag`
4. If not found: log warning, return
5. Build `S_HapticRequest` with profile data
6. Call `PlayHapticInternal()` with the request
7. Broadcast `OnHapticPlayed` with tag
#### `PlayHapticByEvent` → `void`
- **Description:** Play a haptic effect by event type. Convenience wrapper for systems that don't know the exact tag.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `EventType` | `EHapticEvent` | Which event to trigger |
| `IntensityMultiplier` | `Float` | Scale intensity (default 1.0) |
- **Flow:** Converts `EHapticEvent` to default tag (e.g., `Damage``Haptic.Damage.Default`) and calls `PlayHapticByTag`.
#### `StopHaptic` → `void`
- **Description:** Stop all currently playing haptic effects.
- **Flow:**
1. If `CachedPlayerController` valid: call `Stop Force Feedback` node
2. Set `ActiveHapticEffect = None`
3. If `bHeartbeatActive`: call `StopHeartbeatHaptic()`
4. Broadcast `OnHapticStopped`
#### `PlayHeartbeatHaptic` → `void`
- **Description:** Start or update the continuous heartbeat pulse haptic at the given BPM.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `BeatsPerMinute` | `Float` | Heart rate in BPM (from BPC_StateManager) |
- **Flow:**
1. Clamp BPM to `HeartbeatMinBPM``HeartbeatMaxBPM`
2. Calculate pulse interval: `Interval = 60.0 / BPM`
3. Set `bHeartbeatActive = true`
4. Start a looping timer at `Interval` seconds
5. Each tick: call `PlayHapticByTag(Haptic.Heartbeat)` with intensity from BPM
6. If BPM changes: update timer interval
#### `StopHeartbeatHaptic` → `void`
- **Description:** Stop the continuous heartbeat haptic loop.
- **Flow:** Clear heartbeat timer, set `bHeartbeatActive = false`.
#### `SetHapticsEnabled` → `void`
- **Description:** Enable or disable all haptic output. Called by accessibility toggle.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `bEnabled` | `Bool` | New state |
- **Flow:**
1. Set `bHapticsEnabled = bEnabled`
2. If disabled: call `StopHaptic()`
3. Broadcast `OnHapticsEnabledChanged`
#### `SetControllerPlatform` → `void`
- **Description:** Force a specific controller platform (for testing or hot-swap).
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `Platform` | `EControllerPlatform` | Target platform |
#### `GetControllerPlatform` → `EControllerPlatform`
- **Description:** Returns the detected controller platform. Read-only.
#### `IsDualSenseConnected` → `Bool`
- **Description:** Returns true if a PS5 DualSense controller is detected.
- **Flow:** Returns `CurrentPlatform == PS5_DualSense`
#### `SetDualSenseTriggerEffect` → `void`
- **Description:** Set adaptive trigger resistance on a specific DualSense trigger. No-op on non-DualSense platforms.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `TriggerSide` | `Name` | "Left" or "Right" |
| `EffectType` | `Name` | "Resistance", "Vibration", "WeaponFire", "BowDraw", etc. |
| `StartPosition` | `Int32` | Trigger position where effect begins (09) |
| `Strength` | `Int32` | Effect strength (08) |
- **Blueprint Authority:** Local Client Only
- **Flow:**
1. If `CurrentPlatform != PS5_DualSense`: return (graceful no-op)
2. If `bEnableDualSenseTriggers == false`: return
3. Call platform-specific DualSense trigger API via `PlayerController`
4. Log effect for debugging
### Protected / Private Functions
#### `PlayHapticInternal` → `void`
- **Description:** Core haptic playback logic. Resolves platform, selects the right effect asset, handles priority conflicts.
- **Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `Request` | `S_HapticRequest` | Full haptic request |
- **Flow:**
1. Check priority: if `Request.Priority < PendingRequest.Priority` and `PendingRequest` is active → skip
2. If `Request.Priority >= PendingRequest.Priority`: interrupt current effect
3. Resolve platform: select `UForceFeedbackEffect` from `DA_HapticProfile` for `CurrentPlatform`
4. If no platform-specific asset: fall back to generic PC effect
5. Apply `IntensityMultiplier` to `HapticIntensityScale`
6. Call `Play Force Feedback` node on `CachedPlayerController`:
- Input: `ForceFeedbackEffect`, `IntensityMultiplier`, `bLooping=false`, `bIgnoreTimeDilation=true`
7. Store as `ActiveHapticEffect`
8. Set `LastPlayTime = GameTimeInSeconds`
9. Broadcast `OnHapticPlayed`
#### `DetectControllerPlatform` → `void`
- **Description:** Queries the input system to determine which controller is connected.
- **Flow:**
1. Check `UGameplayStatics::GetPlatformName()`
2. If platform contains "PS5" → `PS5_DualSense`
3. If platform contains "PS4" → `PS4_DualShock`
4. If platform contains "Xbox" or "XboxOne" or "XSX" → `Xbox`
5. Otherwise: check connected devices → if gamepad found → `PC_Generic`, else → `Unknown`
---
## 5. Event Dispatchers
| Dispatcher | Parameters | Bind Access | Description |
|------------|-----------|-------------|-------------|
| `OnHapticsControllerInitialized` | — | `Public` | Fired after Initialize completes |
| `OnHapticPlayed` | `FGameplayTag ProfileTag`, `EHapticEvent EventType`, `Float Intensity` | `Public` | Fired when any haptic effect starts |
| `OnHapticStopped` | — | `Public` | Fired when haptics stop (manual or effect ends) |
| `OnHapticsEnabledChanged` | `Bool bEnabled` | `Public` | Fired when master toggle changes |
| `OnControllerPlatformChanged` | `EControllerPlatform NewPlatform` | `Public` | Fired on controller hot-swap |
| `OnDualSenseTriggerActivated` | `Name TriggerSide`, `Name EffectType` | `Public` | Fired when adaptive trigger effect applied (PS5 only) |
---
## 6. Overridden Events / Custom Events
### Event: `BeginPlay`
- **Description:** Startup. Calls `Initialize()`.
- **Flow:**
1. Call `Initialize()`
2. If `CachedPlayerController` is null: log error, return
3. Register for controller connection/disconnection events
### Event: `EndPlay`
- **Description:** Cleanup on component destruction.
- **Flow:**
1. Call `StopHaptic()` (stop all effects)
2. Call `StopHeartbeatHaptic()`
3. Unbind from all dispatchers
4. Clear cached references
---
## 7. Blueprint Graph Logic Flow
```mermaid
flowchart TD
A[BeginPlay] --> B[Initialize]
B --> C{Detect Controller Platform}
C --> D[Set CurrentPlatform]
D --> E[Load DA_HapticProfile Map]
E --> F[Bind to AccessibilitySettings.OnHapticsToggleChanged]
F --> G[Bind to StateManager.OnHeartRateChanged]
G --> H[Broadcast OnInitialized]
I[PlayHapticByTag] --> J{bHapticsEnabled?}
J -->|No| K[Return]
J -->|Yes| L{Cooldown check}
L -->|TooSoon| M[Queue or skip]
L -->|OK| N[Lookup DA_HapticProfile]
N --> O{Found?}
O -->|No| P[Log Warning]
O -->|Yes| Q[Build S_HapticRequest]
Q --> R[PlayHapticInternal]
R --> S{Platform == PS5?}
S -->|Yes| T[Play Force Feedback PS5 Profile]
S -->|No| U[Play Force Feedback Generic]
T --> V[Broadcast OnHapticPlayed]
U --> V
W[PlayHeartbeatHaptic] --> X[Clamp BPM]
X --> Y[Calculate Interval = 60/BPM]
Y --> Z[Start Looping Timer]
Z --> AA[Each Tick: PlayHapticByTag Haptic.Heartbeat]
```
---
## 8. Communication Matrix
| Who Talks | How | What Is Sent |
|-----------|-----|-------------|
| `BPC_HealthSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.Damage.Heavy, Intensity)` on damage taken |
| `BPC_FirearmSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.WeaponFire.Pistol)` on fire |
| `BPC_MeleeSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.MeleeImpact)` on hit |
| `BPC_PhysicsDragSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.Grab)` / `Haptic.Release` |
| `BPC_ScareEventSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.ScareEvent)` on scare trigger |
| `BPC_ReloadSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.WeaponReload)` on reload complete |
| `BP_ItemPickup` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.PickupItem)` on collect |
| `BPC_MovementStateSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.Footstep. + SurfaceTag)` via GASP notify |
| `BPC_StateManager` | `Dispatcher` | `OnHeartRateChanged(BPM)``BPC_HapticsController::PlayHeartbeatHaptic(BPM)` |
| `BPC_AccessibilitySettings` | `Dispatcher` | `OnHapticsToggleChanged(bEnabled)``BPC_HapticsController::SetHapticsEnabled()` |
| `BPC_DeathHandlingSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.Death)` on death |
| `BPC_DamageReceptionSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.Explosion)` on area damage |
| `BPC_StaminaSystem` | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.StaminaExhausted)` on empty |
| `BPC_HealthSystem` (low) | `Function Call` | `BPC_HapticsController::PlayHapticByTag(Haptic.LowHealth)` when <25% HP |
---
## 9. Validation / Testing Checklist
- [ ] `Initialize` correctly detects Xbox controller: `CurrentPlatform = Xbox`
- [ ] `Initialize` correctly detects PS5 DualSense: `CurrentPlatform = PS5_DualSense`
- [ ] `PlayHapticByTag` with valid tag plays force feedback on controller
- [ ] `PlayHapticByTag` with invalid tag logs warning but does not crash
- [ ] `StopHaptic` immediately stops all controller vibration
- [ ] `bHapticsEnabled = false` causes all `PlayHapticByTag` calls to be skipped
- [ ] Heartbeat haptic loops at correct interval (60 BPM 1 pulse/second)
- [ ] Heartbeat BPM changes dynamically when `PlayHeartbeatHaptic(120)` called
- [ ] DualSense trigger resistance activates on PS5 (R2 stiffens when aiming)
- [ ] Non-DualSense platforms gracefully skip trigger effects (no crash, no log spam)
- [ ] Priority conflict: higher priority effect interrupts lower (damage overrides footstep)
- [ ] `MinTimeBetweenEffects` prevents rapid-fire rumble spam
- [ ] Edge case: `PlayHapticByTag` before `Initialize` logs warning and returns
- [ ] Edge case: Controller disconnected mid-effect `StopHaptic` called safely
- [ ] Edge case: Multiple rapid `PlayHapticByTag` calls only highest priority plays
- [ ] Edge case: Platform hot-swap (Xbox PS5) fires `OnControllerPlatformChanged`
---
## 10. Reuse Notes
- Attach this component to the **Player Controller** (not the Pawn). Haptics are per-controller, per-player.
- All gameplay systems trigger haptics via GameplayTag never hardcode `Play Force Feedback` nodes.
- The `DA_HapticProfile` Data Asset stores platform-specific `UForceFeedbackEffect` curves. Designers author these in the Content Browser without touching Blueprints.
- For multiplayer: haptics are **local client only** never replicated. The server doesn't need to know about controller vibration.
- Heartbeat haptic is the only continuous/looping effect. All others are one-shot.
- DualSense adaptive triggers require the **PS5 Controller Plugin** enabled. Framework gracefully degrades on other platforms.
- The `Haptic.` GameplayTag namespace is documented in `DT_Tags_Player.csv` and `DA_GameTagRegistry`.
- Accessibility: `bHapticsEnabled` syncs with `BPC_AccessibilitySettings` so players can disable all vibration from settings.
- For platform profiles: create one `DA_HapticProfile` instance per event per platform, then reference all three in the profile map. `BPC_HapticsController` selects the right one at runtime.
---
## 11. Manual Implementation Guide
> **This section is for a human implementer building the Blueprint manually in UE5.**
> Follow these steps in order. Each function is broken down into specific UE5 Blueprint nodes.
### 11.1 Class Setup
1. Create a new Blueprint Class:
- Parent Class: `ActorComponent`
- Name: `BPC_HapticsController`
- Path: `Content/Framework/Settings/`
2. Add all variables from Section 3 to the Class Defaults.
- Configuration variables: set `Instance Editable`
- Internal variables: set to `Private` (no expose)
3. Add the Event Dispatchers from Section 5.
### 11.2 Variable Initialization (BeginPlay)
```
Event BeginPlay
├─ Get Owner → Cast to PlayerController → Store as CachedPlayerController
│ └─ If NOT valid: Print String "BPC_HapticsController: Owner is not a PlayerController!" → Return
├─ Call DetectControllerPlatform → Set CurrentPlatform
├─ Load Asset Registry → Get All Assets of Class (DA_HapticProfile)
│ └─ ForEach: Add to HapticProfileMap [ProfileTag → Asset]
├─ Get Owner → Get Component by Class (BPC_AccessibilitySettings)
│ └─ If valid: Bind Event OnHapticsToggleChanged → SetHapticsEnabled
│ └─ If valid: Read initial bHapticsEnabled value
├─ Get Owner Pawn → Get Component by Class (BPC_StateManager)
│ └─ If valid: Bind Event OnHeartRateChanged → PlayHeartbeatHaptic
├─ Set bIsInitialized = true
└─ Call OnHapticsControllerInitialized
```
### 11.3 Function Implementations
#### `PlayHapticByTag`
**Input Pins:** `ProfileTag` (GameplayTag), `IntensityMultiplier` (Float)
**Output Pins:** None
**Node-by-Node Logic:**
```
[Function: PlayHapticByTag]
Step 1: Branch on bHapticsEnabled → False: Return
Step 2: Get Game Time in Seconds → Subtract LastPlayTime → Compare to MinTimeBetweenEffects
Branch → Too soon: Return (or queue if needed)
Step 3: HapticProfileMap → Find (ProfileTag) → Store as FoundProfile
Step 4: Branch on FoundProfile valid?
True →
Step 4a: Make S_HapticRequest:
- ProfileTag = ProfileTag
- EventType = FoundProfile.EventType
- IntensityMultiplier = IntensityMultiplier
- DurationOverride = -1 (use profile default)
- Priority = FoundProfile.Priority
Step 4b: Call PlayHapticInternal(S_HapticRequest)
Step 4c: Call OnHapticPlayed(ProfileTag, FoundProfile.EventType, IntensityMultiplier)
False →
Step 4d: Print String Warning: "No haptic profile found for tag: {ProfileTag}"
```
**Nodes Used:** `Branch`, `FindGameplayTag`, `Map Find`, `Make Struct (S_HapticRequest)`, `Call Function`, `Print String`
#### `PlayHapticInternal`
**Input Pins:** `Request` (S_HapticRequest)
**Output Pins:** None
**Node-by-Node Logic:**
```
[Function: PlayHapticInternal]
Step 1: If ActiveHapticEffect is valid → Call StopHaptic (interrupt current)
Step 2: Break S_HapticRequest → get ProfileTag
Step 3: Look up DA_HapticProfile from HapticProfileMap
Step 4: Switch on CurrentPlatform:
Case PS5_DualSense: Get PS5_ForceFeedbackCurve from profile
Case Xbox: Get Xbox_ForceFeedbackCurve from profile
Default: Get Generic_ForceFeedbackCurve from profile
Step 5: Branch on selected curve valid?
True →
Step 5a: CachedPlayerController → Play Force Feedback
- Force Feedback Effect: selected curve asset
- Intensity Multiplier: Request.IntensityMultiplier * HapticIntensityScale
- bLooping: false
- bIgnore Time Dilation: true
Step 5b: Set ActiveHapticEffect = selected curve
False →
Step 5c: Print String Warning: "No ForceFeedbackEffect for platform {CurrentPlatform}"
Step 6: Set LastPlayTime = Get Game Time in Seconds
```
**Nodes Used:** `Switch on EControllerPlatform`, `Break S_HapticRequest`, `Map Find`, `Play Force Feedback (PlayerController)`, `Branch`
#### `PlayHeartbeatHaptic`
**Input Pins:** `BeatsPerMinute` (Float)
**Output Pins:** None
**Node-by-Node Logic:**
```
[Function: PlayHeartbeatHaptic]
Step 1: Clamp (BeatsPerMinute, HeartbeatMinBPM, HeartbeatMaxBPM) → Store as ClampedBPM
Step 2: Divide 60.0 / ClampedBPM → Store as PulseInterval
Step 3: If bHeartbeatActive:
True → Clear Timer by Handle (HeartbeatTimerHandle)
Step 4: Set bHeartbeatActive = true
Step 5: Set Timer by Event:
- Event: Custom Event (HeartbeatPulse)
- Time: PulseInterval
- Looping: true
- Store handle as HeartbeatTimerHandle
[Custom Event: HeartbeatPulse]
→ Call PlayHapticByTag(Haptic.Heartbeat, 1.0)
```
**Nodes Used:** `Clamp (float)`, `Divide`, `Set Timer by Event`, `Clear Timer by Handle`
#### `SetHapticsEnabled`
**Input Pins:** `bEnabled` (Bool)
**Output Pins:** None
```
[Function: SetHapticsEnabled]
Step 1: Set bHapticsEnabled = bEnabled
Step 2: Branch:
False → Call StopHaptic
Step 3: Call OnHapticsEnabledChanged(bEnabled)
```
#### `DetectControllerPlatform`
```
[Function: DetectControllerPlatform]
Step 1: Get Platform Name → Store as PlatformStr
Step 2: String Contains (PlatformStr, "PS5") → True: Set CurrentPlatform = PS5_DualSense → Return
Step 3: String Contains (PlatformStr, "PS4") → True: Set CurrentPlatform = PS4_DualShock → Return
Step 4: String Contains (PlatformStr, "Xbox") → True: Set CurrentPlatform = Xbox → Return
Step 5: Get Input Device Type → Switch on Type:
Gamepad → Set CurrentPlatform = PC_Generic
Default → Set CurrentPlatform = Unknown
```
**Nodes Used:** `Get Platform Name`, `Contains (string)`, `Switch on String`, `Get Input Device Type`
### 11.4 Event Dispatcher Bindings (Inbound Listeners)
| Bind to Dispatcher | Custom Event to Create | What it Does |
|--------------------------------------|------------------------|--------------|
| `BPC_StateManager.OnHeartRateChanged` | `OnHeartRateChanged_Handler` | `PlayHeartbeatHaptic(CurrentHeartRate)` |
| `BPC_AccessibilitySettings.OnHapticsToggleChanged` | `OnHapticsToggle_Handler` | `SetHapticsEnabled(bEnabled)` |
### 11.5 Multiplayer Networking
- This component is **local client only**. No replication needed.
- Haptics play only on the local player's controller.
- No `HasAuthority()` gates needed haptics are cosmetic.
- For listen server hosts: `IsLocalPlayerController()` check before playing effects.
### 11.6 Quick Node Reference
| Node | Where to Find | Used For |
|------|---------------|----------|
| `Play Force Feedback` | Right-click "Play Force Feedback" | Playing rumble effect on controller |
| `Stop Force Feedback` | Right-click "Stop Force Feedback" | Stopping all active vibration |
| `Set Timer by Event` | Right-click "Set Timer by Event" | Looping heartbeat pulse |
| `Get Platform Name` | Right-click "Get Platform Name" | Detecting Xbox/PS5/PC |
| `Clamp (float)` | Right-click "Clamp" | Clamping BPM range |
| `Make Struct` | Right-click "Make S_HapticRequest" | Building haptic request |
| `Map Find` | Right-click "Find" | Looking up profile by tag |
| `Get Game Time in Seconds` | Right-click "Get Game Time" | Cooldown tracking |
---
## 12. Blueprint Build Checklist
- [ ] Create Blueprint class: `BPC_HapticsController` (parent: `ActorComponent`)
- [ ] Add all variables from Section 3 with correct types and defaults
- [ ] Create `EHapticEvent`, `EHapticMotor`, `EControllerPlatform` enums (in Content Browser)
- [ ] Create `S_HapticRequest` struct (in Content Browser)
- [ ] Build `BeginPlay` event `Initialize` chain
- [ ] Implement `DetectControllerPlatform` function
- [ ] Implement `PlayHapticInternal` with Platform Switch
- [ ] Implement `PlayHapticByTag` (public entry point)
- [ ] Implement `PlayHapticByEvent` (convenience wrapper)
- [ ] Implement `StopHaptic` / `StopHeartbeatHaptic`
- [ ] Implement `PlayHeartbeatHaptic` with looping timer
- [ ] Implement `SetHapticsEnabled` / `SetDualSenseTriggerEffect`
- [ ] Create all 6 event dispatchers
- [ ] Bind to `BPC_StateManager.OnHeartRateChanged`
- [ ] Bind to `BPC_AccessibilitySettings.OnHapticsToggleChanged`
- [ ] Create at least one `DA_HapticProfile` instance for `Haptic.Damage.Default`
- [ ] Test: PlayHapticByTag triggers vibration on Xbox controller
- [ ] Test: PlayHapticByTag triggers vibration on PS5 DualSense
- [ ] Test: bHapticsEnabled=false blocks all effects
- [ ] Test: Heartbeat BPM changes pitch/speed of pulse
- [ ] Test: Rapid-fire calls respect MinTimeBetweenEffects
---
*Blueprint Spec: Haptics Controller. Conforms to TEMPLATE.md v2.0 — part of the UE5 Modular Game Framework, SETTINGS layer.*

View File

@@ -51,7 +51,7 @@ The Modular Game Framework uses `UDataAsset` (and subclass `UPrimaryDataAsset` w
| 11 | `DA_ScareEvent` | Adaptive | `BPC_ScareEventSystem` |
| 12 | `DA_RoomMutation` | Adaptive | `BPC_AdaptiveEnvironmentDirector` |
| 13 | `DA_BehaviourVariant` | AI | `BPC_BehaviourVariantSelector` |
| 14 | `DA_HapticProfile` | Settings | `BPC_HapticsController` |
| 14 | `DA_HapticProfile` | Settings | `BPC_HapticsController` (148) |
| 15 | `DA_AdaptationRule` | Adaptive | `BPC_DifficultyManager` |
| 16 | `DA_EquipmentConfig` | Inventory | `BPC_EquipmentSlotSystem` |
| 17 | `DA_PuzzleData` | Interaction | `BP_PuzzleDeviceActor` |

View File

@@ -1,52 +1,178 @@
# DA_HapticProfile — Data Asset
**Parent Class:** `UDataAsset`
**Dependencies:** [`BPC_HapticsController`](../12-settings/)
**Purpose:** Defines haptic feedback profiles for controller vibration and force feedback effects tied to gameplay events.
**Parent Class:** `UPrimaryDataAsset`
**Dependencies:** [`BPC_HapticsController`](../12-settings/148_BPC_HapticsController.md)
**Purpose:** Defines haptic feedback profiles for controller vibration and force feedback effects tied to gameplay events. Each profile maps a GameplayTag to a platform-specific `UForceFeedbackEffect` waveform asset with configurable intensity, duration, motor mask, and priority.
---
## Enums Used
| Enum | Defined In | Values |
|------|-----------|--------|
| `EHapticEvent` | `BPC_HapticsController` (148) | Damage, HeavyDamage, Heartbeat, WeaponFire, WeaponReload, MeleeImpact, Footstep, Explosion, PickupItem, DropItem, GrabObject, ReleaseObject, ScareEvent, AmbientPulse, UI_Confirm, UI_Navigate, LowHealth, StaminaExhausted, Death |
| `EHapticMotor` | `BPC_HapticsController` (148) | Left, Right, Both |
---
## Variables / Structure
### Core Fields
| Field | Type | Description |
|-------|------|-------------|
| `ProfileTag` | `FGameplayTag` | Unique haptic profile identifier |
| `EventType` | `EHapticEvent` | Damage, Heartbeat, Explosion, Footstep, WeaponFire, AmbientPulse |
| `IntensityCurve` | `UCurveFloat*` | Vibration intensity over time |
| `Duration` | `float` | Total haptic effect duration (seconds) |
| `MotorMask` | `EHapticMotor` | Left, Right, Both |
| `Priority` | `int32` | Higher priority overrides lower during conflicts |
| `bCanInterrupt` | `bool` | Can this effect be interrupted by higher priority |
| `PlatformMinIntensity` | `float` | Minimum intensity per platform capability |
| `ProfileTag` | `FGameplayTag` | Unique haptic profile identifier (e.g., `Haptic.Damage.Heavy`) |
| `EventType` | `EHapticEvent` | Event category this profile handles |
| `ForceFeedbackEffect_Generic` | `UForceFeedbackEffect*` | Waveform curve asset for PC/Xbox generic controllers |
| `ForceFeedbackEffect_PS5` | `UForceFeedbackEffect*` | Waveform curve asset for PS5 DualSense (higher fidelity) |
| `ForceFeedbackEffect_Xbox` | `UForceFeedbackEffect*` | Waveform curve asset for Xbox controllers (optional override) |
| `IntensityCurve` | `UCurveFloat*` | Optional: vibration intensity over time (0.01.0) |
| `Duration` | `float` | Total haptic effect duration in seconds |
| `MotorMask` | `EHapticMotor` | Left motor, Right motor, or Both |
| `Priority` | `int32` | Higher priority overrides lower during conflicts (0 = lowest, 100 = highest) |
| `bCanInterrupt` | `bool` | Can this effect be interrupted by a higher-priority effect? |
| `bIgnoreTimeDilation` | `bool` | Should this play at real-time regardless of game speed? |
### Platform-Specific Fields
| Field | Type | Description |
|-------|------|-------------|
| `PlatformMinIntensity` | `float` | Minimum intensity threshold before effect is felt (0.01.0) |
| `DualSense_TriggerSide` | `FName` | PS5 adaptive trigger side ("Left", "Right", "None") |
| `DualSense_TriggerEffect` | `FName` | PS5 trigger effect type ("Resistance", "Vibration", "WeaponFire", "BowDraw", "None") |
| `DualSense_TriggerStartPosition` | `int32` | PS5 trigger position where effect begins (09) |
| `DualSense_TriggerStrength` | `int32` | PS5 trigger effect strength (08) |
### Heartbeat-Specific Fields
| Field | Type | Description |
|-------|------|-------------|
| `bIsHeartbeatProfile` | `bool` | Whether this profile is used for heartbeat pulse effects |
| `TargetBPMRange_Min` | `float` | Minimum BPM this profile handles |
| `TargetBPMRange_Max` | `float` | Maximum BPM this profile handles |
---
## Gameplay Tags
- Namespace: `Haptic.<Event>` (e.g., `Haptic.Damage.Heavy`, `Haptic.Heartbeat`)
- Namespace: `Haptic.<Category>.<Subcategory>`
- Examples: `Haptic.Damage.Heavy`, `Haptic.Heartbeat.Normal`, `Haptic.WeaponFire.Pistol`
- All tags must be registered in `DT_Tags_Player.csv` for validation at startup
### Full Tag Hierarchy
```
Haptic.
├── Damage.Light
├── Damage.Heavy
├── Damage.Critical
├── Heartbeat.Normal
├── Heartbeat.Fast
├── Heartbeat.Panic
├── WeaponFire.Pistol
├── WeaponFire.Shotgun
├── WeaponReload
├── MeleeImpact.Crowbar
├── MeleeImpact.Default
├── Footstep.Tile
├── Footstep.Wood
├── Footstep.Concrete
├── Footstep.Metal
├── Footstep.Gravel
├── Explosion
├── Pickup.Item
├── Pickup.Weapon
├── Grab
├── Release.Throw
├── Scare.JumpScare
├── Scare.TensionRise
├── Ambient.Void
├── Ambient.Default
├── LowHealth
├── StaminaExhausted
├── Death
├── UI.Confirm
└── UI.Navigate
```
---
## Validation Rules
- `ProfileTag` must be unique
- `Duration` must be > 0
- `IntensityCurve` must be valid
- `ProfileTag` must be unique across all profiles
- `Duration` must be > 0.0
- At least one `ForceFeedbackEffect_*` must be assigned (Generic falls back for all platforms)
- `Priority` must be 0100
- If `bIsHeartbeatProfile` is true, `TargetBPMRange_Min` and `TargetBPMRange_Max` must be set
- If `DualSense_TriggerSide != "None"`, trigger effect fields must be valid
---
## Example Data
### Damage Profile — Heavy Hit
| Field | Value |
|-------|-------|
| ProfileTag | `Haptic.Damage.Critical` |
| EventType | Damage |
| Duration | 0.5 |
| MotorMask | Both |
| Priority | 10 |
| `ProfileTag` | `Haptic.Damage.Heavy` |
| `EventType` | `HeavyDamage` |
| `Duration` | `0.4` |
| `MotorMask` | `Both` |
| `Priority` | `80` |
| `bCanInterrupt` | `true` |
| `bIgnoreTimeDilation` | `true` |
| `ForceFeedbackEffect_Generic` | `FFE_Damage_Heavy` |
| `ForceFeedbackEffect_PS5` | `FFE_Damage_Heavy_PS5` |
### Heartbeat Profile — Normal
| Field | Value |
|-------|-------|
| `ProfileTag` | `Haptic.Heartbeat.Normal` |
| `EventType` | `Heartbeat` |
| `Duration` | `0.1` |
| `MotorMask` | `Left` |
| `Priority` | `30` |
| `bCanInterrupt` | `true` |
| `bIsHeartbeatProfile` | `true` |
| `TargetBPMRange_Min` | `60.0` |
| `TargetBPMRange_Max` | `90.0` |
| `ForceFeedbackEffect_Generic` | `FFE_Heartbeat` |
### Weapon Fire — Pistol
| Field | Value |
|-------|-------|
| `ProfileTag` | `Haptic.WeaponFire.Pistol` |
| `EventType` | `WeaponFire` |
| `Duration` | `0.08` |
| `MotorMask` | `Right` |
| `Priority` | `50` |
| `DualSense_TriggerSide` | `Right` |
| `DualSense_TriggerEffect` | `WeaponFire` |
| `DualSense_TriggerStartPosition` | `4` |
| `DualSense_TriggerStrength` | `6` |
---
## Consumed By
- [`BPC_HapticsController`](../12-settings/)
- [`BPC_HapticsController`](../12-settings/148_BPC_HapticsController.md) — loads all profiles into `HapticProfileMap` at initialization
## Referenced By
- `BPC_HealthSystem` (08) — damage haptics
- `BPC_FirearmSystem` (74) — weapon fire haptics
- `BPC_MeleeSystem` (76) — melee impact haptics
- `BPC_ScareEventSystem` (101) — scare event haptics
- `BPC_MovementStateSystem` (11) — footstep haptics
- `BPC_ReloadSystem` (78) — reload haptics
- `BPC_PhysicsDragSystem` (22) — grab/release haptics
- `BP_ItemPickup` (25) — pickup haptics
- `BPC_DeathHandlingSystem` (39) — death haptics
- `BPC_StaminaSystem` (09) — stamina exhausted haptics
---
## Reuse Notes
- Haptic profiles are platform-agnostic; translation handled by PlatformServiceAbstraction
- Haptic profiles are platform-agnostic in design; `BPC_HapticsController` selects the correct `UForceFeedbackEffect` asset at runtime based on `CurrentPlatform`.
- Designers create FFE waveform curves in the Content Browser — no Blueprint changes needed for tuning.
- For heartbeat profiles: create 3 instances (Normal 60-90 BPM, Fast 90-140 BPM, Panic 140-180 BPM). `BPC_HapticsController` auto-selects based on current BPM.
- For footstep profiles: create one per surface type. `BPC_MovementStateSystem` selects based on physical surface trace result.
- Priority guidelines: 020 (ambient/footsteps), 3050 (weapons/reload/pickups), 6080 (damage), 90100 (scares/death).
- The `Haptic.` namespace should be registered in `DT_Tags_Player.csv` so `DA_GameTagRegistry` validates them at startup.

View File

@@ -5,7 +5,7 @@ Primary Data Asset that defines all Enhanced Input bindings across three platfor
## Dependencies
- **Requires:** None (self-contained Data Asset)
- **Required By:** [`SS_EnhancedInputManager`](docs/blueprints/15-input/128_SS_EnhancedInputManager.md) (loads and caches this), [`SS_SettingsSystem`](docs/blueprints/12-settings/105_SS_SettingsSystem.md) (references for key rebinding)
- **Required By:** [`SS_EnhancedInputManager`](docs/blueprints/15-input/128_SS_EnhancedInputManager.md) (loads and caches this), [`SS_SettingsSystem`](docs/blueprints/12-settings/105_SS_SettingsSystem.md) (references for key rebinding), [`BPC_HapticsController`](docs/blueprints/12-settings/148_BPC_HapticsController.md) (reads `bEnableControllerRumble` for haptics master toggle)
- **Engine/Plugin Requirements:** Enhanced Input Plugin, `UInputMappingContext`, `UInputAction`
## Class Info
@@ -68,7 +68,7 @@ Primary Data Asset that defines all Enhanced Input bindings across three platfor
| `PlatformProfiles` | `TArray<S_PlatformProfile>` | `Empty` | `Profiles` | One profile per platform (3 total) |
| `ContextDefinitions` | `TArray<S_ContextDefinition>` | `Empty` | `Contexts` | IMC asset references and defaults |
| `GlobalDeadZone` | `Float` | `0.15` | `Global` | Fallback analog stick dead zone |
| `bEnableControllerRumble` | `Bool` | `true` | `Global` | Master toggle for force feedback |
| `bEnableControllerRumble` | `Bool` | `true` | `Global` | Master toggle for force feedback (read by BPC_HapticsController) |
| `bSwapSticksForLeftHanded` | `Bool` | `false` | `Accessibility` | Swap left/right stick for accessibility |
| `AxisInvertSettings` | `TMap<FName, Bool>` | `Empty` | `Accessibility` | Per-action axis inversion (e.g., "IA_Look" = InvertY) |

View File

@@ -289,6 +289,7 @@ flowchart TD
| `BPC_CutsceneBridge` | `Function Call` | `SS_EnhancedInputManager::PushContext/PopContext` |
| `BPC_HidingSystem` | `Function Call` | `SS_EnhancedInputManager::PushContext(Hiding) / PopContext(Hiding)` |
| `BPC_ActiveItemSystem` | `Function Call` | `SS_EnhancedInputManager::IsActionPressed("IA_QuickSlot1")` |
| `BPC_HapticsController` (148) | `Function Call` | `SS_EnhancedInputManager::GetControllerPlatform()` — for platform detection |
| `WBP_PauseMenu` | `Function Call` | `SS_EnhancedInputManager::PushContext(UI) / PopContext(UI)` |
| `WBP_InventoryMenu` | `Function Call` | `SS_EnhancedInputManager::PushContext(WristwatchUI)` |
| `BP_PuzzleDeviceActor` | `Function Call` | `SS_EnhancedInputManager::PushContext(Inspection)` |

View File

@@ -114,7 +114,7 @@ These systems appear in the Plan but may need explicit spec files or are covered
- `BPC_EndingCompletionTracker` — Not yet created; Master Section 11.4
- `BPC_MetaProgressionSystem` — Not yet created; Master Section 11.5
- `BPC_RunSummarySystem` — Already exists at `05-saveload/43_BPC_RunHistoryTracker.md` (may need rename or separate file)
- `BPC_HapticsController`Not yet created; Master Section 12.2
- `BPC_HapticsController`✅ Created (system 148); `docs/blueprints/12-settings/148_BPC_HapticsController.md`
- `BPC_PlatformServiceAbstraction` — Not yet created; Master Section 12.3
---

View File

@@ -1,6 +1,6 @@
# Master Blueprint Index — UE5 Modular Game Framework
**Version:** 3.4 | **Generated:** 2026-05-22 | **Total Files:** 147 numbered + 1 starter + 1 supplementary (149 total specs) | **C++:** 27 source files (15 full + 10 stubs + 2 utility)
**Version:** 3.5 | **Generated:** 2026-05-22 | **Total Files:** 148 numbered + 1 starter + 1 supplementary (150 total specs) | **C++:** 27 source files (15 full + 10 stubs + 2 utility)
This document is the canonical index of every Blueprint specification file in the framework. Each entry links to its full spec document and includes: file name, asset type, parent class, purpose summary, and key dependencies.
@@ -49,7 +49,7 @@ docs/blueprints/
├── 09-ai/ ← AI, Perception & Encounters (9 files)
├── 10-adaptive/ ← Adaptive Environment, Atmosphere & Scare (15 files)
├── 11-meta/ ← Achievements, Progression & Meta (2 files)
├── 12-settings/ ← Settings, Accessibility & Platform (2 files)
├── 12-settings/ ← Settings, Accessibility, Haptics & Platform (3 files)
├── 13-polish/ ← Tutorial, Loading, Credits, Debug (9 files)
├── 14-data-assets/ ← Data Asset definitions (16 files)
├── 15-input/ ← Enhanced Input System (1 file)
@@ -181,6 +181,7 @@ docs/blueprints/
| — | — | — | — | — | — |
| 104 | [`104_BPC_AccessibilitySettings`](12-settings/104_BPC_AccessibilitySettings.md) | `BPC_` Component | `ActorComponent` | Accessibility; subtitles, colorblind, controller remap, difficulty | 12-settings |
| 105 | [`105_SS_SettingsSystem`](12-settings/105_SS_SettingsSystem.md) | `SS_` Subsystem | `GameInstanceSubsystem` | Settings subsystem; persistent settings, apply, reset, platform | 12-settings |
| 148 | [`148_BPC_HapticsController`](12-settings/148_BPC_HapticsController.md) | `BPC_` Component | `ActorComponent` | Haptics controller; GameplayTag-driven force feedback, DualSense triggers, heartbeat pulse | 12-settings |
| — | — | — | — | — | — |
| 106 | [`106_BPC_AnalyticsTracker`](13-polish/106_BPC_AnalyticsTracker.md) | `BPC_` Component | `ActorComponent` | Analytics; event tracking, session metrics, telemetry | 13-polish |
| 107 | [`107_BPC_DevCheatManager`](13-polish/107_BPC_DevCheatManager.md) | `BPC_` Component | `ActorComponent` | Developer cheats; god mode, noclip, give item, teleport | 13-polish |
@@ -234,7 +235,7 @@ docs/blueprints/
| Prefix | Type | Count |
|--------|------|-------|
| `BPC_` | Blueprint Component | 80 |
| `BPC_` | Blueprint Component | 81 |
| `BP_` | Blueprint Actor | 11 |
| `WBP_` | Widget Blueprint | 14 |
| `DA_` | Data Asset | 19 |
@@ -247,7 +248,7 @@ docs/blueprints/
| `AI_` | AI Controller | 1 |
| `BB_` | Blackboard | 1 |
| `E_` | Enum | 5 |
| **Total** | | **158** |
| **Total** | | **159** |
---
@@ -261,9 +262,10 @@ Below are the most cross-referenced systems — these are the ones the State Man
| `BPC_MovementStateSystem` (11) | StateManager, GASP AnimBP, Stamina, Camera, InteractionDetector, AudioAtmosphere |
| `BPC_HidingSystem` (12) | StateManager, AIPerception, StressSystem, CameraStateLayer |
| `BPC_DeathHandlingSystem` (39) | HealthSystem, StateManager, AltDeathSpace, Corpse, Respawn, RunHistory, UIManager |
| `SS_EnhancedInputManager` (128) | StateManager (context changes), all WBP_ menus, PlayerController |
| `SS_EnhancedInputManager` (128) | StateManager (context changes), all WBP_ menus, PlayerController, BPC_HapticsController (controller platform detection) |
| `BPC_StateManager` (130) | EVERY system (central query point) |
| `SS_AudioManager` (132) | ALL systems that play audio, BP_RoomAudioZone, WBP_SettingsMenu, BPC_StateManager (heart rate → audio) |
| `BPC_HapticsController` (148) | HealthSystem, FirearmSystem, MeleeSystem, ScareEventSystem, PhysicsDrag, MovementState, ReloadSystem, DeathHandling, Staminasystem, StateManager → heartbeat, AccessibilitySettings |
| `ABP_GASP` (external) | StateManager (overlay + action intensity), MovementState, Hiding, Stamina, Embodiment |
---
@@ -294,7 +296,7 @@ Below are the most cross-referenced systems — these are the ones the State Man
| `BPC_DifficultyManager` | 89 | `BPC_DocumentArchiveSystem` | 29 | `DA_EncounterData` | 119 |
| `BPC_EmbodimentSystem` | 13 | `BPC_EndingAccumulator` | 68 | `DA_EquipmentConfig` | 120 |
| `BPC_EquipmentSlotSystem` | 30 | `BPC_ErrorHandler` | 108 | `DA_HapticProfile` | 121 |
| `BPC_FearSystem` | 90 | `BPC_FirearmSystem` | 74 | `DA_InputMappingProfile` | 129 |
| `BPC_FearSystem` | 90 | `BPC_FirearmSystem` | 74 | `BPC_HapticsController` | 148 |
| `BPC_FPSCounter` | 109 | `BPC_HealthSystem` | 8 | `DA_InteractionData` | 122 |
| `BPC_HidingSystem` | 12 | `BPC_HitReactionSystem` | 75 | `DA_ItemData` | 7 |
| `BPC_InteractionDetector` | 16 | `BPC_InventorySystem` | 31 | `DA_NarrativeDataAssets` | 66 |
@@ -326,7 +328,7 @@ Below are the most cross-referenced systems — these are the ones the State Man
---
*Master Blueprint Index v3.4 — The single reference document for every file in the framework. Now 147 files with State Management, MetaSounds Audio, Multiplayer Networking, and Planar Capture System support.*
*Master Blueprint Index v3.5 — The single reference document for every file in the framework. Now 148 files with State Management, MetaSounds Audio, Multiplayer Networking, Planar Capture System, and Haptics Controller support.*
---