Integrating StateTree and Blackboard
Stack decides which AI layer currently owns control, while Queue executes a task plan that has already been chosen. They are not interchangeable. This guide makes an AIController run Unit behavior first, then be overridden by Squad and Command layers before falling back, while also verifying the exact completion result of a formal Queue Dispatch.
1. Configure the Layer Hierarchy and Stack
In Project Settings, configure StateTreeLayerHierarchy from low to high with project layers such as Default, Unit, and Squad. Command is a reserved highest layer and should not be treated as a normal asset layer that competes manually. Add UGAIS_StateTreeStackComponent to the AIController, not the Pawn.
Assign a base StateTree to the Unit layer. After calling SetLayerStateTree, inspect RequestedLayer first: it represents the target selected by policy. Then wait for AppliedLayer: it represents the StateTree actually installed. A temporary difference between the two is normal during a safe transition. Do not assume behavior has changed merely because Requested changed.
After clearing a higher Squad/Unit layer, Applied should fall back to the next valid lower layer. When replacing the StateTree within the same layer, listen to OnActiveLayerStateTreeReplaced rather than treating it as a layer-change event.
2. Integrate the Command StateTree and Blackboard
Commands using UGAIS_CommandExecutionDefinition_StateTree request the Stack's Command route. Stack writes the accepted command's Definition, variant, target, range, and executing Pawn into the Blackboard Keys configured by the project. StateTree consumes only this validated context and reports a result when it terminates.
Keep the default Blackboard Keys in UGAIS_DeveloperSettings during initial integration. If the project renames them, update Settings, the Blackboard asset, and every StateTree that reads them. Changing only one side produces the symptom "the command is in the Command layer, but the Tree cannot read its data."
3. Queue: Use Dispatch Only for Plans That Are Already Decided
Place the Queue component on the AIController as well. Dispatch replaces the current plan and returns a formal Dispatch Handle. When waiting for completion, save and track that exact Handle. Enqueue extends an active Dispatch and delays its completion; without an active Dispatch, it is anonymous work and provides no completion contract that can be awaited.
For example, "move to cover → wait → throw Ability" can be one Dispatch. Use Enqueue to append a finishing animation. Use a new Dispatch to replace it with a different complete plan. Do not use Queue to decide which AI layer has priority; Stack owns priority.
Validation
Check | Expected result |
|---|---|
Unit → Squad override | Requested changes first; Applied changes after the safe transition completes. |
Command start/end | The Command-layer route is installed, then precisely removed and falls back when the command ends. |
Dispatch completion | Read result/reason only for the saved Handle; an old Handle cannot complete a new plan. |
Queue cleared by a layer transition | This is a protection mechanism, not Queue deciding hierarchy. |
For temporary runtime diagnostics, add Task: Debug Overlay Text and enable gais.DebugOverlay.Enable and gais.DebugOverlay.StateTree to draw current-state text above the Pawn. It is for local diagnostics only and does not participate in StateTree completion. See StateTree Debug Overlay.
For detailed responsibilities, see StateTree Orchestration System. For fields, see StateTree Queue and Orchestration Parameters.
