claude-code-arcane 2.3.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +54 -6
  3. package/agents/game/ue-blueprint-specialist.md +125 -0
  4. package/agents/game/ue-gas-specialist.md +133 -0
  5. package/agents/game/ue-umg-specialist.md +131 -0
  6. package/dist/cli.js +5 -0
  7. package/docs/SKILLS-CATALOG.md +42 -3
  8. package/docs/USER-GUIDE.md +2 -2
  9. package/hooks/detect-unreal.sh +90 -0
  10. package/package.json +1 -1
  11. package/profiles/unreal-dev.yaml +97 -0
  12. package/rules/gamedev/unreal-code.md +125 -0
  13. package/skills/install-mcp/SKILL.md +135 -46
  14. package/skills/install-mcp/references/unreal-operations.md +55 -0
  15. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  16. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  17. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  18. package/skills/ue-ai-navigation/SKILL.md +526 -0
  19. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  20. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  21. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  22. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  23. package/skills/ue-animation-system/SKILL.md +521 -0
  24. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  25. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  26. package/skills/ue-async-threading/SKILL.md +433 -0
  27. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  28. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  29. package/skills/ue-audio-system/SKILL.md +527 -0
  30. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  31. package/skills/ue-blueprints/SKILL.md +134 -0
  32. package/skills/ue-blueprints/references/communication.md +82 -0
  33. package/skills/ue-character-movement/SKILL.md +475 -0
  34. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  35. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  36. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  37. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  38. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  39. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  40. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  41. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  42. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  43. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  44. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  45. package/skills/ue-editor-tools/SKILL.md +523 -0
  46. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  47. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  48. package/skills/ue-game-features/SKILL.md +477 -0
  49. package/skills/ue-game-features/references/experience-system.md +222 -0
  50. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  51. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  52. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  53. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  54. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  55. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  56. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  57. package/skills/ue-input-system/SKILL.md +394 -0
  58. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  59. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  60. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  61. package/skills/ue-mass-entity/SKILL.md +476 -0
  62. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  63. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  64. package/skills/ue-materials-rendering/SKILL.md +526 -0
  65. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  66. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  67. package/skills/ue-module-build-system/SKILL.md +487 -0
  68. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  69. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  70. package/skills/ue-naming-conventions/SKILL.md +142 -0
  71. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  72. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  73. package/skills/ue-networking-replication/SKILL.md +452 -0
  74. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  75. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  76. package/skills/ue-niagara-effects/SKILL.md +531 -0
  77. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  78. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  79. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  80. package/skills/ue-packaging/SKILL.md +116 -0
  81. package/skills/ue-physics-collision/SKILL.md +423 -0
  82. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  83. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  84. package/skills/ue-procedural-generation/SKILL.md +505 -0
  85. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  86. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  87. package/skills/ue-project-context/SKILL.md +305 -0
  88. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  89. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  90. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  91. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  92. package/skills/ue-state-trees/SKILL.md +489 -0
  93. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  94. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  95. package/skills/ue-testing-debugging/SKILL.md +520 -0
  96. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  97. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  98. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  99. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  100. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  101. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  102. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  103. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,387 @@
1
+ # Automation Test Patterns
2
+
3
+ Reference for common Unreal Engine automation test setups, latent command patterns, and scenario recipes. All patterns use the real API from `Misc/AutomationTest.h`.
4
+
5
+ ---
6
+
7
+ ## Test Module Setup
8
+
9
+ ### Build Rules
10
+
11
+ ```csharp
12
+ // MyGameTests.Build.cs
13
+ public class MyGameTests : ModuleRules
14
+ {
15
+ public MyGameTests(ReadOnlyTargetRules Target) : base(Target)
16
+ {
17
+ PrivateDependencyModuleNames.AddRange(new string[]
18
+ {
19
+ "Core",
20
+ "CoreUObject",
21
+ "Engine",
22
+ "AutomationController",
23
+ "MyGame", // the module being tested
24
+ });
25
+
26
+ // Include editor-only dependencies when running in Editor context
27
+ if (Target.bBuildEditor)
28
+ {
29
+ PrivateDependencyModuleNames.Add("UnrealEd");
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### Target File Inclusion
36
+
37
+ ```csharp
38
+ // MyGameEditor.Target.cs (editor target — tests run here)
39
+ ExtraModuleNames.Add("MyGameTests");
40
+
41
+ // MyGame.Target.cs (game target — tests excluded unless bWithAutomationTests)
42
+ if (bWithAutomationTests)
43
+ {
44
+ ExtraModuleNames.Add("MyGameTests");
45
+ }
46
+ ```
47
+
48
+ ### Naming Convention
49
+
50
+ ```
51
+ MyGame.Category.SubCategory.TestName
52
+
53
+ Examples:
54
+ MyGame.Inventory.AddItem
55
+ MyGame.Inventory.RemoveItem
56
+ MyGame.Inventory.Overflow
57
+ MyGame.Pathfinding.SimpleGrid
58
+ MyGame.Pathfinding.ObstacleDense
59
+ MyGame.Assets.PrimaryWeaponLoad
60
+ ```
61
+
62
+ The dot-separated path creates a tree in the Session Frontend Automation tab.
63
+
64
+ ---
65
+
66
+ ## Pattern: Pure Logic Test (No World)
67
+
68
+ For testing stateless utility functions and pure C++ classes.
69
+
70
+ ```cpp
71
+ #include "Misc/AutomationTest.h"
72
+ #include "MyMath.h" // the unit under test
73
+
74
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
75
+ FMyMathLerpTest,
76
+ "MyGame.Math.LerpClamped",
77
+ EAutomationTestFlags::EditorContext |
78
+ EAutomationTestFlags::SmokeFilter) // SmokeFilter = fast, runs every check-in
79
+
80
+ bool FMyMathLerpTest::RunTest(const FString& Parameters)
81
+ {
82
+ TestEqual(TEXT("Lerp at 0"), MyMath::LerpClamped(0.f, 10.f, 0.f), 0.f, 0.001f);
83
+ TestEqual(TEXT("Lerp at 1"), MyMath::LerpClamped(0.f, 10.f, 1.f), 10.f, 0.001f);
84
+ TestEqual(TEXT("Lerp at 0.5"), MyMath::LerpClamped(0.f, 10.f, 0.5f), 5.f, 0.001f);
85
+ // Clamped: alpha outside [0,1] saturates
86
+ TestEqual(TEXT("Lerp above 1"), MyMath::LerpClamped(0.f, 10.f, 2.f), 10.f, 0.001f);
87
+ TestEqual(TEXT("Lerp below 0"), MyMath::LerpClamped(0.f, 10.f, -1.f), 0.f, 0.001f);
88
+ return true;
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Pattern: UObject Test (Requires GC)
95
+
96
+ For testing `UObject`-derived classes. `NewObject<>` requires a valid outer.
97
+
98
+ ```cpp
99
+ #include "Misc/AutomationTest.h"
100
+ #include "Engine/Engine.h"
101
+ #include "Inventory/InventoryComponent.h"
102
+
103
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
104
+ FInventoryComponentTest,
105
+ "MyGame.Inventory.AddRemove",
106
+ EAutomationTestFlags::EditorContext |
107
+ EAutomationTestFlags::ProductFilter)
108
+
109
+ bool FInventoryComponentTest::RunTest(const FString& Parameters)
110
+ {
111
+ // Use GetTransientPackage() as outer for test UObjects
112
+ UInventoryComponent* Inv = NewObject<UInventoryComponent>(GetTransientPackage());
113
+ if (!TestNotNull(TEXT("Inventory created"), Inv)) { return false; }
114
+
115
+ Inv->AddItem(FName("Sword"), 3);
116
+ TestEqual(TEXT("Count after add"), Inv->GetCount(FName("Sword")), 3);
117
+
118
+ Inv->RemoveItem(FName("Sword"), 1);
119
+ TestEqual(TEXT("Count after remove"), Inv->GetCount(FName("Sword")), 2);
120
+
121
+ Inv->RemoveItem(FName("Sword"), 99); // over-remove
122
+ TestEqual(TEXT("Count clamped at 0"), Inv->GetCount(FName("Sword")), 0);
123
+
124
+ // TestValid works on TWeakObjectPtr and IsValid()-capable types
125
+ TWeakObjectPtr<UInventoryComponent> WeakInv(Inv);
126
+ TestValid(TEXT("Weak ref valid"), WeakInv);
127
+
128
+ return true;
129
+ }
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Pattern: Parameterized Test Over Asset Paths
135
+
136
+ ```cpp
137
+ IMPLEMENT_COMPLEX_AUTOMATION_TEST(
138
+ FDataAssetValidation,
139
+ "MyGame.Assets.DataAssetValidation",
140
+ EAutomationTestFlags::EditorContext |
141
+ EAutomationTestFlags::ProductFilter)
142
+
143
+ void FDataAssetValidation::GetTests(TArray<FString>& OutBeautifiedNames,
144
+ TArray<FString>& OutTestCommands) const
145
+ {
146
+ // Enumerate assets at editor time
147
+ FAssetRegistryModule& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
148
+ TArray<FAssetData> Assets;
149
+ AR.Get().GetAssetsByClass(UMyItemData::StaticClass()->GetClassPathName(), Assets);
150
+
151
+ for (const FAssetData& Asset : Assets)
152
+ {
153
+ OutBeautifiedNames.Add(Asset.AssetName.ToString());
154
+ OutTestCommands.Add(Asset.GetObjectPathString());
155
+ }
156
+ }
157
+
158
+ bool FDataAssetValidation::RunTest(const FString& Parameters)
159
+ {
160
+ // Parameters = the object path string from OutTestCommands
161
+ UMyItemData* ItemData = LoadObject<UMyItemData>(nullptr, *Parameters);
162
+ UE_RETURN_ON_ERROR(ItemData != nullptr,
163
+ FString::Printf(TEXT("Failed to load %s"), *Parameters));
164
+
165
+ TestFalse(TEXT("DisplayName not empty"),
166
+ ItemData->DisplayName.IsEmpty());
167
+ TestTrue(TEXT("MaxStack > 0"),
168
+ ItemData->MaxStack > 0);
169
+ TestNotNull(TEXT("Icon set"), ItemData->Icon.LoadSynchronous());
170
+
171
+ return true;
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Pattern: Expected Error / Negative Test
178
+
179
+ Use `AddExpectedMessage` to suppress and verify expected error log output.
180
+
181
+ ```cpp
182
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
183
+ FInventoryOverflowNegativeTest,
184
+ "MyGame.Inventory.OverflowRejectsItem",
185
+ EAutomationTestFlags::EditorContext |
186
+ EAutomationTestFlags::ProductFilter |
187
+ EAutomationTestFlags::NegativeFilter)
188
+
189
+ bool FInventoryOverflowNegativeTest::RunTest(const FString& Parameters)
190
+ {
191
+ // Tell the framework to expect (and suppress) this warning
192
+ AddExpectedMessage(TEXT("Inventory is full"),
193
+ ELogVerbosity::Warning,
194
+ EAutomationExpectedMessageFlags::Contains);
195
+
196
+ UInventoryComponent* Inv = NewObject<UInventoryComponent>(GetTransientPackage());
197
+ Inv->SetMaxSlots(1);
198
+ Inv->AddItem(FName("Sword"), 1); // fills the slot
199
+
200
+ // This should log "Inventory is full" and return false
201
+ bool bAdded = Inv->AddItem(FName("Shield"), 1);
202
+ TestFalse(TEXT("Second item rejected"), bAdded);
203
+
204
+ return true;
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Pattern: Latent Command — Wait for Delegate
211
+
212
+ ```cpp
213
+ #include "Misc/AutomationTest.h"
214
+
215
+ // Command that waits until a shared bool flag is set
216
+ DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(
217
+ FWaitForBoolCommand, TSharedPtr<bool>, bDone);
218
+
219
+ bool FWaitForBoolCommand::Update()
220
+ {
221
+ return bDone.IsValid() && *bDone;
222
+ }
223
+
224
+ // Command with timeout
225
+ DEFINE_LATENT_AUTOMATION_COMMAND_TWO_PARAMETER(
226
+ FWaitForBoolOrTimeoutCommand, TSharedPtr<bool>, bDone, float, Timeout);
227
+
228
+ bool FWaitForBoolOrTimeoutCommand::Update()
229
+ {
230
+ if (bDone.IsValid() && *bDone) { return true; }
231
+ if (GetCurrentRunTime() > Timeout)
232
+ {
233
+ // Logging in a latent command does NOT add a test error automatically
234
+ // Store the test ref if you need to call AddError
235
+ return true; // done (timed out)
236
+ }
237
+ return false;
238
+ }
239
+
240
+ // Usage inside a test
241
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
242
+ FAsyncOperationTest,
243
+ "MyGame.Async.SubsystemReady",
244
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter)
245
+
246
+ bool FAsyncOperationTest::RunTest(const FString& Parameters)
247
+ {
248
+ TSharedPtr<bool> bReady = MakeShared<bool>(false);
249
+
250
+ // Kick off async work, flip bReady when done
251
+ UMySubsystem* Sub = GEngine->GetEngineSubsystem<UMySubsystem>();
252
+ if (!TestNotNull(TEXT("Subsystem"), Sub)) { return false; }
253
+
254
+ Sub->InitAsync([bReady]() { *bReady = true; });
255
+
256
+ // Wait up to 5 seconds
257
+ ADD_LATENT_AUTOMATION_COMMAND(FWaitForBoolOrTimeoutCommand(bReady, 5.0f));
258
+
259
+ // Latent commands run after RunTest returns; assertions here run immediately
260
+ // For post-async assertions, use a custom latent command that captures the test ptr
261
+ return true;
262
+ }
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Pattern: Latent Command — Validate After Async
268
+
269
+ To make assertions after async work, capture the test reference in the latent command.
270
+
271
+ ```cpp
272
+ class FValidateAfterAsyncCommand : public IAutomationLatentCommand
273
+ {
274
+ public:
275
+ FValidateAfterAsyncCommand(FAutomationTestBase* InTest,
276
+ TSharedPtr<bool> InbDone,
277
+ TSharedPtr<int32> InResult)
278
+ : Test(InTest), bDone(InbDone), Result(InResult) {}
279
+
280
+ virtual bool Update() override
281
+ {
282
+ if (!bDone.IsValid() || !*bDone) { return false; }
283
+ Test->TestEqual(TEXT("Async result"), *Result, 42);
284
+ return true;
285
+ }
286
+
287
+ private:
288
+ FAutomationTestBase* Test;
289
+ TSharedPtr<bool> bDone;
290
+ TSharedPtr<int32> Result;
291
+ };
292
+
293
+ // In RunTest:
294
+ bool FMyAsyncCalcTest::RunTest(const FString& Parameters)
295
+ {
296
+ auto bDone = MakeShared<bool>(false);
297
+ auto Result = MakeShared<int32>(0);
298
+
299
+ UMyCalc::RunAsync([bDone, Result](int32 Val)
300
+ {
301
+ *Result = Val;
302
+ *bDone = true;
303
+ });
304
+
305
+ ADD_LATENT_AUTOMATION_COMMAND(FValidateAfterAsyncCommand(this, bDone, Result));
306
+ return true;
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Running Tests
313
+
314
+ ### Session Frontend (Editor)
315
+
316
+ 1. Open **Window > Session Frontend > Automation**.
317
+ 2. Connect to the local session.
318
+ 3. Filter by name or flags; check boxes and click **Start Tests**.
319
+
320
+ ### Command Line (Unattended)
321
+
322
+ ```bash
323
+ # Run all tests matching a name filter, exit when done
324
+ UnrealEditor-Cmd MyGame -ExecCmds="Automation RunTests MyGame.Inventory" \
325
+ -unattended -nopause -testexit="Automation Test Queue Empty" \
326
+ -log -abslog=TestOutput.log
327
+
328
+ # Run smoke tests only
329
+ UnrealEditor-Cmd MyGame \
330
+ -ExecCmds="Automation RunFilter Smoke" \
331
+ -unattended -nopause -testexit="Automation Test Queue Empty"
332
+ ```
333
+
334
+ ### Programmatic (C++ / Python)
335
+
336
+ ```python
337
+ # Inside Editor Python (via Editor Python Plugin)
338
+ import unreal
339
+ subsystem = unreal.get_editor_subsystem(unreal.AutomationControllerManager)
340
+ # Use Automation Controller API to queue and run tests
341
+ ```
342
+
343
+ ---
344
+
345
+ ## Context Stack for Test Grouping
346
+
347
+ Use `PushContext` / `PopContext` to annotate which sub-step caused a failure.
348
+
349
+ ```cpp
350
+ bool FMyComplexTest::RunTest(const FString& Parameters)
351
+ {
352
+ ExecutionInfo.PushContext(TEXT("Phase 1: Setup"));
353
+ // ... setup assertions
354
+ ExecutionInfo.PopContext();
355
+
356
+ ExecutionInfo.PushContext(TEXT("Phase 2: Execute"));
357
+ // ... execute assertions
358
+ ExecutionInfo.PopContext();
359
+
360
+ return true;
361
+ }
362
+ ```
363
+
364
+ Errors recorded while a context is active will include the context string in the failure report.
365
+
366
+ ---
367
+
368
+ ## Test Telemetry
369
+
370
+ Report numeric measurements alongside test results (captured by automation infrastructure):
371
+
372
+ ```cpp
373
+ bool FMyPerfTest::RunTest(const FString& Parameters)
374
+ {
375
+ double StartTime = FPlatformTime::Seconds();
376
+ // ... operation
377
+ double Duration = FPlatformTime::Seconds() - StartTime;
378
+
379
+ // Reports DataPoint="SpawnTime", Measurement=Duration to telemetry
380
+ // ExecutionInfo.TelemetryStorage = TEXT("MyGamePerf");
381
+ // ExecutionInfo.TelemetryItems.Emplace(TEXT("SpawnTime"), Duration, TEXT("ms"));
382
+ FAutomationTestFramework::Get().AddAnalyticsItemToCurrentTest(
383
+ FString::Printf(TEXT("SpawnTime=%.2fms"), Duration * 1000.0));
384
+
385
+ return true;
386
+ }
387
+ ```