14 KiB
14 KiB
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 4–7 (Enums, Structs, Variables, Functions) - Read
CONTEXT.md— Sections "State Management Conventions" and "Animation Notify Contract" - Confirm GASP AnimBP (
ABP_GASP) has variableOverlayState(enum),bIsInAction(bool),ActionIntensity(float 0–1) - Confirm
BPC_MovementStateSystem(11) fires dispatchersOnMovementModeChanged,OnPostureChanged,OnSprintStateChanged - Confirm
BPC_HealthSystem(08) fires dispatcherOnDeathwith death context - Confirm
GI_GameFramework(04) hasE_GamePhaseenum and firesOnGamePhaseChanged
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
S_StateChangeRequest— fields per Section 5.1S_StateGatingRule— fields per Section 5.2S_ActionPermissionResult— fields per Section 5.3
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 = trueif multiplayer planned
Step 2.2: Add Configuration Variables
Per Section 6 — Configuration Variables:
GatingRules: Array<S_StateGatingRule>— Expose On SpawnDefaultState: E_PlayerActionState— defaultIdlebLogStateTransitions: Boolean— defaultfalseStateTransitionDelay: Float— default0.0DefaultOverlay: E_OverlayState— defaultEmpty
Step 2.3: Add Internal Variables
Per Section 6 — Internal Variables:
CurrentState: E_PlayerActionState— defaultIdlePreviousState: E_PlayerActionState— defaultIdleCurrentOverlay: E_OverlayState— defaultEmptyLastStateChangeTime: FloatStateHistory: Array<E_PlayerActionState>ForceStack: Array<E_PlayerActionState>bIsTransitioning: BooleanPendingRequests: Array<S_StateChangeRequest>CachedABPRef: ABP_GASP(soft object reference)CurrentActionFlags: Map<GameplayTag, Float>
Phase 3 — Event Dispatchers
Create all 8 dispatchers per Section 8:
OnStateChanged→OldState: E_PlayerActionState,NewState: E_PlayerActionStateOnStateChangeRequested→Request: S_StateChangeRequestOnStateChangeDenied→Request: S_StateChangeRequest,Result: E_ActionRequestResult,Reason: TextOnOverlayStateChanged→OldOverlay: E_OverlayState,NewOverlay: E_OverlayStateOnActionFlagRegistered→Tag: GameplayTag,Duration: FloatOnActionFlagExpired→Tag: GameplayTagOnForceOverridePushed→ForcedState: E_PlayerActionState,PoppedState: E_PlayerActionStateOnForceOverridePopped→RestoredState: E_PlayerActionState
Phase 4 — Core Functions
Step 4.1: BeginPlay (Override)
Per Section 7.13:
- Get Owner as Character
- Cache
ABP_GASPfrom character's skeletal mesh->GetAnimInstance() - Set
CurrentState = DefaultState,CurrentOverlay = DefaultOverlay - Load
GatingRulesfromDA_StateGatingTableif assigned - Bind to
GI_GameFramework.OnGamePhaseChanged - Bind to
BPC_HealthSystem.OnDeath→ callForceStateChange(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 → returnBlocked_CurrentState - Cooldown check: If
GameTime - LastStateChangeTime < StateTransitionDelay→ returnBlocked_Cooldown - Dead check: If
CurrentState == DeadANDNewState != Idle→ returnBlocked_Dead - Gating evaluation: Iterate
GatingRulesmatchingRequesterTag:- BlockedStates contains NewState → return
Blocked_CurrentStatewith reason - BlockedGamePhases contains CurrentGamePhase → return
Blocked_GamePhase - RequiredTags missing or BlockedTags present → return appropriate result
- BlockedStates contains NewState → return
- Transition: Call
ExecuteStateTransition(NewState) - Return
Permitted
Step 4.3: ExecuteStateTransition (Private)
- Set
bIsTransitioning = true PreviousState = CurrentStateCurrentState = NewStateLastStateChangeTime = GameTime- Push
NewStateontoStateHistory(max 20 entries) - Update GASP:
ABP_GASP.bIsInAction = (NewState in action states) - Update GASP:
ABP_GASP.ActionIntensityper state mapping - Fire
OnStateChangeddispatcher - Notify
SS_EnhancedInputManagerof context change - If
bLogStateTransitions→ print transition to log - Set
bIsTransitioning = false - Process
PendingRequestsqueue
Step 4.4: ForceStateChange
Per Section 7.2:
- If
ForceStacktop ==NewState→ return (no-op) - Push
CurrentStateontoForceStack - Fire
OnForceOverridePushed(NewState, CurrentState) - Call
ExecuteStateTransition(NewState) - Log reason if
bLogStateTransitions
Step 4.5: RestorePreviousState
Per Section 7.3:
- If
ForceStackis empty → setNewState = Idle - Else → Pop
ForceStack→NewState = popped - Fire
OnForceOverridePopped(NewState) - Call
ExecuteStateTransition(NewState)
Step 4.6: IsActionPermitted
Per Section 7.6:
- Find all
GatingRuleswhereActionTagmatches - Check CurrentState, GamePhase, RequiredTags, BlockedTags
- Return
S_ActionPermissionResultwith bool, reason, result code
Step 4.7: SetOverlayState
Per Section 7.7:
- If
Overlay == CurrentOverlay→ return CurrentOverlay = Overlay- Set
ABP_GASP.OverlayState = Overlayif cached ref valid - Fire
OnOverlayStateChanged - Notify
BPC_EmbodimentSystem(if on same actor)
Step 4.8: Convenience Functions
GetCurrentState()→ pure getterGetPreviousState()→ pure getterCanTransitionTo(TargetState)→ pre-flight check (calls gating, no transition)IsInCombat()→ CurrentState in[SwingMelee, AimingFirearm, FiringFirearm, Reloading, DeployingShield]IsMovementBlocked()→ CurrentState in blocking list per Section 7.10CanEquipWeapon()→ delegates toIsActionPermitted(Action.Weapon.Equip)
Step 4.9: Action Flag Functions
RegisterActionFlag(Tag, Duration)→ add toCurrentActionFlagsmap, start timer if Duration > 0UnregisterActionFlag(Tag)→ remove from map, clear timerHasActionFlag(Tag)→ lookup in map
Phase 5 — GASP Integration
Per Section 10:
- Read from GASP: Subscribe to
ABP_GASPdispatchers forbStrafing,bSprinting,MovementMode,GroundState - Write to GASP: Set
OverlayState,bIsInAction,ActionIntensityas 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): BindOnDeath→ForceStateChange(Dead). BindOnRespawn→RestorePreviousState()BPC_MovementStateSystem(11):OnMovementModeChangedsets walking/jogging/sprinting state.OnPostureChangedsets crouching/crawlingBPC_HidingSystem(12):OnHideStateChanged→ Hidden triggersRequestStateChange(Hiding); Exposed triggers restoreBPC_ContextualTraversalSystem(21): Traversal start →RequestStateChange(Vaulting/Climbing/Sliding); end → restoreBPC_InteractionDetector(16): Interaction start →RequestStateChange(Interacting); end → restoreBPC_MeleeSystem(76): StartSwing →RequestStateChange(SwingMelee); OnSwingComplete → restoreBPC_FirearmSystem(74): Fire →RequestStateChange(FiringFirearm)(transient, auto-restore)BPC_ReloadSystem(78): StartReload →RequestStateChange(Reloading); Complete → restoreBPC_DeathHandlingSystem(39): OnPlayerDeath →ForceStateChange(Dead). OnRespawn →RestorePreviousState()SS_UIManager(44): Inventory open →RequestStateChange(InInventory); close → restore. Pause →InPauseMenuBPC_DialoguePlaybackSystem(60): Dialogue start →RequestStateChange(InDialogue); end → restoreBPC_CutsceneBridge(64): PlayCutscene →ForceStateChange(InCutscene). OnCutsceneCompleted →RestorePreviousState()BPC_AltDeathSpaceSystem(38): Enter →ForceStateChange(InVoidSpace). Exit →RestorePreviousState()SS_EnhancedInputManager(128): Bind toOnStateChanged→ switchIMC_contexts based on stateBPC_CameraStateLayer(14): Bind toOnStateChanged→ 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→ checkAction.Hide.EnterBPC_FirearmSystem.Fire→ checkAction.Weapon.FireBPC_ReloadSystem.StartReload→ checkAction.Weapon.ReloadBPC_MeleeSystem.StartSwing→ checkAction.Weapon.MeleeSS_UIManager.OpenInventory→ checkAction.Inventory.OpenBPC_InteractionDetector.PerformInteraction→ checkAction.Interact.HoldBPC_ContextualTraversalSystem.AttemptTraversal→ checkAction.Traversal.*BPC_EquipmentSlotSystem.EquipItem→ checkAction.Inventory.EquipBPC_ConsumableSystem.UseConsumable→ checkAction.Consumable.UseBPC_PhysicsDragSystem.GrabObject→ checkAction.Grab.PhysicsObjectBPC_DialoguePlaybackSystem.StartDialogue→ checkAction.Dialogue.StartWBP_PauseMenu.OpenPause→ checkAction.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.