UE State Trees
Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
State Tree is a data-driven hierarchical state machine authored as a UStateTree data asset and executed from C++ through an execution context. Runtime types live in the StateTreeModule (plugin StateTree); actor-facing components and schemas live in GameplayStateTreeModule (plugin GameplayStateTree). Mass-entity behaviours add MassAIBehavior (plugin MassAI, Experimental in 5.8) plus MassEntity, MassCore and MassSignals. Add the modules you use to PublicDependencyModuleNames in your .Build.cs.
Context
Read .agents/ue-project-context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
Architecture
Nodes are USTRUCTs, not UObjects, and every node virtual is const. Mutable per-instance state lives in a separate instance-data struct owned by FStateTreeInstanceData, which is what persists across frames. The execution context is a short-lived view constructed over that instance data.
Tick can be split when transitions must be evaluated after other systems have run: call TickUpdateTasks(DeltaTime) first and TickTriggerTransitions() afterwards.
Execution Contexts
5.8 splits the context by capability. Pick the narrowest one that compiles.
FStateTreeMinimalExecutionContext derives from FStateTreeReadOnlyExecutionContext, and FStateTreeExecutionContext from FStateTreeMinimalExecutionContext, so a node method taking the full context can call anything above it.
Async Completion
Capture FStateTreeWeakExecutionContext (constructed from the live context) and finish the task when the async work returns. See state-tree-patterns.md [blocked] for the full latent-task template.
Inside a tick, a task finishes itself with Context.FinishTask(*this, EStateTreeFinishTaskType::Succeeded) or by returning a completion status from Tick.
Schemas
A schema declares which node structs, which classes and which context data an asset may use. IsStructAllowed is what makes your nodes appear in the editor, so derive custom nodes from the *CommonBase structs the stock schemas accept: FStateTreeTaskCommonBase, FStateTreeConditionCommonBase, FStateTreeEvaluatorCommonBase, FStateTreeConsiderationCommonBase, FStateTreePropertyFunctionCommonBase.
AllowEnterConditions, AllowUtilityConsiderations, AllowEvaluators, AllowMultipleTasks, AllowGlobalParameters, AllowTasksCompletion and AllowQueuedCompilation are declared inside #if WITH_EDITOR (StateTreeSchema.h:96-138) — they only drive the editor/compiler, so your overrides must be guarded the same way or game builds fail with "does not override". IsStructAllowed, IsClassAllowed, IsExternalItemAllowed, IsScheduledTickAllowed, IsStateSelectionAllowed, IsStateTypeAllowed and GetContextDataDescs are runtime virtuals (StateTreeSchema.h:36-79).
Tasks
Every task overrides the virtuals it needs and GetInstanceDataType(). The using FInstanceDataType = …; alias alone allocates nothing; FStateTreeNodeBase::GetInstanceDataType() returns nullptr by default (StateTreeNodeBase.h:94) and the compiler reserves no storage, so Context.GetInstanceData(*this) then hits check(Memory != nullptr) (PropertyBindingDataView.h:116).
Editable parameters usually live on the instance data so they can be bound in the editor; properties placed on the node struct itself are shared by every instance and cannot be bound.
Behavioural flags
Set these in the task constructor.
TransitionHandlingPriority (EStateTreeTransitionPriority) orders TriggerTransitions across tasks of one state.
Conditions
FStateTreeConditionBase::TestCondition(FStateTreeExecutionContext& Context) const returns bool and defaults to false. It must be pure: the selection pass may call it several times per frame.
Conditions also receive EnterState, ExitState and StateCompleted (all no-ops by default) so they can cache work across the state's lifetime.
Stock conditions: FStateTreeCompareIntCondition, FStateTreeCompareFloatCondition, FStateTreeCompareBoolCondition, FStateTreeCompareEnumCondition, FStateTreeCompareNameCondition, FStateTreeCompareDistanceCondition, FStateTreeRandomCondition (Conditions/StateTreeCommonConditions.h), FStateTreeObjectIsValidCondition (Conditions/StateTreeObjectConditions.h) and the gameplay-tag family in Conditions/StateTreeGameplayTagConditions.h. The comparison ones take UE::StateTree::EComparisonOperator.
Considerations
Considerations score a state so a parent can choose between children. The API is marked experimental in the header, so keep custom considerations small.
GetScore is protected; the framework calls the public GetNormalizedScore. Operand and DeltaIndent combine sibling considerations (And = min, Or = max, Multiply = product). Scores only matter for the two utility selection behaviours, and the schema must return true from AllowUtilityConsiderations().
Evaluators
Evaluators are global (not per-state) and tick before transitions and task ticks. Use them for data many nodes read; use external data for stable references.
DeltaTime is 0 when the evaluator is ticked during state pre-selection. Evaluators need GetInstanceDataType() exactly like tasks — the full template is in state-tree-patterns.md [blocked].
Transitions
EStateTreeTransitionTrigger is a bitmask (ENUM_CLASS_FLAGS).
EStateTreeTransitionPriority: Low, Normal, Medium, High, Critical. The first triggered transition of the highest priority wins. Transition types (EStateTreeTransitionType): None, Succeeded, Failed, GotoState, Parent, NextState, NextSelectableState, NextParent, NextSelectableParent (StateTreeTypes.h:76). Per-transition flags bTransitionEnabled and bConsumeEventOnSelect both default to true.
From C++, request a transition with Context.RequestTransition(TargetState, Priority, Fallback) where Fallback is an EStateTreeSelectionFallback.
Delegates
Delegates replace polling when an external system can tell the tree exactly when to react. One node publishes an FStateTreeDelegateDispatcher on its instance data, another publishes an FStateTreeDelegateListener, and the editor connects the two.
A transition with the OnDelegate trigger fires when the bound dispatcher is broadcast, evaluated with the rest of the transitions.
State Types and Selection
EStateTreeStateType: State, Group, Linked, LinkedAsset, Subtree. LinkedAsset states are the sharing mechanism — override them per instance with FStateTreeReferenceOverrides.
EStateTreeStateSelectionBehavior:
FStateTreeActiveStates::MaxStates = 8 caps the depth of the active state path. Flatten deeper designs with subtrees or linked assets.
Events
Events are gameplay-tag messages with an optional payload: FStateTreeEvent { FGameplayTag Tag; FInstancedStruct Payload; FName Origin; }.
FStateTreeEventQueue::MaxActiveEvents = 64 per instance. Iterate with Context.ForEachEvent(Lambda), whose lambda returns EStateTreeLoopEvents (Next, Break, Consume — StateTreeEvents.h:35) and remove one with Context.ConsumeEvent(SharedEvent) (returns void). Context.HasEventToProcess(Tag) is a cheap existence check. For where gameplay tags are declared, see ue-gameplay-tags-messaging.
External Data
External data gives a node a typed reference to an object or struct supplied by the schema's owner — subsystems, the owning actor, components.
Link returns bool ([[nodiscard]] on the base, StateTreeNodeBase.h:116); return true on success, false fails linking.
UStateTreeComponentSchema::IsExternalItemAllowed accepts AActor, UActorComponent and UWorldSubsystem subclasses only. The owning actor is published separately as context data named Actor (and AIController for the AI schema); the idiomatic way to reach it is an instance-data property the editor binds automatically:
There is no FStateTreeActorContext type in the engine — use the above.
Component and AI Setup
UStateTreeComponent : UBrainComponent, IGameplayTaskOwnerInterface, IStateTreeSchemaProvider runs one tree on an actor. UStateTreeAIComponent derives from it and returns UStateTreeAIComponentSchema, which guarantees an AAIController context value — use it on AI controllers.
bStartLogicAutomatically is protected; write it through SetStartLogicAutomatically(const bool). Public surface: SetStateTree, SetStateTreeReference, AddLinkedStateTreeOverrides(FGameplayTag, FStateTreeReference), RemoveLinkedStateTreeOverrides(FGameplayTag), SendStateTreeEvent, GetStateTreeRunStatus, and the BlueprintAssignable OnStateTreeRunStatusChanged. StartLogic, StopLogic, PauseLogic and ResumeLogic come from UBrainComponent.
Subclass and override the protected SetContextRequirements(FStateTreeExecutionContext& Context, bool bLogErrors) / CollectExternalData(const FStateTreeExecutionContext& Context, const UStateTree* StateTree, TArrayView<const FStateTreeExternalDataDesc> Descs, TArrayView<FStateTreeDataView> OutDataViews) const to publish extra context or external data.
FStateTreeReference
GetParameters() returns const FInstancedPropertyBag& — mutating needs GetMutableParameters().
Scheduled Tick
A tree whose active tasks all opt out of ticking can sleep instead of running every frame. FStateTreeScheduledTick::MakeSleep(), MakeNextFrame(), MakeEveryFrames() and MakeCustomTickRate(DeltaTime) describe the desired cadence; FStateTreeMinimalExecutionContext::AddScheduledTickRequest / UpdateScheduledTickRequest / RemoveScheduledTickRequest manage a request, and ScheduleNextTick() wakes the tree. UStateTreeComponent implements this through FStateTreeComponentExecutionExtension, gated by UStateTreeComponentSchema::IsScheduledTickAllowed() and the StateTree.Component.DefaultScheduledTickAllowed console variable. A task that must not be counted sets bConsideredForScheduling = false.
For per-instance descriptions and custom tick scheduling on your own runner, implement FStateTreeExecutionExtension (GetInstanceDescription, ScheduleNextTick, OnLinkedStateTreeOverridesSet, OnBeginApplyTransition) and pass it in FStartParameters::ExecutionExtension.
Mass Entity Integration
Mass behaviours use UMassStateTreeSchema and the FMassStateTreeTaskBase, FMassStateTreeConditionBase and FMassStateTreeEvaluatorBase node types, which add GetDependencies(UE::MassBehavior::FStateTreeDependencyBuilder&) const so the dynamically created UMassStateTreeProcessor (a UMassSignalProcessorBase) can build the right fragment query. Full setup, fragment table, signal names and processor flow are in state-tree-mass-integration.md [blocked]. For Mass architecture itself, see ue-mass-entity.
Deprecated — do not use
Common Mistakes
Omitting GetInstanceDataType(): the single most common State Tree bug. using FInstanceDataType = …; documents the type; only the override registers storage.
Storing the execution context: it is a per-tick view over FStateTreeInstanceData. Keep the instance data as a UPROPERTY(Transient) on the owner and rebuild the context each tick, or capture FStateTreeWeakExecutionContext if you need it later.
Mutating the node struct: every node virtual is const, so Timer += DeltaTime; on a member will not compile. Write to Context.GetInstanceData(*this).
Deriving from FStateTreeTaskBase directly: stock schemas only allow FStateTreeTaskCommonBase and siblings, so the node never appears in the editor picker. Derive from the *CommonBase struct (or the Mass/AI base) that your schema accepts.
Not guarding schema Allow* overrides with #if WITH_EDITOR: the base declares them editor-only (StateTreeSchema.h:96), so an unguarded override compiles in the editor and fails in Game/Shipping targets.
Side effects in TestCondition: selection may test the same condition several times in a frame. Keep it pure; cache in the condition's EnterState instead.
Leaving delegates bound: BindDelegate in EnterState requires UnbindDelegate in ExitState, otherwise the listener fires against a state that is no longer active.
Exceeding MaxStates: the active state path is capped at 8. Deeper hierarchies fail selection rather than warning loudly.
Assuming Tick runs: with bShouldCallTick = false, or when a scheduled tick puts the tree to sleep, tasks do not tick and bound properties are not copied. Drive those tasks from events or delegates.
Related Skills
ue-ai-navigation— behaviour trees, perception, EQS, navigation and Smart Objectsue-mass-entity— Mass processors, fragments, traits, entity queriesue-gameplay-abilities— abilities and effects that drive or react to state changesue-gameplay-framework— controllers, pawns and game-mode lifecycle around the treeue-actor-component-architecture— component ownership, ticking and replication setupue-cpp-foundations—USTRUCTrules, delegates, subsystem accessue-gameplay-tags-messaging— declaring gameplay tags used by State Tree events and transitionsue-gameplay-cameras— spring arms, view targets, camera modifiers, shakes and the Gameplay Camera System


