claude-code-arcane 2.3.0 → 2.5.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 (141) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +131 -41
  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 +642 -478
  7. package/docs/SKILLS-CATALOG.md +42 -3
  8. package/docs/USER-GUIDE.md +28 -54
  9. package/hooks/detect-unreal.sh +90 -0
  10. package/package.json +2 -1
  11. package/profiles/agile.yaml +1 -1
  12. package/profiles/ai.yaml +1 -1
  13. package/profiles/android-native.yaml +1 -1
  14. package/profiles/audio.yaml +1 -1
  15. package/profiles/backend-dotnet.yaml +1 -1
  16. package/profiles/backend-go.yaml +1 -1
  17. package/profiles/backend-nestjs.yaml +1 -1
  18. package/profiles/backend-nextjs.yaml +1 -1
  19. package/profiles/backend-ts.yaml +1 -1
  20. package/profiles/business.yaml +1 -1
  21. package/profiles/clevel.yaml +1 -1
  22. package/profiles/clickup.yaml +1 -1
  23. package/profiles/core.yaml +1 -1
  24. package/profiles/database.yaml +1 -1
  25. package/profiles/design.yaml +1 -1
  26. package/profiles/docs.yaml +1 -1
  27. package/profiles/ecommerce.yaml +1 -1
  28. package/profiles/finance.yaml +1 -1
  29. package/profiles/flutter.yaml +1 -1
  30. package/profiles/freelance.yaml +1 -1
  31. package/profiles/frontend.yaml +1 -1
  32. package/profiles/infra.yaml +1 -1
  33. package/profiles/integrations.yaml +1 -1
  34. package/profiles/ios-native.yaml +1 -1
  35. package/profiles/jira.yaml +1 -1
  36. package/profiles/job-hunt.yaml +1 -1
  37. package/profiles/marketing.yaml +1 -1
  38. package/profiles/mobile.yaml +1 -1
  39. package/profiles/regulatory.yaml +1 -1
  40. package/profiles/second-brain.yaml +1 -1
  41. package/profiles/security.yaml +1 -1
  42. package/profiles/self-improving.yaml +1 -1
  43. package/profiles/statusline.yaml +1 -1
  44. package/profiles/testing.yaml +1 -1
  45. package/profiles/unity-design.yaml +1 -1
  46. package/profiles/unity-dev.yaml +1 -1
  47. package/profiles/unreal-dev.yaml +97 -0
  48. package/profiles/visual-novel.yaml +1 -1
  49. package/rules/gamedev/unreal-code.md +125 -0
  50. package/skills/arcane-list/SKILL.md +12 -7
  51. package/skills/install-mcp/SKILL.md +135 -46
  52. package/skills/install-mcp/references/unreal-operations.md +55 -0
  53. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  54. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  55. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  56. package/skills/ue-ai-navigation/SKILL.md +526 -0
  57. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  58. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  59. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  60. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  61. package/skills/ue-animation-system/SKILL.md +521 -0
  62. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  63. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  64. package/skills/ue-async-threading/SKILL.md +433 -0
  65. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  66. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  67. package/skills/ue-audio-system/SKILL.md +527 -0
  68. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  69. package/skills/ue-blueprints/SKILL.md +134 -0
  70. package/skills/ue-blueprints/references/communication.md +82 -0
  71. package/skills/ue-character-movement/SKILL.md +475 -0
  72. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  73. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  74. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  75. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  76. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  77. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  78. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  79. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  80. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  81. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  82. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  83. package/skills/ue-editor-tools/SKILL.md +523 -0
  84. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  85. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  86. package/skills/ue-game-features/SKILL.md +477 -0
  87. package/skills/ue-game-features/references/experience-system.md +222 -0
  88. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  89. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  90. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  91. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  92. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  93. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  94. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  95. package/skills/ue-input-system/SKILL.md +394 -0
  96. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  97. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  98. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  99. package/skills/ue-mass-entity/SKILL.md +476 -0
  100. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  101. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  102. package/skills/ue-materials-rendering/SKILL.md +526 -0
  103. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  104. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  105. package/skills/ue-module-build-system/SKILL.md +487 -0
  106. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  107. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  108. package/skills/ue-naming-conventions/SKILL.md +142 -0
  109. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  110. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  111. package/skills/ue-networking-replication/SKILL.md +452 -0
  112. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  113. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  114. package/skills/ue-niagara-effects/SKILL.md +531 -0
  115. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  116. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  117. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  118. package/skills/ue-packaging/SKILL.md +116 -0
  119. package/skills/ue-physics-collision/SKILL.md +423 -0
  120. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  121. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  122. package/skills/ue-procedural-generation/SKILL.md +505 -0
  123. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  124. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  125. package/skills/ue-project-context/SKILL.md +305 -0
  126. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  127. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  128. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  129. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  130. package/skills/ue-state-trees/SKILL.md +489 -0
  131. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  132. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  133. package/skills/ue-testing-debugging/SKILL.md +520 -0
  134. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  135. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  136. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  137. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  138. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  139. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  140. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  141. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,520 @@
1
+ ---
2
+ name: ue-testing-debugging
3
+ description: "Automation tests, functional tests, UE_LOG, visual logger, debug drawing"
4
+ category: "gamedev"
5
+ argument-hint: "[test o debug target]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Testing & Debugging
11
+
12
+ You are an expert in testing, debugging, and profiling Unreal Engine C++ projects.
13
+
14
+ Ask before writing: this skill edits automation test classes and functional test assets. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context
17
+
18
+ Read `docs/unreal/project-context.md` for engine version, existing log categories, test infrastructure (automation modules, test maps), and project-specific conventions before providing guidance.
19
+
20
+ ## Before You Start
21
+
22
+ Ask which area the user needs help with if unclear:
23
+ - **Automation tests** — unit/integration tests using IMPLEMENT_SIMPLE_AUTOMATION_TEST
24
+ - **Functional tests** — actor-based AFunctionalTest in maps
25
+ - **Logging** — UE_LOG, custom categories, verbosity filtering
26
+ - **Assertions** — check, ensure, verify and when to use each
27
+ - **Debug drawing** — DrawDebug helpers for runtime visualization
28
+ - **Console commands** — UFUNCTION(Exec), FAutoConsoleCommand, CVars
29
+ - **Profiling** — Unreal Insights, stat commands, SCOPE_CYCLE_COUNTER
30
+
31
+ ---
32
+ ## Automation Framework
33
+
34
+ Automation tests live in a dedicated module (e.g., `MyGameTests`) that depends on `"AutomationController"`. Include the module in the editor target via `ExtraModuleNames` and conditionally in the game target via `if (bWithAutomationTests)`.
35
+
36
+ ### Simple Tests
37
+
38
+ ```cpp
39
+ // Source/MyGameTests/Private/MyFeature.spec.cpp
40
+ #include "Misc/AutomationTest.h"
41
+ // Must specify one application context flag AND exactly one filter flag
42
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMyInventoryTest, "MyGame.Inventory.AddItem",
43
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter)
44
+
45
+ bool FMyInventoryTest::RunTest(const FString& Parameters)
46
+ {
47
+ UInventoryComponent* Inv = NewObject<UInventoryComponent>();
48
+ Inv->AddItem(FName("Sword"), 1);
49
+ TestEqual(TEXT("Item count after add"), Inv->GetItemCount(FName("Sword")), 1);
50
+ TestTrue(TEXT("Has sword"), Inv->HasItem(FName("Sword")));
51
+ TestFalse(TEXT("No axe"), Inv->HasItem(FName("Axe")));
52
+ TestNotNull(TEXT("Inv valid"), Inv);
53
+ return true;
54
+ }
55
+ ```
56
+
57
+ ### Complex / Parameterized Tests
58
+
59
+ `IMPLEMENT_COMPLEX_AUTOMATION_TEST` requires overriding `GetTests()` to populate the parameter list, and `RunTest(Parameters)` receives each entry in turn.
60
+
61
+ ```cpp
62
+ IMPLEMENT_COMPLEX_AUTOMATION_TEST(FMyAssetLoadTest, "MyGame.Assets.LoadByPath",
63
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter)
64
+
65
+ void FMyAssetLoadTest::GetTests(TArray<FString>& OutBeautifiedNames,
66
+ TArray<FString>& OutTestCommands) const
67
+ {
68
+ OutBeautifiedNames.Add(TEXT("Sword")); OutTestCommands.Add(TEXT("/Game/Items/BP_Sword"));
69
+ OutBeautifiedNames.Add(TEXT("Shield")); OutTestCommands.Add(TEXT("/Game/Items/BP_Shield"));
70
+ }
71
+
72
+ bool FMyAssetLoadTest::RunTest(const FString& Parameters)
73
+ {
74
+ UObject* Asset = StaticLoadObject(UObject::StaticClass(), nullptr, *Parameters);
75
+ if (!TestNotNull(TEXT("Asset loaded"), Asset)) { return false; }
76
+ TestTrue(TEXT("Is DataAsset"), Asset->IsA<UPrimaryDataAsset>());
77
+ return true;
78
+ }
79
+ ```
80
+
81
+ ### Test Assertion Methods
82
+
83
+ ```cpp
84
+ // Equality — overloaded for int32, int64, float, double, FVector, FRotator,
85
+ // FTransform, FColor, FLinearColor, FString, FStringView, FText, FName
86
+ TestEqual(TEXT("Label"), Actual, Expected);
87
+ TestEqual(TEXT("Float approx"), ActualF, ExpectedF, 0.001f); // tolerance overload
88
+
89
+ // Boolean
90
+ TestTrue(TEXT("Label"), bCondition);
91
+ TestFalse(TEXT("Label"), bCondition);
92
+
93
+ // Pointer / validity
94
+ TestNotNull(TEXT("Label"), Ptr); // fails if Ptr == nullptr
95
+ TestNull(TEXT("Label"), Ptr); // fails if Ptr != nullptr
96
+ TestValid(TEXT("Label"), WeakPtr); // IsValid() check on TWeakObjectPtr etc.
97
+
98
+ // Custom failure messages
99
+ AddError(FString::Printf(TEXT("Unexpected damage %d"), Damage));
100
+ AddWarning(TEXT("Deprecated path hit"));
101
+
102
+ // Add error and bail — returns false from RunTest if condition fails
103
+ UE_RETURN_ON_ERROR(Ptr != nullptr, TEXT("Ptr must not be null"));
104
+ ```
105
+
106
+ ### Test Flags Reference
107
+
108
+ | Flag | Meaning |
109
+ |---|---|
110
+ | `EditorContext` | Runs in the editor process |
111
+ | `ClientContext` | Runs in game client |
112
+ | `ServerContext` | Runs on dedicated server |
113
+ | `SmokeFilter` | Fast; runs on every CI check-in |
114
+ | `ProductFilter` | Project/game-level tests |
115
+
116
+ ---
117
+ ## Latent Commands (Async Testing)
118
+
119
+ Use latent commands when the test must wait for an async operation. `Update()` returns `true` when done, `false` to retry next frame.
120
+
121
+ ```cpp
122
+ DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(FWaitSecondsCommand, float, Duration);
123
+ bool FWaitSecondsCommand::Update() { return GetCurrentRunTime() >= Duration; }
124
+
125
+ // Enqueue inside RunTest; commands drain sequentially after RunTest returns
126
+ ADD_LATENT_AUTOMATION_COMMAND(FWaitSecondsCommand(2.0f));
127
+ ```
128
+
129
+ See `references/automation-test-patterns.md` for delegate-wait, timeout, and post-async assertion patterns.
130
+
131
+ ---
132
+ ## Functional Tests
133
+
134
+ `AFunctionalTest` is a `UCLASS` actor placed in a test map. Override `StartTest()` and call `FinishTest()` when done.
135
+
136
+ ```cpp
137
+ // MyFunctionalTest.h
138
+ UCLASS()
139
+ class MYGAMETESTS_API AMyFunctionalTest : public AFunctionalTest
140
+ {
141
+ GENERATED_BODY()
142
+ public:
143
+ virtual void StartTest() override;
144
+ private:
145
+ UFUNCTION() void OnTimerExpired();
146
+ FTimerHandle TimerHandle;
147
+ };
148
+
149
+ // MyFunctionalTest.cpp
150
+ void AMyFunctionalTest::StartTest()
151
+ {
152
+ Super::StartTest();
153
+ GetWorldTimerManager().SetTimer(TimerHandle, this,
154
+ &AMyFunctionalTest::OnTimerExpired, 1.0f, false);
155
+ }
156
+
157
+ void AMyFunctionalTest::OnTimerExpired()
158
+ {
159
+ bool bPassed = /* verify world state */ true;
160
+ FinishTest(bPassed ? EFunctionalTestResult::Succeeded
161
+ : EFunctionalTestResult::Failed,
162
+ TEXT("Timer-based check"));
163
+ }
164
+ ```
165
+
166
+ Place actors in `Maps/Test_MyFeature.umap`. Run via `RunAutomationTest "MyGame.Functional.MyFeature"` or the Session Frontend.
167
+
168
+ ### TimeLimit
169
+
170
+ ```cpp
171
+ // Timeout — auto-fail if test exceeds time limit
172
+ void AMyFunctionalTest::PrepareTest()
173
+ {
174
+ Super::PrepareTest();
175
+ TimeLimit = 10.0f; // seconds; 0 = no timeout (default)
176
+ }
177
+ ```
178
+
179
+ ---
180
+ ## Logging
181
+
182
+ ### Declaring and Defining a Category
183
+
184
+ ```cpp
185
+ // MyModule.h — visible across the module
186
+ DECLARE_LOG_CATEGORY_EXTERN(LogMyModule, Log, All);
187
+ // ^Name ^Default ^CompileTime max
188
+
189
+ // MyModule.cpp
190
+ DEFINE_LOG_CATEGORY(LogMyModule);
191
+
192
+ // Single-file static category (no extern needed)
193
+ DEFINE_LOG_CATEGORY_STATIC(LogMyHelper, Warning, All);
194
+ ```
195
+
196
+ ### UE_LOG Usage
197
+
198
+ ```cpp
199
+ // UE_LOG(CategoryName, Verbosity, Format, ...)
200
+ UE_LOG(LogMyModule, Log, TEXT("Player spawned: %s"), *PlayerName);
201
+ UE_LOG(LogMyModule, Warning, TEXT("Inventory full, dropping item %s"), *ItemName);
202
+ UE_LOG(LogMyModule, Error, TEXT("Failed to load asset at %s"), *AssetPath);
203
+ UE_LOG(LogMyModule, Verbose, TEXT("Tick called, dt=%.4f"), DeltaTime);
204
+ UE_LOG(LogMyModule, Fatal, TEXT("Unrecoverable save corruption")); // crashes
205
+
206
+ // Conditional log — condition evaluated only if category/verbosity is active
207
+ UE_CLOG(Health <= 0.f, LogMyModule, Warning, TEXT("Actor %s has zero health"), *GetName());
208
+ ```
209
+
210
+ ### Verbosity Levels (highest to lowest severity)
211
+
212
+ | Level | When to use |
213
+ |---|---|
214
+ | `Fatal` | Crash-worthy unrecoverable errors |
215
+ | `Error` | Operation failed, needs developer attention |
216
+ | `Warning` | Unexpected but recoverable condition |
217
+ | `Display` | User-visible output (always shown) |
218
+ | `Log` | Standard development info |
219
+ | `Verbose` | Detailed per-frame or per-call info |
220
+ | `VeryVerbose` | Trace-level; very high frequency |
221
+
222
+ ### Structured Logging (UE 5.2+)
223
+
224
+ ```cpp
225
+ #include "Logging/StructuredLog.h"
226
+ // Named fields — order does not matter; extra fields beyond the format string are allowed
227
+ UE_LOGFMT(LogMyModule, Warning,
228
+ "Loading '{Name}' failed with error {Error}",
229
+ ("Name", AssetName), ("Error", ErrorCode), ("Flags", LoadFlags));
230
+ ```
231
+
232
+ ### Runtime Log Filtering
233
+
234
+ ```
235
+ # Command line: set a category to Verbose at startup
236
+ -LogCmds="LogMyModule Verbose, LogAI Warning"
237
+
238
+ # Console at runtime
239
+ Log LogMyModule Verbose
240
+ Log LogAI Warning
241
+ Log reset # restore defaults
242
+ ```
243
+
244
+ ---
245
+ ## Assertions
246
+
247
+ Assertions are defined in `Misc/AssertionMacros.h`. Understand the build-configuration behaviour before choosing one.
248
+
249
+ ### check / checkf
250
+
251
+ ```cpp
252
+ // Active in Debug, Development, Test. REMOVED in Shipping (expression not evaluated).
253
+ check(Ptr != nullptr);
254
+ checkf(Index >= 0 && Index < Array.Num(),
255
+ TEXT("Index %d out of range [0,%d)"), Index, Array.Num());
256
+
257
+ // Debug-only (DO_GUARD_SLOW — only Debug builds)
258
+ checkSlow(ExpensiveValidationFn());
259
+
260
+ // Marks unreachable code paths
261
+ checkNoEntry();
262
+
263
+ // Marks code that must only execute once
264
+ checkNoReentry();
265
+ ```
266
+
267
+ ### ensure / ensureMsgf
268
+
269
+ ```cpp
270
+ // Non-fatal. Logs callstack and submits crash report. Execution continues.
271
+ // Fires only ONCE per call site per session (subsequent failures are silent).
272
+ if (ensure(Component != nullptr))
273
+ {
274
+ Component->DoWork(); // safe to call here
275
+ }
276
+
277
+ // With a message
278
+ ensureMsgf(Health > 0.f, TEXT("Actor %s has non-positive health %.1f"),
279
+ *GetName(), Health);
280
+
281
+ // Always fires (not just once per session)
282
+ ensureAlways(bInitialized);
283
+ ensureAlwaysMsgf(bInitialized, TEXT("System not initialized before use"));
284
+ ```
285
+
286
+ ### verify / verifyf
287
+
288
+ ```cpp
289
+ // Expression ALWAYS evaluated (even in Shipping), but only halts in non-Shipping.
290
+ // Use when expression has side effects you always need.
291
+ verify(Manager->Init());
292
+ verifyf(Count++ < MaxCount, TEXT("Exceeded max count %d"), MaxCount);
293
+ ```
294
+
295
+ ### Decision Guide
296
+
297
+ | Situation | Macro |
298
+ |---|---|
299
+ | Class invariant, programmer error | `check` / `checkf` |
300
+ | Recoverable condition, want to continue | `ensure` / `ensureMsgf` |
301
+ | Expression has side effects always needed | `verify` / `verifyf` |
302
+ | Debug-build heavy validation | `checkSlow` |
303
+ | User-facing input validation | **none** — use explicit if/return |
304
+
305
+ ---
306
+ ## Debug Drawing
307
+
308
+ Debug draw functions from `DrawDebugHelpers.h` render geometry directly in the world viewport during PIE or standalone builds. They are stripped by `#if ENABLE_DRAW_DEBUG` in Shipping.
309
+
310
+ ```cpp
311
+ #include "DrawDebugHelpers.h"
312
+
313
+ // Duration > 0 = seconds visible; bPersistentLines = true for permanent.
314
+ // Duration 0 or -1 both show for one frame.
315
+ UWorld* World = GetWorld();
316
+ DrawDebugLine(World, StartLoc, EndLoc, FColor::Red, false, 2.0f, 0, 2.0f);
317
+ DrawDebugSphere(World, Center, Radius, 12, FColor::Green, false, 2.0f);
318
+ DrawDebugBox(World, Center, Extent, FColor::Blue, false, 2.0f);
319
+ DrawDebugCapsule(World, Center, HalfHeight, Radius,
320
+ FQuat::Identity, FColor::Yellow, false, 2.0f);
321
+ DrawDebugPoint(World, Location, 8.0f, FColor::White, false, 2.0f);
322
+ DrawDebugDirectionalArrow(World, Start, End, 40.0f, FColor::Cyan, false, 2.0f);
323
+ DrawDebugString(World, Location, TEXT("Label"), nullptr,
324
+ FColor::White, 2.0f, true);
325
+
326
+ // Clear all persistent debug geometry
327
+ FlushPersistentDebugLines(World);
328
+
329
+ // Guard persistent draws for shipping: #if ENABLE_DRAW_DEBUG ... #endif
330
+ // UKismetSystemLibrary::DrawDebugSphere (and siblings) auto-gate behind ENABLE_DRAW_DEBUG
331
+ ```
332
+
333
+ ---
334
+ ## Console Commands
335
+
336
+ ### Exec Functions
337
+
338
+ ```cpp
339
+ // AMyPlayerController.h
340
+ UFUNCTION(Exec)
341
+ void ToggleGodMode();
342
+
343
+ // AMyPlayerController.cpp
344
+ void AMyPlayerController::ToggleGodMode()
345
+ {
346
+ bGodMode = !bGodMode;
347
+ UE_LOG(LogMyModule, Display, TEXT("GodMode: %s"), bGodMode ? TEXT("ON") : TEXT("OFF"));
348
+ }
349
+ ```
350
+
351
+ Exec functions work when typed in the console (~) if on a `PlayerController`, `Pawn`, `HUD`, `GameMode`, `GameState`, `CheatManager`, or `GameInstance`.
352
+
353
+ ### FAutoConsoleCommand and CVars
354
+
355
+ ```cpp
356
+ // Registers at static init; no world context needed
357
+ static FAutoConsoleCommand GDumpStatsCmd(
358
+ TEXT("MyGame.DumpStats"), TEXT("Dump gameplay stats"),
359
+ FConsoleCommandDelegate::CreateLambda([]()
360
+ {
361
+ UE_LOG(LogMyModule, Display, TEXT("=== GameStats ==="));
362
+ }));
363
+
364
+ // With world + args (PIE-safe; prefer this for gameplay commands)
365
+ static FAutoConsoleCommandWithWorldAndArgs GSpawnItemCmd(
366
+ TEXT("MyGame.SpawnItem"), TEXT("Usage: MyGame.SpawnItem <Name>"),
367
+ FConsoleCommandWithWorldAndArgsDelegate::CreateLambda(
368
+ [](const TArray<FString>& Args, UWorld* World) { /* spawn */ }));
369
+
370
+ // CVar — declare in .cpp to avoid ODR issues
371
+ static TAutoConsoleVariable<float> CVarDamageScale(
372
+ TEXT("MyGame.DamageScale"), 1.0f,
373
+ TEXT("Scales all outgoing damage."), ECVF_Cheat);
374
+ float Scale = CVarDamageScale.GetValueOnGameThread();
375
+
376
+ // Attach CVar to an existing variable
377
+ float GDrawDistance = 5000.0f;
378
+ static FAutoConsoleVariableRef CVarDrawDistance(
379
+ TEXT("MyGame.DrawDistance"), GDrawDistance,
380
+ TEXT("Draw distance for gameplay objects"), ECVF_Default);
381
+ ```
382
+
383
+ ### Runtime Command Registration
384
+
385
+ ```cpp
386
+ // Runtime registration — call from StartupModule, Initialize, or BeginPlay
387
+ IConsoleCommand* Cmd = IConsoleManager::Get().RegisterConsoleCommand(
388
+ TEXT("MyGame.ReloadConfig"),
389
+ TEXT("Reloads runtime config"),
390
+ FConsoleCommandDelegate::CreateUObject(this, &UMySubsystem::ReloadConfig));
391
+ // Unregister when the owning object is destroyed:
392
+ IConsoleManager::Get().UnregisterConsoleObject(Cmd);
393
+ ```
394
+
395
+ Unlike `FAutoConsoleCommand` (static init registration), `RegisterConsoleCommand` registers at runtime and returns a handle for explicit cleanup.
396
+
397
+ ---
398
+ ## Custom Stat Groups & Profiling Markers
399
+
400
+ ```cpp
401
+ // Declare in a .cpp — feeds stat commands and Unreal Insights
402
+ DECLARE_STATS_GROUP(TEXT("MyGame"), STATGROUP_MyGame, STATCAT_Advanced);
403
+ DECLARE_CYCLE_STAT(TEXT("MySystem Tick"), STAT_MySystemTick, STATGROUP_MyGame);
404
+ DECLARE_CYCLE_STAT(TEXT("PathFind"), STAT_PathFind, STATGROUP_MyGame);
405
+
406
+ void UMySystem::Tick(float DeltaTime) { SCOPE_CYCLE_COUNTER(STAT_MySystemTick); }
407
+ FPath UMySystem::FindPath(...) { SCOPE_CYCLE_COUNTER(STAT_PathFind); }
408
+
409
+ // Named events — colored blocks in Insights, no stat overhead
410
+ #include "HAL/PlatformMisc.h"
411
+ void UMySystem::HeavyOperation() { SCOPED_NAMED_EVENT(MyHeavyOp, FColor::Orange); }
412
+
413
+ // CSV profiling — lightweight always-on telemetry written to Saved/Profiling/CSVStats/
414
+ #include "ProfilingDebugging/CsvProfiler.h"
415
+ CSV_DEFINE_CATEGORY(MyGame, true);
416
+ void UMySystem::Tick(float DeltaTime) { CSV_SCOPED_TIMING_STAT(MyGame, SystemTick); }
417
+ ```
418
+
419
+ ---
420
+ ## Debugging Techniques
421
+
422
+ ### Visual Logger
423
+
424
+ ```cpp
425
+ #include "VisualLogger/VisualLogger.h"
426
+ // Window > Visual Logger shows a timeline of shapes and log events per actor
427
+ UE_VLOG_SPHERE(this, LogMyModule, Verbose, GetActorLocation(), 50.0f, FColor::Green, TEXT("Patrol point"));
428
+ UE_VLOG_SEGMENT(this, LogMyModule, Log, From, To, FColor::Red, TEXT("Path"));
429
+ UE_VLOG(this, LogMyModule, Log, TEXT("State: %s"), *StateName);
430
+ ```
431
+
432
+ ### Gameplay Debugger
433
+
434
+ Press `'` (apostrophe) in PIE to open the Gameplay Debugger. It shows AI, EQS, Ability System, and custom categories. Register a custom category in module startup:
435
+
436
+ ```cpp
437
+ IGameplayDebugger::Get().RegisterCategory("MySystem",
438
+ IGameplayDebugger::FOnGetCategory::CreateStatic(&FMyDebugCategory::MakeInstance),
439
+ EGameplayDebuggerCategoryState::EnabledInGame);
440
+ ```
441
+
442
+ ### IDE Breakpoint Debugging
443
+
444
+ Attach Visual Studio or Rider to the running `UnrealEditor` process (Debug > Attach to Process). Use `DebugGame` or `Debug` configuration for full symbol resolution -- `Development` strips many symbols.
445
+
446
+ ```cpp
447
+ // Break on assertion failures -- set breakpoints on these functions:
448
+ // FDebug::AssertFailed (check/checkf)
449
+ // FDebug::EnsureFailed (ensure/ensureMsgf)
450
+ // FDebug::OptionallyLogFormattedEnsureMessageReturningFalse
451
+
452
+ // Conditional breakpoint example (VS/Rider):
453
+ // Condition: Actor->GetName().Contains(TEXT("Enemy"))
454
+ // Hit count: break on 5th hit
455
+ ```
456
+
457
+ For `check()` and `ensure()` failures, set breakpoints on the handler functions above -- they fire before crash/log, letting you inspect the call stack.
458
+
459
+ ### Crash Analysis
460
+
461
+ - Minidumps land in `Saved/Crashes/`. Open with `UnrealEditor-Win64-DebugGame` PDB in WinDbg or Rider.
462
+ - `FDebug::DumpStackTraceToLog(ELogVerbosity::Error)` prints the current callstack to the log.
463
+ - `ensure` submits a callstack to the Crash Reporter without crashing the process.
464
+
465
+ **Network**: `-NetTrace` for replication capture, `stat net` for live bandwidth, `net.ListActorChannels` for actor channels.
466
+
467
+ **Key profiling commands**: `stat startfile`/`stat stopfile` (.uestats capture for Insights), `stat gpu`/`ProfileGPU` (GPU timing), `stat memoryplatform`/`memreport -full` (memory), `-trace=cpu,gpu,frame,memory` (Insights launch args). See `references/profiling-commands.md`.
468
+
469
+ ---
470
+
471
+ ## Common Mistakes
472
+
473
+ **check() in shipping** — `check()` expressions are compiled out of Shipping builds. Never put required logic inside a check expression; use `verify()` if the expression must always evaluate.
474
+
475
+ **ensure fires only once** — After the first ensure failure at a call site, subsequent calls at that site are silent. Use `ensureAlways` if you need every failure reported.
476
+
477
+ **DrawDebug in shipping** — DrawDebug calls do not exist in Shipping without `ENABLE_DRAW_DEBUG`. Wrap persistent draws with `#if ENABLE_DRAW_DEBUG`.
478
+
479
+ **Missing log category** — Defining `UE_LOG` with a category not visible in the current translation unit causes a linker error. Include the header that declares the category.
480
+
481
+ **Automation test without a filter flag** — Every `IMPLEMENT_SIMPLE_AUTOMATION_TEST` must have exactly one filter flag (Smoke, Engine, Product, Perf, Stress, or Negative). Missing it is a compile-time `static_assert` failure.
482
+
483
+ **Latent command after `return true`** — Latent commands are enqueued before the function returns. Do not enqueue them after the `return true;` statement.
484
+
485
+ **Log spam in multiplayer** — Identical log calls fire from both server and each client. Prefix messages with `GetWorld()->GetNetMode()` or use `UE_CLOG(HasAuthority(), ...)` to reduce noise.
486
+
487
+ ---
488
+
489
+ ## Related Skills
490
+
491
+ - `/ue-cpp-foundations` — UE macro system, delegates, FString, UE_LOG basics
492
+ - `/ue-module-build-system` — setting up a dedicated test module and target inclusion
493
+ - `/ue-actor-component-architecture` — AFunctionalTest placement and world interaction
494
+
495
+ ---
496
+ ## References
497
+
498
+ - `references/automation-test-patterns.md` — test setup patterns, latent commands, common scenarios
499
+ - `references/profiling-commands.md` — stat commands, Insights capture, analysis workflow
500
+
501
+ ---
502
+
503
+ ## Checklist
504
+
505
+ Validate before considering the work done:
506
+
507
+ - [ ] Tests assert real behavior and fail for the right reason when broken
508
+ - [ ] Tests run headless in CI without requiring a human in the editor
509
+ - [ ] Logging uses a dedicated category at an appropriate verbosity
510
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
511
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
512
+
513
+ **PASS** — every item holds. **CONCERNS** — the work stands but at least one item is unresolved and worth flagging to the user. **FAIL** — an item is violated in a way that breaks correctness, replication or the frame budget; fix it before handing the work over.
514
+
515
+ ## Next Steps
516
+
517
+ - `/test-setup` — wire the tests into the project test runner
518
+ - `/check` — run the full quality gate
519
+ - `/code-review` — architectural and quality review of the change
520
+ - `/commit` — conventional commit once the change is verified