Configuring a Tactical Assignment Plan

GAIS_Cover
YuewuDev

Author

YuewuDev

Created: Oct 12, 2026Updated: Oct 12, 2026

Table of contents

Configuring a Tactical Assignment Plan

This guide builds a minimal closed loop: a StateTree Task gathers candidate Units and targets from fixed-array Sources, each Unit resolves GAIS.CommandIntent.Engage into a concrete Command, and the system selects and submits at least one assignment. When complete, the Task's AssignmentCount is greater than zero and the candidate Unit's CommandSystem shows the resolved concrete command.

The first pass uses fixed arrays and intentionally excludes EQS, squad adapters, and custom Allocators. This keeps input validity, command executability, and capacity constraints independently testable.

Prerequisites

  • A StateTree driven by an AAIController.
  • At least one candidate Pawn/Character with UGAIS_CommandSystemComponent on the Pawn and the ability to execute the target Command.
  • UGAIS_UnitComponent on the candidate Actor, or an implementation of IGAIS_CommandIntentResolver on the Actor or one of its components.
  • A Command Definition that can already be issued manually and accepts the test target.
  • A test target Actor and an existing GAIS.CommandIntent.* tag in the project.

Tactical Assignment does not bypass CanObeyCommand or IsValidTarget. Confirm that the command works when issued manually first; otherwise an automatic-assignment failure cannot be isolated to either command configuration or planning.

The Task starts on Authority and derives ContextPawn from the AIController's current possession. An invalid Controller, missing Authority, changed Pawn possession, a Plan that cannot be resolved uniquely, or a Plan with no Batch causes the Task to return Failed immediately.

1. Configure the Unit's Intent Mapping

Add an entry to UGAIS_UnitComponent.CommandIntentMappings:

Field

Example

Requirement

IntentTag

GAIS.CommandIntent.Engage

Must exactly match the Batch.

Command.Definition

The project's attack or support command

Must be a valid Definition executable by this Unit.

Command.Index

Default value or a valid variant index

Required only when selecting a specific MultiVariant Command variant.

The default UnitComponent resolves intents from this table. Implement a custom Resolver only when gameplay must choose commands dynamically from equipment, state, or target source. Do not add that complexity to a Source or Allocator during minimal validation.

2. Decide Between a Data Asset and an Inline Plan

Both entry points use the same UGAIS_TacticalAssignmentPlan type and produce the same runtime behavior. Choose based on reuse and ownership.

Situation

Choose

Reason

Multiple squad StateTrees, states, or levels share the same Batch rules

Plan Data Asset

Centralized maintenance; each Task can still bind different Sources.

Designers need to review, validate, and tune the Combat Plan independently

Plan Data Asset

Clear asset boundary and shared updates.

One state needs a quick, single-Batch validation

Inline Plan

No additional asset; configuration stays beside the call site.

The rule is valid only in that state and reuse would be misleading

Inline Plan

Keeps the local rule with its StateTree branch.

Do not fill both Plan and Inline Plan, and do not leave both empty. The Task enters Failed when it cannot resolve exactly one Plan. Neither form stores Sources: Sources always belong to the Task's AssigneeSources / TargetSources, allowing one shared Data Asset to run against different squads.

The following example uses a Data Asset. When using Inline Plan, configure the same Batch fields under the Task's Inline Plan.

3. Create the Plan

Create a UGAIS_TacticalAssignmentPlan Data Asset and start with one Batch:

Field

Minimal setting

Batches

One Batch.

DebugName

For example EngageTargets, to make diagnostics easier.

IntentTag

Same tag as the Unit mapping.

AssigneeFilters, TargetFilters

Empty.

ScoreAdjustment

Default multiplier 1, bias 0.

Allocator

Empty, using the default capacity-aware greedy allocator.

ReevaluationInterval

A positive finite value; the default is suitable for first integration.

The Plan needs at least one Batch, every Batch needs a valid IntentTag, and the reevaluation interval must be positive and finite. These are directly validated Data Asset settings.

4. Configure Top-Level Sources on the StateTree Task

Add Task: Run Tactical Assignment Plan (FGAIS_STT_RunTacticalAssignmentPlan) to the target StateTree state. On the Task:

  1. Bind AIController to the current AIController context.
  2. Set exactly one of Plan and Inline Plan; this example assigns the Data Asset to Plan.
  3. Add Actor Array to AssigneeSources and provide the test Unit Actor.
  4. Add Actor Targets to TargetSources and provide the test target Actor. Set SourceTag when source identity must be distinguished.

Sources belong to the Task, not to Batches. Every Source fills a temporary array independently. The Task merges valid outputs into candidate streams, which the Plan's ordered Batches then consume.

plaintext
1StateTree Task
2 ├─ Plan or Inline Plan (exactly one)
3 ├─ AssigneeSources: Actor Array
4 └─ TargetSources: Actor Targets
5 ↓
6Plan Batch: IntentTag, Filters, ScoreAdjustment, Allocator

Using Task Inputs and Outputs in StateTree Branches

Field

Configuration

StateTree use

AIController

Bind current AIController context.

Determines Authority, Context Pawn, and unique Session owner.

Plan / Inline Plan

Choose exactly one.

Supplies Batches and reevaluation interval.

AssigneeSources

Configure inline or prepare runtime Sources through task data.

Gathers all Actors that may receive Commands.

TargetSources

Configure inline or prepare runtime Sources through task data.

Gathers Actor, Location, or Actor+Location targets.

ReplanCount

Read-only output.

Shows how many evaluations the Session has completed.

LastUpdateResult

Read-only output.

Distinguishes Completed, Deferred, and Failed.

AssignmentCount

Read-only output.

Shows how many assignments the latest completed evaluation retains.

OnAssignmentsAvailable

Edge event.

Drives a transition on the first assignment or a zero-to-nonzero recovery.

OnAssignmentsUnavailable

Edge event.

Drives fallback on the first completed zero result or a nonzero-to-zero transition.

After entering the state, the Task remains Running. Its StateTree Scheduled Tick drives timed reevaluation. On state exit, the Task cancels scheduling and stops the Session; matching Commands and reservations are cleaned up.

5. Enter the State and Validate

The Task evaluates immediately on state entry. Observe in this order:

  1. LastUpdateResult is Completed. A brief world-update conflict may report Deferred and retry later.
  2. ReplanCount increases after a completed evaluation, and AssignmentCount is greater than zero.
  3. The candidate Unit's CommandSystem receives the concrete Command resolved from IntentTag.
  4. In GameplayDebugger, Actor pool, Target pool, Candidates, Selected, and final Outcome match expectations.

OnAssignmentsAvailable fires when assignments first become available and whenever the state recovers from zero assignments to a nonzero count. It does not repeatedly broadcast while assignments remain available. When a world-update guard conflict produces Deferred, the Task remains running and retries later.

6. Use SourceTag to Mark Target Origin

When one Task gathers multiple target categories, use child tags under GAIS.TacticalAssignment.TargetSource.*. For example:

Target Source

SourceTag

Output

EQS Actor Targets

...Perception.Enemy

Enemy Actors found by perception or spatial queries.

Target Data Array / project Source

...Objective.DefensePoint

Defensive positions supplied by the objective system.

Project Source

...Player.Ping

A temporary player-marked target.

SourceTag is the Target Source's default origin tag and is written only when target data has no tag. An item in Target Data Array that already carries a tag keeps its own tag.

Then add Target Source Tag to the Batch's TargetFilters:

  • Attack Batch: allow ...Perception.Enemy and ...Player.Ping in AllowedSourceTags.
  • Hold Batch: allow only ...Objective.DefensePoint.
  • Put permanently forbidden origins in BlockedSourceTags. Blocked is evaluated before Allowed.

This does not create a separate capacity reservation. The same enemy Actor entering once as perception and once as a player ping still shares one world-capacity bucket based on Actor identity.

7. Use Filters So One Source Set Can Serve Multiple Batches

Sources should represent stable data origins; Batch Filters should represent current tactical rules. For a combat squad:

  1. Add one All Squad Units Assignee Source and explicitly bind the current Squad Actor.
  2. Add an enemy EQS Source and a defense-position Source to TargetSources, with different SourceTag values.
  3. Add ordered Batches:
    • EngagePriority: Assignee Filter selects combat roles; Target Filters require Hostile, Has Actor, and enemy origin.
    • HoldPoints: selects guards not claimed by the prior Batch; Target Filters require No Actor and defense-position origin.
    • SupportRemainder: selects healer/support roles from remaining members; Target Filters accept friendly Actor targets.

Every Filter in an array must pass. Assignee Filters prune unsuitable Units before intent resolution. Target Filters prune unsuitable targets before command IsValidTarget. CommandDefinition remains authoritative for final executor and target legality.

Use GameplayDebugger's Actors before -> after and Targets before -> after per Batch:

  • before is already 0: inspect the Source.
  • before has values but after is 0: inspect that Batch's Filters.
  • after has values but result is NoResolvedCommand: inspect Intent mappings.
  • Candidates has values but Selected is 0: inspect capacity and Allocator behavior.

8. Handle Empty Source Output Correctly

The current Source API writes to output arrays and has no runtime success-state return. If EQS produces no result for the current evaluation, a project query temporarily returns an empty set, or a Source output is invalid, that Source contributes zero candidates for the evaluation. Other Sources still contribute, and the evaluation completes normally.

An empty Source output therefore participates in a normal completed evaluation. If candidates disappear from the merged stream, the system reconciles previous assignments and moves no-longer-valid records into Stale cleanup. Deferred specifically indicates a world-update conflict or synchronous reentry; tracked assignments and reservations remain unchanged in that case.

Configuration errors should be fixed rather than awaited: a null Source object, EQS without QueryTemplate, or missing required RoleTag / SquadActor fails validation.

9. Add Real Gameplay Rules One Layer at a Time

After the minimal loop works:

  1. Replace fixed arrays with squad, EQS, or project-container Sources.
  2. Add Assignee Filters and verify Actor-pool before/after counts.
  3. Add Target Filters and verify SourceTag, team attitude, and target shape.
  4. Tune ScoreAdjustment and observe whether candidate order matches design.
  5. Create a custom Allocator only when the default is insufficient. It receives already validated candidates and a world-capacity snapshot; it should not rediscover targets or repeat command validation.

10. Organize Idle / Combat Squad Branches

Place the Task in the StateTree state that owns the tactical semantics. Idle and Combat branches commonly hold separate Tasks:

State

Top-level Sources

Plan Batch

Result

Idle

All Squad Units; targets omitted or formation/job locations supplied.

Inline Plan: Follow or Hold Intent.

Local rules stay with Idle; members follow, occupy positions, or guard.

Combat

All Squad Units; enemy EQS, defense positions, and friendly Target Sources.

Data Asset: Engage, then HoldPosition, then Support.

Reusable combat rules assign different members to attack, hold, or support.

On entering Combat, the Task creates a Session and evaluates immediately. It reevaluates at ReevaluationInterval while the state remains active and stops the Session on exit. Different mappings for the same Intent create role-specific behavior: a front-line Unit resolves Engage to melee, a ranged Unit resolves it to shooting, and a healer participates only in Support. Intent Resolver is the seam where a Unit turns tactical semantics into an executable command.

Complete Six-Member Squad Example

Assume two melee units, one ranged unit, one healer, and two guards.

Assignee Sources

  • All Squad Units: SquadOverride points to the current Squad Actor and returns six members. This Source requires an explicit Squad Actor.
  • If Context Pawn itself has SquadComponent, Squad Units By Role may also be used. With no SquadOverride, it attempts Context Pawn; RoleTag must be valid and uses exact matching.

Target Sources

  • EQS Actor Targets: queries current enemies, with SourceTag = GAIS.TacticalAssignment.TargetSource.Perception.Enemy.
  • EQS Location Targets: queries defensible positions, with SourceTag = GAIS.TacticalAssignment.TargetSource.Defense.Position.
  • All Squad Units: exposes squad members as friendly targets for the healing Batch.

Plan Batches

  1. AttackPriority
    • IntentTag = Engage
    • Assignee Filter: Role Query accepts melee and ranged roles.
    • Target Filters: Team Attitude = Hostile, Has Actor, SourceTag = Enemy.
    • Result: three combat members receive enemy targets first.
  2. HealAllies
    • IntentTag = Support
    • Assignee Filter: Role Query accepts only the healer.
    • Target Filters: Has Actor, ally tags or Friendly attitude.
    • Result: the healer receives a friendly target from members not claimed earlier.
  3. HoldDefensePoints
    • IntentTag = HoldPosition
    • Assignee Filter: Role Query accepts guards.
    • Target Filters: No Actor, SourceTag = Defense.Position.
    • Result: two guards compete for location targets, usually with capacity one per location.

Batch order claims Units. If the healer also passes the Attack Assignee Filter, it is claimed by the first Batch and cannot be used by HealAllies. Role Filters and Batch order jointly decide who acts first. Target capacity decides how many Units can share one target.

Idle may use a short Inline Plan with one FollowSquad Batch. When Follow uses a None or Passive TargetType, TargetSources may remain empty. Entering Combat stops the Idle Session, creates a Combat Session, and issues combat Commands.

11. Validate Real Assignments with the Panel and Logs

Run PIE, open GameplayDebugger, enable the GenericAISystem category, select a Pawn controlled by AIController, and press Shift+7 to switch to Tactical Assignment. Inspect Source counts and Actor/Target pools first, then each Batch's filter before/after counts, Candidate/Selected values, external target usage, and assignment records. This identifies whether failure occurs during gathering, intent resolution, command validation, capacity, or submission more reliably than watching whether the Unit moves.

For Session start/stop, replanning, and submission diagnostics, temporarily run Log LogGAIS_Tactical Verbose. GameplayDebugger shows the current Session/Batch snapshot. Per-Source Actor/Target details are currently emitted through Visual Logger UE_VLOG, not expanded item by item in ordinary text logs. Restore normal logging with Log LogGAIS_Tactical Log. To persist lifecycle text logging across launches, set LogGAIS_Tactical=Verbose under project [Core.Log].

Common Failures

Symptom

Check first

Task immediately enters Failed

Is AIController valid; is exactly one of Plan/Inline Plan set; are deterministic Plan/Source settings complete?

NoResolvedCommand

Does Batch IntentTag match the Unit mapping, and are Resolver and Command Definition valid?

CannotObeyCommand

Executor requirements, resources, and project state of the concrete Command.

NonCancelableCommand

The resolved Command must use Cancelable to participate in continuous reassignment.

InvalidTarget

Does Source output match Command TargetType, and are Target Filters too strict?

Candidates has values but Selected is zero

World-capacity snapshot, existing claims, scoring, and Allocator selection.

One Source has no output

Inspect that Source's inputs and whether other Sources still contribute; evaluation continues with the actual merged result.

None / Passive Commands do not require a Target Source and use local empty target data. Do not add fake targets to shared TargetSources, because other Batches in the same Task may require a real target stream.

Further Reading