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,452 @@
1
+ ---
2
+ name: ue-networking-replication
3
+ description: "Multiplayer networking, replication, RPCs, net roles, server/client authority"
4
+ category: "gamedev"
5
+ argument-hint: "[system o property]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Networking & Replication
11
+
12
+ You are an expert in Unreal Engine's networking and replication systems.
13
+
14
+ Ask before writing: this skill edits replicated properties, RPCs and net serialization code. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context Check
17
+
18
+ Read `docs/unreal/project-context.md` for this project's multiplayer configuration.
19
+ Look for: server topology (dedicated, listen, P2P), player count, replicated classes,
20
+ and any custom net drivers.
21
+
22
+ If the context file is absent, ask:
23
+ 1. Server topology? (dedicated, listen, P2P)
24
+ 2. Maximum player count per session?
25
+ 3. Which actors or components need to replicate data?
26
+ 4. Are you using Gameplay Ability System (GAS)?
27
+
28
+ ---
29
+
30
+ ## Net Roles and Authority
31
+
32
+ UE uses a server-authoritative model: the server is the source of truth for game state.
33
+ Clients predict locally and reconcile with server corrections.
34
+
35
+ Every actor on every machine has a local role and a remote role (`ENetRole`).
36
+
37
+ ```
38
+ ROLE_Authority — owns and can modify this actor (server for replicated actors)
39
+ ROLE_AutonomousProxy — client copy of the locally controlled pawn
40
+ ROLE_SimulatedProxy — client copy of another player's actor; engine interpolates state
41
+ ROLE_None — not replicated
42
+ ```
43
+
44
+ From `Actor.h`:
45
+ ```cpp
46
+ ENetRole GetLocalRole() const { return Role; } // role on current machine
47
+ ENetRole GetRemoteRole() const; // role the other end sees
48
+ bool HasAuthority() const { return (GetLocalRole() == ROLE_Authority); }
49
+ ```
50
+
51
+ Net modes: `NM_Standalone`, `NM_DedicatedServer`, `NM_ListenServer`, `NM_Client`.
52
+
53
+ **Role matrix for a replicated Pawn:**
54
+
55
+ | Machine | GetLocalRole() | GetRemoteRole() |
56
+ |----------------|----------------------|-----------------------------------------|
57
+ | Server | ROLE_Authority | ROLE_AutonomousProxy or SimulatedProxy |
58
+ | Owning Client | ROLE_AutonomousProxy | ROLE_Authority |
59
+ | Other Clients | ROLE_SimulatedProxy | ROLE_Authority |
60
+
61
+ **Listen-server caveat:** the host is both `ROLE_Authority` and locally controlled.
62
+ Use `IsLocallyControlled()` to distinguish logic that should skip the host player.
63
+
64
+ ---
65
+
66
+ ## UNetDriver
67
+
68
+ `UNetDriver` is the core transport class responsible for managing all network connections and
69
+ packet delivery for a world. It owns the list of `UNetConnection` objects and drives the
70
+ replication tick. Access it via `UWorld::GetNetDriver()`.
71
+
72
+ ```cpp
73
+ UNetDriver* Driver = GetWorld()->GetNetDriver();
74
+ // Driver->ClientConnections — all connected clients (server-side)
75
+ // Driver->ServerConnection — connection to server (client-side)
76
+ ```
77
+
78
+ For most gameplay code you never interact with `UNetDriver` directly; it is relevant when
79
+ writing custom net drivers, profiling connection state, or debugging packet loss.
80
+
81
+ ---
82
+
83
+ ## Property Replication
84
+
85
+ ### Actor Setup
86
+
87
+ ```cpp
88
+ AMyActor::AMyActor()
89
+ {
90
+ bReplicates = true; // AActor::SetReplicates() also available at runtime
91
+ SetReplicateMovement(true); // replicates FRepMovement (location/rotation/velocity)
92
+ SetNetUpdateFrequency(10.f); // checks per second
93
+ SetMinNetUpdateFrequency(2.f); // floor when nothing changes
94
+ NetPriority = 1.0f; // higher = preferred when bandwidth is saturated
95
+ }
96
+ ```
97
+
98
+ From `Actor.h`: `SetReplicates`, `SetReplicateMovement`, `SetNetUpdateFrequency`,
99
+ `SetMinNetUpdateFrequency`, and `SetNetCullDistanceSquared` are all `ENGINE_API`.
100
+
101
+ **FRepMovement:** when `bReplicateMovement = true`, the engine serializes position,
102
+ velocity, and rotation into an `FRepMovement` struct (declared in `Actor.h`) and
103
+ sends it to simulated proxies. `UCharacterMovementComponent` bypasses this with its
104
+ own prediction-based replication; it writes compressed moves via `FSavedMove_Character`
105
+ and reconciles them server-side, so `SetReplicateMovement(false)` is the correct
106
+ default for characters using CMC.
107
+
108
+ ### Declaring Properties
109
+
110
+ ```cpp
111
+ UPROPERTY(Replicated)
112
+ int32 Health;
113
+
114
+ UPROPERTY(ReplicatedUsing = OnRep_State)
115
+ EMyState State;
116
+
117
+ UFUNCTION()
118
+ void OnRep_State(EMyState PreviousState); // old value passed as optional parameter
119
+ ```
120
+
121
+ ### GetLifetimeReplicatedProps
122
+
123
+ ```cpp
124
+ // MyActor.cpp
125
+ #include "Net/UnrealNetwork.h"
126
+
127
+ void AMyActor::GetLifetimeReplicatedProps(
128
+ TArray<FLifetimeProperty>& OutLifetimeProps) const
129
+ {
130
+ Super::GetLifetimeReplicatedProps(OutLifetimeProps); // NEVER omit this
131
+ DOREPLIFETIME(AMyActor, Health);
132
+ DOREPLIFETIME_CONDITION(AMyActor, State, COND_OwnerOnly);
133
+ DOREPLIFETIME_CONDITION(AMyActor, SimData, COND_SimulatedOnly);
134
+ DOREPLIFETIME_CONDITION(AMyActor, InitData, COND_InitialOnly);
135
+ DOREPLIFETIME_CONDITION(AMyActor, PublicData, COND_SkipOwner);
136
+ }
137
+ ```
138
+
139
+ **Conditions:** `COND_None` (all), `COND_OwnerOnly`, `COND_SkipOwner`,
140
+ `COND_SimulatedOnly`, `COND_AutonomousOnly`, `COND_InitialOnly`, `COND_Custom`.
141
+
142
+ Use `COND_OwnerOnly` for private player data (inventory, currency).
143
+ Use `COND_InitialOnly` for immutable spawn data (team, character class).
144
+
145
+ **Initial replication burst**: When a client first joins or an actor first becomes relevant, ALL replicated properties send at once regardless of conditions (`COND_InitialOnly` fires exactly once here). This burst can saturate the actor channel — keep initial state compact and use `COND_InitialOnly` for spawn-time-only data to reduce ongoing bandwidth.
146
+
147
+ ### FRepLayout (Internal)
148
+
149
+ `FRepLayout` is an internal engine struct that describes which properties of a class are
150
+ replicated and how. It handles delta compression (only changed properties are sent) and
151
+ evaluates `DOREPLIFETIME_CONDITION` filters per-connection. Developers rarely interact
152
+ with `FRepLayout` directly, but knowing it exists helps when debugging why a property is
153
+ or is not replicating: the layout is built once per class and cached, so dynamic changes
154
+ to conditions require `DOREPLIFETIME_WITH_PARAMS_FAST` or `bIsPushBased` patterns rather
155
+ than modifying the struct at runtime.
156
+
157
+ ### Large Arrays: FFastArraySerializer
158
+
159
+ Plain `TArray` sends the full array on any change. Use `FFastArraySerializer` for
160
+ delta-only replication. See `references/replication-patterns.md` Pattern 3 for
161
+ a complete inventory implementation.
162
+
163
+ ### Custom Struct Serialization
164
+
165
+ Implement `NetSerialize` on a `USTRUCT` and add `TStructOpsTypeTraits` with
166
+ `WithNetSerializer = true` to control binary layout manually. Use
167
+ `FVector_NetQuantize10` (0.1 cm precision) instead of raw `FVector` to halve
168
+ position bandwidth.
169
+
170
+ ---
171
+
172
+ ## Remote Procedure Calls (RPCs)
173
+
174
+ See `references/rpc-decision-guide.md` for the full decision flowchart.
175
+
176
+ ```cpp
177
+ // Client calls → server executes. WithValidation is required for state changes.
178
+ UFUNCTION(Server, Reliable, WithValidation)
179
+ void ServerFireWeapon(FVector_NetQuantize Origin, FVector_NetQuantizeNormal Dir);
180
+
181
+ // Server calls → owning client executes. No WithValidation needed.
182
+ UFUNCTION(Client, Reliable)
183
+ void ClientShowKillConfirm();
184
+
185
+ // Server calls → server + all clients execute.
186
+ UFUNCTION(NetMulticast, Unreliable)
187
+ void MulticastPlayHitEffect(FVector ImpactPoint);
188
+ ```
189
+
190
+ Implementations always end in `_Implementation`. Server RPCs with validation also
191
+ need `_Validate` (return `false` to kick the client).
192
+
193
+ **Reliable** — guaranteed delivery; use for state-changing actions (purchase, spawn,
194
+ possession). **Unreliable** — fire-and-forget; use for high-frequency cosmetics.
195
+
196
+ Real examples from `PlayerController.h`:
197
+ ```cpp
198
+ UFUNCTION(unreliable, server, WithValidation) void ServerSetSpectatorLocation(...);
199
+ UFUNCTION(reliable, server, WithValidation) void ServerAcknowledgePossession(APawn* P);
200
+ UFUNCTION(Reliable, Client) void ClientReceiveLocalizedMessage(...);
201
+ UFUNCTION(Client, Unreliable) void ClientAckTimeDilation(float, int32);
202
+ ```
203
+
204
+ **RPC ownership:** Server RPCs must be called on an actor whose ownership chain
205
+ leads to the calling client's `APlayerController`. Client RPCs must be called on
206
+ an actor owned by a player with a `NetConnection`. Calls on unowned actors are
207
+ silently dropped.
208
+
209
+ **RPC Parameter Rules**: Only net-addressable types are valid — basic types (`int32`,
210
+ `float`, `FString`, `FVector`), replicated `UObject*` pointers (arrive as `nullptr`
211
+ if not replicated), and `USTRUCT(BlueprintType)` structs. Non-replicated `UObject*`
212
+ pointers arrive as `nullptr`; pass an ID and look the object up on the remote side.
213
+ Large payloads (>1 KB) should use replicated properties instead of RPC parameters.
214
+ `TArray` and `TMap` parameters are supported but watch for bandwidth impact.
215
+
216
+ ---
217
+
218
+ ## Ownership and Relevancy
219
+
220
+ ```cpp
221
+ // Server sets owner to control connection routing for RPCs and COND_OwnerOnly
222
+ Weapon->SetOwner(PlayerController);
223
+
224
+ // Relevancy flags (from Actor.h)
225
+ bAlwaysRelevant = true; // replicate to every connection
226
+ bOnlyRelevantToOwner = true; // replicate only to the owning connection
227
+
228
+ // Override for custom logic (e.g., team-based relevancy)
229
+ virtual bool IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget,
230
+ const FVector& SrcLocation) const override;
231
+ ```
232
+
233
+ Default relevancy culls actors beyond `NetCullDistanceSquared` from the client
234
+ viewpoint. `NetPriority` determines which actors win when bandwidth is saturated.
235
+
236
+ **Dormancy:** actors that rarely change can pause replication entirely.
237
+
238
+ ```cpp
239
+ SetNetDormancy(DORM_DormantAll); // stop replication
240
+ FlushNetDormancy(); // send one update then return to dormant
241
+ ```
242
+
243
+ **Re-relevancy**: When an actor moves outside `NetCullDistanceSquared` it stops replicating. When it returns to range, the engine treats it as a fresh relevancy event — sending another initial burst and firing all `OnRep_` callbacks with current server state. Design `OnRep_` functions to be idempotent (tolerate being called multiple times with the same value). Dormant actors (`DORM_DormantAll`) behave similarly when woken — they flush all dirty properties at once.
244
+
245
+ ---
246
+
247
+ ## Subobject Replication
248
+
249
+ ### Modern API (UE 5.1+)
250
+
251
+ From `Actor.h`:
252
+ ```cpp
253
+ ENGINE_API void AddReplicatedSubObject(UObject* SubObject,
254
+ ELifetimeCondition NetCondition = COND_None);
255
+ ENGINE_API void RemoveReplicatedSubObject(UObject* SubObject);
256
+ ENGINE_API void AddActorComponentReplicatedSubObject(UActorComponent* OwnerComponent,
257
+ UObject* SubObject,
258
+ ELifetimeCondition NetCondition = COND_None);
259
+ ```
260
+
261
+ Enable with `bReplicateUsingRegisteredSubObjectList = true` (now the default).
262
+ Call `AddReplicatedSubObject` on the server during `BeginPlay`; call
263
+ `RemoveReplicatedSubObject` in `EndPlay`.
264
+
265
+ ### Legacy API
266
+
267
+ Override `ReplicateSubobjects` when `bReplicateUsingRegisteredSubObjectList = false`:
268
+
269
+ ```cpp
270
+ bool AMyActor::ReplicateSubobjects(UActorChannel* Channel,
271
+ FOutBunch* Bunch, FReplicationFlags* RepFlags)
272
+ {
273
+ bool bWrote = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);
274
+ bWrote |= Channel->ReplicateSubobject(MySubObject, *Bunch, *RepFlags);
275
+ return bWrote;
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Client-Side Prediction
282
+
283
+ Pattern (for non-movement systems without GAS):
284
+
285
+ ```cpp
286
+ // 1. Client predicts immediately
287
+ void AMyCharacter::LocalPredictAbility(int32 AbilityId)
288
+ {
289
+ if (IsLocallyControlled())
290
+ {
291
+ ApplyAbilityEffectLocal(AbilityId); // immediate visual/audio
292
+ ServerActivateAbility(AbilityId); // request server confirmation
293
+ }
294
+ }
295
+
296
+ // 2. Server validates, broadcasts, or corrects
297
+ void AMyCharacter::ServerActivateAbility_Implementation(int32 AbilityId)
298
+ {
299
+ if (CanActivateAbility(AbilityId))
300
+ {
301
+ ApplyAbilityEffectAuthority(AbilityId);
302
+ MulticastAbilityActivated(AbilityId);
303
+ }
304
+ else
305
+ {
306
+ ClientCorrectionAbilityFailed(AbilityId); // roll back client prediction
307
+ }
308
+ }
309
+ ```
310
+
311
+ When the server rejects a prediction, smooth the visual correction to avoid jarring
312
+ snaps: interpolate the actor to the corrected position over 2-3 frames rather than
313
+ teleporting. `UCharacterMovementComponent` handles this automatically via
314
+ `NetworkSmoothingMode` (`Linear`, `Exponential`, or `Disabled`).
315
+
316
+ **CharacterMovementComponent** has full built-in prediction. Extend
317
+ `FSavedMove_Character` and override `PhysCustom` to support custom movement modes.
318
+
319
+ **Prediction eligibility**: Only `UCharacterMovementComponent` and GAS (`UAbilitySystemComponent` with `FPredictionKey`) have engine-managed prediction and rollback. Raw `UPROPERTY(Replicated)` properties have no built-in prediction — if you write them locally before the server confirms, the server's replicated value overwrites the client value with no rollback. For non-CMC/GAS state, use local-only variables for visual prediction and apply the authoritative value in `OnRep_`.
320
+
321
+ **GAS and FPredictionKey:** GAS uses `FPredictionKey` to link client-predicted actions
322
+ with server confirmations. The key is generated on the client (via
323
+ `FPredictionKey::CreateNewPredictionKey`), embedded in the Server RPC, and matched on the
324
+ server when applying `GameplayEffect`s or activating abilities. If the server determines
325
+ the prediction was invalid, every `GameplayEffect` and attribute change tagged with that
326
+ key is automatically rolled back on the client. You do not construct `FPredictionKey`
327
+ manually in most cases; `UAbilitySystemComponent::TryActivateAbility` manages the
328
+ lifecycle. Relevant when writing custom `UGameplayAbility` subclasses that need
329
+ scoped prediction windows (`FScopedPredictionWindow`). See `/ue-gameplay-abilities`
330
+ for the full GAS networking details.
331
+
332
+ ---
333
+
334
+ ## Actor Replication Setup Checklist
335
+
336
+ ```
337
+ [ ] bReplicates = true in constructor
338
+ [ ] SetNetUpdateFrequency / SetMinNetUpdateFrequency set appropriately
339
+ [ ] All UPROPERTY(Replicated) / UPROPERTY(ReplicatedUsing=...) declared
340
+ [ ] GetLifetimeReplicatedProps overridden; Super called first
341
+ [ ] DOREPLIFETIME / DOREPLIFETIME_CONDITION for each property
342
+ [ ] OnRep_ functions declared UFUNCTION() and implemented
343
+ [ ] Server RPCs have WithValidation; _Validate implemented
344
+ [ ] NetMulticast / Client RPCs guarded with HasAuthority() on call site
345
+ [ ] Subobjects registered via AddReplicatedSubObject or ReplicateSubobjects
346
+ [ ] SetOwner() called on server after spawning owned actors
347
+ [ ] DORM_DormantAll set on actors that rarely update
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Replication Graph
353
+
354
+ For large player counts (50+ connections), the default net driver relevancy checks become expensive. `UReplicationGraph` replaces per-connection per-actor relevancy with spatial and policy-based nodes.
355
+
356
+ ```cpp
357
+ // Build.cs: "ReplicationGraph"
358
+ // Project: set ReplicationDriverClassName in DefaultEngine.ini
359
+ // [/Script/OnlineSubsystemUtils.IpNetDriver]
360
+ // ReplicationDriverClassName=/Script/MyGame.MyReplicationGraph
361
+
362
+ UCLASS()
363
+ class UMyReplicationGraph : public UReplicationGraph
364
+ {
365
+ GENERATED_BODY()
366
+ public:
367
+ virtual void InitGlobalActorClassSettings() override;
368
+ virtual void InitGlobalGraphNodes() override;
369
+ virtual void InitConnectionGraphNodes(UNetReplicationGraphConnection* RepGraphConnection) override;
370
+ };
371
+ ```
372
+
373
+ Key node types: `UReplicationGraphNode_GridSpatialization2D` (spatial), `UReplicationGraphNode_AlwaysRelevant` (GameState, managers), `UReplicationGraphNode_AlwaysRelevant_ForConnection` (PlayerController, PlayerState, HUD), `UReplicationGraphNode_ActorList` (custom lists).
374
+
375
+ ---
376
+
377
+ ## Common Mistakes
378
+
379
+ | Mistake | Fix |
380
+ |---------|-----|
381
+ | Modifying state without `HasAuthority()` guard | Add `if (!HasAuthority()) return;` |
382
+ | Server RPC without `WithValidation` — client sends arbitrary values | Add `WithValidation`; validate in `_Validate` |
383
+ | Calling `Client`/`NetMulticast` from the client — silently dropped | Only call from server; guard with `HasAuthority()` |
384
+ | Plain `TArray` on replicated component — full array sent on every change | Use `FFastArraySerializer` |
385
+ | Omitting `Super::GetLifetimeReplicatedProps` — parent properties silently dropped | Always call `Super` first |
386
+ | Passing non-replicated `UObject*` in RPC params — arrives as `nullptr` | Pass an ID; look up object on remote side |
387
+ | Using `NetMulticast` for persistent state — late-joining clients miss it | Use `UPROPERTY(Replicated)` for state |
388
+ | Replicating cosmetic-only properties — increases bandwidth for data clients can compute locally | Only replicate gameplay-critical state; derive visuals client-side |
389
+
390
+ ---
391
+
392
+ ## APlayerController Replication Scope
393
+
394
+ `APlayerController` exists only on the server and the owning client — not on other
395
+ clients. Put data meant for all clients on `APawn` or `APlayerState`.
396
+
397
+ From `PlayerController.h`:
398
+ ```cpp
399
+ // nullptr on local players (server-side); points to the network connection otherwise
400
+ UPROPERTY(DuplicateTransient)
401
+ TObjectPtr<UNetConnection> NetConnection;
402
+ ```
403
+
404
+ **UNetConnection** represents a single client's network connection on the server. Each
405
+ connected client has exactly one `UNetConnection` owned by `UNetDriver`. Retrieve it
406
+ with `APlayerController::GetNetConnection()`. It is used for:
407
+ - Ownership checks: an actor's owning connection determines which client RPCs it can
408
+ receive and which `COND_OwnerOnly` properties it sees.
409
+ - RPC routing: Server RPCs are only accepted from the actor's owning connection.
410
+ - Detecting disconnects: bind to `AGameModeBase::OnLogout` or check
411
+ `NetConnection->GetConnectionState() == USOCK_Closed` (or `IsClosingOrClosed()`) rather than polling `NetConnection` directly.
412
+
413
+ Use `APlayerController` for connection-scoped Client RPCs (HUD updates, voice,
414
+ level streaming notifications). Use `APawn` or `APlayerState` for world-visible state.
415
+
416
+ ---
417
+
418
+ ## Related Skills
419
+
420
+ - `/ue-gameplay-framework` — AGameMode (server-only), AGameState / APlayerState
421
+ (replicated to all), APawn net roles
422
+ - `/ue-gameplay-abilities` — GAS prediction keys, attribute set replication,
423
+ GameplayEffect replication
424
+ - `/ue-cpp-foundations` — UPROPERTY/UFUNCTION macros, module includes
425
+
426
+ ## Reference Files
427
+
428
+ - `references/replication-patterns.md` — health, inventory (FFastArraySerializer),
429
+ ability state, team data, subobject, dormancy, and custom relevancy patterns
430
+ - `references/rpc-decision-guide.md` — Server/Client/NetMulticast decision flowchart,
431
+ Reliable vs Unreliable rules, ownership routing, and common RPC mistakes
432
+
433
+ ---
434
+
435
+ ## Checklist
436
+
437
+ Validate before considering the work done:
438
+
439
+ - [ ] Every replicated property appears in `GetLifetimeReplicatedProps`
440
+ - [ ] Server RPCs validate all client input; nothing trusts the client
441
+ - [ ] Replication conditions and update frequency were set per property, not left default
442
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
443
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
444
+
445
+ **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.
446
+
447
+ ## Next Steps
448
+
449
+ - `/ue-testing-debugging` — test with multiple clients and simulated latency
450
+ - `/security-audit` — review the client-to-server trust boundary
451
+ - `/code-review` — architectural and quality review of the change
452
+ - `/commit` — conventional commit once the change is verified