Claude
Skills
Sign in
Back

ue-networking-replication

Included with Lifetime
$97 forever

Use this skill when working on multiplayer networking, replication, RPC calls, net role logic, server/client authority, prediction, or synchronizing game state. Also use when the user mentions 'DOREPLIFETIME', 'dedicated server', 'replicated', or 'net role'. See references/replication-patterns.md for common patterns and references/rpc-decision-guide.md for RPC type selection. For GAS networking, see ue-gameplay-abilities.

General

What this skill does


# UE Networking & Replication

You are an expert in Unreal Engine's networking and replication systems.

## Context Check

Read `.agents/ue-project-context.md` for this project's multiplayer configuration.
Look for: server topology (dedicated, listen, P2P), player count, replicated classes,
and any custom net drivers.

If the context file is absent, ask:
1. Server topology? (dedicated, listen, P2P)
2. Maximum player count per session?
3. Which actors or components need to replicate data?
4. Are you using Gameplay Ability System (GAS)?

---

## Net Roles and Authority

UE uses a server-authoritative model: the server is the source of truth for game state.
Clients predict locally and reconcile with server corrections.

Every actor on every machine has a local role and a remote role (`ENetRole`).

```
ROLE_Authority       — owns and can modify this actor (server for replicated actors)
ROLE_AutonomousProxy — client copy of the locally controlled pawn
ROLE_SimulatedProxy  — client copy of another player's actor; engine interpolates state
ROLE_None            — not replicated
```

From `Actor.h`:
```cpp
ENetRole GetLocalRole() const { return Role; }   // role on current machine
ENetRole GetRemoteRole() const;                   // role the other end sees
bool HasAuthority() const { return (GetLocalRole() == ROLE_Authority); }
```

Net modes: `NM_Standalone`, `NM_DedicatedServer`, `NM_ListenServer`, `NM_Client`.

**Role matrix for a replicated Pawn:**

| Machine        | GetLocalRole()       | GetRemoteRole()                         |
|----------------|----------------------|-----------------------------------------|
| Server         | ROLE_Authority       | ROLE_AutonomousProxy or SimulatedProxy  |
| Owning Client  | ROLE_AutonomousProxy | ROLE_Authority                          |
| Other Clients  | ROLE_SimulatedProxy  | ROLE_Authority                          |

**Listen-server caveat:** the host is both `ROLE_Authority` and locally controlled.
Use `IsLocallyControlled()` to distinguish logic that should skip the host player.

---

## UNetDriver

`UNetDriver` is the core transport class responsible for managing all network connections and
packet delivery for a world. It owns the list of `UNetConnection` objects and drives the
replication tick. Access it via `UWorld::GetNetDriver()`.

```cpp
UNetDriver* Driver = GetWorld()->GetNetDriver();
// Driver->ClientConnections  — all connected clients (server-side)
// Driver->ServerConnection   — connection to server (client-side)
```

For most gameplay code you never interact with `UNetDriver` directly; it is relevant when
writing custom net drivers, profiling connection state, or debugging packet loss.

---

## Property Replication

### Actor Setup

```cpp
AMyActor::AMyActor()
{
    bReplicates = true;             // AActor::SetReplicates() also available at runtime
    SetReplicateMovement(true);     // replicates FRepMovement (location/rotation/velocity)
    SetNetUpdateFrequency(10.f);    // checks per second
    SetMinNetUpdateFrequency(2.f);  // floor when nothing changes
    NetPriority = 1.0f;            // higher = preferred when bandwidth is saturated
}
```

From `Actor.h`: `SetReplicates`, `SetReplicateMovement`, `SetNetUpdateFrequency`,
`SetMinNetUpdateFrequency`, and `SetNetCullDistanceSquared` are all `ENGINE_API`.

**FRepMovement:** when `bReplicateMovement = true`, the engine serializes position,
velocity, and rotation into an `FRepMovement` struct (declared in `Actor.h`) and
sends it to simulated proxies. `UCharacterMovementComponent` bypasses this with its
own prediction-based replication; it writes compressed moves via `FSavedMove_Character`
and reconciles them server-side, so `SetReplicateMovement(false)` is the correct
default for characters using CMC.

### Declaring Properties

```cpp
UPROPERTY(Replicated)
int32 Health;

UPROPERTY(ReplicatedUsing = OnRep_State)
EMyState State;

UFUNCTION()
void OnRep_State(EMyState PreviousState); // old value passed as optional parameter
```

### GetLifetimeReplicatedProps

```cpp
// MyActor.cpp
#include "Net/UnrealNetwork.h"

void AMyActor::GetLifetimeReplicatedProps(
    TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps); // NEVER omit this
    DOREPLIFETIME(AMyActor, Health);
    DOREPLIFETIME_CONDITION(AMyActor, State,        COND_OwnerOnly);
    DOREPLIFETIME_CONDITION(AMyActor, SimData,      COND_SimulatedOnly);
    DOREPLIFETIME_CONDITION(AMyActor, InitData,     COND_InitialOnly);
    DOREPLIFETIME_CONDITION(AMyActor, PublicData,   COND_SkipOwner);
}
```

**Conditions:** `COND_None` (all), `COND_OwnerOnly`, `COND_SkipOwner`,
`COND_SimulatedOnly`, `COND_AutonomousOnly`, `COND_InitialOnly`, `COND_Custom`.

Use `COND_OwnerOnly` for private player data (inventory, currency).
Use `COND_InitialOnly` for immutable spawn data (team, character class).

**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.

### FRepLayout (Internal)

`FRepLayout` is an internal engine struct that describes which properties of a class are
replicated and how. It handles delta compression (only changed properties are sent) and
evaluates `DOREPLIFETIME_CONDITION` filters per-connection. Developers rarely interact
with `FRepLayout` directly, but knowing it exists helps when debugging why a property is
or is not replicating: the layout is built once per class and cached, so dynamic changes
to conditions require `DOREPLIFETIME_WITH_PARAMS_FAST` or `bIsPushBased` patterns rather
than modifying the struct at runtime.

### Large Arrays: FFastArraySerializer

Plain `TArray` sends the full array on any change. Use `FFastArraySerializer` for
delta-only replication. See `references/replication-patterns.md` Pattern 3 for
a complete inventory implementation.

### Custom Struct Serialization

Implement `NetSerialize` on a `USTRUCT` and add `TStructOpsTypeTraits` with
`WithNetSerializer = true` to control binary layout manually. Use
`FVector_NetQuantize10` (0.1 cm precision) instead of raw `FVector` to halve
position bandwidth.

---

## Remote Procedure Calls (RPCs)

See `references/rpc-decision-guide.md` for the full decision flowchart.

```cpp
// Client calls → server executes. WithValidation is required for state changes.
UFUNCTION(Server, Reliable, WithValidation)
void ServerFireWeapon(FVector_NetQuantize Origin, FVector_NetQuantizeNormal Dir);

// Server calls → owning client executes. No WithValidation needed.
UFUNCTION(Client, Reliable)
void ClientShowKillConfirm();

// Server calls → server + all clients execute.
UFUNCTION(NetMulticast, Unreliable)
void MulticastPlayHitEffect(FVector ImpactPoint);
```

Implementations always end in `_Implementation`. Server RPCs with validation also
need `_Validate` (return `false` to kick the client).

**Reliable** — guaranteed delivery; use for state-changing actions (purchase, spawn,
possession). **Unreliable** — fire-and-forget; use for high-frequency cosmetics.

Real examples from `PlayerController.h`:
```cpp
UFUNCTION(unreliable, server, WithValidation) void ServerSetSpectatorLocation(...);
UFUNCTION(reliable,   server, WithValidation) void ServerAcknowledgePossession(APawn* P);
UFUNCTION(Reliable,   Client)                 void ClientReceiveLocalizedMessage(...);
UFUNCTION(Client,     Unreliable)             void ClientAckTimeDilation(float, int32);
```

**RPC ownership:** Server RPCs must be called on an actor whose ownership chain
leads to the calling client's `APlayerController`. Client RPCs must be called on
an actor owned by a player with a `NetConnection`. Calls on unowned actors are
silently dropped.

**RPC Parameter Rules**: Only net-addressable types are valid — basic types (`int32`,

Related in General