[Unreal]언리얼 엔진 멀티 플레이어 시스템 Part2
RPCs in Detail
1) RPC의 종류
- 정기적이고 대역폭이 제한된 네트워크 업데이트 프로세스의 경우 Property Replication에 적용되고, 네트워크를 통해 즉시 전송하려는 우선순위가 높은 메시지의 경우 RPC를 사용하여 전송하게 된다.
- 모든 UFUNCTION은 Client, Server, Multicast 중 하나로 지정하여 RPC로 만들 수 있다.
- 서버에서 Client RPC를 호출하면 액터를 소유한 클라이언트에서 Implementation 함수가 실행된다.
- 액터를 소유한 클라이언트에서 Server RPC를 호출하면 Implementation 함수가 서버에서 실행된다.
- 서버에서 Multicast RPC를 호출하면 Implementation 함수가 서버 및 모든 클라이언트에서 실행된다.
- Server 및 Client RPC와 달리 관련성은 Multicast RPC의 요소이다. 액터를 소유하지 않은 클라이언트는 액터에 대한 채널을 가지고 있지 않을 수도 있기 때문이다.
- 위와 같은 경우 클라이언트는 단순히 RPC를 수신하지 않는다. 이는 지속적인 상태 변경을 클라이언트에 복제하기 위한 수단으로 Multicast RPC에 의존해서는 안 된다는 것을 의미한다.
2) Reliability (신뢰성)
- RPC는 Reliable(신뢰 가능) 또는 Unreliable(신뢰 불가능)로 설정할 수 있다.
- 대역폭이 포화된 경우 Unreliable RPC가 삭제될 수 있다. 이 경우 도착이 보장되지 않으므로 순서대로 도착한다는 보장도 없다.
- Reliable RPC는 도착하는 것이 보장되며, 단일 액터 내에서는 신뢰할 수 있는 RPC가 호출된 순서대로 도착하는 것이 보장된다.
- 함수 호출이 게임 플레이에 중요한 경우 이러한 안전성이 필요하지만, 과도하게 사용하면 대역폭 포화가 악화되고 패킷 손실 시 병목 현상이 발생할 수 있다.
3) Implementation
- C++에서는 함수의 실제 본문을
_Implementation
접미사로 정의해야 한다.
- 이는 실제로 원격 프로세스에서 실행되는 함수인 반면, 로컬에서 호출하는 함수는 네트워크를 통해 적절한 메시지를 보내는 자동 생성된 Thunk이다.
4) WithValidation
- Server RPC는 WithValidation으로 선언될 수도 있다. 이 경우 기존 함수와 동일한 인수를 사용하고, 해당 값을 신뢰할 수 있는지 여부를 나타내는 부울 값을 반환하는
"_Validate"
함수를 구현해야 한다.
- 이는 치트와 같이 서버가 게임 플레이에 영향을 미치는 방식으로 클라이언트에서 전송된 데이터를 사용하는 경우를 감지하기 위한 수단이다. 서버 RPC가 유효성 검사에 실패하면 해당 RPC를 보낸 클라이언트가 게임에서 추방된다.
- 따라서 RPC는 즉시 전송되고 신뢰할 수 있으므로, Property Replication이 제한될 수 있는 특정 경우에 유용하다.
Property Replication in Detail
- RPC는
"즉각적"
, Property Replication은 "결국"
이 핵심 단어이다.
- 서버에서 복제된 속성을 변경하면 모든 클라이언트가 결국 서버와 동기화 될 것을 기대할 수 있다. 플레이어가 너무 멀리 떨어져 액터와의 관련성이 사라질 때, 서버에서 액터가 변경되면 변경 사항은 계속 유지 된다. 결국 액터가 다시 해당 클라이언트와 관련되면 업데이트된 속성 값을 받게 된다.
- Property Replication은 어떤 경우에도 업데이트 빈도 및 대역폭 제한을 준수한다. 서버의 단일 프레임마다 복제된 속성을 변경할 수 있으며, 클라이언트는 업데이트 될 때마다 가장 최근 값을 가져온다. 즉, 서버는 모든 중간 지점의 값들을 하나씩 보내지 않아도 된다. (여기서는 업데이트 되는 값을 보간 해주었음.)
(동영상 링크) 13:30 ~ 14:05
- Property Replication을 활성화하려면 해당 속성의 UPROPERTY에 Replicated 지정자를 추가하면 된다.
- C++에서는 액터의 .cpp 파일에
GetLifetimeReplicatedProps()
함수를 정의해야 한다. (UnrealNetwork.h도 포함시키는 것이 좋다.) 이 함수에서는 복제해야 하는 속성과 조건을 지정한다. 가장 간단한 경우에는 속성이 항상 모든 클라이언트에 복제되며, 이 때는 DOREPLIFETIME 매크로에서 속성의 이름을 지정하여 이를 수행한다.
- 그러나 복제 조건을 지정할 수도 있는데, 아래와 같은 경우가 있다. (이외에도 존재)
- 1) 소유 클라이언트에 속성을 복제하기만 하면 되는 경우
- 2) 업데이트를 받기 위해 비소유 클라이언트만 필요한 경우
- 3) 생성 시 초기화되지만 런타임 시 변경되지 않는 경우
- 복제된 속성이 업데이트 될 때 일부 코드를 실행해야 하는 경우 RepNotify 함수를 선언하고 ReplicatedUsing 지정자를 사용할 수 있다. 복제 업데이트로 인해 값이 변경될 때마다 지정된 알림 함수가 클라이언트에서 호출된다.
- 블루프린트에서 서버의 속성 값을 변경하면 서버에서 연관된 RepNotify 함수가 자동으로 호출된다는 점에 유의해야 한다. (C++에서는 아님.)
- RepNotify 로직을 클라이언트뿐만 아니라 서버에서도 실행하려면 속성 값을 업데이트 한 후 RepNotify 함수를 수동으로 호출해야 한다.
Authority & Role
- 액터가 가질 수 있는 역할은 여러 가지가 존재하지만, 액터에 대한 권한이 나에게 있는지만 고려하면 된다.
- Authority를 가지고 있는 것은 항상 서버이며, 클라이언트는 그저 업데이트를 받아 업데이트 사이에 액터에 시뮬레이션을 적용할 뿐이다.
- 액터 클래스에서 일부 코드를 실행할 때마다 권한을 확인할 수 있다.
- 권한 O : 싱글 플레이 모드에서 실행되거나, 코드가 서버에 의해 실행되고 있거나, 액터가 클라이언트에만 존재하는 경우
- 권한 X : 클라이언트에서 실행되고, 이 액터는 서버에서 복제된 경우
- PlayerController가 소유 클라이언트에 복제되는 것은 AutonomousProxy이고, 연관된 Pawn 또한 해당 클라이언트에 대한 AutonomousProxy이다. 다른 모든 클라이언트의 경우 Pawn은 SimulatedProxy로 복제된다.
- AutonomousProxy는 클라이언트가 완전한 권한을 가지지는 못하더라도, 액터의 움직임과 행동을 직접적으로 제어한다는 것을 의미한다. (액터가 소유 클라이언트의 플레이어 컨트롤러에 의해 움직이는 경우)
- SimulatedProxy는 마지막으로 전송된 속도에 따라 시뮬레이션하고, AutonomousProxy는 플레이어 컨트롤러에 의해 입력된 정보에 따라 시뮬레이션한다.
👁️🗨️ 출처