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,544 @@
1
+ # Container Patterns Reference
2
+
3
+ Detailed patterns, performance notes, and advanced usage for TArray, TMap, TSet, TOptional, TVariant, and related UE containers.
4
+
5
+ ---
6
+
7
+ ## TArray
8
+
9
+ `TArray<T, AllocatorType>` is defined in `Engine/Source/Runtime/Core/Public/Containers/Array.h`. It stores elements in a contiguous block of memory and is the default container for ordered sequences.
10
+
11
+ ### Core Operations
12
+
13
+ ```cpp
14
+ TArray<int32> Numbers;
15
+
16
+ // Construction
17
+ TArray<int32> FromInit = { 1, 2, 3, 4, 5 };
18
+ TArray<int32> Copy = FromInit;
19
+ TArray<int32> Moved = MoveTemp(FromInit); // Move — FromInit is empty after
20
+
21
+ // Capacity management
22
+ Numbers.Reserve(64); // Pre-allocate without changing Num()
23
+ Numbers.SetNum(10); // Resize, default-initializes new elements
24
+ Numbers.SetNumZeroed(10); // Resize, zero-initializes new elements
25
+ Numbers.SetNumUninitialized(10); // Resize without initialization (POD only)
26
+ Numbers.Shrink(); // Release excess capacity
27
+ Numbers.Empty(); // Clear all elements, free allocation
28
+ Numbers.Reset(); // Clear all elements, keep capacity (no reallocation)
29
+ Numbers.Empty(64); // Clear + hint future capacity
30
+
31
+ // Element count
32
+ int32 Count = Numbers.Num();
33
+ bool bEmpty = Numbers.IsEmpty();
34
+ int32 MaxCap = Numbers.Max(); // Current allocation capacity
35
+ ```
36
+
37
+ ### Adding Elements
38
+
39
+ ```cpp
40
+ TArray<FString> Names;
41
+
42
+ // Add — copies or moves
43
+ Names.Add(TEXT("Alpha"));
44
+ Names.Add(FString(TEXT("Beta"))); // Move from rvalue
45
+
46
+ // Emplace — constructs in-place (avoids copy/move overhead for complex types)
47
+ Names.Emplace(TEXT("Gamma"));
48
+
49
+ // AddUnique — O(n) search before add; use TSet if uniqueness is the main goal
50
+ Names.AddUnique(TEXT("Alpha")); // No-op: already present
51
+
52
+ // Insert at index (shifts all subsequent elements)
53
+ Names.Insert(TEXT("First"), 0);
54
+
55
+ // Append
56
+ TArray<FString> Extra = { TEXT("X"), TEXT("Y") };
57
+ Names.Append(Extra);
58
+ Names.Append({ TEXT("P"), TEXT("Q") }); // Initializer list
59
+
60
+ // Push/Pop (stack semantics)
61
+ Names.Push(TEXT("Top"));
62
+ FString Top = Names.Pop(); // Removes and returns last element
63
+ ```
64
+
65
+ ### Removal
66
+
67
+ ```cpp
68
+ TArray<int32> V = { 1, 2, 3, 2, 4, 2 };
69
+
70
+ // Remove — removes all occurrences; order-preserving; O(n)
71
+ int32 Removed = V.Remove(2); // Removed == 3
72
+
73
+ // RemoveSwap — removes all; swaps with last; O(1) per removal but destroys order
74
+ V.RemoveSwap(3);
75
+
76
+ // RemoveAt — by index; order-preserving; O(n)
77
+ V.RemoveAt(0);
78
+
79
+ // RemoveAtSwap — by index; swaps with last; O(1); destroys order
80
+ V.RemoveAtSwap(0);
81
+
82
+ // RemoveSingle — removes only the first occurrence
83
+ V.RemoveSingle(4);
84
+
85
+ // RemoveAll — removes all matching a predicate
86
+ V.RemoveAll([](int32 N) { return N % 2 == 0; });
87
+
88
+ // RemoveAllSwap — same but unordered (faster)
89
+ V.RemoveAllSwap([](int32 N) { return N < 0; });
90
+
91
+ // Pop — removes the last element
92
+ if (V.Num() > 0)
93
+ {
94
+ int32 Last = V.Pop();
95
+ }
96
+ ```
97
+
98
+ ### Search & Query
99
+
100
+ ```cpp
101
+ TArray<FString> Names = { TEXT("Alpha"), TEXT("Beta"), TEXT("Gamma") };
102
+
103
+ // Find — returns INDEX_NONE if not found
104
+ int32 Idx = Names.Find(TEXT("Beta")); // 1
105
+ int32 Rev = Names.FindLast(TEXT("Beta")); // 1 (from end)
106
+
107
+ // Contains — bool
108
+ bool bHas = Names.Contains(TEXT("Delta")); // false
109
+
110
+ // FindByPredicate — returns pointer to first match or nullptr
111
+ FString* Match = Names.FindByPredicate([](const FString& S)
112
+ {
113
+ return S.StartsWith(TEXT("G"));
114
+ });
115
+ // Use as: if (Match) { ... }
116
+
117
+ // IndexOfByPredicate — returns index or INDEX_NONE
118
+ int32 GIdx = Names.IndexOfByPredicate([](const FString& S)
119
+ {
120
+ return S.Contains(TEXT("amm"));
121
+ });
122
+
123
+ // ContainsByPredicate
124
+ bool bAnyLong = Names.ContainsByPredicate([](const FString& S)
125
+ {
126
+ return S.Len() > 4;
127
+ });
128
+
129
+ // FilterByPredicate — returns a new TArray
130
+ TArray<FString> Long = Names.FilterByPredicate([](const FString& S)
131
+ {
132
+ return S.Len() > 4;
133
+ });
134
+
135
+ // IsValidIndex
136
+ bool bValid = Names.IsValidIndex(5); // false
137
+ ```
138
+
139
+ ### Sorting
140
+
141
+ ```cpp
142
+ TArray<int32> Numbers = { 5, 3, 1, 4, 2 };
143
+
144
+ // Sort with operator< (modifies in-place)
145
+ Numbers.Sort();
146
+
147
+ // Sort with predicate
148
+ Numbers.Sort([](int32 A, int32 B) { return A > B; }); // Descending
149
+
150
+ // StableSort — preserves relative order of equal elements
151
+ Numbers.StableSort([](int32 A, int32 B) { return A < B; });
152
+
153
+ // Sort array of pointers/objects by a member
154
+ TArray<FWeaponStats*> Weapons;
155
+ Weapons.Sort([](const FWeaponStats* A, const FWeaponStats* B)
156
+ {
157
+ return A->BaseDamage > B->BaseDamage;
158
+ });
159
+
160
+ // HeapSort (O(n log n), not stable, slightly faster than Sort)
161
+ Numbers.HeapSort();
162
+ ```
163
+
164
+ ### Iteration Patterns
165
+
166
+ ```cpp
167
+ TArray<AActor*> Actors;
168
+
169
+ // Ranged-for (do NOT add/remove during iteration)
170
+ for (AActor* Actor : Actors)
171
+ {
172
+ if (IsValid(Actor)) { Actor->Destroy(); }
173
+ }
174
+
175
+ // Indexed (safe for removal when iterating backwards)
176
+ for (int32 i = Actors.Num() - 1; i >= 0; --i)
177
+ {
178
+ if (!IsValid(Actors[i]))
179
+ {
180
+ Actors.RemoveAtSwap(i);
181
+ }
182
+ }
183
+
184
+ // Iterator with inline removal
185
+ for (auto It = Actors.CreateIterator(); It; ++It)
186
+ {
187
+ if (!IsValid(*It))
188
+ {
189
+ It.RemoveCurrent();
190
+ }
191
+ }
192
+
193
+ // Const iterator
194
+ for (auto It = Actors.CreateConstIterator(); It; ++It)
195
+ {
196
+ UE_LOG(LogTemp, Log, TEXT("%s"), *(*It)->GetName());
197
+ }
198
+ ```
199
+
200
+ ### Memory & Performance Notes
201
+
202
+ - `Add` / `Emplace` are O(1) amortized; worst-case O(n) when reallocation occurs.
203
+ - `Remove` / `RemoveAt` are O(n) — they shift elements. Use `RemoveSwap` / `RemoveAtSwap` for O(1) when order does not matter.
204
+ - `Reserve` before filling large arrays eliminates reallocation churn.
205
+ - Use `Emplace` over `Add` for non-trivial types to avoid an extra copy.
206
+ - `SetNumUninitialized` is the fastest way to resize for POD bulk-fill patterns.
207
+ - Avoid `Contains` / `Find` in hot paths on large arrays — O(n). Use `TSet` or `TMap` instead.
208
+
209
+ ### Fixed-Size Inline Allocation
210
+
211
+ ```cpp
212
+ // TArray with inline storage for up to N elements (avoids heap for small arrays)
213
+ TArray<int32, TInlineAllocator<8>> SmallList;
214
+ SmallList.Add(1); // Stored inline; no heap alloc if <= 8 elements
215
+
216
+ // Fixed max size (compile-time assertion on overflow)
217
+ TArray<int32, TFixedAllocator<16>> FixedList;
218
+ ```
219
+
220
+ ---
221
+
222
+ ## TMap
223
+
224
+ `TMap<K, V>` is a hash map backed by a sparse array. Average O(1) lookup, insertion, and removal. Defined in `Engine/Source/Runtime/Core/Public/Containers/Map.h`.
225
+
226
+ ### Core Operations
227
+
228
+ ```cpp
229
+ TMap<FName, float> WeaponDamage;
230
+
231
+ // Add — overwrites if key exists
232
+ WeaponDamage.Add(FName("Rifle"), 35.f);
233
+ WeaponDamage.Add(FName("Shotgun"), 80.f);
234
+
235
+ // Emplace — constructs value in-place
236
+ WeaponDamage.Emplace(FName("Pistol"), 20.f);
237
+
238
+ // FindOrAdd — returns ref to existing or newly-default-inserted value
239
+ float& RifleRef = WeaponDamage.FindOrAdd(FName("Rifle")); // Returns 35.f ref
240
+ float& SniperRef = WeaponDamage.FindOrAdd(FName("Sniper")); // Inserts 0.f, returns ref
241
+ SniperRef = 120.f;
242
+
243
+ // Find — returns pointer; nullptr if absent
244
+ float* DamagePtr = WeaponDamage.Find(FName("Rifle"));
245
+ if (DamagePtr)
246
+ {
247
+ *DamagePtr *= 1.5f; // Modify in-place
248
+ }
249
+
250
+ // FindRef — returns value copy (or default if absent) — no way to distinguish "absent" from "zero"
251
+ float GrenadeDmg = WeaponDamage.FindRef(FName("Grenade")); // 0.f (not found)
252
+
253
+ // Contains
254
+ bool bHasRifle = WeaponDamage.Contains(FName("Rifle")); // true
255
+
256
+ // Remove
257
+ int32 NumRemoved = WeaponDamage.Remove(FName("Pistol")); // 1
258
+
259
+ // Num / IsEmpty
260
+ int32 Count = WeaponDamage.Num();
261
+ bool bEmpty = WeaponDamage.IsEmpty();
262
+ ```
263
+
264
+ ### Iteration
265
+
266
+ ```cpp
267
+ TMap<FName, int32> ItemCounts;
268
+
269
+ // Iterate all pairs
270
+ for (const TPair<FName, int32>& Pair : ItemCounts)
271
+ {
272
+ UE_LOG(LogTemp, Log, TEXT("%s = %d"), *Pair.Key.ToString(), Pair.Value);
273
+ }
274
+
275
+ // Structured bindings (C++17)
276
+ for (auto& [Key, Value] : ItemCounts)
277
+ {
278
+ Value += 10;
279
+ }
280
+
281
+ // Keys only
282
+ TArray<FName> Keys;
283
+ ItemCounts.GetKeys(Keys);
284
+
285
+ // Values only
286
+ TArray<int32> Values;
287
+ ItemCounts.GenerateValueArray(Values);
288
+
289
+ // Key-value arrays
290
+ TArray<FName> OutKeys;
291
+ TArray<int32> OutValues;
292
+ ItemCounts.GenerateKeyArray(OutKeys);
293
+ ItemCounts.GenerateValueArray(OutValues);
294
+
295
+ // Iterator with removal
296
+ for (auto It = ItemCounts.CreateIterator(); It; ++It)
297
+ {
298
+ if (It.Value() <= 0)
299
+ {
300
+ It.RemoveCurrent();
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### Memory & Performance Notes
306
+
307
+ - TMap uses a hash table with open addressing on a sparse array. Iteration visits only live pairs (no gaps for the user).
308
+ - Keys must implement `GetTypeHash()` and `operator==`. FName, FString, int32, FGuid, etc. are supported out of the box.
309
+ - `Reserve` before bulk-adding: `WeaponDamage.Reserve(64)`.
310
+ - `TMap::Empty(Slack)` clears and reserves `Slack` slots.
311
+ - For read-heavy maps that rarely change, prefer building once then querying.
312
+ - `TMultiMap<K, V>` allows duplicate keys — access with `MultiFind()`.
313
+
314
+ ### Custom Key Hashing
315
+
316
+ ```cpp
317
+ // For custom struct keys, provide GetTypeHash and operator==
318
+ struct FItemKey
319
+ {
320
+ FName Category;
321
+ int32 Tier;
322
+
323
+ bool operator==(const FItemKey& Other) const
324
+ {
325
+ return Category == Other.Category && Tier == Other.Tier;
326
+ }
327
+ };
328
+
329
+ inline uint32 GetTypeHash(const FItemKey& Key)
330
+ {
331
+ return HashCombine(GetTypeHash(Key.Category), GetTypeHash(Key.Tier));
332
+ }
333
+
334
+ TMap<FItemKey, float> ItemValues;
335
+ ```
336
+
337
+ ---
338
+
339
+ ## TSet
340
+
341
+ `TSet<T>` is a hash set — unique elements, O(1) average operations. Backed by the same sparse array as TMap (without values).
342
+
343
+ ### Core Operations
344
+
345
+ ```cpp
346
+ TSet<FName> Tags;
347
+
348
+ // Add
349
+ Tags.Add(FName("Flying"));
350
+ Tags.Add(FName("Aquatic"));
351
+ Tags.Add(FName("Flying")); // No-op — already present
352
+
353
+ // Contains
354
+ bool bFlying = Tags.Contains(FName("Flying")); // true
355
+
356
+ // Remove
357
+ Tags.Remove(FName("Aquatic"));
358
+
359
+ // Num / IsEmpty
360
+ int32 Count = Tags.Num();
361
+
362
+ // Reserve
363
+ Tags.Reserve(32);
364
+ ```
365
+
366
+ ### Set Operations
367
+
368
+ ```cpp
369
+ TSet<FName> A = { FName("Fire"), FName("Ice"), FName("Wind") };
370
+ TSet<FName> B = { FName("Ice"), FName("Wind"), FName("Earth") };
371
+
372
+ TSet<FName> Intersection = A.Intersect(B); // { Ice, Wind }
373
+ TSet<FName> Union = A.Union(B); // { Fire, Ice, Wind, Earth }
374
+ TSet<FName> Difference = A.Difference(B); // { Fire }
375
+
376
+ bool bSubset = B.Includes(A); // false (A has Fire which B doesn't)
377
+ ```
378
+
379
+ ### Iteration
380
+
381
+ ```cpp
382
+ TSet<FName> Tags;
383
+
384
+ for (const FName& Tag : Tags)
385
+ {
386
+ UE_LOG(LogTemp, Log, TEXT("Tag: %s"), *Tag.ToString());
387
+ }
388
+
389
+ // Iterator with removal
390
+ for (auto It = Tags.CreateIterator(); It; ++It)
391
+ {
392
+ if (It->IsNone())
393
+ {
394
+ It.RemoveCurrent();
395
+ }
396
+ }
397
+ ```
398
+
399
+ ---
400
+
401
+ ## TOptional
402
+
403
+ `TOptional<T>` represents a value that may or may not be present. Avoids sentinel values like `-1` or `nullptr`.
404
+
405
+ ```cpp
406
+ TOptional<int32> MaybeLevel;
407
+
408
+ // Check and access
409
+ if (MaybeLevel.IsSet())
410
+ {
411
+ int32 Level = MaybeLevel.GetValue(); // Asserts if not set
412
+ }
413
+
414
+ // Safe access with default
415
+ int32 Level = MaybeLevel.Get(1); // Returns 1 if not set
416
+
417
+ // Set
418
+ MaybeLevel = 5;
419
+
420
+ // Reset (clear)
421
+ MaybeLevel.Reset();
422
+
423
+ // IsSet shorthand in conditions
424
+ if (MaybeLevel.IsSet() && MaybeLevel.GetValue() > 10)
425
+ {
426
+ // ...
427
+ }
428
+
429
+ // Return from function
430
+ TOptional<FVector> FindSpawnPoint(const FString& ZoneName)
431
+ {
432
+ if (ZoneName.IsEmpty()) return {}; // NullOpt
433
+ return FVector(100.f, 200.f, 0.f);
434
+ }
435
+
436
+ if (TOptional<FVector> Pt = FindSpawnPoint(TEXT("Start")))
437
+ {
438
+ SpawnAt(Pt.GetValue());
439
+ }
440
+ ```
441
+
442
+ ---
443
+
444
+ ## TVariant
445
+
446
+ `TVariant<T1, T2, ...>` is a type-safe discriminated union (like `std::variant`).
447
+
448
+ ```cpp
449
+ #include "Misc/TVariant.h"
450
+
451
+ TVariant<int32, float, FString> Val;
452
+
453
+ // Set
454
+ Val.Set<int32>(42);
455
+ Val.Set<FString>(TEXT("Hello"));
456
+
457
+ // Check active type
458
+ if (Val.IsType<FString>())
459
+ {
460
+ FString& S = Val.Get<FString>();
461
+ }
462
+
463
+ // Visit pattern — UE5 provides Visit() via TVariantHelper
464
+ Visit([](auto& V) { /* handle each type */ }, Val);
465
+ ```
466
+
467
+ ---
468
+
469
+ ## Sparse Arrays & Indirect Arrays
470
+
471
+ ### TSparseArray
472
+
473
+ Used internally by TSet and TMap. Elements can have "holes" (removed indices remain allocated but invalid). Access by `FSetElementId`.
474
+
475
+ ```cpp
476
+ // Rarely used directly — prefer TSet/TMap
477
+ TSparseArray<FMyStruct> SparseData;
478
+ FSparseArrayAllocationInfo AllocInfo = SparseData.AddUninitialized();
479
+ new (AllocInfo.Pointer) FMyStruct();
480
+ ```
481
+
482
+ ### TIndirectArray
483
+
484
+ Holds heap-allocated objects; owns and deletes them on removal.
485
+
486
+ ```cpp
487
+ TIndirectArray<FMyNonCopyable> Objects;
488
+ Objects.Add(new FMyNonCopyable());
489
+ // Objects deletes all entries on destruction
490
+ ```
491
+
492
+ ---
493
+
494
+ ## UPROPERTY-Compatible Container Rules
495
+
496
+ When containers are UPROPERTY members:
497
+
498
+ - `TArray<UPROPERTY-type>` — fully supported, GC-tracked element pointers
499
+ - `TMap<UPROPERTY-type, UPROPERTY-type>` — supported
500
+ - `TSet<UPROPERTY-type>` — supported
501
+ - **Keys in TMap UPROPERTY must be value types** (no UObject* keys)
502
+ - `TArray<TArray<T>>` — **not supported** as UPROPERTY (use a wrapper struct)
503
+ - Containers of raw pointers **without UPROPERTY** are invisible to GC
504
+
505
+ ```cpp
506
+ // Correct: TArray of TObjectPtr for UE5 GC-tracked arrays
507
+ UPROPERTY()
508
+ TArray<TObjectPtr<UMyObject>> ManagedObjects;
509
+
510
+ // Correct: TMap with value-type key and UObject ptr value
511
+ UPROPERTY()
512
+ TMap<FName, TObjectPtr<UDataAsset>> AssetRegistry;
513
+
514
+ // WRONG: nested TArray as UPROPERTY
515
+ UPROPERTY()
516
+ TArray<TArray<int32>> Matrix; // Compile error
517
+
518
+ // WORKAROUND: wrap inner array
519
+ USTRUCT(BlueprintType)
520
+ struct FIntRow { GENERATED_BODY() UPROPERTY() TArray<int32> Values; };
521
+
522
+ UPROPERTY()
523
+ TArray<FIntRow> Matrix;
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Performance Comparison
529
+
530
+ | Operation | TArray | TMap | TSet |
531
+ |-----------|--------|------|------|
532
+ | Add | O(1) amortized | O(1) amortized | O(1) amortized |
533
+ | Find/Contains | O(n) | O(1) avg | O(1) avg |
534
+ | Remove by value | O(n) | O(1) avg | O(1) avg |
535
+ | Remove by index | O(n) (shift) | — | — |
536
+ | Iteration | O(n), cache-friendly | O(n), sparse | O(n), sparse |
537
+ | Sorted iteration | Sort first: O(n log n) | No | No |
538
+ | Memory | Compact contiguous | Sparse + hash table | Sparse + hash table |
539
+
540
+ **Guidelines:**
541
+ - Use `TArray` when: ordered, index-based access, frequent iteration, small N.
542
+ - Use `TMap` when: key-based lookup, O(1) find matters, order irrelevant.
543
+ - Use `TSet` when: uniqueness enforced, fast membership test, no associated value needed.
544
+ - Consider `TArray` + `Sort` + binary search for read-heavy sorted lookups.