Unreal Engine 5(UE5)에서 네트워크 멀티플레이어를 구축할 때는 RPC(Remote Procedure Call)와 Replication(리플리케이션) 두 가지 개념이 핵심입니다.
이 문서는 UE5 기준으로 RPC와 리플리케이션의 원리를 설명하고, C++에서 구현하는 방법 및 코드 예시, 그리고 대역폭 최적화·보안 기법·디버깅 팁 등을 정리한 심층 가이드입니다.
목차
1. RPC(Remote Procedure Call)
RPC 개념
- RPC는 클라이언트와 서버가 서로 함수를 호출하는 메커니즘입니다.
- UE5에서는 C++에서
UFUNCTION()매크로에 특정 키워드를 붙여 구현합니다.Server: 클라이언트가 함수를 호출하면 서버에서 실행Client: 서버에서 함수를 호출하면 특정 클라이언트(소유자)에서 실행NetMulticast: 서버에서 함수를 호출하면 서버 & 모든 클라이언트에서 실행
RPC 종류
Server RPC (클라이언트 → 서버)
- 클라이언트가 호출, 서버에서 실행
- 주로 입력 처리(예: 공격 요청)나 상태 변경 알림을 서버에 전달할 때 사용
UFUNCTION(Server, Reliable/Unreliable)로 선언
Client RPC (서버 → 특정 클라이언트)
- 서버가 호출, 특정 클라이언트(Actor의 Owner)에서 실행
- 개인적인 알림(예: 개인 점수 갱신)이나 UI 업데이트에 활용
UFUNCTION(Client, Reliable/Unreliable)
NetMulticast RPC (서버 → 모든 클라이언트 + 서버 자신)
- 서버가 호출, 연결된 모든 클라이언트 및 서버 본인에서 실행
- 폭발 이펙트나 전역 이벤트 브로드캐스트 등에 사용
UFUNCTION(NetMulticast, Reliable/Unreliable)
주의: NetMulticast RPC는 서버에서만 브로드캐스트 효과가 발생합니다. 클라이언트가 호출하면 자기 자신에게만 실행되고 다른 클라이언트에는 전달되지 않습니다.
Reliable vs Unreliable
Reliable RPC
- 반드시 도달이 보장, 재전송을 통해 안정성을 확보
- 중요한 게임 로직(사망 판정, 아이템 획득 등)에 사용
- 너무 자주 사용하면 네트워크 지연이 늘어날 수 있음
Unreliable RPC
- 손실될 수 있지만(미보장) 오버헤드가 적음
- 매우 빈번하거나, 한두 번 누락되어도 게임 진행에 큰 문제 없는 경우 사용
- 탄환 발사 이펙트, 발소리 재생 등 시각·청각 효과 트리거에 적합
RPC C++ 구현 예시
// 예: 캐릭터가 공격(발사) 요청 시 서버에 알리고, 모든 클라이언트에 이펙트를 뿌리는 예
// MyCharacter.h
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
void HandleFire(); // 로컬 입력 핸들
protected:
// 클라이언트 -> 서버
UFUNCTION(Server, Reliable)
void ServerHandleFire();
// 서버 -> 전체(멀티캐스트, 비중요 효과는 Unreliable 사용 가능)
UFUNCTION(NetMulticast, Unreliable)
void MulticastPlayMuzzleFlash();
void PerformFire();
// 총알 스폰용 클래스
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AActor> BulletClass;
// 이펙트
UPROPERTY(EditDefaultsOnly)
UParticleSystem* MuzzleFlash;
};
// MyCharacter.cpp
#include "MyCharacter.h"
#include "Net/UnrealNetwork.h"
void AMyCharacter::HandleFire()
{
// 서버 권한이면 직접 실행, 클라면 서버에 RPC
if (HasAuthority())
{
PerformFire();
}
else
{
ServerHandleFire();
}
}
void AMyCharacter::ServerHandleFire_Implementation()
{
PerformFire(); // 서버에서 총알 스폰 + 이펙트 브로드캐스트
}
void AMyCharacter::PerformFire()
{
if (!HasAuthority()) return;
// 탄환 생성(서버)
if (BulletClass)
{
FVector SpawnLoc = GetActorLocation() + GetActorForwardVector() * 100.0f;
FRotator SpawnRot = GetControlRotation();
FActorSpawnParameters Params;
Params.Owner = this;
Params.Instigator = this;
GetWorld()->SpawnActor<AActor>(BulletClass, SpawnLoc, SpawnRot, Params);
}
// 총구이펙트 모든 클라에 뿌림 (Unreliable)
MulticastPlayMuzzleFlash();
}
void AMyCharacter::MulticastPlayMuzzleFlash_Implementation()
{
if (MuzzleFlash)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleFlash, GetActorLocation());
}
}
2. Replication(리플리케이션)
Replication 개념
- Replication은 서버가 가지고 있는 Actor(또는 ActorComponent)와 변수의 상태를 클라이언트와 동기화해주는 시스템입니다.
- 주로 지속적인 상태 데이터(체력, 탄약, 위치 등)를 자동으로 전파하고, 클라이언트는 이를 읽기 전용으로 사용합니다.
변수/액터 리플리케이션 구현
Actor 복제 설정
bReplicates = true;로 설정해야 해당 Actor가 네트워크 복제 대상이 됩니다.- 서버에서 Spawn할 때
bReplicates가 설정된 Actor는 연결된 클라이언트들에게 자동으로 생성·동기화됩니다.
Replicated 변수 선언
- 헤더에서
UPROPERTY(Replicated)또는UPROPERTY(ReplicatedUsing=OnRep_X)를 선언 - 클래스 안에서
GetLifetimeReplicatedProps오버라이드하여DOREPLIFETIME(MyClass, MyVar)매크로로 변수 등록
- 헤더에서
// 예: 체력 변수를 리플리케이션
UPROPERTY(Replicated)
float Health;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyCharacter, Health);
}
ReplicatedUsing / OnRep 사용
UPROPERTY(ReplicatedUsing=OnRep_Health)처럼 선언하면,- 클라이언트에서 해당 변수가 갱신될 때 자동으로
OnRep_Health()가 호출되어 추가 로직(예: UI 갱신)을 실행 - 서버에는 OnRep 함수가 자동 호출되지 않으므로, 서버도 같은 로직이 필요하다면 별도 호출이 필요
// 체력 OnRep 예시
UPROPERTY(ReplicatedUsing=OnRep_Health)
float Health;
UFUNCTION()
void OnRep_Health();
// cpp
void AMyCharacter::OnRep_Health()
{
// 클라이언트 측 체력 UI 갱신 등
UpdateHealthUI(Health);
if (Health <= 0.f) { PlayDeathAnimation(); }
}
Replication C++ 예시
// MyCharacter.h
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
UPROPERTY(ReplicatedUsing=OnRep_Health)
float Health;
UFUNCTION()
void OnRep_Health();
void TakeDamage(float DamageAmount);
protected:
// 리플리케이션용 함수
virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const override;
private:
UPROPERTY(EditDefaultsOnly)
float MaxHealth;
};
// MyCharacter.cpp
#include "MyCharacter.h"
#include "Net/UnrealNetwork.h"
AMyCharacter::AMyCharacter()
{
bReplicates = true;
bReplicateMovement = true;
Health = 100.f;
MaxHealth = 100.f;
}
void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyCharacter, Health);
}
void AMyCharacter::TakeDamage(float DamageAmount)
{
if (!HasAuthority()) return;
Health = FMath::Clamp(Health - DamageAmount, 0.f, MaxHealth);
if (Health <= 0.f)
{
// 서버측 사망 처리
}
// 클라이언트 OnRep_Health() 호출 유도
OnRep_Health(); // (서버에서 시각 효과도 필요하면 수동 호출)
}
void AMyCharacter::OnRep_Health()
{
UpdateHealthUI(Health);
if (Health <= 0.f)
{
PlayDeathAnimation();
}
}
3. 최적화 고려 사항
신뢰성 수준(Reliable/Unreliable) 분배
- 중요 이벤트(사망, 아이템 획득 등)는 Reliable
- 빈번하고 손실 가능(애니·이펙트 등)은 Unreliable
- Reliable RPC를 과도하게 호출하면 재전송 대기로 인해 지연이 커지고, 최악의 경우 연결 종료 위험이 있음
Replication 빈도 및 조건 제어
- NetUpdateFrequency: 초당 몇 번 Actor 상태를 체크/전송할지 설정 가능
- 조건부 복제:
DOREPLIFETIME_CONDITION(COND_OwnerOnly, COND_SkipOwner 등)을 사용해 특정 대상에게만 전송 - 최소 필요 빈도로 전송하고, 불필요한 클라이언트에게는 상태를 안 보내도록 설계하면 대역폭 절감
Net Dormancy와 Relevancy
- Dormancy: 더 이상 변경되지 않는 Actor를 휴면(Dormant) 상태로 전환해 네트워크 업데이트를 중지
- 상태가 다시 변하면
FlushNetDormancy등으로 깨워 전송 재개 - Relevancy: Player와 너무 멀리 떨어진 Actor의 데이터를 보내지 않도록 관리 (NetCullDistanceSquared 등)
멀티캐스트(RPC) 최소화
- NetMulticast RPC는 서버 → 모든 클라이언트 전송이므로, 플레이어 수가 많아질수록 트래픽 부담이 커짐
- 꼭 필요한 전역 이벤트만 멀티캐스트하고, 일부 플레이어에게만 필요한 경우 개별 Client RPC나 조건부 Replication 사용
4. 보안 고려 사항
서버 권위 모델
- 클라이언트는 신뢰할 수 없으므로, 중요 게임 로직(체력·위치·점수 등)은 반드시 서버에서 결정
- 클라이언트에서 변수를 조작해도 서버가 승인하지 않으면 무의미
RPC WithValidation
UFUNCTION(Server, WithValidation)을 사용하면_Implementation과_Validate함수를 구현할 수 있음_Validate에서 false를 반환하면 엔진이 해당 클라이언트를 강제로 접속 종료 처리- 부정 조작(예: 말도 안 되는 데미지 등)을 감지해 차단 가능
UFUNCTION(Server, Reliable, WithValidation)
void ServerHeal(int32 HealAmount);
bool AMyCharacter::ServerHeal_Validate(int32 HealAmount)
{
if (HealAmount < 0 || HealAmount > 100) // 예시 조건
return false;
return true;
}
void AMyCharacter::ServerHeal_Implementation(int32 HealAmount)
{
Health = FMath::Clamp(Health + HealAmount, 0.f, MaxHealth);
OnRep_Health();
}
Owner·Role 검사 및 서버 측 논리 검증
- Owning Connection: 클라이언트가 소유하지 않은 Actor에 Server RPC를 호출하면 엔진에서 무시
- 게임 로직에서도
HasAuthority()나 적절한 Role 검사를 통해 보안 이중화 - 서버는 항상 “클라이언트 입력은 의심스러운 것”으로 보고, 논리 검증을 거쳐 상태를 확정
5. 네트워크 디버깅 & 프로파일링
Stat Net
- 콘솔에서
stat net입력 시 현재 송수신 바이트/패킷 수, 채널 정보, 대기열 등을 실시간 확인 - 대역폭 사용량이 언제 급증하는지 모니터링 가능
Network Profiler & Unreal Insights
- Network Profiler
net.StartNetworkProfiler명령어로 프로파일링 시작- 세션 종료 후
.nprof파일 분석: 어떤 Actor/변수가 얼마나 트래픽을 차지했는지 확인
- Unreal Insights
- UE 4.23+부터 도입
Window -> Developer Tools -> Unreal Insights에서 Networking 관련 데이터를 시각적으로 확인- RPC 호출 타이밍, Replication 트래픽 분포 등을 확인 가능
패킷 손실·지연 시뮬레이션
Net PktLoss=X,Net PktLag=Y같은 콘솔 명령으로 인위적인 손실/지연 적용- 클라이언트 예측, 서버 보정이 잘 동작하는지, Unreliable 패킷이 유실돼도 큰 문제가 없는지 테스트 가능
로그와 경고 확인
- “No owning connection for actor” 같은 경고 로그는 RPC가 잘못 호출된 상황 (Actor 소유권 문제)
LogNet카테고리를 Verbose 이상으로 설정해 네트워크 관련 로그를 자세히 모니터링 가능
6. 결론
- RPC는 함수 호출을 통해 이벤트나 요청을 전달하고, Replication은 상태 동기화를 자동화하는 메커니즘입니다.
- 멀티플레이어 시스템에서는 “서버 권위”가 핵심이며, 클라이언트는 반드시 서버를 통해 중요한 로직을 처리해야 합니다.
- RPC/Replication 사용 시에는 빈도·신뢰성·조건 등을 고려하여 최적화하고, 적절한 보안 기법(Validation, 권한 검사)을 적용해야 합니다.
stat net, Network Profiler, Unreal Insights 등을 활용해 실시간 트래픽을 모니터링하고, 병목을 조정해나가면 보다 안정적인 멀티플레이어 경험을 제공할 수 있습니다.
7. 참고 자료
- The UFUNCTION Macro | UE4: Guidebook
- Reliable vs. Unreliable RPC performance and ordering - Epic Developer Community Forums
- Unreal Engine Multiplayer Tips and Tricks - WizardCell
- RPC Validation with Unreal Engine - Cyrex
- Replication | An Unreal Engine Blog by Cedric Neukirchen
- Unreal Engine Documentation: Networking and Multiplayer
위 문서는 UE5 C++ 멀티플레이어 개발에서 RPC와 리플리케이션을 종합적으로 다룬 가이드입니다.
안정적이고 확장성 높은 네트워크 구조를 설계하는 데 참고하시기 바랍니다.'UnraealEngine' 카테고리의 다른 글
| 언리얼 엔진 5에서 스팀 OSS 기능 구현 가이드 (0) | 2025.03.13 |
|---|---|
| 언리얼 엔진 5 멀티플레이어 가이드: 세션 관리 & Net Role/Authority 심층 (0) | 2025.03.13 |
| Unreal4 이벤트와 델리게이트 처리하기 5)TimeofDay 핸들러 생성 (0) | 2021.08.25 |
| Unreal4 이벤트와 델리게이트 처리하기 5)사용자 정의 이벤트 생성 (0) | 2021.08.24 |
| Unreal4 이벤트와 델리게이트 처리하기 4)멀티캐스트 델리게이트 생성 (0) | 2021.08.24 |