claude-code-arcane 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +104 -55
- package/agents/career/career-strategist.md +88 -0
- package/agents/career/cv-reviewer.md +81 -0
- package/agents/career/hiring-manager.md +68 -0
- package/agents/career/mock-interviewer.md +76 -0
- package/agents/freelance/client-screener.md +84 -0
- package/agents/freelance/discovery-call.md +65 -0
- package/agents/freelance/pipeline-strategist.md +99 -0
- package/agents/freelance/proposal-reviewer.md +82 -0
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +57 -13
- package/docs/RELEASE-SETUP.md +1 -1
- package/docs/SKILLS-CATALOG.md +67 -4
- package/docs/USER-GUIDE.md +77 -72
- package/docs/agent-hierarchy.md +21 -1
- package/docs/presentations/build_arcane_deck.py +2 -2
- package/docs/presentations/build_arcane_deck_12.py +2 -2
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -2
- package/profiles/freelance.yaml +43 -0
- package/profiles/job-hunt.yaml +5 -2
- package/profiles/unreal-dev.yaml +97 -0
- package/rules/drafter-reviewer.md +16 -3
- package/rules/freelance-guardrails.md +53 -0
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/career-registry/SKILL.md +95 -0
- package/skills/career-registry/scripts/career_registry.py +488 -0
- package/skills/client-screen/SKILL.md +83 -0
- package/skills/client-screen/references/red-flags.md +95 -0
- package/skills/cover-letter/SKILL.md +4 -3
- package/skills/cv-tailor/SKILL.md +11 -2
- package/skills/freelance-deliver/SKILL.md +90 -0
- package/skills/freelance-hunt/SKILL.md +126 -0
- package/skills/freelance-hunt/references/templates/Connects.md +39 -0
- package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
- package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
- package/skills/freelance-kickoff/SKILL.md +94 -0
- package/skills/freelance-pipeline/SKILL.md +109 -0
- package/skills/freelance-pipeline/scripts/import_history.py +425 -0
- package/skills/freelance-profile/SKILL.md +93 -0
- package/skills/freelance-proposal/SKILL.md +112 -0
- package/skills/freelance-scan/SKILL.md +196 -0
- package/skills/freelance-scan/references/dedup.md +35 -0
- package/skills/freelance-scan/references/platforms.md +167 -0
- package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/interview-prep/SKILL.md +11 -3
- package/skills/job-aplicar/SKILL.md +5 -1
- package/skills/job-hunt/SKILL.md +17 -0
- package/skills/job-outcome/SKILL.md +15 -1
- package/skills/job-upskill/SKILL.md +10 -2
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- package/templates/gamedev/unreal-project-context.md +107 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# State Tree Patterns
|
|
2
|
+
|
|
3
|
+
Complete code templates for custom State Tree nodes. All signatures are source-verified from UE headers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Custom Task Template
|
|
8
|
+
|
|
9
|
+
```cpp
|
|
10
|
+
// MyTimedTask.h
|
|
11
|
+
#pragma once
|
|
12
|
+
#include "StateTreeTaskBase.h"
|
|
13
|
+
#include "StateTreeExecutionContext.h"
|
|
14
|
+
#include "StateTreeLinker.h"
|
|
15
|
+
#include "MyTimedTask.generated.h"
|
|
16
|
+
|
|
17
|
+
USTRUCT()
|
|
18
|
+
struct FMyTimedTaskInstanceData
|
|
19
|
+
{
|
|
20
|
+
GENERATED_BODY()
|
|
21
|
+
|
|
22
|
+
UPROPERTY()
|
|
23
|
+
float ElapsedTime = 0.f;
|
|
24
|
+
|
|
25
|
+
UPROPERTY()
|
|
26
|
+
bool bHasTriggered = false;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
USTRUCT(meta=(DisplayName="My Timed Task"))
|
|
30
|
+
struct FMyTimedTask : public FStateTreeTaskBase
|
|
31
|
+
{
|
|
32
|
+
GENERATED_BODY()
|
|
33
|
+
|
|
34
|
+
// Required — framework uses this to allocate per-instance storage
|
|
35
|
+
typedef FMyTimedTaskInstanceData FInstanceDataType;
|
|
36
|
+
|
|
37
|
+
// Configuration (set in editor, shared across all instances)
|
|
38
|
+
UPROPERTY(EditAnywhere, Category = "Parameter")
|
|
39
|
+
float TriggerDelay = 3.0f;
|
|
40
|
+
|
|
41
|
+
UPROPERTY(EditAnywhere, Category = "Parameter")
|
|
42
|
+
FGameplayTag EventToSend;
|
|
43
|
+
|
|
44
|
+
virtual EStateTreeRunStatus EnterState(FStateTreeExecutionContext& Context,
|
|
45
|
+
const FStateTreeTransitionResult& Transition) const override
|
|
46
|
+
{
|
|
47
|
+
FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
48
|
+
Data.ElapsedTime = 0.f;
|
|
49
|
+
Data.bHasTriggered = false;
|
|
50
|
+
return EStateTreeRunStatus::Running;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
virtual EStateTreeRunStatus Tick(FStateTreeExecutionContext& Context,
|
|
54
|
+
float DeltaTime) const override
|
|
55
|
+
{
|
|
56
|
+
FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
57
|
+
Data.ElapsedTime += DeltaTime;
|
|
58
|
+
|
|
59
|
+
if (!Data.bHasTriggered && Data.ElapsedTime >= TriggerDelay)
|
|
60
|
+
{
|
|
61
|
+
Data.bHasTriggered = true;
|
|
62
|
+
Context.SendEvent(EventToSend, FConstStructView(), TEXT("MyTimedTask"));
|
|
63
|
+
return EStateTreeRunStatus::Succeeded;
|
|
64
|
+
}
|
|
65
|
+
return EStateTreeRunStatus::Running;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
virtual void ExitState(FStateTreeExecutionContext& Context,
|
|
69
|
+
const FStateTreeTransitionResult& Transition) const override
|
|
70
|
+
{
|
|
71
|
+
// Cleanup if needed (stop audio, cancel async ops, etc.)
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Task with External Data
|
|
77
|
+
|
|
78
|
+
```cpp
|
|
79
|
+
USTRUCT(meta=(DisplayName="Move To Target"))
|
|
80
|
+
struct FMoveToTargetTask : public FStateTreeTaskBase
|
|
81
|
+
{
|
|
82
|
+
GENERATED_BODY()
|
|
83
|
+
typedef FMoveToTargetInstanceData FInstanceDataType;
|
|
84
|
+
|
|
85
|
+
// External data — linked at setup, accessed at runtime
|
|
86
|
+
TStateTreeExternalDataHandle<FStateTreeActorContext,
|
|
87
|
+
EStateTreeExternalDataRequirement::Required> ActorHandle;
|
|
88
|
+
|
|
89
|
+
UPROPERTY(EditAnywhere)
|
|
90
|
+
float AcceptanceRadius = 100.f;
|
|
91
|
+
|
|
92
|
+
// Bindable input — editor can bind this to evaluator output
|
|
93
|
+
UPROPERTY(EditAnywhere, Category = "Input")
|
|
94
|
+
FVector TargetLocation = FVector::ZeroVector;
|
|
95
|
+
|
|
96
|
+
virtual bool Link(FStateTreeLinker& Linker) override
|
|
97
|
+
{
|
|
98
|
+
Linker.LinkExternalData(ActorHandle);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
virtual EStateTreeRunStatus EnterState(FStateTreeExecutionContext& Context,
|
|
103
|
+
const FStateTreeTransitionResult& Transition) const override
|
|
104
|
+
{
|
|
105
|
+
auto& ActorCtx = Context.GetExternalData(ActorHandle);
|
|
106
|
+
AActor* Actor = ActorCtx.GetActor();
|
|
107
|
+
if (!Actor) return EStateTreeRunStatus::Failed;
|
|
108
|
+
|
|
109
|
+
// Start movement...
|
|
110
|
+
return EStateTreeRunStatus::Running;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
virtual EStateTreeRunStatus Tick(FStateTreeExecutionContext& Context,
|
|
114
|
+
float DeltaTime) const override
|
|
115
|
+
{
|
|
116
|
+
auto& ActorCtx = Context.GetExternalData(ActorHandle);
|
|
117
|
+
AActor* Actor = ActorCtx.GetActor();
|
|
118
|
+
if (!Actor) return EStateTreeRunStatus::Failed;
|
|
119
|
+
|
|
120
|
+
float Dist = FVector::Dist(Actor->GetActorLocation(), TargetLocation);
|
|
121
|
+
return Dist <= AcceptanceRadius
|
|
122
|
+
? EStateTreeRunStatus::Succeeded : EStateTreeRunStatus::Running;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Custom Condition Template
|
|
130
|
+
|
|
131
|
+
```cpp
|
|
132
|
+
USTRUCT()
|
|
133
|
+
struct FHealthCheckConditionInstanceData
|
|
134
|
+
{
|
|
135
|
+
GENERATED_BODY()
|
|
136
|
+
|
|
137
|
+
// Bindable — connect to evaluator or context data in editor
|
|
138
|
+
UPROPERTY(EditAnywhere, Category = "Input")
|
|
139
|
+
float CurrentHealth = 100.f;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
USTRUCT(meta=(DisplayName="Health Below Threshold"))
|
|
143
|
+
struct FHealthBelowThresholdCondition : public FStateTreeConditionBase
|
|
144
|
+
{
|
|
145
|
+
GENERATED_BODY()
|
|
146
|
+
typedef FHealthCheckConditionInstanceData FInstanceDataType;
|
|
147
|
+
|
|
148
|
+
UPROPERTY(EditAnywhere, Category = "Parameter")
|
|
149
|
+
float Threshold = 25.f;
|
|
150
|
+
|
|
151
|
+
// TestCondition must be a PURE FUNCTION — no side effects
|
|
152
|
+
// May be called multiple times per frame during transition evaluation
|
|
153
|
+
virtual bool TestCondition(FStateTreeExecutionContext& Context) const override
|
|
154
|
+
{
|
|
155
|
+
const FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
156
|
+
return Data.CurrentHealth < Threshold;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Evaluator Template
|
|
164
|
+
|
|
165
|
+
Evaluators run every tick before transitions. Use them to inject world data into the tree via property bindings.
|
|
166
|
+
|
|
167
|
+
```cpp
|
|
168
|
+
USTRUCT()
|
|
169
|
+
struct FNearestEnemyEvaluatorInstanceData
|
|
170
|
+
{
|
|
171
|
+
GENERATED_BODY()
|
|
172
|
+
|
|
173
|
+
// Output — bind task/condition inputs to these in the editor
|
|
174
|
+
UPROPERTY(EditAnywhere, Category = "Output")
|
|
175
|
+
TObjectPtr<AActor> NearestEnemy = nullptr;
|
|
176
|
+
|
|
177
|
+
UPROPERTY(EditAnywhere, Category = "Output")
|
|
178
|
+
float DistanceToNearest = MAX_FLT;
|
|
179
|
+
|
|
180
|
+
// Internal cache
|
|
181
|
+
float TimeSinceLastQuery = 0.f;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
USTRUCT(meta=(DisplayName="Nearest Enemy Evaluator"))
|
|
185
|
+
struct FNearestEnemyEvaluator : public FStateTreeEvaluatorBase
|
|
186
|
+
{
|
|
187
|
+
GENERATED_BODY()
|
|
188
|
+
typedef FNearestEnemyEvaluatorInstanceData FInstanceDataType;
|
|
189
|
+
|
|
190
|
+
UPROPERTY(EditAnywhere, Category = "Parameter")
|
|
191
|
+
float QueryInterval = 0.5f; // Don't query every frame
|
|
192
|
+
|
|
193
|
+
TStateTreeExternalDataHandle<FStateTreeActorContext,
|
|
194
|
+
EStateTreeExternalDataRequirement::Required> ActorHandle;
|
|
195
|
+
|
|
196
|
+
virtual bool Link(FStateTreeLinker& Linker) override
|
|
197
|
+
{
|
|
198
|
+
Linker.LinkExternalData(ActorHandle);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
virtual void TreeStart(FStateTreeExecutionContext& Context) const override
|
|
203
|
+
{
|
|
204
|
+
FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
205
|
+
Data.NearestEnemy = nullptr;
|
|
206
|
+
Data.DistanceToNearest = MAX_FLT;
|
|
207
|
+
Data.TimeSinceLastQuery = QueryInterval; // Force immediate first query
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
virtual void Tick(FStateTreeExecutionContext& Context, float DeltaTime) const override
|
|
211
|
+
{
|
|
212
|
+
FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
213
|
+
Data.TimeSinceLastQuery += DeltaTime;
|
|
214
|
+
|
|
215
|
+
if (Data.TimeSinceLastQuery < QueryInterval) return;
|
|
216
|
+
Data.TimeSinceLastQuery = 0.f;
|
|
217
|
+
|
|
218
|
+
auto& ActorCtx = Context.GetExternalData(ActorHandle);
|
|
219
|
+
AActor* Owner = ActorCtx.GetActor();
|
|
220
|
+
if (!Owner) return;
|
|
221
|
+
|
|
222
|
+
// Perform query (overlap, EQS, etc.)
|
|
223
|
+
// Update Data.NearestEnemy and Data.DistanceToNearest
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
virtual void TreeStop(FStateTreeExecutionContext& Context) const override
|
|
227
|
+
{
|
|
228
|
+
FInstanceDataType& Data = Context.GetInstanceData(*this);
|
|
229
|
+
Data.NearestEnemy = nullptr;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## FStateTreeReference Setup
|
|
237
|
+
|
|
238
|
+
Use `FStateTreeReference` for linked assets and runtime parameter overrides:
|
|
239
|
+
|
|
240
|
+
```cpp
|
|
241
|
+
// In your component or controller
|
|
242
|
+
UPROPERTY(EditAnywhere, Category = "StateTree")
|
|
243
|
+
FStateTreeReference StateTreeRef;
|
|
244
|
+
|
|
245
|
+
void SetupStateTree(UStateTree* TreeAsset, float CustomAggroRange)
|
|
246
|
+
{
|
|
247
|
+
StateTreeRef.SetStateTree(TreeAsset);
|
|
248
|
+
StateTreeRef.SyncParameters(); // sync defaults from asset
|
|
249
|
+
StateTreeRef.GetParameters().SetValueFloat(TEXT("AggroRange"), CustomAggroRange);
|
|
250
|
+
|
|
251
|
+
StateTreeComp->SetStateTreeReference(StateTreeRef);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Runtime variant swapping via FStateTreeReferenceOverrides
|
|
255
|
+
UPROPERTY(EditAnywhere)
|
|
256
|
+
FStateTreeReferenceOverrides TreeOverrides;
|
|
257
|
+
|
|
258
|
+
void SwitchToCombatVariant(FStateTreeReference& CombatRef)
|
|
259
|
+
{
|
|
260
|
+
TreeOverrides.AddOverride(
|
|
261
|
+
FGameplayTag::RequestGameplayTag("Variant.Combat"), CombatRef);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Event Patterns
|
|
268
|
+
|
|
269
|
+
### Sending Events from External Systems
|
|
270
|
+
|
|
271
|
+
```cpp
|
|
272
|
+
// From perception callback
|
|
273
|
+
void AMyAIController::OnTargetPerceived(AActor* Target)
|
|
274
|
+
{
|
|
275
|
+
FMyPerceptionPayload Payload;
|
|
276
|
+
Payload.PerceivedActor = Target;
|
|
277
|
+
Payload.ThreatLevel = CalculateThreat(Target);
|
|
278
|
+
|
|
279
|
+
StateTreeComp->SendStateTreeEvent(
|
|
280
|
+
FGameplayTag::RequestGameplayTag("AI.TargetPerceived"),
|
|
281
|
+
FConstStructView::Make(Payload),
|
|
282
|
+
TEXT("Perception"));
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Consuming Events in Tasks
|
|
287
|
+
|
|
288
|
+
```cpp
|
|
289
|
+
virtual EStateTreeRunStatus EnterState(FStateTreeExecutionContext& Context,
|
|
290
|
+
const FStateTreeTransitionResult& Transition) const override
|
|
291
|
+
{
|
|
292
|
+
// Iterate events pending in the queue; ConsumeEvent(Event) removes a specific event
|
|
293
|
+
Context.ForEachEvent([&](const FStateTreeSharedEvent& SharedEvent)
|
|
294
|
+
{
|
|
295
|
+
const FStateTreeEvent& Event = *SharedEvent;
|
|
296
|
+
if (Event.Tag == MyExpectedTag)
|
|
297
|
+
{
|
|
298
|
+
// Process payload from the triggering event
|
|
299
|
+
Context.ConsumeEvent(SharedEvent); // void — does not return bool
|
|
300
|
+
}
|
|
301
|
+
return EStateTreeLoopEvents::Continue;
|
|
302
|
+
});
|
|
303
|
+
return EStateTreeRunStatus::Running;
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Transition Design Patterns
|
|
310
|
+
|
|
311
|
+
### Event-Driven (decoupled, reactive)
|
|
312
|
+
Use `OnEvent` trigger with a GameplayTag. Best for external stimuli (perception, damage, game events). Set `bConsumeEventOnSelect = true` to prevent double-handling.
|
|
313
|
+
|
|
314
|
+
### Tick-Based with Conditions (polled)
|
|
315
|
+
Use `OnTick` trigger with conditions gating the transition. Best for continuous checks (distance thresholds, timer expiry). Keep conditions lightweight since they evaluate every frame.
|
|
316
|
+
|
|
317
|
+
### Completion-Based (sequential)
|
|
318
|
+
Use `OnStateCompleted` / `OnStateSucceeded` / `OnStateFailed` triggers. Best for linear state sequences where the next state depends on the previous state's outcome. Use `NextState` target for sequential flows.
|
|
319
|
+
|
|
320
|
+
### Priority Escalation
|
|
321
|
+
Set `Critical` priority on interrupt transitions (damage, death) so they override normal transitions regardless of state depth. Lower priorities for optional transitions (idle variations).
|