ue-networking-replication
Original:🇺🇸 English
Translated
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.
4installs
Added on
NPX Install
npx skill4agent add quodsoler/unreal-engine-skills ue-networking-replicationTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →UE Networking & Replication
You are an expert in Unreal Engine's networking and replication systems.
Context Check
Read for this project's multiplayer configuration.
Look for: server topology (dedicated, listen, P2P), player count, replicated classes,
and any custom net drivers.
.agents/ue-project-context.mdIf the context file is absent, ask:
- Server topology? (dedicated, listen, P2P)
- Maximum player count per session?
- Which actors or components need to replicate data?
- 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 ().
ENetRoleROLE_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 replicatedFrom :
Actor.hcpp
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_StandaloneNM_DedicatedServerNM_ListenServerNM_ClientRole 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 and locally controlled.
Use to distinguish logic that should skip the host player.
ROLE_AuthorityIsLocallyControlled()UNetDriver
UNetDriverUNetConnectionUWorld::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 directly; it is relevant when
writing custom net drivers, profiling connection state, or debugging packet loss.
UNetDriverProperty 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 : , , ,
, and are all .
Actor.hSetReplicatesSetReplicateMovementSetNetUpdateFrequencySetMinNetUpdateFrequencySetNetCullDistanceSquaredENGINE_APIFRepMovement: when , the engine serializes position,
velocity, and rotation into an struct (declared in ) and
sends it to simulated proxies. bypasses this with its
own prediction-based replication; it writes compressed moves via
and reconciles them server-side, so is the correct
default for characters using CMC.
bReplicateMovement = trueFRepMovementActor.hUCharacterMovementComponentFSavedMove_CharacterSetReplicateMovement(false)Declaring Properties
cpp
UPROPERTY(Replicated)
int32 Health;
UPROPERTY(ReplicatedUsing = OnRep_State)
EMyState State;
UFUNCTION()
void OnRep_State(EMyState PreviousState); // old value passed as optional parameterGetLifetimeReplicatedProps
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: (all), , ,
, , , .
COND_NoneCOND_OwnerOnlyCOND_SkipOwnerCOND_SimulatedOnlyCOND_AutonomousOnlyCOND_InitialOnlyCOND_CustomUse for private player data (inventory, currency).
Use for immutable spawn data (team, character class).
COND_OwnerOnlyCOND_InitialOnlyInitial replication burst: When a client first joins or an actor first becomes relevant, ALL replicated properties send at once regardless of conditions ( fires exactly once here). This burst can saturate the actor channel — keep initial state compact and use for spawn-time-only data to reduce ongoing bandwidth.
COND_InitialOnlyCOND_InitialOnlyFRepLayout (Internal)
FRepLayoutDOREPLIFETIME_CONDITIONFRepLayoutDOREPLIFETIME_WITH_PARAMS_FASTbIsPushBasedLarge Arrays: FFastArraySerializer
Plain sends the full array on any change. Use for
delta-only replication. See Pattern 3 for
a complete inventory implementation.
TArrayFFastArraySerializerreferences/replication-patterns.mdCustom Struct Serialization
Implement on a and add with
to control binary layout manually. Use
(0.1 cm precision) instead of raw to halve
position bandwidth.
NetSerializeUSTRUCTTStructOpsTypeTraitsWithNetSerializer = trueFVector_NetQuantize10FVectorRemote Procedure Calls (RPCs)
See for the full decision flowchart.
references/rpc-decision-guide.mdcpp
// 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 . Server RPCs with validation also
need (return to kick the client).
_Implementation_ValidatefalseReliable — guaranteed delivery; use for state-changing actions (purchase, spawn,
possession). Unreliable — fire-and-forget; use for high-frequency cosmetics.
Real examples from :
PlayerController.hcpp
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 . Client RPCs must be called on
an actor owned by a player with a . Calls on unowned actors are
silently dropped.
APlayerControllerNetConnectionRPC Parameter Rules: Only net-addressable types are valid — basic types (,
, , ), replicated pointers (arrive as
if not replicated), and structs. Non-replicated
pointers arrive as ; pass an ID and look the object up on the remote side.
Large payloads (>1 KB) should use replicated properties instead of RPC parameters.
and parameters are supported but watch for bandwidth impact.
int32floatFStringFVectorUObject*nullptrUSTRUCT(BlueprintType)UObject*nullptrTArrayTMapOwnership and Relevancy
cpp
// Server sets owner to control connection routing for RPCs and COND_OwnerOnly
Weapon->SetOwner(PlayerController);
// Relevancy flags (from Actor.h)
bAlwaysRelevant = true; // replicate to every connection
bOnlyRelevantToOwner = true; // replicate only to the owning connection
// Override for custom logic (e.g., team-based relevancy)
virtual bool IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget,
const FVector& SrcLocation) const override;Default relevancy culls actors beyond from the client
viewpoint. determines which actors win when bandwidth is saturated.
NetCullDistanceSquaredNetPriorityDormancy: actors that rarely change can pause replication entirely.
cpp
SetNetDormancy(DORM_DormantAll); // stop replication
FlushNetDormancy(); // send one update then return to dormantRe-relevancy: When an actor moves outside it stops replicating. When it returns to range, the engine treats it as a fresh relevancy event — sending another initial burst and firing all callbacks with current server state. Design functions to be idempotent (tolerate being called multiple times with the same value). Dormant actors () behave similarly when woken — they flush all dirty properties at once.
NetCullDistanceSquaredOnRep_OnRep_DORM_DormantAllSubobject Replication
Modern API (UE 5.1+)
From :
Actor.hcpp
ENGINE_API void AddReplicatedSubObject(UObject* SubObject,
ELifetimeCondition NetCondition = COND_None);
ENGINE_API void RemoveReplicatedSubObject(UObject* SubObject);
ENGINE_API void AddActorComponentReplicatedSubObject(UActorComponent* OwnerComponent,
UObject* SubObject,
ELifetimeCondition NetCondition = COND_None);Enable with (now the default).
Call on the server during ; call
in .
bReplicateUsingRegisteredSubObjectList = trueAddReplicatedSubObjectBeginPlayRemoveReplicatedSubObjectEndPlayLegacy API
Override when :
ReplicateSubobjectsbReplicateUsingRegisteredSubObjectList = falsecpp
bool AMyActor::ReplicateSubobjects(UActorChannel* Channel,
FOutBunch* Bunch, FReplicationFlags* RepFlags)
{
bool bWrote = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);
bWrote |= Channel->ReplicateSubobject(MySubObject, *Bunch, *RepFlags);
return bWrote;
}Client-Side Prediction
Pattern (for non-movement systems without GAS):
cpp
// 1. Client predicts immediately
void AMyCharacter::LocalPredictAbility(int32 AbilityId)
{
if (IsLocallyControlled())
{
ApplyAbilityEffectLocal(AbilityId); // immediate visual/audio
ServerActivateAbility(AbilityId); // request server confirmation
}
}
// 2. Server validates, broadcasts, or corrects
void AMyCharacter::ServerActivateAbility_Implementation(int32 AbilityId)
{
if (CanActivateAbility(AbilityId))
{
ApplyAbilityEffectAuthority(AbilityId);
MulticastAbilityActivated(AbilityId);
}
else
{
ClientCorrectionAbilityFailed(AbilityId); // roll back client prediction
}
}When the server rejects a prediction, smooth the visual correction to avoid jarring
snaps: interpolate the actor to the corrected position over 2-3 frames rather than
teleporting. handles this automatically via
(, , or ).
UCharacterMovementComponentNetworkSmoothingModeLinearExponentialDisabledCharacterMovementComponent has full built-in prediction. Extend
and override to support custom movement modes.
FSavedMove_CharacterPhysCustomPrediction eligibility: Only and GAS ( with ) have engine-managed prediction and rollback. Raw 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 .
UCharacterMovementComponentUAbilitySystemComponentFPredictionKeyUPROPERTY(Replicated)OnRep_GAS and FPredictionKey: GAS uses to link client-predicted actions
with server confirmations. The key is generated on the client (via
), embedded in the Server RPC, and matched on the
server when applying s or activating abilities. If the server determines
the prediction was invalid, every and attribute change tagged with that
key is automatically rolled back on the client. You do not construct
manually in most cases; manages the
lifecycle. Relevant when writing custom subclasses that need
scoped prediction windows (). See
for the full GAS networking details.
FPredictionKeyFPredictionKey::CreateNewPredictionKeyGameplayEffectGameplayEffectFPredictionKeyUAbilitySystemComponent::TryActivateAbilityUGameplayAbilityFScopedPredictionWindowue-gameplay-abilitiesActor Replication Setup Checklist
[ ] bReplicates = true in constructor
[ ] SetNetUpdateFrequency / SetMinNetUpdateFrequency set appropriately
[ ] All UPROPERTY(Replicated) / UPROPERTY(ReplicatedUsing=...) declared
[ ] GetLifetimeReplicatedProps overridden; Super called first
[ ] DOREPLIFETIME / DOREPLIFETIME_CONDITION for each property
[ ] OnRep_ functions declared UFUNCTION() and implemented
[ ] Server RPCs have WithValidation; _Validate implemented
[ ] NetMulticast / Client RPCs guarded with HasAuthority() on call site
[ ] Subobjects registered via AddReplicatedSubObject or ReplicateSubobjects
[ ] SetOwner() called on server after spawning owned actors
[ ] DORM_DormantAll set on actors that rarely updateReplication Graph
For large player counts (50+ connections), the default net driver relevancy checks become expensive. replaces per-connection per-actor relevancy with spatial and policy-based nodes.
UReplicationGraphcpp
// Build.cs: "ReplicationGraph"
// Project: set ReplicationDriverClassName in DefaultEngine.ini
// [/Script/OnlineSubsystemUtils.IpNetDriver]
// ReplicationDriverClassName=/Script/MyGame.MyReplicationGraph
UCLASS()
class UMyReplicationGraph : public UReplicationGraph
{
GENERATED_BODY()
public:
virtual void InitGlobalActorClassSettings() override;
virtual void InitGlobalGraphNodes() override;
virtual void InitConnectionGraphNodes(UNetReplicationGraphConnection* RepGraphConnection) override;
};Key node types: (spatial), (GameState, managers), (PlayerController, PlayerState, HUD), (custom lists).
UReplicationGraphNode_GridSpatialization2DUReplicationGraphNode_AlwaysRelevantUReplicationGraphNode_AlwaysRelevant_ForConnectionUReplicationGraphNode_ActorListCommon Mistakes
| Mistake | Fix |
|---|---|
Modifying state without | Add |
Server RPC without | Add |
Calling | Only call from server; guard with |
Plain | Use |
Omitting | Always call |
Passing non-replicated | Pass an ID; look up object on remote side |
Using | Use |
| Replicating cosmetic-only properties — increases bandwidth for data clients can compute locally | Only replicate gameplay-critical state; derive visuals client-side |
APlayerController Replication Scope
APlayerControllerAPawnAPlayerStateFrom :
PlayerController.hcpp
// nullptr on local players (server-side); points to the network connection otherwise
UPROPERTY(DuplicateTransient)
TObjectPtr<UNetConnection> NetConnection;UNetConnection represents a single client's network connection on the server. Each
connected client has exactly one owned by . Retrieve it
with . It is used for:
UNetConnectionUNetDriverAPlayerController::GetNetConnection()- Ownership checks: an actor's owning connection determines which client RPCs it can
receive and which properties it sees.
COND_OwnerOnly - RPC routing: Server RPCs are only accepted from the actor's owning connection.
- Detecting disconnects: bind to or check
AGameModeBase::OnLogout(orNetConnection->GetConnectionState() == USOCK_Closed) rather than pollingIsClosingOrClosed()directly.NetConnection
Use for connection-scoped Client RPCs (HUD updates, voice,
level streaming notifications). Use or for world-visible state.
APlayerControllerAPawnAPlayerStateRelated Skills
- — AGameMode (server-only), AGameState / APlayerState (replicated to all), APawn net roles
ue-gameplay-framework - — GAS prediction keys, attribute set replication, GameplayEffect replication
ue-gameplay-abilities - — UPROPERTY/UFUNCTION macros, module includes
ue-cpp-foundations
Reference Files
- — health, inventory (FFastArraySerializer), ability state, team data, subobject, dormancy, and custom relevancy patterns
references/replication-patterns.md - — Server/Client/NetMulticast decision flowchart, Reliable vs Unreliable rules, ownership routing, and common RPC mistakes
references/rpc-decision-guide.md