블루프린트에서의 리플리케이션
지난 두 절에서는 게임 모드, 스테이트, 컨트롤러, 폰 클래스가 게임 규칙/상태/조작을 어떻게 분담하는지 살펴봤습니다. 이 구조는 특히 멀티플레이어 게임에서 중요하며, 이를 가능하게 하는 핵심 메커니즘이 리플리케이션(Replication), 즉 네트워크 복제입니다.
이번 절에서는 블루프린트에서 리플리케이션이 어떻게 동작하고, 상태/이벤트를 네트워크로 동기화하는지 정리합니다.
리플리케이션이란 무엇인가?
리플리케이션(Replication)은 멀티플레이어 게임 환경에서 서버와 클라이언트 간에 게임의 상태(변수, 오브젝트의 위치 등)와 이벤트(함수 호출)를 네트워크를 통해 동기화하는 과정을 의미합니다. 언리얼 엔진은 서버-클라이언트 모델을 기반으로 하며, 서버가 게임의 진실된 상태를 소유하고 관리하며, 이 상태를 모든 클라이언트에 복제하여 동기화합니다.
리플리케이션이 필요한 이유- 게임 상태 동기화: 모든 플레이어의 컴퓨터가 동일한 게임 월드와 상태를 공유해야 합니다. (예: 다른 플레이어의 캐릭터 위치, 아이템 획득 여부, 적의 체력 등)
- 공정한 게임플레이: 서버가 모든 중요한 게임 로직(데미지 계산, 충돌 처리 등)을 처리함으로써 클라이언트 조작(Cheating)을 방지하고 공정한 게임플레이를 보장합니다.
- 효율적인 네트워크 통신: 언리얼 엔진은 필요한 데이터만 효율적으로 복제하여 네트워크 대역폭 사용을 최적화합니다.
블루프린트에서 리플리케이션 설정하기
블루프린트에서 리플리케이션을 설정하는 방법은 크게 세 가지 유형으로 나눌 수 있습니다.
변수 리플리케이션
액터의 특정 변수 값을 서버에서 변경하면, 해당 값이 자동으로 모든 클라이언트에 동기화되도록 설정할 수 있습니다.
변수 생성: 블루프린트에서 복제하고자 하는 변수(예: 플레이어의 Health, 적의 CurrentAmmo)를 생성합니다.
리플리케이션 설정: 변수를 선택하고 디테일(Details) 패널의 리플리케이션(Replication) 섹션에서 Replication 드롭다운을 Replicated로 설정합니다.
적용: 이제 서버에서 이 변수의 값을 변경하면, 클라이언트의 해당 액터 인스턴스에 있는 변수 값도 자동으로 업데이트됩니다.
- 주의:
RepNotify를 사용하여 변수 값이 복제된 후 특정 로직을 실행할 수 있습니다.
RepNotify (Rep_Notify):
RepNotify는 Replicated 변수가 클라이언트에 성공적으로 복제되어 값이 변경되었을 때 특정 함수를 자동으로 호출하는 기능입니다. 이를 통해 클라이언트에서 변수 값의 변화에 따른 시각적/청각적 효과를 구현할 수 있습니다.
- 설정: 변수를
Replicated로 설정한 후, 드롭다운에서Replicated Using을 선택합니다. 그러면 새로운 함수가 자동으로 생성됩니다. (예:OnRep_Health) - 활용:
OnRep_Health함수 내에 체력 바 UI 업데이트, 피격 사운드 재생, 데미지 이펙트 표시 등의 로직을 구현합니다. 이 함수는 서버에서도 호출되지만, 주로 클라이언트의 시각적 피드백을 위해 사용됩니다.
함수 호출 리플리케이션 - RPC
특정 함수가 서버에서 실행되도록 클라이언트가 요청하거나, 서버에서 클라이언트에 특정 함수를 실행하도록 지시할 수 있습니다. 이를 RPC (Remote Procedure Call)라고 합니다.
함수 세부 정보 패널에서 Replication 섹션의 Replicates 드롭다운을 통해 설정합니다.
Run on Server (서버에서 실행)- 클라이언트가 서버에 함수 실행을 요청할 때 사용합니다. (예: 플레이어가 공격 버튼을 눌렀을 때, 클라이언트가 서버에게 나 공격할게!라고 알림)
- 설정: 함수를 생성하고
Replicates를Run on Server로 설정합니다.Reliable옵션을 체크하면 네트워크 불안정 시에도 반드시 호출되도록 보장합니다. - 주의:
Run on Server함수는 오직 소유권(Ownership)을 가진 클라이언트만이 호출할 수 있습니다. 일반적으로PlayerController와Pawn/Character가 소유권을 가집니다. 다른 액터(예: 월드에 있는 문)의 함수를 서버에서 실행하고 싶다면, 그 액터에 대한Run on Server함수를PlayerController나Pawn에 만들고, 거기서 다시 해당 액터의 함수를 호출하는 방식으로 우회해야 합니다.
Multicast (멀티캐스트)- 서버가 모든 클라이언트에 함수 실행을 지시할 때 사용합니다. (예: 서버가 모든 클라이언트는 이펙트 재생!이라고 알림)
- 설정: 함수를 생성하고
Replicates를Multicast로 설정합니다.Reliable옵션을 체크하면 네트워크 불안정 시에도 반드시 호출되도록 보장합니다. - 주의:
Multicast함수는 오직 서버에서만 호출될 수 있습니다. 클라이언트에서Multicast함수를 호출하려 하면 경고가 뜨며 작동하지 않습니다. 이 함수는 서버에서도 실행되고, 모든 클라이언트에서도 실행됩니다.
Run on Owning Client (소유 클라이언트에서 실행)- 서버가 특정 폰/캐릭터의 소유권을 가진 클라이언트에만 함수 실행을 지시할 때 사용합니다. (예: 서버가 특정 플레이어에게만 너 데미지 입었어!라고 알림)
- 설정: 함수를 생성하고
Replicates를Run on Owning Client로 설정합니다.Reliable옵션을 체크하면 네트워크 불안정 시에도 반드시 호출되도록 보장합니다. - 주의: 이 함수는 오직 서버에서만 호출될 수 있으며, 소유권을 가진 클라이언트에서만 실행됩니다.
액터 리플리케이션 (Replicating Actors)
게임 월드에 스폰되는 액터(예: 아이템, 투사체, 적 AI) 자체가 모든 클라이언트에 존재하도록 설정할 수 있습니다.
액터 블루프린트 열기: 복제하고자 하는 액터 블루프린트 (예: BP_PickupItem)를 엽니다.
리플리케이션 설정: 클래스 디폴트(Class Defaults)를 클릭하고 디테일(Details) 패널에서 리플리케이션(Replication) 섹션을 찾습니다.
Replicates: 체크합니다. (이 액터와 그 컴포넌트들이 모든 클라이언트에 복제되도록 허용)Replicate Movement: 체크합니다. (액터의 위치, 회전, 스케일이 자동으로 복제되도록 함. 폰/캐릭터는 기본적으로 체크되어 있음)Net Update Frequency: 해당 액터가 초당 몇 번 복제 업데이트를 보낼지 설정합니다. (높을수록 정확하지만 네트워크 부하 증가)
리플리케이션 흐름 및 중요 규칙
언리얼 엔진의 멀티플레이어 환경은 기본적으로 서버-클라이언트 모델입니다.- 서버의 권한: 게임의 모든 핵심 로직, 상태 변경, 물리 시뮬레이션 등은 서버에서만 발생하고 결정됩니다. 클라이언트는 서버의 복제품을 가지고 있을 뿐입니다.
-
신뢰성 (Reliable) vs. 비신뢰성 (Unreliable)
- Reliable (신뢰성): 중요한 데이터나 이벤트에 사용합니다. 네트워크 상태가 나쁘더라도 반드시 전달되도록 보장합니다. (재전송 메커니즘 포함)
- Unreliable (비신뢰성): 자주 업데이트되거나 실시간성이 중요한 데이터에 사용합니다. 데이터 손실이 허용되며, 최신 값으로 덮어쓰여지므로 지연이 발생해도 이전 값은 중요하지 않을 때 사용합니다. (예: 캐릭터 위치 업데이트, 프레임마다 변하는 값)
-
오너십 (Ownership)
- 각 폰(Pawn)은 하나의 컨트롤러(Controller) (플레이어 컨트롤러 또는 AI 컨트롤러)에 의해 소유됩니다.
- 플레이어가 조작하는 폰은 해당 플레이어의 플레이어 컨트롤러가 소유합니다.
Run on ServerRPC는 소유권을 가진 클라이언트만 호출할 수 있습니다.- AI가 제어하는 폰은 서버의 AI 컨트롤러가 소유합니다.
- 소유권은 네트워크 통신 및 권한 부여에 중요한 역할을 합니다.
리플리케이션 예시: 아이템 줍기
플레이어가 아이템을 주웠을 때, 이 아이템이 모든 클라이언트의 월드에서 사라지고, 플레이어의 인벤토리에 추가되는 로직을 리플리케이션으로 구현해봅시다.
BP_PickupItem (아이템 액터)클래스 디폴트에서Replicates와Replicate Movement를 체크합니다.- 콜리전 컴포넌트의
On Component Begin Overlap이벤트에서 로직을 시작합니다. -
이벤트 그래프
On Component Begin Overlap>Other Actor를Cast To BP_PlayerCharacter로 캐스팅합니다.- 캐스팅 성공 시,
Has Authority노드를 사용하여 현재 코드가 서버에서 실행 중인지 확인합니다. (아이템 줍기 로직은 서버에서만 처리해야 함) Has Authority가True일 경우:Run on ServerRPC (예:Server_PickupItem)를 호출합니다. 이 RPC에BP_PlayerCharacter와 주운 아이템(Self참조)을 파라미터로 넘깁니다.
BP_PlayerCharacter (플레이어 캐릭터)- 함수 생성:
Server_PickupItem이라는 커스텀 이벤트를 만들고,Replicates를Run on Server로 설정합니다. Server_PickupItem함수 내부- 아이템을 실제로 플레이어 인벤토리에 추가하는 로직을 구현합니다. (인벤토리 변수 업데이트 등)
- 아이템 액터를
Destroy Actor노드로 파괴합니다. MulticastRPC (예:Multicast_PlayPickupEffect)를 호출하여 모든 클라이언트에 줍기 효과(사운드, 이펙트)를 재생하도록 지시합니다. (서버에서만 호출 가능)
BP_PlayerCharacter (계속)- 함수 생성:
Multicast_PlayPickupEffect라는 커스텀 이벤트를 만들고,Replicates를Multicast로 설정합니다. Multicast_PlayPickupEffect함수 내부- 아이템 줍는 사운드 (
Play Sound at Location) - 아이템 줍는 이펙트 (
Spawn Emitter at Location) - 주의: 이 함수는 서버와 모든 클라이언트에서 실행되므로, 이펙트/사운드 재생은
Is Dedicated Server체크를 통해 전용 서버에서는 건너뛰거나, 필요하다면Is Locally Controlled체크를 통해 특정 클라이언트에서만 실행되도록 할 수 있습니다.
- 아이템 줍는 사운드 (
이러한 방식으로 서버가 모든 게임 로직을 처리하고, 필요한 정보와 시각적/청각적 피드백을 클라이언트에 복제함으로써 멀티플레이어 환경에서 일관된 게임 경험을 제공할 수 있습니다.
블루프린트 네트워크 디버깅 팁
Net Mode변경: 에디터에서플레이(Play)버튼 옆의 드롭다운을 클릭하여Play As Client또는Listen Server모드로 테스트할 수 있습니다.Number of Players를 늘려 여러 클라이언트를 동시에 실행할 수도 있습니다.- 네트워크 통계: 게임 플레이 중
~키를 눌러 콘솔을 열고stat net을 입력하면 네트워크 대역폭 사용량, 패킷 손실률 등 다양한 네트워크 통계 정보를 확인할 수 있습니다. - RPC 호출 확인:
log net명령어를 통해 네트워크 로그를 활성화하여 RPC 호출 및 변수 복제 흐름을 추적할 수 있습니다. ShowDebug: AI나 캐릭터의 네트워크 정보를 디버그 드로잉으로 표시할 수 있습니다. (예:showdebug net또는showdebug all)
리플리케이션은 멀티플레이어 게임 개발의 핵심이자 가장 복잡한 부분 중 하나입니다. 서버-클라이언트 모델과 각 클래스의 역할, 그리고 리플리케이션의 종류와 규칙을 명확히 이해하는 것이 중요합니다.
GAS(게임플레이 능력 시스템)를 사용하는 경우에도 동일한 원칙이 적용됩니다. 능력 실행 권한, 코스트/쿨다운 적용, 예측 보정 흐름은 9장 5절의 멀티플레이어 기준 실행 흐름과 함께 보면 구현 실수를 줄일 수 있습니다.
이번 절에서는 언리얼 엔진 블루프린트에서 리플리케이션이 어떻게 작동하며, 변수, 함수, 액터의 복제를 통해 게임의 상태와 이벤트를 네트워크를 통해 동기화하는 방법에 대해 알아보았습니다. 리플리케이션은 멀티플레이어 게임의 핵심이자 안정적인 게임플레이를 위한 필수 요소입니다.