6 - 원격 프러시저 호출
개요
원격 프러시저 호출 또는 RPC는 모든 네트워크 라이브러리의 가장 일반적인 기능 중 하나이며 일반 메소드에 대한 직관적인 매핑을 통해 공유된 세계에서 여러 클라이언트를 결합하려고 할 때 쉬운 첫 번째 선택이 됩니다. 불행하게도 이는 최선의 선택이 아닐 수도 있습니다.
Fusion과 같은 틱 기반 상태 동기화 라이브러리에서 RPC는 특정 틱에 묶이지 않고 서로 다른 클라이언트에서 서로 다른 시간에 실행되기 때문에 문제가 될 수 있습니다. 하지만 더 중요한 것은 네트워크 상태의 일부가 아니기 때문에 RPC가 전송된 후 연결되거나 다시 연결되거나 신뢰할 수 없게 전송되어 수신되지 않은 플레이어는 그 결과를 결코 볼 수 없다는 것입니다.
대부분의 경우 상태 동기화 자체만으로도 플레이어의 정렬 상태를 유지할 수 있으며, 네트워크 속성에 OnChange 리스너를 추가하면 애플리케이션이 실제 상태 자체뿐만 아니라 상태 변경에 관심을 갖는 대부분의 전환 사례를 처리할 수 있습니다.
여전히 RPC가 좋은 선택인 사용 사례가 있습니다. 다음은 몇 가지 예입니다:
- 플레이어 간의 조롱 메시지 또는 기타 휘발성 비게임 플레이 상호 작용을 전송합니다.
- 정확한 타이밍이 중요하지 않은 게임 내 상점에서 장비를 구매하고, RPC 호출의 직접적인 결과(자금 차감 및 재고 추가)는 호출을 수행한 플레이어에게만 중요합니다. (즉, RPC를 사용하여 해당 구매를 장착하지 마십시오.)
- 이름, 색, 피부와 같은 초기 플레이어 속성 설정. (즉, 플레이어의 "희귀한" 입력의 직접적인 결과인 모든 플레이어 입력. 기본적으로 틱 단위의 Input 구조체에서 가지고 싶지 않은 모든 플레이어 입력)
- 게임을 시작하는 것(게임 모드, 맵 또는 플레이어가 준비되었음을 호스트에게 표시하는 것).
Fusion RPC
RPC가 적합한 몇 가지 경우에 Fusion을 사용하면 매우 간단합니다. NetworkBehaviour
에서 RPC 속성을 가진 기존 메소드에 태그를 지정하고 해당 메소드를 호출할 수 있는 플레이어와 호출을 수신할 플레이어를 지정합니다. 메소드에 접두사 또는 포스트픽스(특정 대문자 없음)로 RPC가 있는지 확인하고 호출할 준비가 되었는지 확인하십시오.
이 작은 예제의 목표는 R
키를 누를 때 모든 플레이어에게 "Hello Mate!" 메시지를 보내는 것입니다.
RPC 호출하기
우선 씬에 텍스트 필드를 추가합니다.
GameObject > UI > Text - TextMeshPro
(필요한 경우 TextMeshPro Essentials 가져옵니다). 텍스트 필드의 크기를 전체 화면을 채우도록 변경하여 텍스트를 쉽게 읽을 수 있습니다.
RPC 자체를 추가하기 전에 입력 처리를 확장할 필요가 있습니다. RPC 호출은 실제 네트워크로 연결된 메시지이므로 입력 구조체를 확장할 필요가 없습니다. 또한 RPC가 틱 정렬되어 있지 않기 때문에 Fusion 입력 처리를 사용할 필요가 없으므로 Player.cs
를 열고 다음과 같이 추가합니다:
C#
private void Update()
{
if (Object.HasInputAuthority && Input.GetKeyDown(KeyCode.R))
{
RPC_SendMessage("Hey Mate!");
}
}
Object.HasInputAuthority
를 확인하십시오 - 이 코드는 모든 클라이언트에서 실행되지만 이 플레이어를 제어하는 클라이언트만 RPC를 호출해야 하기 때문입니다.
RPC 구현
Player.cs
에 RPC 바디 자체를 추가합니다. [Rpc]
속성이 태그 되고 메소드 이름이 다음과 같이 "RPC"로 시작됩니다:
C#
private TMP_Text _messages;
[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority, HostMode = RpcHostMode.SourceIsHostPlayer)]
public void RPC_SendMessage(string message, RpcInfo info = default)
{
RPC_RelayMessage(message, info.Source);
}
[Rpc(RpcSources.StateAuthority, RpcTargets.All, HostMode = RpcHostMode.SourceIsServer)]
public void RPC_RelayMessage(string message, PlayerRef messageSource)
{
if (_messages == null)
_messages = FindObjectOfType<TMP_Text>();
if (messageSource == Runner.LocalPlayer)
{
message = $"You said: {message}\n";
}
else
{
message = $"Some other player said: {message}\n";
}
_messages.text += message;
}
왜 여기에 단 하나의 RPC만 있는 것이 아니라 두 개의 RPC가 있는 것일까요? 이것은 Fusion 호스트 모드가 스타 토폴로지이기 때문입니다. 클라이언트는 RPC를 사용하여 직접 다른 클라이언트에게 데이터를 보낼 방법이 없습니다. 클라이언트는 호스트에만 RPC를 보낼 수 있고, 호스트는 모든 클라이언트에게 메시지를 전달해야 합니다.
SendMessage
RPC의 속성을 살펴보겠습니다:
RpcSources.InputAuthority
=> 객체에 대한 입력 권한을 가진 클라이언트만이 메시지를 보내기 위해 RPC를 트리거 할 수 있습니다.RpcTargets.StateAuthority
=> SendMessage RPC는 호스트(StateAuthority)로 전송됩니다.RpcHostMode.SourceIsHostPlayer
=> 호스트는 서버 또는 클라이언트이기 때문에 RPC를 호출할 호스트를 지정해야 합니다.
RelayMessage
RPC의 속성은 다음과 같습니다:
RpcSources.StateAuthority
=> 서버/호스트가 이 RPC를 보내는 중입니다.RpcTargets.All
=> 모든 클라이언트는 이 RPC를 받아야 합니다.HostMode = RpcHostMode.SourceIsServer
=> 호스트 애플리케이션의 서버 부분이 이 RPC를 전송하고 있습니다.
플레이어가 R
키를 누를 때마다 메시지가 각 클라이언트로 전송됩니다.
게임 플레이하기
호스트 모드 기본 튜토리얼이 완료되었습니다. 빌드를 만들고 두 클라이언트에서 플레이 모드를 시작합니다. 하나는 호스트, 다른 하나는 클라이언트입니다. 플레이어는 R
키를 눌러 이동하고 마우스 버튼으로 구를 생성하고 RPC를 보낼 수 있습니다.