claude-code-arcane 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +131 -41
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +642 -478
- package/docs/SKILLS-CATALOG.md +42 -3
- package/docs/USER-GUIDE.md +28 -54
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -1
- package/profiles/agile.yaml +1 -1
- package/profiles/ai.yaml +1 -1
- package/profiles/android-native.yaml +1 -1
- package/profiles/audio.yaml +1 -1
- package/profiles/backend-dotnet.yaml +1 -1
- package/profiles/backend-go.yaml +1 -1
- package/profiles/backend-nestjs.yaml +1 -1
- package/profiles/backend-nextjs.yaml +1 -1
- package/profiles/backend-ts.yaml +1 -1
- package/profiles/business.yaml +1 -1
- package/profiles/clevel.yaml +1 -1
- package/profiles/clickup.yaml +1 -1
- package/profiles/core.yaml +1 -1
- package/profiles/database.yaml +1 -1
- package/profiles/design.yaml +1 -1
- package/profiles/docs.yaml +1 -1
- package/profiles/ecommerce.yaml +1 -1
- package/profiles/finance.yaml +1 -1
- package/profiles/flutter.yaml +1 -1
- package/profiles/freelance.yaml +1 -1
- package/profiles/frontend.yaml +1 -1
- package/profiles/infra.yaml +1 -1
- package/profiles/integrations.yaml +1 -1
- package/profiles/ios-native.yaml +1 -1
- package/profiles/jira.yaml +1 -1
- package/profiles/job-hunt.yaml +1 -1
- package/profiles/marketing.yaml +1 -1
- package/profiles/mobile.yaml +1 -1
- package/profiles/regulatory.yaml +1 -1
- package/profiles/second-brain.yaml +1 -1
- package/profiles/security.yaml +1 -1
- package/profiles/self-improving.yaml +1 -1
- package/profiles/statusline.yaml +1 -1
- package/profiles/testing.yaml +1 -1
- package/profiles/unity-design.yaml +1 -1
- package/profiles/unity-dev.yaml +1 -1
- package/profiles/unreal-dev.yaml +97 -0
- package/profiles/visual-novel.yaml +1 -1
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/arcane-list/SKILL.md +12 -7
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- 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
|