출처: https://youtu.be/JOJP0CvpB8w
Net Mode
- Net Mode는 World의 상태다. 4가지 상태 중 하나여야 한다.
플레이 가능한가? 월드에 권한이 있는가? 다른 사용자를 받을 수 있는가? NM_Standalone O O X NM_DedicatedServer X O O NM_ListenServer O O O NM_Client O X X
- 게임이 시작되면
UGameEngine
가 생기고 그 밑에UGameInstance
와ULocalPlayer
가 생긴다. 그러면 우리는 브라우저에 URL을 통해 해당 게임 서버에 접속할 수 있다. 이 때, Net Mode도 함께 입력해야 한다. 예를 들어, NM_Client라면 게임을 플레이할 수 있지만 월드에 대한 전적인 권한은 가질 수 없다. 만약 DedicatedServer라면ULocalPlayer
는 없다.
Replication System Basics
- 멀티플레이어 게임이 실행되면 언리얼의
Replication System
은 각 인스터스가 가지고 있는UGameInstance
의 싱크를 맞추기 위해 일한다. 이를 위해Replication System
은 3개의 클래스가 필요하다.UNetDriver
: 서버 인스턴스가 시작하면UGameEngine
이 만들어지고 이 때,UNetDriver
는 사용자로부터 접속을 기다릴 수 있도록InitListen()
을 시작한다. 반대로 클라이언트의UNetDriver
의InitListen()
은 서버에게 연결을 요청한다.
UNetConnection
: 만약 서버와 클라이언트 간 연결이 성공하면UNetDriver
는UNetConnection
을 생성한다. 서버는 각 클라이언트의 연결마다UNetConnection
을 유지한다.
UChannel
: 각UNetConnection
은 여러UChannel
을 가진다. 보통UControlChannel
,UVoiceChannel
을 가지고 레플리케이션된 각 엑터마다UActorChannel
을 가진다.
- 즉, 레플리케이션의 기본 단위가 액터가 되는 것이다. 어떤 액터가 모든 클라이언트에 대해 싱크를 맞추기 원한다면
bReplicates = true
라고 해줘야 한다. 그러면 액터에 채널이 할당되고 이를 통해 싱크가 맞춰진다.
Actor Replication
- 레플리케이션된 액터는 3개 요소에 영향을 받게 된다.
- Lifetime: 액터의 생애 주기가 서버와 클라이언트에서 모두 동기화된다. 서버에서 레플리케이션된 액터가 만들어지면 클라이언트에도 만들어진다.
- Property Replication: 레플리케이션에서 실질적인 일꾼. 어떤 프로퍼티가 레플리케이션이라고 지정됐다면 해당 프로퍼티가 변할 때마다 서버는 이를 클라이언트에게도 알려줘서 값을 동기화시킨다.
- RPCs(Remote Procedure Calls): 어떤 함수를
Multicast RPC
로 지정했다면 그 함수를 서버에서 실행시키면 이 함수의 콜이 각 클라이언트의 해당 액터에서 발동한다.- Client RPC: 서버에서 호출하지만 클라이언트에서 실행되는 RPC
- Server RPC: 클라이언트에서 호출하지만 서버에서 실행되는 RPC
Ownership
- 모든 액터는 자신의 Owner를 가지고 있다. 스폰할 때 Owner를 설정해줄 수 있고, 런타임에서
SetOwner()
를 통해 Owner를 바꿀 수 있다.
APlayerController
가 Ownership에서 중요하다. 기본적으로UNetConnection
은 각 플레이어를 의미한다. 그렇기에UNetConnection
은APlayerController
를 소유(own)한다.APlayerController
는APllayerState
와APawn
을 소유한다.
- 예를 들어, 플레이어의 Pawn이 Weapon을 가지고 있다면, 서버는 AWeapon → APawn → APlayerController → UNetconnection이라는 구조를 통해 Weapon의 소유권을 판별한다.
Enabling Actor Replication
SomeActor->SetReplication(true);
를 통해 쉽게 레플리케이션 되도록 설정할 수 있다.
- 당연히 블루프린트나 Details 패널에서도 이를 설정할 수 있고 이는 런타임에서 바꿀 수도 있다.
Relevancy
- Actor의 relevancy는 이 액터가 어느 클라이언트에 레플리케이션돼야 하는지를 의미한다. 만약 always relevant라면 모든 클라이언트에 이에 대한 채널을 가지고 있는 것이다.
- Ownership이 여기서 중요하게 역할한다.
bOnlyRelevantToOwner = true
로 설정할 수 있기 때문이다.
- 기본적으로 Owner가 없는 액터는 렌더링도 안되고 콜리젼도 꺼진다. 이 때,
NetCullDistanceSquared
의 값에 따라 Relevancy가 바뀌어지도록 설정된다.
Update Frequency & Priority
- Frequency가 높을 수록 레플리케이션되는 주기가 짧아진다.
- 이 때, Priority 순으로 줄을 세워서 업데이트를 하고 만약 bandwidth가 넘어버린 액터는 스킵된다. 액터와 가까울 수록 높은 Priority를 가진다.
RPCs in Detail
- 모든 UFUNCTION은 RPC 값을 설정할 수 있다.
- Client RPC: 서버에서 호출하면 Owner에서도 호출된다.
- Server RPC: 클라이언트에서 호출하면 Server에서도 호출된다.
- Multicast RPC: 서버에서 호출하면 모든 Client에서 호출된다.
- 당연히 이때에도 Relevancy를 가지고 있지 않은 Client는 호출받지 않는다. 채널이 없으니까.
- RPC에 Reliable 또는 Unreliable을 붙일 수 있다.
- Unreliable하다면 Bandwidth에 따라 호출이 안될 수도 있다.
- C++ 에서 Server RPC는
_Implementation
이라는 suffix를 붙여 구현한다. 이를 통해 클라이언트에서 실행되는 게 아니라 서버에서 실행되도록 할 수 있다. 또한WithValidation
을 붙이면_Validate
suffix를 붙인 함수를 또 만들 수 있는데, 이를 통해 서버에 보내는 정보가 유효한지 미리 체크할 수 있다.
- 그렇기 때문에 RPC는 좀더 즉각적이고 믿음직하다.
Property Replication in Detail
- RPCs가 즉각적(NOW)이라면 Property Replication은 상황에 따라 발생(Eventually)한다.
- 해당 액터가 Relevancy하다면 업데이트가 진행되고 그렇지 않다면 업데이트가 중지(suspend)된다. 이 또한 Frequency나 Ownership의 영향을 받는다.
// Header UPROPERTY(Replicated, EditAnywhere, ...) int32 SomeProperty; // Cpp // 이 함수에서 어떤 프로퍼티가 어떤 조건에서 레플리케이션돼야 하는지 서술할 수 있다. void ASomeActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty)& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ASomeActor, SomeProperty); // 무조건 레플리케이션한다. DOREPLIFETIME_CONDITION(ASomeActor, SomeProperty, COND_InitialOnly); // 조건에 따라 레플리케이션한다. }
- Replication이 될 때에 Notify가 발생하므로 이에 대해서 훅을 걸어둘 수 있다.
// Header UPROPERTY(ReplicatedUsing=OnRep_SomeProperty, ...) int32 SomeProperty; UFUNCTION() void OnRep_SomeProperty(); // 바인드되어 있는 프로퍼티가 레플리케이션되면 이 함수가 호출된다.
Authority & Role
- 기본적으로 다음과 같이 Role이 정의되어 있지만
enum ENetRole { ROLE_None, ROLE_SimulatedProxy, ROLE_AutonomousProxy, ROLE_Authority };
- 간단히 보자면 둘 중 하나다. Authority가 있는가? 없는가? 이 관점에선
ROLE_Authority
만 Authority를 가지고 있다.
- Authority는
HasAuthority()
를 통해 체크할 수 있는데, 가지고 있는 경우는 4가지다.- GameInstance 가
NM_Standalone
또는NM_DedicatedServer
또는 NM_ListenServer
- GameInstance가
NM_Client
이고 해당 액터가 해당 클라이언트에 의해 만들어졌을 경우
- GameInstance 가
- 만약, 해당 액터에 대해 Authority가 없다면, Role은 보통
ROLE_SimulatedProxy
에 해당한다.
ROLE_AutonomousProxy
는 Player와 관련했을 때 쓰인다.
'Coding > Unreal, C++' 카테고리의 다른 글
[C++ Primer Plus] 2. Setting Out to C++ (0) | 2022.05.26 |
---|---|
[C++ Primer Plus] 1. Getting Started with C++ (0) | 2022.05.24 |
언리얼에서 낮 밤 만들기 (+시간 시스템) (2) | 2022.04.04 |
UE4: Delegate (0) | 2022.03.24 |
#17 Enemy AI: Attack (0) | 2022.03.18 |
Uploaded by Notion2Tistory v1.1.0