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,393 @@
1
+ # RPC Decision Guide
2
+
3
+ Reference for choosing the correct RPC type (Server, Client, NetMulticast) and
4
+ reliability level (Reliable, Unreliable) in Unreal Engine multiplayer code.
5
+ All patterns are grounded in real `APlayerController` usage from `PlayerController.h`.
6
+
7
+ ---
8
+
9
+ ## RPC Type Quick Reference
10
+
11
+ | Specifier | Called on | Executes on | Typical use |
12
+ |-----------------|------------|--------------------------|----------------------------------------|
13
+ | `Server` | Client | Server (Authority) | Player input, purchase, ability use |
14
+ | `Client` | Server | Owning client only | UI updates, player-specific feedback |
15
+ | `NetMulticast` | Server | Server + all clients | World effects visible to everyone |
16
+
17
+ ---
18
+
19
+ ## Decision Flowchart
20
+
21
+ ```
22
+ Is this a request from a player to change game state?
23
+ YES --> use Server RPC (client calls, server executes)
24
+ NO --> continue
25
+
26
+ Should this run only on one specific player's machine?
27
+ YES --> use Client RPC (server calls, owning client executes)
28
+ NO --> continue
29
+
30
+ Should this run on the server AND every connected client simultaneously?
31
+ YES --> use NetMulticast RPC (server calls, all machines execute)
32
+ NO --> reconsider: is property replication a better fit?
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Server RPC
38
+
39
+ **Who calls it**: the client (specifically the owning client of the actor).
40
+ **Who executes it**: the server.
41
+ **Primary use**: forwarding player intent to the authoritative machine.
42
+
43
+ All Server RPCs that change game state must include `WithValidation`. This generates
44
+ a `_Validate` function the engine calls before `_Implementation`. Returning `false`
45
+ from `_Validate` kicks the calling client.
46
+
47
+ ```cpp
48
+ // Declaration
49
+ UFUNCTION(Server, Reliable, WithValidation)
50
+ void ServerFireWeapon(FVector_NetQuantize MuzzleLocation,
51
+ FVector_NetQuantizeNormal Direction);
52
+
53
+ // Implementation (.cpp)
54
+ void AMyCharacter::ServerFireWeapon_Implementation(
55
+ FVector_NetQuantize MuzzleLocation,
56
+ FVector_NetQuantizeNormal Direction)
57
+ {
58
+ // Server performs authoritative hit trace
59
+ FHitResult Hit;
60
+ FCollisionQueryParams Params;
61
+ Params.AddIgnoredActor(this);
62
+
63
+ if (GetWorld()->LineTraceSingleByChannel(
64
+ Hit, MuzzleLocation, MuzzleLocation + Direction * 10000.f,
65
+ ECC_Pawn, Params))
66
+ {
67
+ if (AMyCharacter* Victim = Cast<AMyCharacter>(Hit.GetActor()))
68
+ {
69
+ Victim->ApplyDamage_Authority(WeaponDamage);
70
+ }
71
+ }
72
+
73
+ // Spawn bullet tracer effect on all clients
74
+ MulticastSpawnTracer(MuzzleLocation, Hit.ImpactPoint);
75
+ }
76
+
77
+ bool AMyCharacter::ServerFireWeapon_Validate(
78
+ FVector_NetQuantize MuzzleLocation,
79
+ FVector_NetQuantizeNormal Direction)
80
+ {
81
+ // Reject zero directions
82
+ if (Direction.IsNearlyZero()) return false;
83
+ // Reject muzzle locations impossibly far from actor
84
+ if (FVector::Dist(MuzzleLocation, GetActorLocation()) > 500.f) return false;
85
+ return true;
86
+ }
87
+ ```
88
+
89
+ Real examples from `PlayerController.h`:
90
+
91
+ ```cpp
92
+ // Player acknowledges pawn possession — must not be lost, Reliable
93
+ UFUNCTION(reliable, server, WithValidation)
94
+ void ServerAcknowledgePossession(class APawn* P);
95
+
96
+ // Spectator position — sent frequently, OK to drop, Unreliable
97
+ UFUNCTION(unreliable, server, WithValidation)
98
+ void ServerSetSpectatorLocation(FVector NewLoc, FRotator NewRot);
99
+
100
+ // Server restart — must not be dropped, Reliable
101
+ UFUNCTION(reliable, server, WithValidation)
102
+ void ServerRestartPlayer();
103
+
104
+ // Camera update — sent frequently, can be dropped, Unreliable
105
+ UFUNCTION(unreliable, server, WithValidation)
106
+ void ServerUpdateCamera(FVector_NetQuantize CamLoc, int32 CamPitchAndYaw);
107
+ ```
108
+
109
+ ### When to use Reliable vs Unreliable for Server RPCs
110
+
111
+ | Scenario | Reliability |
112
+ |-----------------------------------|--------------|
113
+ | Purchase, ability activation | Reliable |
114
+ | Possession / respawn | Reliable |
115
+ | Player name or setting change | Reliable |
116
+ | Level streaming notification | Reliable |
117
+ | Frequent position / camera update | Unreliable |
118
+ | High-frequency input relay | Unreliable |
119
+
120
+ ---
121
+
122
+ ## Client RPC
123
+
124
+ **Who calls it**: the server.
125
+ **Who executes it**: the owning client of the actor.
126
+ **Primary use**: sending player-specific information or triggering private feedback.
127
+
128
+ `Client` RPCs do not need `WithValidation` — the server already has authority.
129
+
130
+ ```cpp
131
+ // Declaration
132
+ UFUNCTION(Client, Reliable)
133
+ void ClientShowMatchResult(bool bWon, int32 FinalScore);
134
+
135
+ // Implementation
136
+ void AMyPlayerController::ClientShowMatchResult_Implementation(
137
+ bool bWon, int32 FinalScore)
138
+ {
139
+ // Runs only on the owning client — safe to access local UI
140
+ if (UMyHUD* HUD = Cast<UMyHUD>(GetHUD()))
141
+ {
142
+ HUD->ShowMatchResult(bWon, FinalScore);
143
+ }
144
+ }
145
+ ```
146
+
147
+ Real examples from `PlayerController.h`:
148
+
149
+ ```cpp
150
+ // Tell the client it's been muted — Reliable, player must know
151
+ UFUNCTION(Reliable, Client)
152
+ void ClientMutePlayer(FUniqueNetIdRepl PlayerId);
153
+
154
+ // Send a localized message to the owning client — Reliable
155
+ UFUNCTION(Reliable, Client)
156
+ void ClientReceiveLocalizedMessage(TSubclassOf<ULocalMessage> Message,
157
+ int32 Switch,
158
+ APlayerState* RelatedPlayerState_1,
159
+ APlayerState* RelatedPlayerState_2,
160
+ UObject* OptionalObject);
161
+
162
+ // Client spectator waiting state — Reliable, state change must not be lost
163
+ UFUNCTION(client, reliable)
164
+ void ClientSetSpectatorWaiting(bool bWaiting);
165
+
166
+ // Async physics timestamp sync — Reliable, setup data
167
+ UFUNCTION(Client, Reliable)
168
+ void ClientSetupNetworkPhysicsTimestamp(FAsyncPhysicsTimestamp Timestamp);
169
+
170
+ // Time dilation update — Unreliable, continuously corrected
171
+ UFUNCTION(Client, Unreliable)
172
+ void ClientAckTimeDilation(float TimeDilation, int32 ServerStep);
173
+ ```
174
+
175
+ ### When to use Reliable vs Unreliable for Client RPCs
176
+
177
+ | Scenario | Reliability |
178
+ |--------------------------------------------|--------------|
179
+ | UI state change (match result, kill feed) | Reliable |
180
+ | Player kicked / game over notification | Reliable |
181
+ | View target / camera set | Reliable |
182
+ | Sound / haptic triggered by server event | Reliable |
183
+ | Camera time dilation correction | Unreliable |
184
+ | High-frequency positional feedback effect | Unreliable |
185
+
186
+ ---
187
+
188
+ ## NetMulticast RPC
189
+
190
+ **Who calls it**: the server.
191
+ **Who executes it**: the server AND all clients that have this actor replicated to them.
192
+ **Primary use**: cosmetic world events that everyone should see.
193
+
194
+ ```cpp
195
+ // Declaration
196
+ UFUNCTION(NetMulticast, Unreliable)
197
+ void MulticastPlayExplosionEffect(FVector Location, float Radius);
198
+
199
+ // Implementation
200
+ void AMyActor::MulticastPlayExplosionEffect_Implementation(
201
+ FVector Location, float Radius)
202
+ {
203
+ // Runs on server and all clients — guard so server doesn't spawn visual effects
204
+ if (!HasAuthority())
205
+ {
206
+ UGameplayStatics::SpawnEmitterAtLocation(
207
+ GetWorld(), ExplosionFX, Location);
208
+ UGameplayStatics::PlaySoundAtLocation(
209
+ GetWorld(), ExplosionSound, Location);
210
+ }
211
+ // Both server and client: apply physics impulse to overlapping actors
212
+ ApplyExplosionImpulse(Location, Radius);
213
+ }
214
+ ```
215
+
216
+ ### Multicast vs Property Replication
217
+
218
+ Prefer multicast for **one-shot events** (sounds, VFX, transient animations).
219
+ Prefer **property replication** for **persistent state** (health, flags, positions).
220
+
221
+ | Data type | Mechanism |
222
+ |------------------------------------|----------------------------------|
223
+ | Plays once, no recovery needed | NetMulticast (Unreliable) |
224
+ | Plays once, must not be missed | NetMulticast (Reliable) |
225
+ | Persists on clients that join late | UPROPERTY(Replicated) |
226
+ | Different value per client | Client RPC |
227
+
228
+ ---
229
+
230
+ ## Reliable vs Unreliable — Definitive Rules
231
+
232
+ ### Use Reliable when
233
+
234
+ - The action has **permanent game state consequences** (purchase, death, spawn).
235
+ - The receiver must **acknowledge** receipt to proceed (possession, level load).
236
+ - The data is **not redundant** — there is no future update that carries the same info.
237
+ - Dropping the packet would cause a **visible or gameplay-breaking desync**.
238
+
239
+ ### Use Unreliable when
240
+
241
+ - The data is **superseded frequently** by the next tick's update (position, rotation).
242
+ - It is purely **cosmetic** (hit sparks, footstep dust, screenshake).
243
+ - Dropping it produces only a minor visual glitch, not a gameplay error.
244
+ - The RPC is called **very often** (every tick or multiple times per second) — using
245
+ Reliable for high-frequency calls saturates the reliable channel and causes lag spikes.
246
+
247
+ ### Reliable Channel Saturation Warning
248
+
249
+ The reliable channel is a FIFO queue. If too many reliable messages queue up (e.g.,
250
+ a Server Reliable RPC called every frame), the connection will stall waiting for
251
+ acknowledgments. This manifests as rubberbanding and eventually a timeout disconnect.
252
+
253
+ **Rule**: never call a Reliable RPC more than once per server tick per connection.
254
+
255
+ ---
256
+
257
+ ## Ownership Requirement for RPCs
258
+
259
+ RPCs will silently fail (not execute, not error) if the actor does not have a valid
260
+ network connection through its ownership chain.
261
+
262
+ ### Server RPC routing
263
+
264
+ The calling client must own the actor in the chain:
265
+ `APlayerController -> APawn -> AWeapon`
266
+
267
+ ```
268
+ Client calls WeaponActor->ServerFire()
269
+ -> Engine looks up WeaponActor->GetOwner() -> APawn
270
+ -> APawn->GetOwner() -> APlayerController
271
+ -> APlayerController->NetConnection == the calling client connection
272
+ -> RPC is routed correctly
273
+ ```
274
+
275
+ If `WeaponActor->GetOwner()` is `nullptr` or another player's controller, the RPC
276
+ will be dropped on the client. Fix: call `SetOwner(PlayerController)` on the server
277
+ after spawning the weapon.
278
+
279
+ ### Client RPC routing
280
+
281
+ The server must own the actor and it must be associated with a specific player's
282
+ `NetConnection`. This is why most Client RPCs are called on `APlayerController`
283
+ directly:
284
+
285
+ ```cpp
286
+ // Server code — send a message to a specific player
287
+ APlayerController* PC = GetPlayerController(PlayerIndex);
288
+ PC->ClientReceiveLocalizedMessage(Message, Switch, nullptr, nullptr, nullptr);
289
+ ```
290
+
291
+ Calling a Client RPC on an actor with no owning player connection will silently fail.
292
+
293
+ ---
294
+
295
+ ## Common RPC Mistakes
296
+
297
+ ### Calling a Server RPC from the Server
298
+
299
+ A Server RPC called from the server's own code executes locally — the engine
300
+ skips routing. This is not harmful but is misleading and wastes a function call.
301
+ Prefer calling the `_Implementation` function directly from server code if you need
302
+ to invoke the logic without network routing.
303
+
304
+ ```cpp
305
+ // MISLEADING — on the server, this just calls Implementation directly
306
+ ServerDoThing();
307
+
308
+ // CLEAR — explicitly call the implementation when you know you're on the server
309
+ if (HasAuthority())
310
+ {
311
+ ServerDoThing_Implementation(Params);
312
+ }
313
+ ```
314
+
315
+ ### Calling a Client RPC from the Client
316
+
317
+ A Client RPC called from the client is silently ignored — it does not route up to
318
+ the server and back down. If you need to trigger something on the server that then
319
+ responds to the client, use a Server RPC + Client RPC pair.
320
+
321
+ ### Using NetMulticast Instead of Property Replication for State
322
+
323
+ Multicast RPCs are not replayed for clients that join after the call. If a new player
324
+ joins after an explosion, they will not see the aftermath if it was communicated only
325
+ via multicast. Use replicated properties for persistent state.
326
+
327
+ ```cpp
328
+ // WRONG — late-joining clients miss this
329
+ MulticastSetDoorOpen(true);
330
+
331
+ // CORRECT — new clients see the correct state on join
332
+ bDoorOpen = true; // replicated property — MARK_PROPERTY_DIRTY if using Iris
333
+ ```
334
+
335
+ ### Missing WithValidation on Server RPCs That Modify State
336
+
337
+ Any Server RPC that changes game state (inventory, health, abilities) without
338
+ validation is a security hole. Malicious clients can send arbitrary parameter values.
339
+
340
+ ```cpp
341
+ // INSECURE
342
+ UFUNCTION(Server, Reliable)
343
+ void ServerAddItem(int32 ItemId, int32 Quantity); // client can claim any quantity
344
+
345
+ // SECURE
346
+ UFUNCTION(Server, Reliable, WithValidation)
347
+ void ServerRequestPurchase(int32 ItemId); // server looks up price from data tables
348
+ ```
349
+
350
+ ### RPC Parameters Containing Non-Replicated Object Pointers
351
+
352
+ Object pointers in RPC parameters must be net-addressable. Passing a pointer to a
353
+ locally spawned, non-replicated UObject will result in a `nullptr` on the remote side.
354
+
355
+ ```cpp
356
+ // WRONG — LocalEffect is not replicated; remote gets nullptr
357
+ ServerDoThingWithEffect(LocalEffect);
358
+
359
+ // CORRECT — pass a data class reference or an ID, look it up on the remote side
360
+ UFUNCTION(Server, Reliable, WithValidation)
361
+ void ServerActivateEffectById(int32 EffectDataId);
362
+ ```
363
+
364
+ ---
365
+
366
+ ## RPC vs Property Replication Decision
367
+
368
+ | Situation | Preferred mechanism |
369
+ |----------------------------------------------------|--------------------------------------------|
370
+ | Value changes on server, clients just read it | `UPROPERTY(Replicated)` |
371
+ | Value changes, client needs custom callback logic | `UPROPERTY(ReplicatedUsing = OnRep_Func)` |
372
+ | One-shot event, all clients react simultaneously | `NetMulticast` RPC |
373
+ | One-shot event, only one specific client reacts | `Client` RPC |
374
+ | Client requests server to do something | `Server` RPC |
375
+ | Ordering matters AND property replication is lossy | `Client` RPC (as noted in `PlayerController.h` comments) |
376
+ | High-frequency cosmetic (dust, sparks) | `NetMulticast Unreliable` RPC |
377
+ | Late-join clients must see current state | `UPROPERTY(Replicated)` always |
378
+
379
+ ---
380
+
381
+ ## RPC Implementation Naming Convention
382
+
383
+ UE generates the implementation and validation function names automatically from the
384
+ declared function name:
385
+
386
+ | Declared name | Generated names |
387
+ |-------------------------|----------------------------------------------------|
388
+ | `ServerFireWeapon` | `ServerFireWeapon_Implementation`, `ServerFireWeapon_Validate` |
389
+ | `ClientShowResult` | `ClientShowResult_Implementation` |
390
+ | `MulticastPlayEffect` | `MulticastPlayEffect_Implementation` |
391
+
392
+ The `UFUNCTION` macro declaration uses the base name. The body you write is always
393
+ `_Implementation`. Only Server RPCs with `WithValidation` also need `_Validate`.