Files
UE5-Modular-Game-Framework/docs/blueprints/16-state/130_BPC_StateManager.md
Lefteris Notas 411edea8ce add blueprints
2026-05-19 13:22:27 +03:00

39 KiB
Raw Blame History

130 — Central State Authority (BPC_StateManager)

Purpose

Single source of truth for "what can the player do right now?" Every system queries IsActionPermitted(Tag) instead of checking other systems' states directly. Manages exclusive action states, upper-body overlay states, action action gating, vital signs (heart rate), and the force-stack pattern for nested overrides (death, cutscenes, void space). Communicates with GASP exclusively through overlay state variables — never touches motion matching internals.

Dependencies

  • Requires: GI_GameFramework (04 — game phase changes), BPC_HealthSystem (08 — death + injury bindings), BPC_StressSystem (10 — stress tier), BPC_StaminaSystem (09 — exhaustion), BPC_MovementStateSystem (11 — movement mode tracking), GI_GameTagRegistry (01 — tag queries), SS_EnhancedInputManager (128 — context switching), ABP_GASP (external — overlay + intensity variables)
  • Required By: EVERY gameplay system (central query point for action permission)
  • Engine/Plugin Requirements: GameplayTags plugin, GASP plugin (read-only)

Class Info

Property Value
Parent Class ActorComponent
Class Type Blueprint Component
Asset Path Content/Framework/Player/BPC_StateManager.uasset
Implements Interfaces I_AnimNotifyInterface (receives GASP notifies)

1. Enums

E_PlayerActionState — Exclusive Action States (45 values)

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

E_OverlayState — Upper-Body Overlay for GASP AnimBP (18 values)

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)

E_ActionRequestResult — Result Enum for RequestStateChange (8 values)

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

E_PlayerVitalSignals — Vital Signal Enum for HeartRate / Breathing (5 values)

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

2. Structs

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

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)

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

3. 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
DefaultOverlay E_OverlayState Empty State Config Default overlay state
StateTransitionDelay Float 0.0 State Config Minimum time between state changes (anti-spam)
InjuryHealthThreshold Float 0.30 State Config Health ratio (0-1) below which player becomes Injured
InjurySpeedMultiplier Float 0.65 State Config Walk speed multiplier when 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
StateGatingTable DA_StateGatingTable None State Config External Data Asset for designer-tunable gating rules
bLogStateTransitions Boolean false Debug Log all state transitions to console

Internal (Private / Protected, No Expose)

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, smoothed)
CurrentVitalSignal E_PlayerVitalSignals Normal Vital Signs Current vital signal category
bIsInjured Boolean false Vital Signs True when health ≤ InjuryHealthThreshold

4. Functions

Public Functions

RequestStateChangeE_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.
  • Parameters:
    Param Type Description
    NewState E_PlayerActionState The desired new action state
    RequesterTag GameplayTag Identifies which system is requesting
    Priority Integer (default 0) 0=Normal, 50=High, 100=Force
  • Blueprint Authority: Any
  • Flow:
    1. If Priority == 100 (Force): bypass gating, go directly to state transition
    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. Fire OnStateChangeRequested
    6. Iterate GatingRules matching RequesterTag:
      • If NewState is in BlockedStates for any rule → fire OnStateChangeDenied, return Blocked_CurrentState with BlockReason
      • If CurrentGamePhase is in BlockedGamePhases → return Blocked_GamePhase
      • If required tags missing or blocked tags present → return appropriate result
    7. Execute state transition (set PreviousState, set CurrentState, update GASP, fire dispatchers)
    8. Return Permitted

ForceStateChangevoid

  • Description: Bypasses ALL gating. Used by death system, cutscene bridge, void space entry, and developer cheats. Pushes current state onto ForceStack.
  • Parameters:
    Param Type Description
    NewState E_PlayerActionState The forced state to enter
    Reason Text Human-readable reason for force
  • Blueprint Authority: Any (Server-authoritative if multiplayer)
  • Flow:
    1. If ForceStack already has NewState at top: return (prevents double-force)
    2. Push CurrentState onto ForceStack
    3. Fire OnForceOverridePushed
    4. Execute state transition with NewState
    5. Log reason to console if bLogStateTransitions

RestorePreviousStatevoid

  • Description: Pops the force stack. Used when exiting cutscenes, void space, or force-override states.
  • Parameters: (none)
  • Blueprint Authority: Any
  • Flow:
    1. If ForceStack is empty: set to Idle or previously known normal state, return
    2. Pop top of ForceStack
    3. Fire OnForceOverridePopped
    4. Execute state transition to popped state

GetCurrentStateE_PlayerActionState

  • Description: Pure getter — returns CurrentState. No side effects.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

GetPreviousStateE_PlayerActionState

  • Description: Pure getter — returns PreviousState. No side effects.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

IsActionPermittedS_ActionPermissionResult

  • Description: Non-mutating query. Does NOT change state. Any system can ask "can I do this right now?"
  • Parameters:
    Param Type Description
    ActionTag GameplayTag The action tag to check
  • Blueprint Authority: Any (Pure)
  • 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

SetOverlayStatevoid

  • Description: Tells GASP AnimBP which upper-body overlay to use. Does NOT change E_PlayerActionState. Called by equipment system, weapon system, and inspection.
  • Parameters:
    Param Type Description
    Overlay E_OverlayState The new overlay state
  • Blueprint Authority: Any
  • Flow:
    1. If Overlay == CurrentOverlay: return (no-op)
    2. Set CurrentOverlay = Overlay
    3. If CachedABPRef is valid: set ABP_GASP.OverlayState = Overlay
    4. Fire OnOverlayStateChanged
    5. Update visible first-person arm mesh via BPC_EmbodimentSystem

CanTransitionToS_ActionPermissionResult

  • Description: Pre-flight check without executing. Used by UI to enable/disable buttons.
  • Parameters:
    Param Type Description
    TargetState E_PlayerActionState The state to check transition eligibility for
  • Blueprint Authority: Any (Pure)

UpdateHeartRatevoid

  • Description: Recalculates heart rate each tick based on current state, stress, stamina, and health. Evaluates E_PlayerVitalSignals thresholds. Called automatically from Tick.
  • Parameters: (none — reads internal state and bound systems)
  • Blueprint Authority: Internal (Tick-driven)
  • Flow:
    1. Calculate base rate from current state:
      • 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

EvaluateInjuryStatevoid

  • Description: Called when health changes. Sets bIsInjured flag and auto-transitions to/from Injured state if health crosses threshold.
  • Parameters: (none — reads BPC_HealthSystem)
  • Blueprint Authority: Internal (called by health change binding)
  • 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
      • Fire OnInjuryStateChanged(true, HealthRatio)
    3. If HealthRatio > InjuryHealthThreshold AND bIsInjured:
      • Set bIsInjured = false
      • If CurrentState == Injured: RequestStateChange(Idle, Tag.Health)
      • Restore movement speed
      • Fire OnInjuryStateChanged(false, HealthRatio)

IsInCombatBoolean

  • Description: Convenience — returns true if CurrentState is SwingMelee, AimingFirearm, FiringFirearm, Reloading, or DeployingShield.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

IsMovementBlockedBoolean

  • Description: Convenience — returns true if player cannot move at all. True when CurrentState is Dead, InCutscene, InDialogue, InInventory, InJournal, InPauseMenu, InMainMenu, UsingObject, Sitting, KnockedDown, Panicked, Staggered, Exhausted, Loading, InPhotoMode.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

IsMovementRestrictedBoolean

  • 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.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

GetHeartRateFloat

  • 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.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

GetVitalSignalE_PlayerVitalSignals

  • Description: Returns CurrentVitalSignal. Used by atmosphere system (audio tension layers), camera (breathing sway), and narrative system (dialogue conditionals).
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

CanEquipWeaponBoolean

  • Description: Checks if weapon equip is permitted in current state. Convenience wrapper around IsActionPermitted.
  • Parameters: (none)
  • Blueprint Authority: Any (Pure)

RegisterActionFlagvoid

  • Description: Lightweight flag system for transient action permissions. Duration of -1 = permanent until unregistered. Fires OnActionFlagRegistered.
  • Parameters:
    Param Type Description
    Tag GameplayTag The flag tag to register
    Duration Float (default -1.0) How long the flag persists (-1 = permanent)

UnregisterActionFlagvoid

  • Description: Removes a previously registered action flag. Fires OnActionFlagExpired if the flag was active.
  • Parameters:
    Param Type Description
    Tag GameplayTag The flag tag to remove

HasActionFlagBoolean

  • Description: Returns true if the given tag is currently registered as an action flag.
  • Parameters:
    Param Type Description
    Tag GameplayTag The flag tag to check
  • Blueprint Authority: Any (Pure)

5. 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

6. Overridden Events / Custom Events

Event: BeginPlayInitialize

  • Description: Sets up all bindings, caches references, loads default state, and enables tick.
  • Flow:
    1. Get owner as Character (validate — log error and disable if invalid)
    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, "Death"))
    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)

Event: TickUpdateHeartRate

  • Description: Called every tick. Recalculates heart rate and evaluates vital signals.
  • Flow: (see UpdateHeartRate function flow above)

Event: OnComponentDestroyed

  • Description: Cleanup — unbind all bound delegates, null cached references.
  • Flow:
    1. Unbind from GI_GameFramework.OnGamePhaseChanged
    2. Unbind from BPC_HealthSystem.OnDeath and OnHealthChanged
    3. Unbind from BPC_StressSystem.OnStressTierChanged
    4. Unbind from BPC_StaminaSystem.OnExhaustionStateChanged
    5. Set CachedABPRef = None

7. Blueprint Graph Logic Flow

RequestStateChange Flow

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]

Overlay State Pipeline

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

8. State Gating Reference Tables

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

State Walk Allowed Sprint Allowed Jump Allowed Crouch Allowed Camera Freelook Notes
Sitting No No No No Yes (head only) Must StandUp to move
Injured Slowed (×0.65) No No Yes Yes Limp anim. Heals above threshold
Hiding (Locker/Under) No No No No No (fixed cam) Fully enclosed — zero movement
Hiding (BehindCover) No No No N/A Limited (peek) Cannot leave cover position
Hiding (InShadow) Yes (slow) No No Yes Yes Standing in shadow
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 — wait for regen
Panicked Stumble No No No Random jerks Camera shakes
HoldingBreath No No No No Yes Must release breath before moving
InPhotoMode No (free cam) No No No Full (free cam) Gameplay input disabled

9. GASP Integration Notes

What BPC_StateManager 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

What BPC_StateManager 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.01.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

What BPC_StateManager 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. Communication Matrix

Who Talks How What Is Sent
Any System RequestStateChange() E_PlayerActionState, RequesterTag: GameplayTag, Priority: Int
Any System IsActionPermitted() GameplayTagS_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
BPC_StateManager Dispatcher: OnVitalSignalChanged OldSignal, NewSignal to SS_AudioManager, BPC_CameraStateLayer
BPC_StateManager Dispatcher: OnHeartRateChanged NewBPM: Float to SS_AudioManager, WBP_AccessibilityUI
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

11. Validation / 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
  • Heart rate correctly interpolates and fires threshold change events
  • Vital signal changes fire OnVitalSignalChanged
  • Injury state auto-transitions when health crosses threshold
  • 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)
  • Edge case: RequestStateChange with invalid/missing RequesterTag logs warning

12. 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.
  • The action flag system (RegisterActionFlag/UnregisterActionFlag/HasActionFlag) enables lightweight transient permission tracking without formal state transitions.
  • E_PlayerVitalSignals drives audio heartbeat tempo, camera breathing sway, controller haptics, and accessibility visual heartbeat all from a single source of truth.

Blueprint Spec: BPC_StateManager — Central Nervous System for the Modular Game Framework. Architecture document: bpc-statemanager.md