본문 바로가기

언리얼 엔진 리플리케이션 Replication

@iamrain2025. 10. 24. 09:43

1. 리플리케이션?

리플리케이션은 언리얼 엔진의 핵심적인 네트워크 기능으로, 서버의 게임 상태(액터, 프로퍼티 등) 변화를 클라이언트들에게 자동으로 전파하여 모든 플레이어가 동기화된 월드를 경험하게 만드는 프로세스다. 즉, 서버에서 일어난 일을 클라이언트들에게 "복제"하는 과정이다.

언리얼 엔진은 신뢰성 있는 서버(Authoritative Server) 모델을 채택하고 있는데 게임의 모든 주요 로직과 상태 변화가 서버에서만 발생하며, 서버가 "진실"의 원천임을 의미한다. 클라이언트는 서버로부터 받은 정보를 바탕으로 월드를 렌더링하고, 자신의 입력을 서버로 보내 게임에 영향을 준다. 이 구조는 치팅을 방지하고 모든 플레이어 간의 일관성을 보장하는 데 매우 효과적이다.

2. 리플리케이션의 핵심 구성 요소

2.1. 액터 (Actor) 와 역할 (Role)

리플리케이션의 가장 기본적인 단위는 액터(Actor)다. 리플리케이션되도록 설정된 액터는 네트워크를 통해 서버와 클라이언트 간에 상태를 동기화할 수 있다.

모든 액터는 특정 시점에 해당 액터에 대해 서버와 클라이언트가 어떤 권한을 갖는지를 정의하는 역할(Role)을 가진다

  • Authority (권위): 해당 액터를 완전히 제어할 수 있는 권한. 신뢰성 있는 서버 모델에서, 서버는 항상 모든 리플리케이션된 액터에 대해 Authority를 가진다.
  • Simulated Proxy (시뮬레이션된 프록시): 액터의 움직임이나 애니메이션과 같이 시각적인 부분을 클라이언트 측에서 부드럽게 보간(interpolate)하고 예측(predict)하여 보여주는 역할. 서버로부터 주기적인 업데이트를 받지만, 그 사이의 움직임은 자체적으로 시뮬레이션한다. (예: 다른 플레이어 캐릭터)
  • Autonomous Proxy (자율 프록시): Simulated Proxy와 유사하지만, 플레이어의 직접적인 입력을 받아 예측적으로 움직임을 처리할 수 있는 추가적인 권한을 가진다. (예: 자신이 조종하는 플레이어 캐릭터)

AActor 클래스의 RoleRemoteRole 프로퍼티를 통해 현재 로컬 머신과 원격 머신에서의 역할을 알 수 있다. 예를 들어, 서버에서 특정 액터를 보면 RoleROLE_Authority이고, 해당 액터를 보고 있는 클라이언트의 RemoteRoleROLE_SimulatedProxy 또는 ROLE_AutonomousProxy가 된다.

2.2. 소유권 (Ownership)

소유권은 어떤 클라이언트가 특정 액터에 대해 특별한 권한(주로 RPC 호출)을 갖는지를 결정하는 개념이다. 일반적으로 플레이어 컨트롤러(APlayerController)는 자신이 빙의(possess)한 폰(APawn)을 소유한다. 이 소유권 체인을 통해 플레이어는 자신의 캐릭터에 대한 RPC를 서버로 보낼 수 있다.

3. 리플리케이션의 종류

리플리케이션은 크게 프로퍼티 리플리케이션(Property Replication)함수 리플리케이션(RPC, Remote Procedure Call)으로 나뉜다.

3.1. 프로퍼티 리플리케이션 (Property Replication)

서버에 있는 액터의 UPROPERTY가 변경되었을 때, 그 변경 사항을 클라이언트의 해당 액터 프로퍼티에 자동으로 복제하는 기능이다.

구현 방식:

  1. 헤더 파일 (.h):
    • 리플리케이션할 프로퍼티에 UPROPERTY(Replicated) 또는 UPROPERTY(ReplicatedUsing=FunctionName) 매크로를 추가한다.
    • ReplicatedUsing은 프로퍼티가 리플리케이션될 때 클라이언트에서 특정 함수(OnRep_PropertyName)를 호출하도록 한다. 시각 효과 재생, UI 업데이트 등 상태 변화에 따른 부가적인 로직을 처리할 때 유용하다.
    • 액터 클래스 선언부에서 virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; 함수를 오버라이드해야 한다.
  2. 소스 파일 (.cpp):
    • #include "Net/UnrealNetwork.h" 헤더를 포함해야 한다.
    • GetLifetimeReplicatedProps 함수 내에서 DOREPLIFETIME(ClassName, PropertyName); 매크로를 사용하여 리플리케이션할 프로퍼티를 등록한다.

조건부 리플리케이션 (Conditional Replication)

DOREPLIFETIME_CONDITION 매크로를 사용하면 특정 조건에서만 프로퍼티를 리플리케이션하여 네트워크 대역폭을 절약할 수 있다.

  • COND_OwnerOnly: 액터를 소유한 클라이언트에만 전송.
  • COND_SkipOwner: 소유자를 제외한 모든 클라이언트에 전송.
  • COND_SimulatedOnly: Simulated Proxy에만 전송.
  • COND_AutonomousOnly: Autonomous Proxy에만 전송.

3.2. 함수 리플리케이션 (RPC - Remote Procedure Call)

네트워크를 통해 다른 머신(서버 또는 클라이언트)에 있는 함수를 호출하는 기능이다. RPC는 단발성 이벤트(총 발사, 문 열기 등)를 전달하는 데 주로 사용된다.

UFUNCTION 키워드:

  • Server: 클라이언트가 호출하며, 서버에서 실행. 신뢰성 검증(Validation)을 추가하는 것이 좋다.
  • Client: 서버가 호출하며, 특정 액터를 소유한 클라이언트에서만 실행.
  • NetMulticast: 서버가 호출하며, 서버와 모든 클라이언트(해당 액터를 볼 수 있는)에서 실행. 파티클 효과, 사운드 재생 등 모든 클라이언트가 봐야 하는 시각적/청각적 이벤트에 사용.

신뢰성 (Reliability):

  • Reliable: RPC가 반드시 전송되고 실행됨을 보장. 중요한 이벤트(예: 게임 시작, 플레이어 사망)에 사용됨. 실패 시 재전송을 시도하므로 네트워크 부하를 줄 수 있다.
  • Unreliable: RPC 전송을 보장하지 않는다. 네트워크 상황에 따라 유실될 수 있다. 자주 발생하지만 개별 호출이 중요하지 않은 이벤트(예: 플레이어 발소리)에 사용된다. (기본값)

예시:

// 클라이언트가 호출 -> 서버에서 실행
UFUNCTION(Server, Reliable, WithValidation)
void Server_DoSomething(int32 Value);

// 서버가 호출 -> 소유 클라이언트에서 실행
UFUNCTION(Client, Unreliable)
void Client_ShowEffect();

// 서버가 호출 -> 모든 클라이언트에서 실행
UFUNCTION(NetMulticast, Unreliable)
void Multicast_PlaySound();

4. 리플리케이션의 내부 동작과 계층 구조

리플리케이션은 여러 계층을 거쳐 동작하는 복잡한 시스템이다.

  1. 게임플레이 계층 (Gameplay Layer):
    • 개발자가 UPROPERTY(Replicated), UFUNCTION(Server) 등과 같이 액터와 컴포넌트 수준에서 리플리케이션을 설정하는 가장 상위 계층임.
  2. 액터 채널 (Actor Channel):
    • 서버와 클라이언트 간의 각 리플리케이션된 액터는 고유한 액터 채널(UActorChannel)을 가짐. 이 채널은 해당 액터와 관련된 모든 데이터(프로퍼티, RPC) 전송을 담당함.
    • 서버는 매 틱마다 리플리케이션이 필요한 액터 목록을 확인함.
    • 액터가 클라이언트와 관련성(Relevancy)이 있다고 판단되면, 해당 클라이언트에 대한 액터 채널이 생성됨.
    • 채널은 액터의 프로퍼티 변경 사항을 추적하고, 변경된 프로퍼티만 모아서 패킷에 담아 보낼 준비를 함.
  3. 넷 드라이버 (Net Driver):
    • UNetDriver는 네트워크 통신의 핵심 관리자. 서버와 클라이언트 간의 연결(UNetConnection)을 관리하고, 데이터 전송을 총괄함.
    • 서버의 UNetDriver는 모든 클라이언트 연결을 관리하며, 각 연결에 대해 어떤 액터가 관련성이 있는지 결정함.
    • ServerReplicateActors 함수가 매 틱 호출되어 다음을 수행함.
      1. 액터 수집: 리플리케이션되도록 설정된 모든 액터를 수집.
      2. 우선순위 정렬: 각 액터의 중요도(우선순위)를 계산하여 정렬. 플레이어와 가까이 있거나, 최근에 활동이 있었던 액터가 높은 우선순위를 가진다.
      3. 리플리케이션: 우선순위가 높은 액터부터, 할당된 네트워크 대역폭 내에서 최대한 많은 액터의 데이터를 액터 채널을 통해 클라이언트로 전송. 이 과정 때문에 모든 프로퍼티 변경이 즉시 전송되지 않을 수 있다.
  4. 소켓 계층 (Socket Layer):
    • UNetDriver가 준비한 데이터 패킷을 UDP 프로토콜을 사용하여 실제로 네트워크 하드웨어를 통해 전송하는 가장 낮은 계층.

5. 심화 주제: 효율적인 리플리케이션

5.1. 관련성 (Relevancy) 과 우선순위 (Priority)

모든 액터를 모든 클라이언트에게 항상 리플리케이션하는 것은 대역폭 낭비다. 언리얼은 관련성(Relevancy) 개념을 통해 이를 최적화한다.

  • 관련성: 특정 클라이언트가 한 액터에 대한 정보를 받을 필요가 있는지를 결정하는 규칙이다. 기본적으로 액터가 클라이언트의 카메라로부터 일정 거리 안에 있을 때 관련성이 있다고 판단한다. AActor::IsNetRelevantFor 함수를 오버라이드하여 이 규칙을 커스터마이징할 수 있다.
  • 우선순위: 관련성이 있는 액터들 사이에서 어떤 액터의 데이터를 먼저 보낼지를 결정하는 값이다. AActorNetPriority 프로퍼티와 AActor::GetNetPriority 함수를 통해 조절할 수 있다. 플레이어 캐릭터나 중요한 게임 목표물은 높은 우선순위를 갖는 것이 좋다.

5.2. 리플리케이션 그래프 (Replication Graph)

대규모 멀티플레이어 게임(예: 배틀로얄)에서는 수백 명의 플레이어와 수많은 액터가 존재하여 기본 리플리케이션 시스템의 ServerReplicateActors 함수가 병목이 될 수 있다. 이 함수가 모든 연결에 대해 모든 액터를 순회하며 관련성을 검사하기 때문이다.

리플리케이션 그래프(UReplicationGraph)는 이 문제를 해결하기 위한 고도로 최적화된 시스템이다. 관련성 검사를 매번 모든 액터에 대해 수행하는 대신, 월드를 그리드(Grid) 같은 구조로 나누고, 액터와 플레이어를 노드(Node)로 만들어 효율적으로 관리한다.

  • 플레이어가 특정 그리드 셀에 들어가면, 해당 셀 및 주변 셀에 있는 액터들(노드)에 대한 관련성만 검사하면 되므로 계산량이 크게 줄어든다.
  • 항상 관련성이 있는 액터(예: 게임 상태 AGameStateBase)나 소유자에게만 관련성이 있는 액터(예: 플레이어 인벤토리)를 위한 특수 노드를 제공하여 더욱 효율적인 처리가 가능하다.
  • 포트나이트와 같은 대규모 게임에서 사용되며, 상당한 수준의 C++ 지식과 네트워크 이해도를 요구하는 고급 기능이다.

6. 요약

 언리얼 엔진의 리플리케이션은 서버의 게임 상태를 클라이언트들에게 자동으로 복제하여 모든 플레이어가 동기화된 경험을 하도록 만드는 시스템입니다. 언리얼은 '신뢰성 있는 서버' 모델을 사용하는데, 이는 게임의 모든 중요한 로직은 서버에서만 처리되고 서버가 게임의 최종 상태를 결정한다는 의미입니다.

 

 리플리케이션은 크게 두 가지로 나뉩니다. 첫째는 프로퍼티 리플리케이션으로, 서버에 있는 액터의 변수 값이 바뀌면 이 값이 클라이언트에 자동으로 복제되는 기능입니다. 예를 들어 캐릭터의 체력(HP) 값이 서버에서 줄어들면, 이 값이 모든 클라이언트의 UI에 반영되는 식입니다. UPROPERTY(Replicated) 매크로를 사용해 구현합니다.

 둘째는 RPC(Remote Procedure Call), 즉 원격 함수 호출입니다. 이것은 총을 쏘거나 문을 여는 것처럼 단발성 이벤트를 처리할 때 사용됩니다. 클라이언트가 서버의 함수를 호출하는 Server RPC, 서버가 특정 클라이언트의 함수를 호출하는 Client RPC, 그리고 서버가 모든 클라이언트의 함수를 호출하는 NetMulticast RPC가 있습니다.

 

 이러한 리플리케이션의 내부 동작을 보면, 서버는 매 틱마다 어떤 액터의 정보가 변경되었고, 어떤 클라이언트에게 이 정보를 보내야 하는지, 즉 '관련성'을 판단합니다. 그리고 액터의 중요도에 따라 '우선순위'를 매겨서, 한정된 네트워크 대역폭 안에서 가장 중요한 정보부터 전송하여 시스템을 최적화합니다. 대규모 게임에서는 '리플리케이션 그래프'라는 더 발전된 시스템을 사용하여 이런 관련성 검사 자체를 더욱 효율적으로 처리하기도 합니다.

'Unreal' 카테고리의 다른 글

NetRole  (0) 2025.10.27
Replication Condition  (0) 2025.10.24
언리얼 엔진 리플렉션 시스템 Unreal Engine Reflection System  (0) 2025.10.23
UE5 Cast의 내부 동작 원리  (0) 2025.10.22
CDO (Class Default Object)  (0) 2025.10.21
iamrain
@iamrain :: Annals of Unreal

iamrain 님의 블로그 입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차