Files
UE5-Modular-Game-Framework/docs/checklists/bpc-statemanager.md
2026-05-19 10:18:28 +00:00

14 KiB
Raw Blame History

BPC_StateManager — Implementation Checklist

Target: Code Agent (Game Dev mode)
Architecture Doc: docs/architecture/bpc-statemanager.md
Parent System: Player Character (sits alongside BPC_MovementStateSystem, BPC_HealthSystem, etc.)


Pre-Implementation Verification

  • Read docs/architecture/bpc-statemanager.md — Sections 47 (Enums, Structs, Variables, Functions)
  • Read CONTEXT.md — Sections "State Management Conventions" and "Animation Notify Contract"
  • Confirm GASP AnimBP (ABP_GASP) has variable OverlayState (enum), bIsInAction (bool), ActionIntensity (float 01)
  • Confirm BPC_MovementStateSystem (11) fires dispatchers OnMovementModeChanged, OnPostureChanged, OnSprintStateChanged
  • Confirm BPC_HealthSystem (08) fires dispatcher OnDeath with death context
  • Confirm GI_GameFramework (04) has E_GamePhase enum and fires OnGamePhaseChanged

Phase 1 — Enum & Struct Creation (Core/)

Step 1.1: Create E_PlayerActionState Enum

  • Asset path: Content/Framework/Core/E_PlayerActionState
  • 42 values per Section 4.1
  • Display names match exactly

Step 1.2: Create E_OverlayState Enum

  • Asset path: Content/Framework/Core/E_OverlayState
  • 18 values per Section 4.2
  • Display names match exactly

Step 1.3: Create E_ActionRequestResult Enum

  • Asset path: Content/Framework/Core/E_ActionRequestResult
  • 7 values per Section 4.3

Step 1.4: Create Structs

Step 1.5: Create DA_StateGatingTable Data Asset

  • Parent class: PrimaryDataAsset
  • Asset path: Content/Framework/Core/DA_StateGatingTable
  • Variable: GatingRules: Array<S_StateGatingRule>
  • Populate with Section 9 gating rules (25+ rules)

Phase 2 — BPC_StateManager Component Creation

Step 2.1: Create Blueprint Component

  • Asset path: Content/Framework/Player/BPC_StateManager
  • Parent class: ActorComponent
  • Network: Check bReplicates = true if multiplayer planned

Step 2.2: Add Configuration Variables

Per Section 6 — Configuration Variables:

  • GatingRules: Array<S_StateGatingRule> — Expose On Spawn
  • DefaultState: E_PlayerActionState — default Idle
  • bLogStateTransitions: Boolean — default false
  • StateTransitionDelay: Float — default 0.0
  • DefaultOverlay: E_OverlayState — default Empty

Step 2.3: Add Internal Variables

Per Section 6 — Internal Variables:

  • CurrentState: E_PlayerActionState — default Idle
  • PreviousState: E_PlayerActionState — default Idle
  • CurrentOverlay: E_OverlayState — default Empty
  • LastStateChangeTime: Float
  • StateHistory: Array<E_PlayerActionState>
  • ForceStack: Array<E_PlayerActionState>
  • bIsTransitioning: Boolean
  • PendingRequests: Array<S_StateChangeRequest>
  • CachedABPRef: ABP_GASP (soft object reference)
  • CurrentActionFlags: Map<GameplayTag, Float>

Phase 3 — Event Dispatchers

Create all 8 dispatchers per Section 8:

  • OnStateChangedOldState: E_PlayerActionState, NewState: E_PlayerActionState
  • OnStateChangeRequestedRequest: S_StateChangeRequest
  • OnStateChangeDeniedRequest: S_StateChangeRequest, Result: E_ActionRequestResult, Reason: Text
  • OnOverlayStateChangedOldOverlay: E_OverlayState, NewOverlay: E_OverlayState
  • OnActionFlagRegisteredTag: GameplayTag, Duration: Float
  • OnActionFlagExpiredTag: GameplayTag
  • OnForceOverridePushedForcedState: E_PlayerActionState, PoppedState: E_PlayerActionState
  • OnForceOverridePoppedRestoredState: E_PlayerActionState

Phase 4 — Core Functions

Step 4.1: BeginPlay (Override)

Per Section 7.13:

  • Get Owner as Character
  • Cache ABP_GASP from character's skeletal mesh ->GetAnimInstance()
  • Set CurrentState = DefaultState, CurrentOverlay = DefaultOverlay
  • Load GatingRules from DA_StateGatingTable if assigned
  • Bind to GI_GameFramework.OnGamePhaseChanged
  • Bind to BPC_HealthSystem.OnDeath → call ForceStateChange(Dead, "Death")

Step 4.2: RequestStateChange

Per Section 7.1:

  • Priority 100 check: If Priority == 100 → bypass gating → go to transition
  • Transition guard: If bIsTransitioning → queue request → return Blocked_CurrentState
  • Cooldown check: If GameTime - LastStateChangeTime < StateTransitionDelay → return Blocked_Cooldown
  • Dead check: If CurrentState == Dead AND NewState != Idle → return Blocked_Dead
  • Gating evaluation: Iterate GatingRules matching RequesterTag:
    • BlockedStates contains NewState → return Blocked_CurrentState with reason
    • BlockedGamePhases contains CurrentGamePhase → return Blocked_GamePhase
    • RequiredTags missing or BlockedTags present → return appropriate result
  • Transition: Call ExecuteStateTransition(NewState)
  • Return Permitted

Step 4.3: ExecuteStateTransition (Private)

  • Set bIsTransitioning = true
  • PreviousState = CurrentState
  • CurrentState = NewState
  • LastStateChangeTime = GameTime
  • Push NewState onto StateHistory (max 20 entries)
  • Update GASP: ABP_GASP.bIsInAction = (NewState in action states)
  • Update GASP: ABP_GASP.ActionIntensity per state mapping
  • Fire OnStateChanged dispatcher
  • Notify SS_EnhancedInputManager of context change
  • If bLogStateTransitions → print transition to log
  • Set bIsTransitioning = false
  • Process PendingRequests queue

Step 4.4: ForceStateChange

Per Section 7.2:

  • If ForceStack top == NewState → return (no-op)
  • Push CurrentState onto ForceStack
  • Fire OnForceOverridePushed(NewState, CurrentState)
  • Call ExecuteStateTransition(NewState)
  • Log reason if bLogStateTransitions

Step 4.5: RestorePreviousState

Per Section 7.3:

  • If ForceStack is empty → set NewState = Idle
  • Else → Pop ForceStackNewState = popped
  • Fire OnForceOverridePopped(NewState)
  • Call ExecuteStateTransition(NewState)

Step 4.6: IsActionPermitted

Per Section 7.6:

  • Find all GatingRules where ActionTag matches
  • Check CurrentState, GamePhase, RequiredTags, BlockedTags
  • Return S_ActionPermissionResult with bool, reason, result code

Step 4.7: SetOverlayState

Per Section 7.7:

  • If Overlay == CurrentOverlay → return
  • CurrentOverlay = Overlay
  • Set ABP_GASP.OverlayState = Overlay if cached ref valid
  • Fire OnOverlayStateChanged
  • Notify BPC_EmbodimentSystem (if on same actor)

Step 4.8: Convenience Functions

  • GetCurrentState() → pure getter
  • GetPreviousState() → pure getter
  • CanTransitionTo(TargetState) → pre-flight check (calls gating, no transition)
  • IsInCombat() → CurrentState in [SwingMelee, AimingFirearm, FiringFirearm, Reloading, DeployingShield]
  • IsMovementBlocked() → CurrentState in blocking list per Section 7.10
  • CanEquipWeapon() → delegates to IsActionPermitted(Action.Weapon.Equip)

Step 4.9: Action Flag Functions

  • RegisterActionFlag(Tag, Duration) → add to CurrentActionFlags map, start timer if Duration > 0
  • UnregisterActionFlag(Tag) → remove from map, clear timer
  • HasActionFlag(Tag) → lookup in map

Phase 5 — GASP Integration

Per Section 10:

  • Read from GASP: Subscribe to ABP_GASP dispatchers for bStrafing, bSprinting, MovementMode, GroundState
  • Write to GASP: Set OverlayState, bIsInAction, ActionIntensity as variables on cached AnimBP ref
  • Never touch: Motion Matching database, Camera Manager, GASP internal state machine, root motion
  • Overlay pipeline: Verify SetOverlayState(Pistol) → blends upper body correctly

Phase 6 — System Integration (Bind Other Systems)

  • BPC_HealthSystem (08): Bind OnDeathForceStateChange(Dead). Bind OnRespawnRestorePreviousState()
  • BPC_MovementStateSystem (11): OnMovementModeChanged sets walking/jogging/sprinting state. OnPostureChanged sets crouching/crawling
  • BPC_HidingSystem (12): OnHideStateChanged → Hidden triggers RequestStateChange(Hiding); Exposed triggers restore
  • BPC_ContextualTraversalSystem (21): Traversal start → RequestStateChange(Vaulting/Climbing/Sliding); end → restore
  • BPC_InteractionDetector (16): Interaction start → RequestStateChange(Interacting); end → restore
  • BPC_MeleeSystem (76): StartSwing → RequestStateChange(SwingMelee); OnSwingComplete → restore
  • BPC_FirearmSystem (74): Fire → RequestStateChange(FiringFirearm) (transient, auto-restore)
  • BPC_ReloadSystem (78): StartReload → RequestStateChange(Reloading); Complete → restore
  • BPC_DeathHandlingSystem (39): OnPlayerDeath → ForceStateChange(Dead). OnRespawn → RestorePreviousState()
  • SS_UIManager (44): Inventory open → RequestStateChange(InInventory); close → restore. Pause → InPauseMenu
  • BPC_DialoguePlaybackSystem (60): Dialogue start → RequestStateChange(InDialogue); end → restore
  • BPC_CutsceneBridge (64): PlayCutscene → ForceStateChange(InCutscene). OnCutsceneCompleted → RestorePreviousState()
  • BPC_AltDeathSpaceSystem (38): Enter → ForceStateChange(InVoidSpace). Exit → RestorePreviousState()
  • SS_EnhancedInputManager (128): Bind to OnStateChanged → switch IMC_ contexts based on state
  • BPC_CameraStateLayer (14): Bind to OnStateChanged → adjust FOV/offset per state

Phase 7 — Integration Pattern (Replace Hardcoded State Checks)

For each of the 36+ state-gated actions:

OLD pattern (remove):

If (PlayerState != Dead && PlayerState != Hiding && PlayerState != Cutscene...)
    → Execute Action

NEW pattern (replace with):

If (BPC_StateManager.IsActionPermitted(ActionTag).bPermitted)
    → Execute Action
Else
    → Show blocked feedback using result.BlockReason

Systems to Update:

  • BPC_HidingSystem.EnterHideSpot → check Action.Hide.Enter
  • BPC_FirearmSystem.Fire → check Action.Weapon.Fire
  • BPC_ReloadSystem.StartReload → check Action.Weapon.Reload
  • BPC_MeleeSystem.StartSwing → check Action.Weapon.Melee
  • SS_UIManager.OpenInventory → check Action.Inventory.Open
  • BPC_InteractionDetector.PerformInteraction → check Action.Interact.Hold
  • BPC_ContextualTraversalSystem.AttemptTraversal → check Action.Traversal.*
  • BPC_EquipmentSlotSystem.EquipItem → check Action.Inventory.Equip
  • BPC_ConsumableSystem.UseConsumable → check Action.Consumable.Use
  • BPC_PhysicsDragSystem.GrabObject → check Action.Grab.PhysicsObject
  • BPC_DialoguePlaybackSystem.StartDialogue → check Action.Dialogue.Start
  • WBP_PauseMenu.OpenPause → check Action.Pause.Open

Phase 8 — Testing

Per Section 13 Testing Checklist:

  • Valid state changes return Permitted
  • Dead blocks all actions except respawn
  • Force bypasses all gating
  • ForceStack push/pop restores correct state
  • Overlay state correctly writes to GASP
  • Game phase changes gate actions correctly
  • Rapid requests are throttled by StateTransitionDelay
  • 25+ action gating rules all work
  • Edge case: double Force same state = no-op
  • Edge case: RestorePreviousState with empty stack = Idle
  • Edge case: Owner destroyed during transition = graceful null check

Files Created (Summary)

File Type Path
E_PlayerActionState Enum Content/Framework/Core/
E_OverlayState Enum Content/Framework/Core/
E_ActionRequestResult Enum Content/Framework/Core/
S_StateChangeRequest Struct (Blueprint-internal)
S_StateGatingRule Struct (Blueprint-internal)
S_ActionPermissionResult Struct (Blueprint-internal)
DA_StateGatingTable Data Asset Content/Framework/Core/
BPC_StateManager Blueprint Component Content/Framework/Player/

Checklist v1.0 — Aligned with docs/architecture/bpc-statemanager.md. Ready for Code agent implementation.