[DAY63] Unreal Engine Network Authority

베리투스·2025년 11월 14일

TIL: Today I Learned

목록 보기
53/93

멀티플레이 개발의 가장 큰 혼란은 "똑같은 코드가 대체 어디서 실행되는 거지?"라는 질문에서 시작된다. 오늘은 이 혼란을 해결해 줄 NetMode 라는 '네트워크 신분증'에 대해 학습했다. 더 나아가, 이 신분증이 어떤 원리로 발급되는지를 이해하기 위해 네트워크 통신의 핵심 3요소인 NetDriver(네트워크 관리자), NetConnection(통신 파이프), 그리고 Ownership(소유권)의 관계를 파헤쳤다. 이 개념들을 통해 왜 중요한 로직은 반드시 서버에서만 실행해야 하는지에 대한 기술적인 근거를 명확히 알게 되었다.


📌 오늘의 목표

  • NetMode의 필요성을 이해하고, 현재 실행 위치(서버/클라이언트)를 구분하는 방법 알기
  • 네트워크 통신의 핵심 객체인 NetDriverNetConnection의 역할과 관계 설명하기
  • RPC와 복제의 기반이 되는 Ownership(소유권) 개념의 중요성 파악하기

📚 이론 및 원리

APlayerCharacter::BeginPlay() 함수에 로그를 하나 찍고 실행하면, 서버와 클라이언트 모두에서 로그가 찍히는 것을 볼 수 있다. 싱글플레이 환경에서는 당연했지만, 멀티플레이에서는 이 현상이 모든 문제의 시작점이 된다. "HP가 깎이는 로직을 모든 PC에서 실행해야 할까?" 정답은 '아니오'다.

1. 나의 네트워크 신분증, NetMode 🆔

NetMode는 현재 이 게임 인스턴스(프로세스)가 네트워크 상에서 어떤 역할을 수행 중인지 알려주는 열거형(Enum)이다. 월드(World) 객체가 이 속성을 가지고 있으며, 크게 4가지 상태로 나뉜다.

  • NM_Standalone: 싱글플레이 상태. 서버도, 클라이언트도 아니다.
  • NM_ListenServer: 리슨 서버. 서버이면서 동시에 자기 자신이라는 로컬 플레이어(클라이언트)를 가진다.
  • NM_DedicatedServer: 데디케이티드 서버. 플레이어 없이 오직 서버 로직만 실행한다.
  • NM_Client: 클라이언트. 서버에 연결된 원격 플레이어다.

"플레이어의 HP를 변경하는 로직"처럼 게임의 규칙에 중대한 영향을 미치는 코드는 해킹 방지를 위해 반드시 서버에서만 실행되어야 한다. 이럴 때 우리는 NetMode를 확인하여 "여기가 서버가 맞나?"를 검사하는 코드를 추가해야 한다.

void AMyCharacter::TakeDamage(float Damage)
{
    // GetWorld()->GetNetMode() 가 NM_ListenServer 또는 NM_DedicatedServer 일 때만 실행
    // 혹은 더 좋은 방법인 HasAuthority() 체크를 사용!
    if (HasAuthority()) 
    {
        HP -= Damage;
    }
}

HasAuthority()NetMode를 직접 비교하는 것보다 더 권장되는 방식인데, 내부적으로 현재 액터가 '권위'를 가진, 즉 서버에 존재하는지를 판단해주는 편리한 함수다.

2. 통신의 실체: NetDriverNetConnection 🔌

NetMode가 신분증이라면, 이 신분증은 어떻게 발급되는 걸까? 그 근간에는 NetDriverNetConnection이 있다.

  • NetDriver (네트워크 관리자): 멀티플레이 세션이 시작될 때 각 PC(서버, 클라이언트 모두)에 생성되는 객체다. 이름처럼 네트워크 통신의 모든 로우레벨 동작을 '운전'하고 관리한다. 서버의 NetDriver는 여러 클라이언트와의 연결을, 클라이언트의 NetDriver는 단 하나의 서버와의 연결을 관리한다.
  • NetConnection (통신 파이프): 두 PC 간의 실제 연결 통로다. 클라이언트가 서버에 접속하면, 서버의 NetDriver에는 해당 클라이언트를 위한 ClientConnection 객체가 추가되고, 클라이언트의 NetDriver에는 서버를 향한 ServerConnection 객체가 생성된다. 즉, 서버는 접속한 클라이언트 수만큼 NetConnection을, 클라이언트는 오직 1개의 NetConnection을 갖는다.

UNetDriver::IsServer() 함수 내부를 보면 ServerConnection == NULL 인지를 체크하는데, 클라이언트는 반드시 서버 커넥션을 가지므로 이 값이 false가 나오고, 서버는 이 변수가 NULL이므로 true가 반환되는 원리다.

3. 권한의 사슬, Ownership 👑

NetConnection이 물리적인 '랜선'이라면, Ownership은 이 랜선을 통해 어떤 데이터를 보낼 수 있는지 결정하는 '소유권' 정보다.

PlayerController는 자신만의 NetConnection을 소유한다. 그리고 이 PlayerController가 빙의(Possess)한 Pawn(캐릭터)은 자신의 Owner를 해당 PlayerController로 설정한다. 만약 이 Pawn이 무기를 장착하면, 무기 액터의 OwnerPawn으로 설정될 수 있다.

ClientConnection -> PlayerController -> Pawn -> Weapon

이렇게 연결된 소유 관계의 최상단에는 결국 NetConnection이 있다. 어떤 액터가 GetNetConnection() 함수를 호출하면, 이 소유 관계를 거슬러 올라가 자신의 주인이 누구인지, 즉 어떤 플레이어의 통신 파이프에 연결되어 있는지를 찾아낸다. 이 Ownership 체인은 나중에 배울 RPC(원격 함수 호출)가 오직 '자신이 소유한' 액터에 대해서만 클라이언트에서 서버로 호출할 수 있도록 제한하는 핵심적인 보안 장치가 된다.


✅ 핵심 요약

개념설명비고
NetMode현재 게임 인스턴스의 네트워크 역할 (서버/클라이언트 등).HasAuthority()로 서버인지 확인하는 것이 더 일반적이고 권장됨.
NetDriver각 PC의 네트워크 통신을 총괄하는 관리자 객체.멀티플레이 시에만 생성되며, NetConnection들을 소유하고 관리함.
NetConnection두 PC 사이의 실제 데이터 통신 채널(파이프).서버는 다수, 클라이언트는 단 1개의 NetConnection을 가짐.
Ownership액터의 소유자 관계. RPC 호출 권한 등 보안의 기반이 된다.PlayerControllerNetConnection과 액터들을 잇는 중요한 연결고리.
profile
Shin Ji Yong // Unreal Engine 5 공부중입니다~

0개의 댓글