Intro
#
- Unreal network system is based on
Server-Client model.
- If developers consider about “Replication”, game can support both singleplayer and multiplayer.
- UE4 Clients can not communicate without Server (p2p is not currently supported)
Struct
#
Network Mode
#
ENetMode
NM_Standalone
- Authoritative : true
- Listening : false
- LocalPlayer : true
NM_DedicatedServer
- Authoritative : true
- Listening : true
- LocalPlayer : false
NM_ListenServer
- Authoritative : true
- Listening : true
- LocalPlayer : true
NM_Client
- Authoritative : false
- Listening : false
- LocalPlayer : true
NM_MAX
Role, RemoteRole
#
ENetRole
ROLE_None
- not related with replication
ROLE_SimulatedProxy
- copy of
ROLE_Authority
- extrapolative-predicted with server values
ROLE_AutonomousProxy
- copy of
ROLE_Authority
- extrapolative-predicted with server values + local functions (e.g. player input)
- currently, only for possessed actor with ownership
ROLE_Authority
- origin
- not available for
NM_Client
currently
ROLE_MAX
Ownership
#
- PlayerController is root of ownership
- Pawn that possessed by PlayerController and Actors owned by the Pawn is owned by the Player
- Subobjects owned by its outer’s owner
- needed for
- Client RPC destination
- replication relevancy
- conditional property replication
COND_OwnerOnly
, COND_InitialOrOwner
, COND_SkipOwner
ROLE_AutonomousProxy
to ROLE_SimulatedProxy
ROLE_AutonomousProxy
is only allowed for owner client
Method
#
Property Replication
#
class ENGINE_API AActor : public UObject
{
UPROPERTY( Replicated ) // originally, it's ReplicatedWith specifier
AActor * Owner;
UPROPERTY(EditDefaultsOnly, ReplicatedUsing=OnRep_ReplicatedMovement, Category=Replication, AdvancedDisplay)
struct FRepMovement ReplicatedMovement;
UFUNCTION()
virtual void OnRep_ReplicatedMovement();
};
void AActor::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const
{
DOREPLIFETIME( AActor, Owner );
DOREPLIFETIME_CONDITION( AActor, ReplicatedMovement, COND_SimulatedOnly );
// check "UnrealNetwork.h" for more variations
}
void AActor::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker )
{
DOREPLIFETIME_ACTIVE_OVERRIDE( AActor, ReplicatedMovement, bReplicateMovement );
}
void AActor::OnRep_ReplicatedMovement() { ... }
- server to client only
- reliable
ELifetimeCondition
COND_None
COND_InitialOnly
COND_OwnerOnly
COND_SkipOwner
COND_SimulatedOnly
COND_AutonomousOnly
COND_SimulatedOrPhysics
COND_InitialOrOwner
COND_Custom
+ SetCustonIsActiveOverride(...)
COND_ReplayOrOwner
COND_ReplayOnly
COND_SimulatedOnlyNoReplay
COND_SimulatedOrPhysicsNoReplay
COND_SkipReplay
COND_Never
COND_Max
NetUpdateFrequency
- and
MinNetUpdateFrequency
for Adaptive Network Frequency
- with
UPROPERTY(replicated)
, UObject references are replicated via FNetworkGUID
- check with
UObject::IsSupportedForNetwork()
- refernce replication occurs in one of them :
- replicated actor
- stably named actor
- replicated component
- stably named component
- UObject from loaded package
- “stably named” means
- existing in both server and client with exactly same name
- actors from package are stably named (not spawned during gameplay)
- components under are stably named
- from package
- added with construction script (static component)
- manually marked (via
UActorComponent::SetNetAddressable(...)
)
Remote Procedure Call (RPC)
#
UFUNCTION(Server, WithValidation)
void FunctionThatCalledOnServer();
UFUNCTION(Client, Reliable)
void FunctionThatCalledOnOwnerClient();
UFUNCTION(NetMulticast)
void FunctionThatCalledOnEveryActor();
void ClassName::FunctionThatCalledOnServer_Implementation() {}
bool ClassName::FunctionThatCalledOnServer_Validation() {return true;}
void ClassName::FunctionThatCalledOnOwnerClient_Implementation() {}
void ClassName::FunctionThatCalledOnEveryActor_Implementation() {}
- Only executed on Actor that is replicating
- If you want to make sure RPC executed. you should set
Reliable
specifier on RPC’s UFUNCTION().- RPC is Unreiiable by default.
- If you spam
Reliable
like every ticks, client may get disconnected due to preventation of DDOS.
WithValidation
specifier declares _Validation
function with bool return and same parameters._Validation
function must be followed after WithValidation
specifier.- disconnect client if return is
false
- execute RPC if return is
true
- Server RPC requires WithValidation
- when calling RPC on Server
actor \ specifier | none | NetMulticast | Server | Client |
---|
Owned by client | server | server & all clients | server | owning client |
Owned by server | server | server & all clients | server | server |
Unowned | server | server & all clients | server | server |
- when calling RPC on Client
actor \ specifier | none | NetMulticast | Server | Client |
---|
Owned by self | self | self | server | self |
Owned by other | self | self | none | self |
Owned by server | self | self | none | self |
Unowned | self | self | none | self |
Component Replication
#
Optimization
#
Relevancy
#
AActor::IsNetRelevantFor()
- return true :
bIsAlwaysRelevant
| Owned | Pawn | Instigated by Pawn - return owner’s :
bNetUseOwnerRelevancy
& Owned - return false :
bOnlyRelevantToOwner
& not 1. - return base’s : attached to skeleton of another actor
- return false :
bHidden
& root component not collide- warning if there is no root component
- return ture : distance based relevancy (AGameNetworkManager) & closer than net cull distance
- Pawn and PlayerController return different result (overriding)
- bStatic Actors can also be replicated
- imperfect
- large actor
- sound occlusion of ambient sound
- though, packet loss is more critical so it’s affordable
Priority
#
NetPriority
- weight for bandwidth load balancing
- default values
- Actor = 1.0
- Matinee = 2.7
- Pawn = 3.0
- PlayerController = 3.0
AActor::GetNetPriority()
= NetPriority
* replication waiting time (plus location and distance, etc)
Dormancy
#
ENetDormancy
DORM_Never
DORM_Awake
DORM_DormantAll
DORM_DormantPartial
+ GetNetDormancy()
DORM_Initial
DORM_Max
NetClientTicksPerSecond
#
Replication Graph
#
Conceptual Tips
#
- reduce bReplicates
- reduce NetUpdateFrequency
- use Dormancy
- use Relevancy
- reduce NetClientTicksPerSecond
- use Quantizing (e.g. FVector_NetQuantize)
- minimize RPC : replace into RepNotify
- remove Server RPC that unused on clients
- reduce NetMulticast RPC
- reduce FName as RPC parameter
- don’t spam reliable RPC
- check
ROLE_Authority
for server logic - check
IsLocallyControlled
for owner logic
Flow
#
UNetDriver::ServerReplicateActors flow
#
Character Movement Component flow
#
Others
#
Travelling
#
- Seamless (non-blocking)
- Non-Seamless (blocking)
- first map loading
- client-to-server first connect
- ending game, starting new game
UEngine::Browse(...)
UWorld::ServerTravel(...)
APlayerController::ClientTravel(...)
- Transition Map
UGameMapSetting::TransitionMap
AGameModeBase::bUseSeamlessTravel
- Seamless Travel Flow
- Mark persistent actors to transition map
- Travel to transition map
- Mark persistent actors to final map
- Travel to final map
- Persistent actors
- GameMode actor (server only)
- Actors added by
AGameModeBase::GetSeamlessTravelActorList
- Controllers with valid PlayerState (server only)
- All PlayerControllers (server only)
- All local PlayerControllers (server and clients)
- Actors added by
APlayerController::GetSeamlessTravelActorList
on local
Online Subsystem
#
Session
#
Online Beacons
#
Practical
#
Network Profiler
#
Testing Multiplay
#