Debugging & Troubleshooting

Documentation Unreal Engine AI FAQ

Debug flags, console variables, common failures, and FAQ.


Flip Debug flags on the combat components or run SEC.Debug.* console variables when an enemy misbehaves. Match log output to the sections below.

Component Debug Flags

Toggle these on the AI controller, which is where the evaluation components sit.
Details
Action Evaluation Component (ActionEvaluationComponent)
Debug
Debug Log Decisions
Debug Log Execution
Component flags OR matching SEC.Debug.* console variables enable the same logs.
Details
Movement Evaluator Component (MovementEvaluatorComponent)
Debug | Draw
Debug Draw Scoring
Debug Draw Avoidance
Debug Draw Nav
Debug | Log
Debug Log Movement
Debug Log Tick
Debug Log Scoring
Debug Log Avoidance
Debug Log Strafe Swap
Debug Log Strafe State
Component flags OR matching SEC.Debug.Movement.* console variables enable the same output.
Threat: bDebugLogThreat / bDebugDrawThreat on UThreatDetectionComponent. See Threat Detection.
Reactions: bDebugLogReactions on UReactionEvaluationComponent, or SEC.Debug.LogReactions 1.
Melee traces: bDrawDebug on USECMeleeTraceComponent, or SEC.Debug.Melee.DrawTracing 1.
With bDebugLogDecisions or SEC.Debug.LogActionDecisions 1, the Output Log prints lines like:
[EvalComp] LightAttack: Ctx=1.00 Nov=1.00 Chain=1.00 Risk=1.00 Runtime=1.00 Custom=0.95 -> 0.95
[EvalComp] HeavyAttack BLOCKED: On cooldown (1.2s remaining)
[EvalComp] Committed to: LightAttack (score 0.95)
An action stopped by a hard gate never reaches a score line; it prints BLOCKED with the reason instead. Custom folds every scorer on the action (Distance, Angle, Health, Speed, plus any you add). Per-scorer values sit in the score breakdown under each scorer's display name.
Component flags and their matching CVars stack: either one turns the output on.

Console Commands

All commands are cheat CVars. Pass 0 or 1 unless noted.
Console variableOutput
SEC.Debug.LogActionDecisionsAction scoring and selection
SEC.Debug.LogActionExecutionStart, end, cooldowns
SEC.Debug.LogReactionsReaction evaluation and execution
SEC.Debug.LogRoleAssignmentsRole assignment (2 = verbose)
SEC.Debug.Threat.LogThreat events
SEC.Debug.Threat.DrawThreat cone, progress arc, AI color grading
SEC.Debug.Movement.DrawScoringDirection sample lines (red low, green high)
SEC.Debug.Movement.DrawAvoidanceAvoidance radius and blocked pawns
SEC.Debug.Movement.DrawNavNav sample validity (blue blocked, white walkable)
SEC.Debug.Movement.LogMovementLayer changes, pathfinding, stuck, detour
SEC.Debug.Movement.LogTickPer-tick state dump (high frequency)
SEC.Debug.Movement.LogScoringDirection scoring
SEC.Debug.Movement.LogAvoidanceAvoidance detection
SEC.Debug.Movement.LogStrafeSwapStrafe swap decisions
SEC.Debug.Movement.LogStrafeStateStrafe state and timers
SEC.Debug.Melee.DrawTracingWeapon sweep shapes

Common Issues

AI doesn't attack
Check first:
  • The ASC on the pawn holds the ability with a tag that matches the ActionSet entry.
  • The action is off cooldown and FinalScore > 0 after scorers run.
  • ActiveActionSet on ActionEvaluationComponent points at the set you expect.
Ability not granted: The action system grants the execution method's Ability Class to the ability system itself, once a valid one exists. Two log lines explain a failure: Cannot grant ability for <action> - ASC is invalid! means the ability system was not ready when actions initialised, and <action> doesn't have any ability or behavior tree set means the execution method carries no class. BTTask_ActivateAbility exposes bGrantAbilityIfMissing for a standalone Behavior Tree setup that bypasses the action system.
Tag mismatch: TryActivateAbilitiesByTag matches tags on the ability CDO's AbilityTags. If the ability has no tags there, switch the execution method to ByEvent or add the tag in class defaults.
ByEvent path: The ability class needs a Trigger entry with Trigger Source = Gameplay Event for the event tag.
No ASC found: Custom pawns must implement IAbilitySystemInterface and return a valid ASC. The no-C++ path is reparenting to EnemyCharacterBase. See Getting Started.
Range: Add a Distance Scorer to the action and tune its Range. An action with no Distance Scorer ignores distance.
Debug: Enable bDebugLogDecisions and read why each action failed or lost selection.
Enemy pauses between attacks
Recovery time blocks offensive action selection while movement and reactions keep running. Cooldown is separate.
Tune on UEnemyAIConfig, Recovery section:
  • ActionRecoveryTime: gap between attacks. All zeros disable recovery.
  • InterruptRecoveryTime: lockout after parry or stagger. Keep it below ActionRecoveryTime.
  • Per-action RecoveryTime when bOverrideRecoveryTime is on replaces the global for that action only.
Confirm: SEC.Debug.LogActionDecisions 1 prints Recovering (X.Xs remaining). IsActionRecovering() exposes the same timer to a debug widget.
A behavior tree action starts nothing
Cause: The blackboard has no key for the action's payload, so the tree receives nothing to act on. A blackboard write to a missing key is dropped by the engine, and the log names the key once per blackboard: could not hand its payload to the behavior tree.
Fix: Add these keys to the blackboard asset:
KeyTypeBase Class
SEC_PayloadObjectSECBehaviorTreePayload
SEC_ActionIdName
SEC_TargetActorObject
SEC_SelfActorObject
SEC_DistanceFloat
Then point the Payload Key on the Activate Blackboard Ability node at SEC_Payload.
AI stuck after attacking
Cause: The ability the action started never ends, so the action keeps waiting on it.
Fix:
  • Give the ability a path that reaches End Ability on completion, on cancel, and on interrupt. An ability that plays a montage through Play Montage and Wait ends when the montage does.
  • Set Ability Timeout on the action to bound the wait. A 30 second safety limit catches it either way, and logs the action and ability that hit it.
  • For an ability that is meant to keep running, use the Gameplay Ability (Fire And Forget) method so the action finishes immediately without waiting.
A revived or pooled enemy never acts again
Cause: Death blocks action evaluation on that controller, and only a revive releases it. An enemy brought back, or a controller reused from a pool, is still holding the block.
Fix: Call HandleRevive() on the SEC Combat Controller component when the enemy comes back. It releases the block, restarts the brain, and turns threat detection, perception and role registration back on. Re-equip the weapon yourself; death dropped it.
Weapon doesn't deal damage
Read the Output Log first. The trace component names most of these itself: a socket a window asked for that nothing registered, a window opening while another was still open, a socket sweeping from a mesh that is not refreshing its bones, an Object Types filter with an empty list, and a socket ID another component already holds.
Check:
  • Socket IDs on the anim notify match TraceSockets on the weapon exactly.
  • The Trace Filter reaches the target: in Channel mode the channel the target blocks, in Object Types mode the type it belongs to (use SEC.Debug.Melee.DrawTracing 1).
  • The pawn has USECMeleeTraceComponent (EnemyCharacterBase adds it by default).
  • Default Damage Config on the trace component or Damage Config on the melee notify state supplies a USECDamageConfig. Damage does not come from the weapon actor class alone.
AI doesn't move
Check:
  • A NavMeshBoundsVolume covers the play area. Press P in the viewport to visualize it.
  • In a StateTree graph, AI Movement stays in a running state during combat so STTask_AIMovement can tick. See StateTree Integration.
  • HybridSwitchDistance on MovementEvaluatorComponent (default 800 cm) sets where tactical sampling hands off to strategic pathfinding. Lower it if the enemy never switches to pathfinding at range; raise it if it pathfinds too close.
Enable bDebugLogMovement or SEC.Debug.Movement.LogMovement 1 for layer and pathfinding events.
Enemy jogs instead of running while closing distance
Cause: sideways movement costs speed, and direction scoring angles the approach a few degrees while the AI holds a strafe side or steps around another enemy.
Fix: raise StrafeFreeAngle on MovementEvaluatorComponent (default 15 degrees), the band around straight ahead that costs no speed. StrafeSpeedPenalty (0.75) softens the cost everywhere including real circling, and 0 turns it off. Also check the run window in your locomotion graph, since a 30 degree approach keeps 65% of its speed by design.
AI walks off ledges or into hazards
Check:
  • NavMesh ends before the visual drop (press P).
  • bEnableNavAwareSampling is on and NavScoreWeight is above 0.
  • A hazard painted only as high nav cost still reads as walkable at close range. Add the NavArea subclass to Hazard Area Avoidance on the movement component with a strength around 0.75; the value is the avoidance weight, where 0 ignores the area and 1 scores it like a wall.
Debug: SEC.Debug.Movement.DrawNav 1 marks blocked directions with blue spheres.
Tune NavProbeDistance (default 120): lower in tight spaces, higher for fast movers. See Movement System.
AI grinds against a wall
The target sits behind cover. Straight-line distance stays short while the nav path is long, so the AI strafes into geometry.
Check on MovementEvaluatorComponent, Hybrid Movement > Detour:
  • bEnableDetourEscalation is on.
  • NavMesh routes around the obstacle.
  • bDetourEscalateOnStall catches tight corners; raise DetourStallSpeed if a slow grind does not register.
  • Lower DetourEnterRatio (try 1.4) or DetourMinExcess when a longer detour still reads as minor.
Debug: SEC.Debug.Movement.LogMovement 1 logs detour recheck lines (ENGAGE, HOLD, release).
Waiter or Flanker freezes after the player jumps a gap
The player sits close in a straight line but the walkable route still wraps around the pit. Waiter and Flanker can already be inside their desired-distance band, so tactical steering idles at the rim while sight stays clear across the gap.
Check on MovementEvaluatorComponent, Hybrid Movement > Detour:
  • bEnableDetourEscalation is on.
  • Both sides of the gap sit on connected navmesh. A route that stops at the rim means there is no walkable way across, and the AI correctly stays tactical rather than walking into a dead end.
  • Leave bDetourUseLineOfSightPreGate on. It reads the navmesh along the straight line, so a gap engages the detour with sight clear.
  • Lower DetourReleaseRatio only if the AI gives up the route too early on a short way around.
Debug: SEC.Debug.Movement.LogMovement 1 prints Detour eval: active, HOLD while the route still detours, and Detour eval: skip (no reachable route) when the far side is not connected.

FAQ

Can I use this with my existing character?
Add SECCombatControllerComponent to your AI controller and the pawn components from Getting Started. Assign an EnemyAIConfig and ActionSet. Leave Default State Tree empty for the native combat loop, or assign a StateTree asset. You do not need to inherit EnemyControllerBase or EnemyCharacterBase.
Does this work with multiplayer?
Yes. AI logic runs on the server. Health, action execution, combat roles, and the active ActionSet replicate to clients. See Multiplayer.
Can I use this without GAS?
Melee trace works without GAS. Action execution through abilities needs GAS for blocking tags, cooldown integration, and GameplayAbilityBase end-tag wiring. Behavior Tree-only execution methods skip ability activation when you wire them that way.
What engine versions are supported?
UE 5.6, 5.7, and 5.8. Plugin version 3.0.0.
How do I handle death (ragdoll, weapon drop, dissolve)?
Call HandleDeath() on SECCombatControllerComponent. It shuts down SEC systems in order and fires OnDeath.
Weapon drop: HandleDeath unequips with bSimulatePhysics = true. Override K2_OnUnequipped on the weapon Blueprint for mesh physics and impulse. Set bDropWeaponOnDeath to false on the combat controller to handle the drop yourself (for example from a death montage notify).
Ragdoll: Enable it from OnDeath or K2_OnDeath. Combat systems are already off.
Dissolve / destroy: Use SetLifeSpan or a timer in K2_OnDeath before destroying the actor.
Is source code included?
Yes. Full C++ source ships with the plugin.

Support

Purchase and updates: Fab Marketplace
Support and feature requests: Discord, Fab Marketplace, or email (contact details on the product page).