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.
Files changed (144) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +104 -55
  3. package/agents/career/career-strategist.md +88 -0
  4. package/agents/career/cv-reviewer.md +81 -0
  5. package/agents/career/hiring-manager.md +68 -0
  6. package/agents/career/mock-interviewer.md +76 -0
  7. package/agents/freelance/client-screener.md +84 -0
  8. package/agents/freelance/discovery-call.md +65 -0
  9. package/agents/freelance/pipeline-strategist.md +99 -0
  10. package/agents/freelance/proposal-reviewer.md +82 -0
  11. package/agents/game/ue-blueprint-specialist.md +125 -0
  12. package/agents/game/ue-gas-specialist.md +133 -0
  13. package/agents/game/ue-umg-specialist.md +131 -0
  14. package/dist/cli.js +57 -13
  15. package/docs/RELEASE-SETUP.md +1 -1
  16. package/docs/SKILLS-CATALOG.md +67 -4
  17. package/docs/USER-GUIDE.md +77 -72
  18. package/docs/agent-hierarchy.md +21 -1
  19. package/docs/presentations/build_arcane_deck.py +2 -2
  20. package/docs/presentations/build_arcane_deck_12.py +2 -2
  21. package/hooks/detect-unreal.sh +90 -0
  22. package/package.json +2 -2
  23. package/profiles/freelance.yaml +43 -0
  24. package/profiles/job-hunt.yaml +5 -2
  25. package/profiles/unreal-dev.yaml +97 -0
  26. package/rules/drafter-reviewer.md +16 -3
  27. package/rules/freelance-guardrails.md +53 -0
  28. package/rules/gamedev/unreal-code.md +125 -0
  29. package/skills/career-registry/SKILL.md +95 -0
  30. package/skills/career-registry/scripts/career_registry.py +488 -0
  31. package/skills/client-screen/SKILL.md +83 -0
  32. package/skills/client-screen/references/red-flags.md +95 -0
  33. package/skills/cover-letter/SKILL.md +4 -3
  34. package/skills/cv-tailor/SKILL.md +11 -2
  35. package/skills/freelance-deliver/SKILL.md +90 -0
  36. package/skills/freelance-hunt/SKILL.md +126 -0
  37. package/skills/freelance-hunt/references/templates/Connects.md +39 -0
  38. package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
  39. package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
  40. package/skills/freelance-kickoff/SKILL.md +94 -0
  41. package/skills/freelance-pipeline/SKILL.md +109 -0
  42. package/skills/freelance-pipeline/scripts/import_history.py +425 -0
  43. package/skills/freelance-profile/SKILL.md +93 -0
  44. package/skills/freelance-proposal/SKILL.md +112 -0
  45. package/skills/freelance-scan/SKILL.md +196 -0
  46. package/skills/freelance-scan/references/dedup.md +35 -0
  47. package/skills/freelance-scan/references/platforms.md +167 -0
  48. package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
  49. package/skills/install-mcp/SKILL.md +135 -46
  50. package/skills/install-mcp/references/unreal-operations.md +55 -0
  51. package/skills/interview-prep/SKILL.md +11 -3
  52. package/skills/job-aplicar/SKILL.md +5 -1
  53. package/skills/job-hunt/SKILL.md +17 -0
  54. package/skills/job-outcome/SKILL.md +15 -1
  55. package/skills/job-upskill/SKILL.md +10 -2
  56. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  57. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  58. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  59. package/skills/ue-ai-navigation/SKILL.md +526 -0
  60. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  61. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  62. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  63. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  64. package/skills/ue-animation-system/SKILL.md +521 -0
  65. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  66. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  67. package/skills/ue-async-threading/SKILL.md +433 -0
  68. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  69. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  70. package/skills/ue-audio-system/SKILL.md +527 -0
  71. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  72. package/skills/ue-blueprints/SKILL.md +134 -0
  73. package/skills/ue-blueprints/references/communication.md +82 -0
  74. package/skills/ue-character-movement/SKILL.md +475 -0
  75. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  76. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  77. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  78. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  79. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  80. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  81. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  82. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  83. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  84. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  85. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  86. package/skills/ue-editor-tools/SKILL.md +523 -0
  87. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  88. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  89. package/skills/ue-game-features/SKILL.md +477 -0
  90. package/skills/ue-game-features/references/experience-system.md +222 -0
  91. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  92. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  93. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  94. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  95. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  96. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  97. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  98. package/skills/ue-input-system/SKILL.md +394 -0
  99. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  100. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  101. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  102. package/skills/ue-mass-entity/SKILL.md +476 -0
  103. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  104. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  105. package/skills/ue-materials-rendering/SKILL.md +526 -0
  106. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  107. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  108. package/skills/ue-module-build-system/SKILL.md +487 -0
  109. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  110. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  111. package/skills/ue-naming-conventions/SKILL.md +142 -0
  112. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  113. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  114. package/skills/ue-networking-replication/SKILL.md +452 -0
  115. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  116. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  117. package/skills/ue-niagara-effects/SKILL.md +531 -0
  118. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  119. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  120. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  121. package/skills/ue-packaging/SKILL.md +116 -0
  122. package/skills/ue-physics-collision/SKILL.md +423 -0
  123. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  124. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  125. package/skills/ue-procedural-generation/SKILL.md +505 -0
  126. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  127. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  128. package/skills/ue-project-context/SKILL.md +305 -0
  129. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  130. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  131. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  132. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  133. package/skills/ue-state-trees/SKILL.md +489 -0
  134. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  135. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  136. package/skills/ue-testing-debugging/SKILL.md +520 -0
  137. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  138. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  139. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  140. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  141. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  142. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  143. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  144. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,533 @@
1
+ ---
2
+ name: ue-cpp-foundations
3
+ description: "UPROPERTY, UFUNCTION, UCLASS, TArray, TMap, delegates, FString, garbage collection, smart pointers"
4
+ category: "gamedev"
5
+ argument-hint: "[class, type o question]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE C++ Foundations
11
+
12
+ You are an expert in Unreal Engine's C++ extensions and property system.
13
+
14
+ Ask before writing: this skill edits C++ headers and source files under `Source/`. 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, coding conventions, and project-specific rules. Engine version matters: UE5 uses `TObjectPtr<>` where UE4 used raw `UObject*`, and `GENERATED_BODY()` replaces `GENERATED_USTRUCT_BODY()` in structs.
19
+
20
+ ## Before You Start
21
+
22
+ Ask which area the user needs help with if unclear:
23
+ - **Macros & Reflection** — UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM
24
+ - **Containers** — TArray, TMap, TSet, TOptional
25
+ - **Delegates** — static, dynamic, multicast, binding patterns
26
+ - **Strings** — FName, FString, FText conversion and formatting
27
+ - **Memory & GC** — TObjectPtr, TWeakObjectPtr, TSharedPtr, GC roots
28
+ - **Logging** — UE_LOG, log categories, verbosity
29
+ - **Subsystems** — GameInstance, World, LocalPlayer subsystems
30
+
31
+ ---
32
+
33
+ ## UObject Macros & Reflection
34
+
35
+ All UE reflection macros require `GENERATED_BODY()` inside the class/struct and the corresponding `.generated.h` include.
36
+
37
+ ### UCLASS()
38
+
39
+ | Specifier | Effect |
40
+ |-----------|--------|
41
+ | `Blueprintable` | Blueprint subclassing allowed |
42
+ | `BlueprintType` | Usable as Blueprint variable |
43
+ | `Abstract` | Cannot be instantiated |
44
+ | `NotBlueprintable` | Blocks Blueprint subclassing |
45
+ | `Config=<Name>` | Loads UPROPERTY(Config) from `<Name>.ini` |
46
+ | `Transient` | Not saved/serialized |
47
+ | `Within=<OuterClass>` | Outer must be of given type |
48
+
49
+ ```cpp
50
+ UCLASS(Blueprintable, BlueprintType)
51
+ class MYGAME_API UMyDataObject : public UObject
52
+ {
53
+ GENERATED_BODY()
54
+ public:
55
+ UMyDataObject();
56
+ };
57
+ ```
58
+
59
+ Full specifier list: [references/property-specifiers.md](references/property-specifiers.md).
60
+
61
+ ### UPROPERTY()
62
+
63
+ ```cpp
64
+ UCLASS(Blueprintable)
65
+ class MYGAME_API AMyCharacter : public ACharacter
66
+ {
67
+ GENERATED_BODY()
68
+ public:
69
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
70
+ float MaxHealth = 100.f;
71
+
72
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
73
+ float CurrentHealth;
74
+
75
+ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config")
76
+ int32 MaxLevel = 50;
77
+
78
+ UPROPERTY(ReplicatedUsing=OnRep_Health, Category="Replication")
79
+ float ReplicatedHealth;
80
+
81
+ UPROPERTY(Transient) // Not serialized; GC still tracks
82
+ TObjectPtr<UParticleSystemComponent> CachedFX;
83
+
84
+ UPROPERTY(SaveGame, BlueprintReadWrite, Category="Persistence")
85
+ int32 PlayerScore;
86
+
87
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats",
88
+ meta=(ClampMin="0.0", ClampMax="1.0"))
89
+ float DamageMultiplier = 1.f;
90
+
91
+ UFUNCTION()
92
+ void OnRep_Health();
93
+
94
+ virtual void GetLifetimeReplicatedProps(
95
+ TArray<FLifetimeProperty>& OutLifetimeProps) const override;
96
+ };
97
+ ```
98
+
99
+ ### UFUNCTION()
100
+
101
+ ```cpp
102
+ UFUNCTION(BlueprintCallable, Category="Actions")
103
+ void PerformAttack(float Damage);
104
+
105
+ UFUNCTION(BlueprintPure, Category="Queries")
106
+ float GetHealthPercent() const;
107
+
108
+ UFUNCTION(BlueprintNativeEvent, Category="Events") // C++ provides _Implementation
109
+ void OnDamageTaken(float Amount);
110
+ virtual void OnDamageTaken_Implementation(float Amount);
111
+
112
+ UFUNCTION(BlueprintImplementableEvent, Category="Events") // Blueprint must implement
113
+ void OnLevelUp(int32 NewLevel);
114
+
115
+ UFUNCTION(Server, Reliable, WithValidation) // RPC: runs on server
116
+ void ServerFireWeapon(FVector Origin, FVector Direction);
117
+ void ServerFireWeapon_Implementation(FVector Origin, FVector Direction);
118
+ bool ServerFireWeapon_Validate(FVector Origin, FVector Direction);
119
+
120
+ UFUNCTION(Client, Reliable) // RPC: runs on owning client
121
+ void ClientShowDamageNumber(float Amount);
122
+ void ClientShowDamageNumber_Implementation(float Amount);
123
+
124
+ UFUNCTION(NetMulticast, Reliable) // RPC: runs on all
125
+ void MulticastPlayEffect(FVector Location);
126
+ void MulticastPlayEffect_Implementation(FVector Location);
127
+
128
+ UFUNCTION(Exec) // Console command (~ in-game)
129
+ void DebugResetStats(); // Works on PC, Pawn, HUD, GM, GI, CheatManager
130
+ ```
131
+
132
+ ### USTRUCT() and UENUM()
133
+
134
+ ```cpp
135
+ // UE5: always GENERATED_BODY() — never GENERATED_USTRUCT_BODY()
136
+ USTRUCT(BlueprintType)
137
+ struct MYGAME_API FWeaponStats
138
+ {
139
+ GENERATED_BODY()
140
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) float BaseDamage = 10.f;
141
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) float FireRate = 0.5f;
142
+ };
143
+
144
+ // DataTable row
145
+ USTRUCT(BlueprintType)
146
+ struct MYGAME_API FEnemyTableRow : public FTableRowBase
147
+ {
148
+ GENERATED_BODY()
149
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) FName EnemyID;
150
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) TSoftClassPtr<AActor> SpawnClass;
151
+ };
152
+
153
+ UENUM(BlueprintType)
154
+ enum class EWeaponState : uint8
155
+ {
156
+ Idle UMETA(DisplayName="Idle"),
157
+ Firing UMETA(DisplayName="Firing"),
158
+ Reloading UMETA(DisplayName="Reloading"),
159
+ };
160
+ ```
161
+
162
+ ---
163
+
164
+ ## UE Containers
165
+
166
+ See [references/container-patterns.md](references/container-patterns.md) for full API and performance guide.
167
+
168
+ ### TArray — Ordered Dynamic Array
169
+
170
+ ```cpp
171
+ TArray<FString> Names;
172
+ Names.Add(TEXT("Alpha"));
173
+ Names.Emplace(TEXT("Beta")); // Construct in-place (avoids copy)
174
+ Names.Reserve(100); // Pre-allocate
175
+
176
+ FString First = Names[0];
177
+ bool bHas = Names.Contains(TEXT("Alpha"));
178
+ int32 Idx = Names.Find(TEXT("Beta")); // INDEX_NONE if absent
179
+ FString* Ptr = Names.FindByPredicate([](const FString& S){ return S.StartsWith(TEXT("A")); });
180
+
181
+ Names.Sort([](const FString& A, const FString& B){ return A.Len() < B.Len(); });
182
+ Names.Remove(TEXT("Alpha")); // Order-preserving O(n)
183
+ Names.RemoveAtSwap(0); // Fast O(1), destroys order
184
+
185
+ for (const FString& N : Names) { /* do NOT add/remove during ranged-for */ }
186
+ for (int32 i = Names.Num()-1; i >= 0; --i) { if (Names[i].IsEmpty()) Names.RemoveAt(i); }
187
+ ```
188
+
189
+ ### TMap — Hash Map
190
+
191
+ ```cpp
192
+ TMap<FName, int32> ItemCounts;
193
+ ItemCounts.Add(FName("Sword"), 3);
194
+
195
+ int32& Ref = ItemCounts.FindOrAdd(FName("Sword")); // Insert default if absent
196
+ int32* Ptr = ItemCounts.Find(FName("Axe")); // nullptr if absent
197
+ bool bHas = ItemCounts.Contains(FName("Shield"));
198
+ ItemCounts.Remove(FName("Shield"));
199
+
200
+ for (const TPair<FName, int32>& Pair : ItemCounts) { /* ... */ }
201
+ ```
202
+
203
+ ### TSet — Hash Set
204
+
205
+ ```cpp
206
+ TSet<FName> Tags;
207
+ Tags.Add(FName("Flying"));
208
+ bool bFlying = Tags.Contains(FName("Flying"));
209
+ TSet<FName> Intersect = Tags.Intersect(OtherTags);
210
+ TSet<FName> Union = Tags.Union(OtherTags);
211
+ ```
212
+
213
+ ### TOptional
214
+
215
+ ```cpp
216
+ TOptional<float> MaybeHP;
217
+ if (MaybeHP.IsSet()) { float H = MaybeHP.GetValue(); }
218
+ float Safe = MaybeHP.Get(0.f); // Default if not set
219
+ MaybeHP = 75.f;
220
+ MaybeHP.Reset();
221
+ ```
222
+
223
+ ### TVariant
224
+
225
+ ```cpp
226
+ // Type-safe tagged union — avoids unsafe casts
227
+ TVariant<int32, float, FString> Value;
228
+ Value.Set<FString>(TEXT("Hello"));
229
+
230
+ if (Value.IsType<FString>())
231
+ {
232
+ const FString& Str = Value.Get<FString>();
233
+ }
234
+
235
+ // Visit — use explicit overloads; LexToString(V) fails when V is FString.
236
+ Visit(TOverloaded{
237
+ [](int32 V) { UE_LOG(LogTemp, Log, TEXT("%d"), V); },
238
+ [](float V) { UE_LOG(LogTemp, Log, TEXT("%f"), V); },
239
+ [](const FString& V) { UE_LOG(LogTemp, Log, TEXT("%s"), *V); },
240
+ }, Value);
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Delegates
246
+
247
+ See [references/delegate-patterns.md](references/delegate-patterns.md) for all declaration macros and binding methods.
248
+
249
+ ### Choosing the Right Type
250
+
251
+ | Type | Bindings | Blueprint | When to Use |
252
+ |------|----------|-----------|-------------|
253
+ | `DECLARE_DELEGATE` | 1 | No | Internal single-owner callback |
254
+ | `DECLARE_MULTICAST_DELEGATE` | N | No | Internal multi-listener events |
255
+ | `DECLARE_DYNAMIC_DELEGATE` | 1 | Yes | Blueprint-assignable single callback |
256
+ | `DECLARE_DYNAMIC_MULTICAST_DELEGATE` | N | Yes | Blueprint-bindable events (most common) |
257
+
258
+ ### Declaration, Binding, Invocation
259
+
260
+ ```cpp
261
+ // File scope (before UCLASS)
262
+ DECLARE_DELEGATE_OneParam(FOnItemPickedUp, AActor*);
263
+ DECLARE_MULTICAST_DELEGATE_TwoParams(FOnHealthChanged, float, float);
264
+ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnHealthChangedDynamic, float, CurrentHealth, float, MaxHealth);
265
+
266
+ UCLASS()
267
+ class AMyActor : public AActor
268
+ {
269
+ GENERATED_BODY()
270
+ public:
271
+ UPROPERTY(BlueprintAssignable, Category="Events")
272
+ FOnHealthChangedDynamic OnHealthChanged; // Dynamic multicast in UPROPERTY
273
+ };
274
+
275
+ // Static single delegate
276
+ FOnItemPickedUp D;
277
+ D.BindUObject(this, &AMyCharacter::HandlePickup);
278
+ D.BindLambda([this](AActor* Item){ UE_LOG(LogTemp, Log, TEXT("%s"), *Item->GetName()); });
279
+ D.ExecuteIfBound(SomeActor);
280
+ // Multicast: add/broadcast/remove
281
+ FDelegateHandle H = HealthDelegate.AddUObject(this, &AMyHUD::OnHealthChanged);
282
+ HealthDelegate.Broadcast(75.f, 100.f);
283
+ HealthDelegate.Remove(H);
284
+ // Dynamic multicast
285
+ OnHealthChanged.AddDynamic(this, &AMyCharacter::HandleHealthChange);
286
+ OnHealthChanged.RemoveDynamic(this, &AMyCharacter::HandleHealthChange);
287
+ OnHealthChanged.Broadcast(75.f, 100.f);
288
+ ```
289
+
290
+ ---
291
+
292
+ ## String Types
293
+
294
+ | Type | Use For | Comparison | Mutable |
295
+ |------|---------|-----------|---------|
296
+ | `FName` | Identifiers, asset names, tags | O(1) integer | No |
297
+ | `FString` | General-purpose strings, file paths | O(n) | Yes |
298
+ | `FText` | Player-visible display strings | — | No |
299
+
300
+ ```cpp
301
+ // FName — global name table, case-insensitive O(1) compare
302
+ FName Tag("WeaponTag_Rifle");
303
+ FString S = Tag.ToString();
304
+ FName N = FName(*S);
305
+
306
+ // FString — heap string, Printf for formatting
307
+ FString Msg = FString::Printf(TEXT("HP: %.1f"), Health);
308
+ UE_LOG(LogTemp, Log, TEXT("%s"), *Msg); // * dereferences to TCHAR*
309
+ int32 Num = FCString::Atoi(*FString("42"));
310
+
311
+ // FText — localized display text
312
+ // LOCTEXT requires a namespace defined in the same translation unit:
313
+ #define LOCTEXT_NAMESPACE "MyGame"
314
+ FText Label = LOCTEXT("Key", "Assault Rifle");
315
+ FText Fmt = FText::Format(LOCTEXT("HP", "HP: {0}/{1}"),
316
+ FText::AsNumber(Cur), FText::AsNumber(Max));
317
+ #undef LOCTEXT_NAMESPACE // Or: NSLOCTEXT("MyGame", "Key", "...") without a define
318
+ ```
319
+
320
+ **Conversion:** `Name.ToString()` → FString, `FName(*Str)` ← FString, `FText::FromString(Str)`, `Text.ToString()`.
321
+
322
+ ---
323
+
324
+ ## Memory & Garbage Collection
325
+
326
+ UE's GC tracks every `UObject*` reachable from a root. Unreachable objects are destroyed.
327
+
328
+ ```cpp
329
+ // UE5: TObjectPtr<> for UPROPERTY member UObject pointers
330
+ UPROPERTY()
331
+ TObjectPtr<UStaticMeshComponent> MeshComp; // GC-tracked, lazy-load aware
332
+ // Without UPROPERTY — invisible to GC, pointer may dangle
333
+ UMyObject* UnsafePtr; // BAD
334
+ // TWeakObjectPtr — non-owning, safe (becomes null after GC)
335
+ TWeakObjectPtr<AMyActor> WeakRef;
336
+ if (WeakRef.IsValid()) { WeakRef->DoSomething(); }
337
+ // TSharedPtr/TWeakPtr — for non-UObject plain C++ types ONLY
338
+ TSharedPtr<FMyData> Data = MakeShared<FMyData>();
339
+ TWeakPtr<FMyData> Weak = Data;
340
+ if (TSharedPtr<FMyData> Pinned = Weak.Pin()) { Pinned->Process(); }
341
+ // NEVER use TSharedPtr for UObject-derived types
342
+ // GC root: AddToRoot (use sparingly)
343
+ UMyObject* Obj = NewObject<UMyObject>();
344
+ Obj->AddToRoot();
345
+ // ...
346
+ Obj->RemoveFromRoot();
347
+ // FGCObject: preferred for non-UObject C++ classes holding UObject refs
348
+ // UE 5.3+: use TObjectPtr<> — raw UObject* crashes with incremental GC.
349
+ class FMyManager : public FGCObject
350
+ {
351
+ public:
352
+ virtual void AddReferencedObjects(FReferenceCollector& Collector) override
353
+ {
354
+ Collector.AddReferencedObject(ManagedObject);
355
+ }
356
+ virtual FString GetReferencerName() const override { return TEXT("FMyManager"); }
357
+ private:
358
+ TObjectPtr<UMyObject> ManagedObject = nullptr;
359
+ };
360
+ ```
361
+
362
+ ---
363
+
364
+ ## Logging
365
+
366
+ ```cpp
367
+ // MyGameLog.h / .cpp
368
+ DECLARE_LOG_CATEGORY_EXTERN(LogMyGame, Log, All);
369
+ DEFINE_LOG_CATEGORY(LogMyGame);
370
+
371
+ // Single-file: DEFINE_LOG_CATEGORY_STATIC(LogLocal, Log, All);
372
+
373
+ UE_LOG(LogMyGame, Log, TEXT("Loaded: %s"), *LevelName);
374
+ UE_LOG(LogMyGame, Warning, TEXT("HP low: %.1f"), Health);
375
+ UE_LOG(LogMyGame, Error, TEXT("Spawn failed: %s"), *ClassName);
376
+ UE_CLOG(Health < 0.f, LogMyGame, Error, TEXT("Negative HP: %.1f"), Health);
377
+ ```
378
+
379
+ | Verbosity | Visible | When |
380
+ |-----------|---------|------|
381
+ | `Fatal` | Always | Crash-level |
382
+ | `Error` | Always | Operation failed |
383
+ | `Warning` | Always | Unexpected but recoverable |
384
+ | `Log` | Non-shipping | Standard trace |
385
+ | `Verbose` | `-LogCmds` | Fine-grained trace |
386
+
387
+ ---
388
+
389
+ ## Subsystems
390
+
391
+ Auto-registered singletons — no manual `AddToRoot` needed.
392
+
393
+ | Subsystem | Owner | Persists Level Load | Per Player |
394
+ |-----------|-------|---------------------|------------|
395
+ | `UGameInstanceSubsystem` | `UGameInstance` | Yes | No |
396
+ | `UWorldSubsystem` | `UWorld` | No | No |
397
+ | `ULocalPlayerSubsystem` | `ULocalPlayer` | Yes | Yes |
398
+ | `UEngineSubsystem` | `UEngine` | Yes (whole session) | No |
399
+
400
+ ```cpp
401
+ UCLASS()
402
+ class MYGAME_API UInventorySubsystem : public UGameInstanceSubsystem
403
+ {
404
+ GENERATED_BODY()
405
+ public:
406
+ virtual void Initialize(FSubsystemCollectionBase& Collection) override;
407
+ virtual void Deinitialize() override;
408
+
409
+ UFUNCTION(BlueprintCallable) void AddItem(FName ItemID, int32 Count);
410
+ private:
411
+ TMap<FName, int32> Inventory;
412
+ };
413
+
414
+ // Access — each subsystem type has a different accessor
415
+ UInventorySubsystem* Inv = GetGameInstance()->GetSubsystem<UInventorySubsystem>();
416
+ USpawnSubsystem* Sp = GetWorld()->GetSubsystem<USpawnSubsystem>();
417
+ UUIStateSubsystem* UI = GetLocalPlayer()->GetSubsystem<UUIStateSubsystem>();
418
+ UMyEngineSubsystem* ES = GEngine->GetEngineSubsystem<UMyEngineSubsystem>();
419
+ ```
420
+
421
+ Subsystems have `Initialize()` and `Deinitialize()` -- override for setup/teardown. `UGameInstanceSubsystem` persists across map changes; `UWorldSubsystem` reinitializes per world. Call `GetSubsystem<T>()` via the owning context (`GetGameInstance()`, `GetWorld()`, `GetLocalPlayer()`).
422
+
423
+ ---
424
+
425
+ ## Replicated Properties
426
+
427
+ Both `UPROPERTY` specifier AND `GetLifetimeReplicatedProps` are required:
428
+
429
+ ```cpp
430
+ UPROPERTY(ReplicatedUsing = OnRep_Health)
431
+ float Health;
432
+
433
+ UFUNCTION()
434
+ void OnRep_Health(); // Called on clients when server updates Health
435
+
436
+ void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutProps) const
437
+ {
438
+ Super::GetLifetimeReplicatedProps(OutProps);
439
+ DOREPLIFETIME_CONDITION(AMyActor, Health, COND_OwnerOnly);
440
+ // COND_None, COND_OwnerOnly, COND_SkipOwner, COND_SimulatedOnly, COND_InitialOnly
441
+ }
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Conditional Compilation Guards
447
+
448
+ ```cpp
449
+ #if WITH_EDITOR
450
+ // Editor-only properties — stripped from shipping builds
451
+ UPROPERTY(EditAnywhere, Category="Debug")
452
+ bool bShowDebugSpheres = false;
453
+
454
+ virtual void PostEditChangeProperty(FPropertyChangedEvent& E) override;
455
+ #endif
456
+
457
+ #if !UE_BUILD_SHIPPING
458
+ // Available in Development + Debug, stripped from Shipping
459
+ void DrawDebugInfo();
460
+ #endif
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Common Mistakes
466
+
467
+ **Raw UObject* member without UPROPERTY — dangling pointer:**
468
+ ```cpp
469
+ UMyObject* Obj; // BAD — GC invisible
470
+ UPROPERTY() TObjectPtr<UMyObject> Obj; // GOOD
471
+ ```
472
+
473
+ **Modify TArray during ranged-for — undefined behavior:**
474
+ ```cpp
475
+ for (const AActor* A : Actors) { Actors.Remove(A); } // CRASH
476
+ for (int32 i = Actors.Num()-1; i >= 0; --i) { if (ShouldRemove(Actors[i])) Actors.RemoveAt(i); }
477
+ ```
478
+
479
+ **TSharedPtr on a UObject — GC + refcount conflict:**
480
+ ```cpp
481
+ TSharedPtr<UMyObject> P = MakeShared<UMyObject>(); // BAD — leaks or double-free
482
+ UPROPERTY() TObjectPtr<UMyObject> P; // GOOD
483
+ ```
484
+
485
+ **Missing GetLifetimeReplicatedProps:**
486
+ ```cpp
487
+ void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
488
+ {
489
+ Super::GetLifetimeReplicatedProps(OutLifetimeProps);
490
+ DOREPLIFETIME(AMyActor, ReplicatedHealth);
491
+ DOREPLIFETIME_CONDITION(AMyActor, TeamScore, COND_OwnerOnly);
492
+ }
493
+ ```
494
+
495
+ **GENERATED_USTRUCT_BODY() in UE5 structs — use GENERATED_BODY() instead.**
496
+
497
+ **AddDynamic with a non-UFUNCTION — compile error or crash at runtime.**
498
+
499
+ ---
500
+
501
+ ## Related Skills
502
+
503
+ - `/ue-module-build-system` — Build.cs, module dependencies, include paths, PCH configuration
504
+ - `/ue-actor-component-architecture` — AActor/UActorComponent lifecycle, spawning, tick groups, component setup
505
+ - `/ue-blueprints` — the visual-scripting side of the C++/Blueprint boundary
506
+
507
+ ## Reference Files
508
+
509
+ - `references/property-specifiers.md` — full `UPROPERTY`/`UFUNCTION` specifier list
510
+ - `references/container-patterns.md` — `TArray`/`TMap`/`TSet` API and performance guide
511
+ - `references/delegate-patterns.md` — delegate declaration macros and binding methods
512
+ - `references/gameplay-classes-cpp.md` — editor-side workflow for the gameplay framework classes in C++
513
+ - `references/components-and-gc.md` — component ownership and garbage-collection rules
514
+
515
+ ---
516
+
517
+ ## Checklist
518
+
519
+ Validate before considering the work done:
520
+
521
+ - [ ] Every UObject reference is a `TObjectPtr<>` with `UPROPERTY()` markup
522
+ - [ ] Containers are `TArray`/`TMap`/`TSet`, strings use the right `FName`/`FText`/`FString` role
523
+ - [ ] No `new`/`delete` on UObjects — `NewObject<>`/`CreateDefaultSubobject<>` only
524
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
525
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
526
+
527
+ **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.
528
+
529
+ ## Next Steps
530
+
531
+ - `/ue-actor-component-architecture` — apply these types to actor design
532
+ - `/code-review` — architectural and quality review of the change
533
+ - `/commit` — conventional commit once the change is verified
@@ -0,0 +1,107 @@
1
+ > Adapted from the `unreal-cpp-gameplay` skill in [awesome-gamedev-agent-skills](https://github.com/gamedev-skills/awesome-gamedev-agent-skills) (Apache-2.0). Cross-skill references were remapped to Arcane slash commands.
2
+
3
+ # Components, garbage collection & replication primer (UE 5.8 C++)
4
+
5
+ Depth for `/ue-cpp-foundations`. Verified against the Gameplay Framework docs and the UE5
6
+ C++ programming references. Covers component creation/attachment, the UPROPERTY/GC ownership
7
+ rules that trip up newcomers, and a minimal replication example.
8
+
9
+ ## Creating and attaching components
10
+
11
+ Default subobjects are created in the constructor; runtime components use `NewObject` +
12
+ `RegisterComponent`.
13
+
14
+ ```cpp
15
+ // In the constructor — built into the Class Default Object, editable in the Blueprint subclass.
16
+ ACharacterBase::ACharacterBase()
17
+ {
18
+ SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
19
+ SpringArm->SetupAttachment(RootComponent); // attach to an existing component
20
+ SpringArm->TargetArmLength = 300.f;
21
+
22
+ Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
23
+ Camera->SetupAttachment(SpringArm); // socket chain: root -> arm -> camera
24
+ }
25
+ ```
26
+
27
+ ```cpp
28
+ // At runtime (e.g. add a component after spawn):
29
+ UAudioComponent* Audio = NewObject<UAudioComponent>(this);
30
+ Audio->RegisterComponent(); // required, or it won't tick/render
31
+ Audio->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
32
+ ```
33
+
34
+ - `CreateDefaultSubobject` is **only** valid in a constructor; using it later asserts.
35
+ - `SetupAttachment` is for constructor-time hierarchy; `AttachToComponent` is the runtime call.
36
+
37
+ ## Garbage collection ownership (the #1 newcomer crash)
38
+
39
+ The UE garbage collector only keeps `UObject`s alive if it can reach them through a reflected
40
+ reference. A raw `UObject*` member that isn't a `UPROPERTY` is invisible to the GC and can be
41
+ collected, leaving a dangling pointer.
42
+
43
+ ```cpp
44
+ UPROPERTY() // GC sees it -> stays alive while this owner lives
45
+ TObjectPtr<UMyDataObject> Data;
46
+
47
+ UPROPERTY()
48
+ TArray<TObjectPtr<AActor>> Tracked; // containers of UObjects also need UPROPERTY
49
+
50
+ UMyDataObject* Raw; // BUG: not tracked; may be GC'd -> crash
51
+ ```
52
+
53
+ Rules:
54
+ - Every `UObject`/Actor pointer that must persist gets a `UPROPERTY` (use `TObjectPtr<T>` in
55
+ UE5; raw pointers still compile but `TObjectPtr` adds access tracking in the editor).
56
+ - Plain C++ data (ints, FStrings, FVectors, USTRUCTs of POD) doesn't need this — it's owned by
57
+ value.
58
+ - For a UObject you create that has no UPROPERTY owner (rare), `AddToRoot()` pins it and
59
+ `RemoveFromRoot()` releases it — but prefer proper ownership.
60
+
61
+ ## USTRUCT and UENUM for reflected data
62
+
63
+ ```cpp
64
+ UENUM(BlueprintType)
65
+ enum class EWeaponType : uint8 { Pistol, Rifle, Shotgun };
66
+
67
+ USTRUCT(BlueprintType)
68
+ struct FWeaponStats
69
+ {
70
+ GENERATED_BODY()
71
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Damage = 10;
72
+ UPROPERTY(EditAnywhere, BlueprintReadWrite) float FireRate = 0.25f;
73
+ };
74
+ ```
75
+
76
+ `BlueprintType` makes the enum/struct usable as Blueprint variables.
77
+
78
+ ## Minimal replication (multiplayer)
79
+
80
+ ```cpp
81
+ // Header
82
+ UPROPERTY(ReplicatedUsing = OnRep_Health)
83
+ float Health = 100.f;
84
+
85
+ UFUNCTION()
86
+ void OnRep_Health(); // client callback when Health replicates
87
+
88
+ // Source
89
+ #include "Net/UnrealNetwork.h"
90
+ void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const
91
+ {
92
+ Super::GetLifetimeReplicatedProps(Out);
93
+ DOREPLIFETIME(AMyActor, Health); // register the property for replication
94
+ }
95
+ ```
96
+
97
+ - Set `bReplicates = true;` in the constructor for the actor to replicate at all.
98
+ - Server authority: gameplay changes happen on the server; clients receive replicated state and
99
+ react in `OnRep_` callbacks.
100
+
101
+ ## Gotchas
102
+
103
+ - `NewObject` without `RegisterComponent` gives a component that exists but never ticks or
104
+ renders.
105
+ - Forgetting `#include "Net/UnrealNetwork.h"` breaks `DOREPLIFETIME`.
106
+ - `TObjectPtr` implicitly converts to the raw pointer for calls, so existing `->`/`.` usage is
107
+ unchanged; the difference is GC visibility and editor tooling, not syntax at call sites.