Coding/Unreal, C++

Replication

출처: 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 가 생기고 그 밑에 UGameInstanceULocalPlayer 가 생긴다. 그러면 우리는 브라우저에 URL을 통해 해당 게임 서버에 접속할 수 있다. 이 때, Net Mode도 함께 입력해야 한다. 예를 들어, NM_Client라면 게임을 플레이할 수 있지만 월드에 대한 전적인 권한은 가질 수 없다. 만약 DedicatedServer라면 ULocalPlayer 는 없다.
Replication System Basics
  • 멀티플레이어 게임이 실행되면 언리얼의 Replication System은 각 인스터스가 가지고 있는 UGameInstance 의 싱크를 맞추기 위해 일한다. 이를 위해 Replication System은 3개의 클래스가 필요하다.
    • UNetDriver : 서버 인스턴스가 시작하면 UGameEngine 이 만들어지고 이 때, UNetDriver 는 사용자로부터 접속을 기다릴 수 있도록 InitListen() 을 시작한다. 반대로 클라이언트의 UNetDriverInitListen() 은 서버에게 연결을 요청한다.
    • UNetConnection : 만약 서버와 클라이언트 간 연결이 성공하면 UNetDriverUNetConnection을 생성한다. 서버는 각 클라이언트의 연결마다 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은 각 플레이어를 의미한다. 그렇기에 UNetConnectionAPlayerController소유(own)한다. APlayerControllerAPllayerStateAPawn소유한다.
  • 예를 들어, 플레이어의 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가지다.
    1. GameInstance 가 NM_Standalone 또는 NM_DedicatedServer 또는 NM_ListenServer
    1. GameInstance가 NM_Client이고 해당 액터가 해당 클라이언트에 의해 만들어졌을 경우
  • 만약, 해당 액터에 대해 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