Action System

Documentation Unreal Engine AI Actions

Action selection that scores available moves and picks the highest for the current context.


Scores every action against live battlefield data: context tags, plus distance, angle, and health when you add scorers for those dimensions.
Action Evaluation Flow
Content>Plugins>SoulslikeEnemyCombat>Components
ActionEvaluationComponent
EvaluateBestAction()
Gameplay Ability
(Simple Action)
Behavior Tree Sequence
(Complex Logic)
The system dynamically chooses the execution method. Behavior Trees can be chained for complex sequences.

When to Use This

  • Any AI that needs to choose between multiple attacks or behaviors
  • Enemies with distance-dependent movesets (melee vs ranged)
  • Boss fights with phase-based action sets
  • Group AI where different roles use different attack patterns
This system runs on its own. You can use it without the other plugin systems.

How Scoring Works

On every evaluation, all valid actions compete. The highest score above zero wins.
Final Score
ActionEvaluationComponent>Scoring
Final Score
Selection Weight
Risk Penalty
Tag Multipliers
Novelty
Penalizes recent use
Chain Bonus
Scorers
Distance · Angle · Health · Speed · custom
Runtime Modifiers
GlobalMultiplier × SetActionOverride
Jitter
±5%, deterministic
Highest score above zero wins. Leave a scorer off and that dimension drops out of the product. Jitter is deterministic from the decision context seed.
Runtime modifiers scale every action's score: SetGlobalMultiplier buffs or nerfs the whole moveset (0 blocks all selection), and SetActionOverride(ActionId, Multiplier) targets one action. They multiply together in the formula.
A small jitter factor (deterministic ±5% from the decision context seed) breaks ties so two enemies with the same data do not pick identically every tick.
Two base numbers sit on every action:
  • Selection Weight biases the action up or down. Weight 2.0 doubles its score against a weight 1.0 action.
  • Risk Penalty divides the final score to hold risky moves back. 1.0 is no penalty, 2.0 halves the score (a high-risk heavy attack), 0.5 doubles it (a safe move).
Scorers fold in as multipliers, one per dimension you opt into. Leave a dimension off and it does not affect the score: an action with no Distance Scorer scores the same at any range. A scorer that returns 0 zeroes the whole product for that action. The full set of built-ins is in Scorers & Gates.

Range Curves

Every built-in scorer shapes its dimension through one Range property, an FRangeEval curve. Below Min Value the score is 0; it ramps up to 1.0 across Optimal Min, holds at 1.0 through the Optimal Min → Optimal Max sweet spot, then ramps back down to 0 at Max Value. Exponent shapes the falloff. So an attack can be valid from 0-500cm while its score peaks at 150-250cm.
Distance Scorer Range at the melee-preset default:
Range
Min Value
0
Optimal Min
100
Optimal Max
250
Max Value
500
Exponent
2
Clamp To Zero
Presets to assign to a scorer's Range:
  • MakeMeleeRange(): Close-range distance band (0-100-250-500)
  • MakeRangedRange(): Long-range distance band (300-500-1000-1800)
  • MakeFrontalAngle(): Forward-facing cone (0-0-30-90, Angle Scorer)
  • MakeLowHealthRange(): Peaks at low health (0-0-0.25-0.5, Health Scorer, for desperate moves)
  • MakeAlwaysOne(): Always returns 1.0 (no preference)
A scorer left at MakeAlwaysOne() has no effect, which is the default for the Health and Speed Scorers. Shape the Health Scorer's Range to favor low or high health, and use the Speed Scorer for pace-dependent moves such as a running attack that should score only while sprinting.

Cooldowns & Variance

An action's Cooldown group controls reuse. Cooldown Duration is the base delay. Initial Cooldown blocks the move at spawn so enemies cannot open with a heavy hit. Randomization (%) adds ±variance (0.2 = ±20%). Spawn Cooldown Chance rolls a starting cooldown so a pack does not attack in lockstep. Max Consecutive Uses (-1 = unlimited, 2 = must switch after two uses) stops spam. Defaults:
Cooldown
Cooldown Duration
5
Initial Cooldown
0
Randomization (%)
0.2
Interrupt Refund (%)
0
Spawn Cooldown Chance
0
Max Consecutive Uses
-1
An action commits its cooldown only after BeginExecute succeeds and PreExecute hooks do not veto. If activation fails or a hook sets bVetoExecution, no cooldown is stamped and the action can retry next tick. A CanActivateAbility refusal during ability activation follows the same rule: off cooldown, free to retry.
Interrupt Refund (%) covers the case where an action starts, commits its cooldown, and is then cut short: an attack stopped in its windup would otherwise pay the same price as one that landed. 0.5 hands back half the time that was left. A clean finish and a timeout pay in full. It defaults to 0, so nothing changes until you set it.

Recovery Time

Recovery time suspends offensive action selection for a set number of seconds after an enemy commits a move. The enemy still strafes, repositions, and reacts (parry, dodge, counter). It does not start a new attack. Use it when a relentless attacker needs gaps between swings.
Cooldown gates re-use of one move. Recovery gates all offensive actions after one ends. Tune the global windows on UEnemyAIConfig under Recovery. Every field defaults to 0, so recovery stays off until you set a value.
FieldSets
ActionRecoveryTimeSeconds suspended after an action completes or times out.
InterruptRecoveryTimeSeconds suspended after an action is interrupted or cancelled. Keep it shorter than ActionRecoveryTime so a parry or stagger does not double-stun.
ActionRecoveryTimeRandomizationPlus or minus jitter on the completion recovery, so a pack does not act in lockstep.
Per-action override. On the action's Recovery group, enable bOverrideRecoveryTime and set RecoveryTime. The value replaces the global for that action; it does not add to it. With config ActionRecoveryTime = 3, a jab that sets RecoveryTime = 1 recovers in one second while other moves recover in three.
To watch the gate at runtime, set SEC.Debug.LogActionDecisions 1. While an enemy is held off, the decision log prints Recovering (X.Xs remaining). For a HUD, BlueprintPure IsActionRecovering(float& OutRemaining) returns whether the enemy is recovering and the seconds left.
AdvancedRecovery window by exit path, and combo follow-ups
By exit path:
  • Completed uses the action's effective recovery (the override if set, otherwise the global ActionRecoveryTime).
  • Interrupted or cancelled uses InterruptRecoveryTime.
  • Timed out uses the global ActionRecoveryTime, never the per-action override.
  • Failed stamps no recovery window.
Combos flow through recovery. An action's chain-link targets can still be selected while the enemy recovers, for ChainFollowupWindowSeconds after the action ends. Set that window on the evaluation component (default 0.6). 0 makes the follow-up wait out recovery like any other action. Only the actions its chain links name bypass the gate. A non-completion end (interrupt or cancel) clears it, so a parried enemy cannot combo through its own recovery.
Stacked or conditional recovery. For recovery that depends on state (extra recovery at low health), call RequestRecoveryTime from a Lifecycle Hook PostExecute. The contribution folds into the window.

Novelty & Chains

  • Novelty: Recently used actions take a score penalty, so the AI mixes moves without hard randomization.
  • Chains: Add an entry to an action's Chain Links, naming the follow-up it prefers and the Bonus Multiplier that follow-up receives (default 1.5). After a Light Attack completes, Heavy Finisher scores higher for a short window. One action can prefer several follow-ups, each with its own bonus.
Wiring these on a canvas, and watching a chain fire, is what the Action Set Editor is for.

Organic Combos

Raise Smash's score after Hit. If the player rolls out of range, the AI drops the combo. It does not swing at air.

Preconditions (Hard Gates)

Before scoring, every action runs hard gates. Fail one and the action drops out for that tick.
GateBlocks the action when
Enabled (bEnabled)The action is toggled off in the ActionSet.
SEC.Action.BlockActionsThe tag sits on the AI's ability system component (add it via a reaction's AddTags to freeze offense).
Valid execution methodThe action has no configured method, or HasValidData returns false.
Cooldown / repeat limitThe action is still cooling down, or Max Consecutive Uses is exhausted.
RecoveryThe AI is in a post-action recovery window (chain follow-ups excepted).
RequiresTagsThe combined Self/Target/World tags don't hold all of them.
BlockTagsAny of them sits on Self, Target, or World.
Require Line Of SightThe box is ticked and the AI has no clear view of its target.
GatesAny USECGate in the action's CustomScoring → Gates array returns false. See Scorers & Gates.
Stamina only blocks when you add a Stamina Gate (MinStamina) to the Scoring list, a Vital Gate for any named pool, or an Attribute Gate for a GAS stamina pool. Decision-context Stamina reads the AI's stamina vital when one is authored, else it defaults to 100, so an action with no Stamina Gate ignores stamina.
Require Line Of Sight reads FDecisionContext::bHasLOS. The Build Decision Context task traces from the AI's eyes to the target each tick. Tick the box for ranged shots and gap-closers. Leave it off for moves that land blind (radial slam, taunt).
While an action runs it applies its AddTags to the AI's ability system component. SEC.State.IsMovementBlocked ships in that list by default and holds the enemy still mid-swing. Remove it from AddTags to let the AI move during that action.

Execution Methods

Each action runs through an Execution Method: an instanced object under Execution that owns how the action runs. Two built-ins ship. You can write your own.
MethodRuns
Gameplay AbilityA single Gameplay Ability, activated by tag or event.
Behavior Tree SequenceOne or more Behavior Trees, one after another.
Pick a method once per action. Its fields appear inline under it: ability actions show ability fields, behavior-tree actions show the tree list.

Gameplay Ability

Pick an ability class. That is the setup. SEC grants the ability to the character, works out how to start it from the ability's own class defaults, and finishes the action when the ability ends.
Execution
Execution Method
Ability
Ability Class
GA_SEC_TwoHanded_DoubleAttack
Advanced
Ability Timeout
0

Grants the ability, starts it, and finishes the action when the ability ends.

The Execution Method combo above is live. Pick another method to see the properties that class exposes.
Ability Class is the ability this action runs. Ability Timeout sits under Advanced and caps one run in seconds; 0 leaves the ability's own end as the only limit, backed by a 30 second safety.
Two siblings cover the cases a class does not:
MethodUse it for
Gameplay Ability By TagAn ability granted somewhere else. Takes an Activation Tag instead of a class. Every granted ability carrying the tag starts, and the action finishes when the first of them ends.
Gameplay Ability (Fire And Forget)A buff, a shout, or anything the AI should not stand still for. Starts the ability and finishes the action in the same frame without cancelling it. Use the action's Recovery Time to hold off the next action.
Nothing has to report back. SEC watches the ability system for the ability it started, so an ability that reaches End Ability on completion, cancel, and interrupt works with no extra wiring.
UGameplayAbilityBase provides rotation lock (bLockAIRotation: the AI commits to the attack direction with no mid-swing tracking), a ledge guard so a root-motion attack does not walk the enemy off an edge, motion warping toward the target, and the action context (target, distance, direction, magnitude, tags) on activation.

Motion Warping

Steer an attack toward its target. UGameplayAbilityBase registers a warp target from the resolved action context. The montage's Motion Warp notify performs the warp.
AdvancedMotion warping setup and tuning
UGameplayAbilityBase steers an attack toward its target with Unreal's Motion Warping. On activation the ability registers a warp target from the resolved action context: the event payload's target for event-driven activations, or AIController::GetFocusActor() when tag or direct activations carry no payload target. The plugin registers the target. The montage's Motion Warp anim notify performs the warp.
The pawn must carry a UMotionWarpingComponent. AEnemyCharacterBase does not add one, so warping no-ops on pawns without it.
PropertyDefaultEffect
MotionWarpingTargetNameTargetWarp target key. Must match the Warp Target Name on the montage's Motion Warp notify. Set to None to disable warp setup for the ability.
MotionWarpingOffset100.0Warp point offset in cm, placed in front of the target toward the AI. Doubles as a switch-off distance: once the AI is closer than this, root-motion warping pauses so the attack does not overshoot. The ability sets up that pause only while the offset is above 0.
MaxWarpDistance0.0Skip gate. If the AI is closer than this when the ability activates, no warp target is set up. The default of 0 leaves the gate off (any distance warps).
bLockAIRotationtrueStops the controller from yawing the pawn toward focus during the ability. Warping runs on a separate path and still rotates the pawn during the notify window.
bPreventLedgeFallDuringAbilitytrueKeeps the character on the ledge while the ability runs, so an attack or backward dodge with root motion slides along the edge instead of dropping over it. The character's own Can Walk Off Ledges setting comes back when the ability ends, including on cancel and interrupt.
AdvancedWhat the ledge guard does not cover
Ground movement only. Montage root motion keeps the character in walking mode, which is where the engine's ledge check runs, so attacks and dodges are covered. An ability that calls Launch Character, or one using a root motion source with vertical velocity, leaves the ground on purpose and still drops.
To stop an enemy dropping at any time, untick Can Walk Off Ledges on its Character Movement component instead. That holds for the pawn's whole life, which also means it can never take a drop-down nav link, and is why the plugin does this per ability.
Several things can hold the guard at once. Two overlapping abilities release independently, and the authored value returns only when nothing is asking for it. Hold the same window from an anim notify through the SEC Movement Guard subsystem's Acquire Ledge Guard and Release Ledge Guard.
In multiplayer the guard applies wherever the ability runs. SEC's AI abilities run on both sides, so enemies are covered. A player ability derived from this base needs a net execution policy that also runs on the owning client, otherwise the client predicts the drop and gets corrected.
Setup:
  1. Add a UMotionWarpingComponent to your character, in the Blueprint through Add Component or in a C++ subclass through CreateDefaultSubobject.
  2. Place a Motion Warp notify window over the attack's windup in the montage.
  3. Set the ability's MotionWarpingTargetName to the notify's Warp Target Name.
Where the AI tracks versus commits depends on the notify window: rotation warps toward the target across the window, then the swing commits past it. bLockAIRotation and warping run on separate paths, so a committed attack can still track during the warp window while controller facing stays locked.
AM_SEC_TwoHanded_TripleAttack_Montage in the showcase content has a working Motion Warp setup. Copy its notify and warp values as a starting point.

Activation Modes

Most abilities activate by tag (the default). Switch to event activation when the ability needs its payload on the first frame.
AdvancedByTag vs ByEvent activation
SEC picks the route from the ability. An ability whose only Blueprint graph is Activate Ability From Event starts through a gameplay event so that graph receives the payload; anything else starts directly on its granted ability. An action fired through ExecuteActionWithContext takes the event route, since that is how its payload reaches the ability.
The behavior tree Activate Ability node states its route directly:
ModeHow It Works
ByTag (default)Calls TryActivateAbilitiesByTag using AbilityTag. The ability must have matching AbilityTags in its class defaults.
ByEventSends a Gameplay Event using AbilityTag as the event tag. The ability must have a matching Trigger entry (Gameplay Event) in its class defaults, or use WaitGameplayEvent.
ByEvent mode sends a payload with the instigator and current target actor. Your ability can read them on the first frame.
// Standard tag-based activation (default)
ActivationMode = EAbilityActivationMode::ByTag;
AbilityTag = "SEC.Action.Attack.Light";
 
// Event-based activation
ActivationMode = EAbilityActivationMode::ByEvent;
AbilityTag = "SEC.Action.Attack.SweepEvent";  // Used as the event tag
ByEvent abilities do not need AbilityTags in their class defaults. Instead, add a Trigger entry with the matching tag and set its source to Gameplay Event. The AbilityTag field serves double duty: tag activation in ByTag mode, event tag in ByEvent mode.

Behavior Tree Sequence

Runs one or more Behavior Trees in order. Use it for multi-stage behaviors: circling, investigating, boss sequences. Set these on the method:
Execution
Execution Method
Behavior Tree
Behavior Tree Sequence
1 Array element
Index [ 0 ]
BT_SEC_AbilityAction
Behavior Tree Timeout
0
Payload
Payload
Ability Class
GA_SEC_TwoHanded_TripleAttack
Advanced
Payload Key Name
SEC_Payload

Runs the trees in order, handing each one the payload through a blackboard key.

Behavior Tree Sequence lists the trees to run, in order. Behavior Tree Timeout caps each tree in seconds; 0 waits for each one to finish, backed by a 30 second safety on the action.
Payload is the data the action hands to its trees. Leave it None for a sequence that needs nothing. Pick Ability Payload to name a gameplay ability, which SEC grants so an Activate Blackboard Ability node can start it. Setting a payload reveals Payload Key Name under Advanced, the blackboard key the payload is written to, SEC_Payload by default.
AdvancedCarrying your own data into a tree
Subclass Behavior Tree Payload in Blueprint to carry fields of your own: a montage, a damage multiplier, a socket name. Assign your subclass on the action, and read it inside any tree in the sequence with Get Action Payload, whose output pin resolves to your subclass with no cast node.
Get Action Payload For Pawn reads the same payload from a pawn, for use inside an ability the tree started or in an animation notify.
AdvancedBlackboard keys and the ability-activation BT tasks
Before the first tree starts, the method writes these blackboard keys:
Blackboard KeyTypeValue
SEC_ActionIdNameThe action's ActionId
SEC_PayloadObjectThe action's payload. Set the key's Base Class to SECBehaviorTreePayload so tree nodes offer it.
SEC_TargetActorObjectThe current target (focus) actor
SEC_SelfActorObjectThe AI pawn
SEC_DistanceFloatDistance to target
These keys must exist in your Blackboard Data Asset with the exact types above, or the writes are dropped by the engine. A missing payload key is reported in the log once per blackboard, naming the key to add.
The plugin provides two Behavior Tree tasks for activating abilities inside a BT:
Activate Blackboard Ability reads the payload key, starts the ability that payload names, and waits for it to end. Point its Payload Key at SEC_Payload. Fallback Activation Tag covers a tree running outside the action system, and Fail When No Ability decides whether a branch with nothing to start fails or succeeds.
Activate Ability is a standalone task where you set the ability class directly. Its Activation Mode is By Tag or By Event, and an Activation Tag field appears on the By Event route. Use it to start a specific ability from a tree without going through the action system.
Both nodes wait for the ability to end, and both fail the branch when something cancels it. Untick Wait For Ability End for a node that should start an ability and move on.

Custom Execution Methods

The two built-ins cover abilities and behavior trees. For a latent task, spawned projectile, timeline, or third-party system, write your own method. USECExecutionMethod is Blueprintable (Blueprint or C++).
AdvancedWriting a custom execution method
Subclass USECExecutionMethod in Blueprint or C++. Your method carries its own payload fields and slots into the action's Execution Method picker next to the built-ins.
The action holds your method as a definition and never mutates it. On execution the component duplicates the definition. The running instance can hold per-execution state (spawned actor, montage handle, elapsed counter) as ordinary properties.
Override the phases you need:
FunctionWhen it runsWhat to do
PreloadAssetsThe AI takes on the action set, before any action runsStart loading soft references in your payload so the first execution does not stall on them.
BeginExecuteThe action startsStart your work. Return false to fail the start; the action charges no cooldown and can retry.
TickExecuteEach frame while runningPoll or advance. A method that implements it receives the per-frame call.
AbortExecuteThe action is interrupted or cancelledTear down: cancel timers, destroy spawned actors, unbind callbacks, restore state.
Call FinishExecution(bSuccess, Reason) when your work ends. The component completes the action on the next tick, so completion never re-enters your BeginExecute. The ability method calls it from the ability's end-tag event; the behavior-tree method calls it when the last tree finishes.
The component owns everything around the method: cooldowns, recovery, lifecycle hooks, the timeout, and the started and completed delegates. Your method owns only the mechanism.
Four definition-side queries shape how the component treats the method. Keep them as pure reads:
QueryReturns
HasValidDataWhether the method is configured. An action whose method returns false is skipped, the same as an action with no execution data.
GetAbilityToGrantAn ability class to auto-grant to the character's ASC, or none for a method that grants nothing.
GetExecutionTimeoutSeconds before the component force-ends the method. Return 0 to wait on FinishExecution alone.
GetDisplayNameThe label shown on the action's Execution Method slot and in the logs.
Report completion by calling FinishExecution. A method that never calls it and returns 0 from GetExecutionTimeout ends only when the 30-second hard safety fires.
A method instance is stateful and private to one execution, unlike a Scorer or Gate, which stays stateless and shared across every AI using the asset. Hold per-execution state on the method; the component discards the instance when the action ends.

Choosing the Action Set

The plugin resolves which ActionSet an enemy uses through a priority chain. Combat role changes trigger SECCombatControllerComponent to sync.
The resolver walks this chain and returns the first match:
PrioritySourceUse
1 (highest)Runtime OverrideSetRuntimeOverride(ActionSet). For boss phase transitions.
2Provided SetA set pushed onto the pawn, which is how an equipped weapon's moveset arrives.
3Config RoleRole-specific ActionSet from EnemyAIConfig (Attacker vs Flanker).
4Config DefaultFallback ActionSet from EnemyAIConfig.
5Component DefaultSECActionSetComponent → DefaultActionSet on the pawn.
6NoneNo ActionSet found. The AI moves but never attacks.
Weapon and override changes take effect immediately. No role change required.
SECReactionSetComponent uses the same resolution chain for reaction sets.

Weapon-Driven AI

A weapon's own set outranks Config. Give a skeleton a Bow and it becomes a sniper. Take the bow away and it falls back to its Config set as a brawler.

Giving a weapon its own moveset

Fill in Weapon Action Set on the weapon Blueprint. While the enemy holds that weapon it fights from that set, and releasing the weapon hands the enemy back to its AI Config. See Weapons for how the weapon reaches the enemy.
Leave the field empty and the enemy keeps whatever its Config gives it.
AdvancedAnswering with a different set per combat role
Weapon Action Set answers the same set for every role. To vary it, override Get Weapon Action Set For Role on the weapon and branch on the incoming role tag. Return nothing for a role to leave that role on its Config set.
The equipment component asks again whenever the pawn's combat role changes, so a per-role answer stays current.
A weapon that derives from something other than SEC Weapon Base adds the SEC Weapon Action Set Provider interface in Class Settings and overrides the same event.
C++Pushing a set without a weapon
The slot is not weapon-specific. Anything can drive it.
Pawn->ActionSetComponent->SetProvidedActionSet(ActionSet);
Pawn->ActionSetComponent->SetProvidedActionSet(nullptr);  // fall back to Config resolution
USECEquipmentComponent is what pushes it for an equipped weapon, so a pawn using the component leaves this alone.

Dynamic Actions

AdvancedGranting and revoking actions at runtime
Grant and revoke individual actions without swapping the whole set. These are BlueprintCallable (Blueprint or C++).
Pawn->ActionSetComponent->GrantAction(ThrowGrenadeSpec);
Pawn->ActionSetComponent->RevokeAction("ThrowGrenade");
Granted actions persist across role changes and action set swaps. They participate in evaluation alongside the base ActionSet: same scoring, same cooldowns.
For bulk operations:
Pawn->ActionSetComponent->GrantActionsFromSet(BonusActionSet);  // Add all from set
Pawn->ActionSetComponent->RevokeActionsFromSet(BonusActionSet); // Remove all from set
Pawn->ActionSetComponent->ClearGrantedActions();                // Remove all granted

Scorers & Gates

Every scoring dimension past Selection Weight, Risk Penalty, tags, novelty, and chains is a Scorer or Gate on the action. Distance, angle, health, and speed each have a built-in scorer. Tags stay built into the pipeline. For mana, ally count, terrain, or faction state, attach your own. Each FActionSpec has a Scoring group with two arrays:
Content Browser
Content>Plugins>SoulslikeEnemyCombat>ActionSets
Scoring list
Action Scorers
SelectionWeight
Always present · × base
No scorers or gates, so the action scores on weight alone.
score = Weight × Distance · (Stamina pass) × Yours
Add from library
Distance ScorerData Asset (Scorer)
Stamina GateData Asset (Gate)
Create customBlueprint (USECScorer)
Each scorer multiplies in; each gate can veto. Mix built-ins with custom subclasses.
TypeBase ClassReturnsEffect
ScorerUSECScorerA multiplier (1.0 = no effect)Folds into the action score. Above 1 favors, below 1 disfavors.
GateUSECGatetrue / falseA false drops the action from selection, like a built-in precondition.
Add an entry, pick a built-in class or your own Blueprint/C++ subclass, and set its parameters inline. Same authoring pattern as Role Evaluators and Positioning Rules.
An action with an empty Scoring list scores on SelectionWeight alone. No scorer or gate can veto it. Built-in hard gates still apply (cooldown, block tags, ability activation). Adding a scorer opts the action into that dimension. Omitting it leaves the action indifferent to it.

Built-in Classes

ClassKindPropertyUse
Distance ScorerScorerRange (default MakeMeleeRange())Score by AI-to-target distance in cm (0 with no target). The Range OptimalMin/OptimalMax also feed the positioning query.
Angle ScorerScorerRange (default MakeFrontalAngle())Score by angle to the target in degrees, 0 facing it, 180 away (0 with no target).
Health ScorerScorerRange (default MakeAlwaysOne())Score by AI health, a 0-1 fraction sourced from the pawn's health vital. For any other pool, use Vital Scorer; for a GAS health attribute, use Attribute Scorer.
Speed ScorerScorerRange (default MakeAlwaysOne())Score by AI horizontal speed in cm/s.
Vital ScorerScorerVitalTag, bUseFraction (default true), Range (default MakeAlwaysOne())Score by any named vital, the general form behind Health Scorer. No effect on a pawn with no vitals component or no row for the tag.
Stamina GateGateMinStamina (default 0)Veto unless decision-context Stamina is at least MinStamina, sourced from the pawn's stamina vital when authored (else the 100 default). For any other pool, use Vital Gate; for a GAS stamina attribute, use Attribute Gate.
Vital GateGateVitalTag, MinValue (default 0), bUseFraction (default false)Veto unless a named vital holds at least MinValue, the general form behind Stamina Gate. No effect on a pawn with no vitals component or no row for the tag.
Attribute ScorerScorerAttribute, NormalizeBy, ValueEvalScale by a GameplayAttribute through an FRangeEval curve. Optional normalize-by attribute (e.g. Mana / MaxMana).
Attribute GateGateAttribute, MinValue, MaxValueAllow only while an attribute sits between a min and a max.
Combat Token GateGateTokenTag, Cost (default 1)Veto unless the target has a free permission slot, then hold that slot until the action ends. Caps how many enemies run the action against one target at once. See Combat Tokens.
The decision context does not read GAS attributes. Health Scorer and Stamina Gate read the snapshot sourced from the pawn's vitals, defaulting to full health and 100 stamina when the pawn carries no vitals component or no row for the configured tag. For an attribute, reach for Attribute Scorer or Attribute Gate; for a specific pool, a Vital Scorer or Vital Gate.

Examples

Cast a spell only above a mana threshold. Add an Attribute Gate, set Attribute = Mana, MinValue = 30. The spell drops out whenever mana is below 30.
Favor a heavy attack as rage builds. Add an Attribute Scorer, set Attribute = Rage, NormalizeBy = MaxRage, and shape the curve to peak near full. The attack scores higher as rage fills.
Let one enemy swing at a time. Add a Combat Token Gate to every melee attack, set TokenTag = SEC.Token.Attack, and drop that pool to 1 in Project Settings. The rest circle until the slot frees. See Combat Tokens.
The same Scorers and Gates work on reactions. On the reaction path the component builds a live spatial snapshot (distance, angle, speed, health) from the pawn and TargetOverride instead of the action decision context. See Reaction System.

Custom Scorers & Gates

For anything the built-ins miss, write your own. USECScorer and USECGate are both Blueprintable (Blueprint or C++).
AdvancedWriting a custom scorer or gate
Subclass USECScorer or USECGate and override its one function (ScoreMultiplier or PassesGate). FSECScoringContext carries the controller, target, owning ASC, the seed that SeededRandom uses, and a decision-context snapshot (below).
Keep scorer and gate subclasses stateless. Every AI using the asset shares one instance, so mutable fields alias across enemies. For randomness, use the SeededRandom helper.
SeededRandom draws from the per-action seed in FSECScoringContext. On the reaction path that seed is 0, so SeededRandom returns a fixed value. Vary reaction randomness through a built-in factor or your own context read.
The scoring context snapshot. FSECScoringContext copies a decision-context snapshot once per evaluation. Built-in Distance/Angle/Health/Speed Scorers and the Stamina Gate read from it; Vital Scorer and Vital Gate read the pawn's vitals component directly through the Vitals field instead:
FieldMeaning
DistanceDistance to the focus target in cm (0 with no target).
AngleDegAbsAbsolute angle to the target in degrees, 0 facing it (0 with no target).
SpeedAI horizontal movement speed in cm/s.
HealthPercentageAI health as a 0-1 fraction.
StaminaAI stamina (default scale 0-100).
VitalsThe pawn's vitals component, or null when the pawn carries none.
These fields fill from the action decision context on the action path. On the reaction path, ReactionEvaluationComponent builds a separate live snapshot (distance, angle, speed, health, and stamina from the pawn and TargetOverride). Pass TargetOverride when evaluating reactions so spatial scorers measure against the attacker.
Labeling. Each scorer and gate reports a display name through overridable GetDisplayName() (BlueprintNativeEvent). It defaults to the class display name and drives the decision log, the score breakdown, and the editor array row title on UE 5.7+. Override it for a custom or dynamic label (fold the configured range into the name).

Project-Wide Hooks

Built-in scorers and gates cover per-action rules. For logic that applies to every action, use the two override hooks or a lifecycle hook.

Custom Scoring Hooks

AdvancedCanExecuteAction and ModifyActionScore
ActionEvaluationComponent exposes two BlueprintNativeEvent hooks (Blueprint or C++). Prefer Scorers & Gates for per-action rules.
CanExecuteAction: Veto an action after all built-in gates pass.
bool CanExecuteAction(FName ActionId, const FDecisionContext& Context);
// Return false to block the action.
ModifyActionScore: Adjust the score after the pipeline computes it.
float ModifyActionScore(FName ActionId, float BaseScore, const FDecisionContext& Context);
// Return a modified score. Return BaseScore for no change.
Override these in a Blueprint or C++ subclass of UActionEvaluationComponent.

Lifecycle Hooks

A lifecycle hook runs your logic around an action as it executes, on every exit path. Use it for a telegraph before a heavy swing, analytics, or a veto scorers cannot express. USECActionHook is Blueprintable (Blueprint or C++).
AdvancedAuthoring and attaching a lifecycle hook
Subclass USECActionHook (Instanced, abstract) and override the phases you need.
USECActionHook override functions in the Blueprint editor: PreExecute, TickExecute, and PostExecute under the SEC category, plus GetDisplayName
A hook has three phases:
PhaseWhen it runsGives you
PreExecuteAfter BeginExecute succeeds, before cooldown commit, AddTags, and started delegatesA chance to abort: set bVetoExecution to tear down the start without stamping cooldown.
TickExecuteEach tick while the action executesPer-frame work. A Blueprint method that implements this event receives the call; nothing to opt into.
PostExecuteWhen the action ends, on every exit pathThe end reason (Completed, Interrupted, Cancelled, TimedOut, or Failed).
Attach a hook in two places. Per action: FActionSpec.Hook. For the whole enemy: UEnemyAIConfig.GlobalHook (under Recovery), which runs for every action it commits.
When both are set they compose, global first then per-action, in each phase:
  • Veto is OR. If either hook sets bVetoExecution in PreExecute, the action aborts.
  • Recovery accumulates. RequestRecoveryTime contributions from both hooks add up.
For stacked or conditional recovery time, call RequestRecoveryTime on the context in PostExecute. Example: add extra recovery when the enemy ends the action below a health threshold.

World State Tags

WorldTags carry global game state (boss phases, weather, arena state) into AI scoring. Push them through USECWorldTagSubsystem (or the one-node USECWorldTagLibrary helper). The build task copies them into FDecisionContext::WorldTags each tick, where they feed RequiresTags, BlockTags, and TagScoreMultipliers.
The plugin ships three example world tags: SEC.World.Combat.Active, SEC.World.Boss.Active, and SEC.World.Boss.Casting. Use them as starters or define your own.
AdvancedWorld tag API: mutators and client reads
// Server BP, anywhere
USECWorldTagLibrary::AddWorldTag(this, SEC.World.Combat.Active);
USECWorldTagLibrary::AddWorldTagForDuration(this, SEC.World.Boss.Casting, 3.0f);
USECWorldTagLibrary::AddWorldTagUntil(this, SEC.World.Boss.Active, {YourGame.Boss.Defeated});
VariantBehavior
AddWorldTagPermanent until RemoveWorldTag.
AddWorldTagForDurationRemoves after N seconds. Re-adding refreshes the timer.
AddWorldTagUntilRemoves when any sentinel tag is added.
Mutators run on the server only (BlueprintAuthorityOnly); client calls no-op silently.
Client-side reads (UI, audio): drop USECWorldTagComponent on GameState. The component replicates the subsystem's tags and broadcasts OnTagsChanged on clients. Without the component, USECWorldTagLibrary::GetWorldTags returns empty on clients and warns once.

Contextual Execution

Sometimes an action needs a specific target, item, or magnitude. Creating a new ActionId per variation does not scale. Pass Context.
AdvancedExecuting with context and gating on the payload

1. Execute with Context

Call this from Blueprint or C++ to pass dynamic data:
FSECExecutionContext Context;
Context.Target = CustomTargetActor;
Context.OptionalObject = SomeItem;
Context.Magnitude = 0.5f;
Context.ContextTags.AddTag(Tag_QuickVariant);
 
ActionEvaluationComponent->ExecuteActionWithContext("SpecialAttack", Context);

2. Receive in Ability

Your ability (inheriting from UGameplayAbilityBase) captures this data.
  • Event: On Action Context Received (Blueprint)
  • Accessor: GetActionContext() (Blueprint Pure)
Context mapping:
Context FieldMaps To
TargetActionContext.Target
OptionalObjectActionContext.OptionalObject
MagnitudeActionContext.Magnitude
ContextTagsActionContext.ContextTags
If Target is not provided in context, the system falls back to the AI's current Focus Actor.

3. Gate Before Activation

SEC hydrates the context before the ability activates. Override CanActivateAbility (Blueprint or C++) on your UGameplayAbilityBase, read GetActionContext(), and return false to block.
  • Event-triggered activations (ByEvent, Execute With Context, reactions) fill the context from the payload.
  • Tag and direct activations fill it from the AI's focus target.
// Inside your ability's CanActivateAbility override:
const FSECExecutionContext& Ctx = GetActionContext();
if (!Ctx.GetTarget() || Ctx.Magnitude < RequiredCharge)
{
    return false; // refuse before the ability runs
}
A refusal costs nothing: SEC commits no cooldown and interrupts no running action. Use it when your rule needs the payload. Use CanExecuteAction for self or world gates that do not.

Quick Setup

  1. Create Asset: Right-click → MiscellaneousData AssetActionSet.
  2. Define Actions: Each entry needs an ActionId, SelectionWeight, an Execution Method, and (for range behavior) a Distance Scorer in its Scoring list. Toggle bEnabled off to disable an action without deleting it.
  3. Assign: Drop the ActionSet into your EnemyAIConfig, or set it for testing:
ActionEvaluationComponent->ActiveActionSet = MyActionSet;
See Configuration Reference for the full EnemyAIConfig structure.

Debug Tools

To watch an enemy score these actions while the game runs, open its Action Set and press Play: the Action Set Editor lights each action up with its live score, its cooldown, and the gate that refused it.
For a record you can scroll back through, the component logs the same reasoning:
// On ActionEvaluationComponent:
ActionEvalComp->bDebugLogDecisions = true;  // Log scoring breakdown
ActionEvalComp->bDebugLogExecution = true;  // Log execution flow
The SEC.Debug.LogActionDecisions 1 console variable does the same globally without touching the component.

Integration Points

SystemHow It Connects
Movement SystemProvides distance/angle for scoring context
Combat RolesRole changes trigger automatic ActionSet swaps
Threat DetectionThreat level feeds into FDecisionContext
VitalsHealth and stamina in the scoring context come from the pawn's vitals; Vital Scorer and Vital Gate cost or favor actions by any pool
MultiplayerAction state replicates to clients via SECActionSetComponent
Custom character classes: ActionEvaluationComponent resolves the AbilitySystemComponent from the possessed pawn via IAbilitySystemInterface on possession. Pawns that do not implement this interface cause ability-based actions to silently fail. See Getting Started for setup details.

Key API

AdvancedComponent and delegate reference
ComponentLocationRole
ActionEvaluationComponentControllerScoring, evaluation, execution
SECActionSetComponentPawnResolution, replication, weapon/override management
SECCombatControllerComponentControllerOrchestrates sync on role changes
ActionEvaluationComponent (Controller)
  • EvaluateBestAction(Context, Time, OutChosen): Run the scoring pipeline.
  • ExecuteAction(ActionId): Force-execute a specific action.
  • ExecuteActionWithContext(Id, Context): Execute with custom data (Target, etc.).
  • SetGlobalMultiplier(Multiplier): Runtime buff/nerf for every action (0 blocks all selection).
  • SetActionOverride(ActionId, Multiplier): Per-action multiplier, folded with the global value.
  • CanExecuteAction() / ModifyActionScore(): Override hooks (see above).
SECActionSetComponent (Pawn)
  • SetProvidedActionSet(ActionSet): Set pushed in above Config, cleared with null.
  • SetRuntimeOverride(ActionSet) / ClearRuntimeOverride(): Boss phase override.
  • GrantAction() / RevokeAction(): Runtime action management.
  • OnActionExecutionStarted / OnActionExecutionCompleted: Replicated delegates for client UI/FX.
  • OnActionSetChanged: Fires when the active ActionSet changes (replicated).
  • OnActionCooldownStarted(ActionId, Duration) / OnActionCooldownExpired(ActionId): Cooldown lifecycle delegates (replicated).
  • GetRemainingCooldown(ActionId) / IsActionOnCooldown(ActionId) / GetAllActiveCooldowns(): Query current cooldown state.
AdvancedUpgrading from an older version
ActionSet assets migrate once on load; behavior is unchanged, and re-saving the asset persists the migration.
  • Execution methods. Each action's execution mode becomes an Execution Method carrying the same ability or trees and the same timeout. An ability action lands on Gameplay Ability, on Gameplay Ability By Tag when it named a tag and no class, or on Gameplay Ability (Fire And Forget) when it was set not to wait. A Behavior Tree action becomes Behavior Tree Sequence, and the ability fields it carried become an Ability Payload on that method.
  • Ability end tags. SEC watches the ability system for the ability it started, so the end tag fields are removed along with the SEC_AbilityEndTag blackboard key. An ability that reaches End Ability needs no other wiring. One that never ends is caught by Ability Timeout, or by a 30 second safety when that is 0.
  • Scorers and gates (from v1.6). Each action's old distance and angle evaluations become a Distance Scorer and Angle Scorer, a non-default health or speed range becomes a Health or Speed Scorer, and a stamina cost above 0 becomes a Stamina Gate. New actions you author ship with no scorers, so they are distance-agnostic until you add a Distance Scorer.
  • Display names. GetDisplayName() replaces the old ScorerName / GateName text fields, which are removed. Any label typed into them on a pre-existing asset is lost on load; re-label through a GetDisplayName() override.