1. RPC
RPC(Remote Procedure Call, 원격 프로시저 호출)는 한 컴퓨터(예: 클라이언트)에서 실행된 함수를 다른 컴퓨터(예: 서버)에 있는 액터에서 실행하도록 요청하는 메커니즘이다. 프로퍼티 복제(Property Replication)가 액터의 '상태(state)'를 지속적으로 동기화하는 것이라면, RPC는 '이벤트(event)'를 전달하는 데 사용된다.
예를 들어, 플레이어가 총을 쏘는 행위는 순간적인 이벤트다. 이 때 클라이언트는 서버에게 "나 총 쐈어!"라고 RPC를 통해 알린다. 그러면 서버는 이 요청을 받아 총알을 발사하는 로직을 실행하고, 변경된 총알 수(프로퍼티)를 모든 클라이언트에게 복제하며, 총소리나 발사 이펙트 같은 시각적 효과를 NetMulticast RPC를 통해 모든 클라이언트에게 전파할 수 있다.
RPC는 단방향으로만 호출되며, 반환 값을 가질 수 없다.
2. RPC의 종류와 UFUNCTION 키워드
RPC는 UFUNCTION 매크로에 특정 키워드를 추가하여 선언한다. 호출 방향에 따라 세 가지 주요 유형이 있다.
| 키워드 | 호출 위치 | 실행 위치 | 주요 목적 |
|---|---|---|---|
Server |
클라이언트 | 서버 | 클라이언트가 서버에게 특정 액션을 요청 (입력 처리, 아이템 사용 등) |
Client |
서버 | 액터의 소유 클라이언트 | 서버가 특정 클라이언트에게만 명령을 전달 (개인용 UI 업데이트, 카메라 효과 등) |
NetMulticast |
서버 | 서버 및 모든 클라이언트 | 서버가 모든 클라이언트에게 이벤트를 전파 (폭발 이펙트, 전역 공지 등) |
추가 키워드
Reliable/UnreliableUnreliable(기본값): RPC가 전송은 되지만, 네트워크 상태에 따라 유실될 수 있다. UDP처럼 빠르지만 신뢰성은 낮다. 발소리, 사소한 파티클 효과처럼 한두 번 유실되어도 게임 플레이에 지장이 없는 이벤트에 적합하다.Reliable: RPC가 수신 측에 도달하는 것을 보장한다. TCP처럼 신뢰성이 높지만, 확인 및 재전송 로직으로 인해 더 많은 대역폭과 지연을 유발할 수 있다. 아이템 사용, 스킬 시전, 게임 시작/종료와 같이 반드시 실행되어야 하는 중요한 이벤트에 사용해야 한다.
WithValidationServerRPC의 보안을 강화하기 위한 필수적인 키워드다. 클라이언트가 악의적인 데이터를 담아 RPC를 호출하는 것을 방지한다. 이 키워드를 사용하면, RPC 구현 함수 외에 유효성 검사 함수를 반드시 함께 정의해야 한다. 만약 유효성 검사에 실패하면, 서버는 해당 클라이언트의 연결을 즉시 끊어버린다.
3. RPC 구현 방법
RPC를 선언하면, 언리얼 헤더 툴(UHT)이 접미사가 붙은 함수들을 자동으로 생성한다. 개발자는 이 함수들을 구현해야 한다.
MyRPC(): 실제 코드에서 호출하는 함수.MyRPC_Implementation(): RPC의 실제 로직이 담기는 함수.MyRPC_Validate():WithValidation사용 시, 파라미터 유효성을 검사하는 로직이 담기는 함수.
예제 코드: Server RPC with Validation
// MyCharacter.h
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 클라이언트에서 호출하여 서버에서 실행될 함수
UFUNCTION(Server, Reliable, WithValidation)
void Server_FireWeapon(const FVector& MuzzleLocation, const FRotator& MuzzleRotation);
};
// MyCharacter.cpp
// Server_FireWeapon의 유효성 검사 함수
bool AMyCharacter::Server_FireWeapon_Validate(const FVector& MuzzleLocation, const FRotator& MuzzleRotation)
{
// 예: 발사 위치가 캐릭터로부터 너무 멀리 떨어져 있으면 비정상적인 호출로 간주
if (FVector::Dist(MuzzleLocation, GetActorLocation()) > 200.0f)
{
return false; // 유효성 검사 실패
}
return true; // 유효성 검사 성공
}
// Server_FireWeapon의 실제 구현 함수
void AMyCharacter::Server_FireWeapon_Implementation(const FVector& MuzzleLocation, const FRotator& MuzzleRotation)
{
// 서버에서 실행될 로직
// 1. 총알을 스폰
// 2. 총알 수 감소
// 3. 발사 이펙트를 모든 클라이언트에 전파 (NetMulticast RPC 호출)
}
// 플레이어가 발사 버튼을 눌렀을 때 호출되는 함수
void AMyCharacter::OnFire()
{
// ... MuzzleLocation, MuzzleRotation 계산 ...
// 서버 RPC 호출. 내부적으로는 _Validate와 _Implementation이 처리됨.
Server_FireWeapon(MuzzleLocation, MuzzleRotation);
}
4. 호출 규칙과 소유권(Ownership)
RPC 호출에는 엄격한 규칙이 적용되며, 대부분 액터의 소유권과 관련이 있다.
ServerRPC: 오직ROLE_AutonomousProxy역할을 가진 액터에서만 호출할 수 있다. 즉, 클라이언트는 자신이 조종하는 캐릭터에 대해서만 서버 RPC를 호출할 수 있으며, 다른 플레이어의 캐릭터나 AI에게 명령을 내릴 수 없다.ClientRPC: 서버에서 호출하며, 해당 액터를 소유한 특정 클라이언트에서만 실행된다. 만약 액터의 소유자가 없다면 (예: 월드에 놓인 돌멩이), 이 RPC는 아무데서도 실행되지 않는다.NetMulticastRPC: 서버에서 호출해야 의미가 있다. 서버에서 호출하면 서버 자신과 연결된 모든 클라이언트에서 실행된다. 만약 클라이언트가NetMulticastRPC를 호출하면, 다른 누구에게도 전파되지 않고 오직 해당 클라이언트 로컬에서만 실행된다.
5. 내부 구현 및 계층 구조
RPC가 호출되고 실행되기까지의 과정은 여러 시스템 계층을 거친다.
- 사용자 코드 계층 (Application Layer)
- 개발자가
.h파일에UFUNCTION(Server)등의 키워드로 RPC를 선언한다.
- 개발자가
- 언리얼 헤더 툴 (Unreal Header Tool - UHT)
- UHT가 매크로를 파싱하여
_Implementation,_Validate함수의 선언부와, RPC 호출을 위한 '썽크(thunk)' 함수를generated.h파일에 생성한다. 이 썽크 함수가 바로 우리가 코드에서Server_FireWeapon()처럼 호출하는 함수다.
- UHT가 매크로를 파싱하여
- 엔진 - RPC 호출 계층 (Engine - RPC Invocation)
- 클라이언트에서
Server_FireWeapon()을 호출하면, UHT가 생성한 썽크 함수가 실행된다. - 썽크 함수는 먼저
GetLocalRole()을 확인한다. 역할이ROLE_Authority가 아니므로, 이 호출을 네트워크로 보내야 함을 인지한다. - 함수 호출 정보(고유 ID)와 파라미터(MuzzleLocation, MuzzleRotation)를
FNetBitWriter를 사용해 비트 스트림으로 직렬화한다.
- 클라이언트에서
- 엔진 - 리플리케이션 시스템 계층 (Engine - Replication System)
- 직렬화된 RPC 데이터는 해당 액터의
UActorChannel에 큐로 쌓인다. - 매 틱마다
UNetDriver는 이 큐에 쌓인 RPC 데이터와 프로퍼티 변경 데이터를 모아 하나의 패킷으로 만든다.
- 직렬화된 RPC 데이터는 해당 액터의
- 네트워크 전송 계층 (Network Transport Layer)
UNetConnection을 통해 이 패킷이 서버로 전송된다.ReliableRPC의 경우, 이 패킷이 제대로 도착했는지 확인하는 로직이UNetConnection수준에서 추가로 동작한다.
- 엔진 - RPC 수신 및 실행 계층 (서버 측)
- 서버의
UNetDriver가 패킷을 수신하고, 어떤 액터 채널(UActorChannel)로부터 온 데이터인지 확인한다. FNetBitReader를 사용해 RPC 데이터를 역직렬화하여 함수 ID와 파라미터를 추출한다.- (보안)
WithValidation이 설정된 함수라면, 먼저_Validate함수를 추출된 파라미터로 호출한다. 여기서false가 반환되면 즉시 해당 클라이언트의 연결을 끊는다. - 유효성 검사를 통과하면, 함수 ID에 해당하는
_Implementation함수를 찾아ROLE_Authority를 가진 서버의 액터에서 최종적으로 실행한다.
- 서버의
6. 요약
프로시저 리플리케이션이 체력이나 위치 같은 액터의 '상태'를 지속적으로 동기화하는 데 사용된다면 RPC, 즉 원격 프로시저 호출은 클라이언트나 서버에서 발생한 '이벤트'를 다른 컴퓨터로 전달하여 함수를 실행시키는 기능입니다. 예를 들어, 플레이어가 총을 쏘는 행위는 RPC로 서버에 알리고, 그 결과로 변하는 총알 수는 프로퍼티 복제를 통해 동기화하는 것처럼, 둘은 상호 보완적으로 사용됩니다.
- Server RPC는 클라이언트가 서버에게 특정 행동을 요청할 때 사용합니다. 예를 들어, 클라이언트가 '아이템을 사용하겠다'고 서버에 요청하는 경우입니다. 보안을 위해
WithValidation키워드를 함께 사용하는 것이 중요합니다. - Client RPC는 서버가 특정 클라이언트에게만 명령을 내릴 때 사용합니다. 예를 들어, 퀘스트를 완료한 플레이어에게만 '퀘스트 완료' UI를 띄우라고 지시하는 경우입니다.
- NetMulticast RPC는 서버가 모든 클라이언트에게 동일한 이벤트를 전파할 때 사용합니다. 예를 들어, 캐릭터가 죽었을 때 모든 플레이어 화면에서 폭발 이펙트와 소리가 나도록 하는 경우입니다.
'Unreal' 카테고리의 다른 글
| UE5 ActorComponent와 SceneComponent (0) | 2025.10.28 |
|---|---|
| Gameplay Framework (0) | 2025.10.27 |
| NetRole (0) | 2025.10.27 |
| Replication Condition (0) | 2025.10.24 |
| 언리얼 엔진 리플리케이션 Replication (1) | 2025.10.24 |
