원격 프로시저 호출
소개
RPC(원격 프로시저 호출)는 특정 이벤트를 네트워크 클라이언트 간에 공유하기에 이상적입니다. 반면에, [Networked] 속성은 지속적으로 변하는 상태를 공유하는 데 적합한 기본 솔루션입니다.
예를 들어, 플레이어가 자신에게 입력 권한이 없는 객체(예: 인벤토리의 특정 키를 사용하여 잠긴 문을 여는 것)와 드문 복잡한 상호작용을 수행하려고 할 때 RPC를 사용할 수 있습니다. 기술적으로 입력 구조체에 추가 필드를 포함하여 이를 수행할 수 있지만, 이는 입력 구조체를 복잡하게 만들고 다루기 어렵게 만듭니다.
게다가 입력 구조체는 신뢰할 수 없는 메시지로 전송됩니다(즉, 패킷이 손실될 수 있음). 이는 지속적인 입력(예: 캐릭터 이동)에는 거의 영향을 미치지 않지만, 플레이어가 보장되기를 기대하는 단일 일회성 동작에는 치명적일 수 있습니다. 이 상황에서는 원격 프로시저 호출이 최선의 방법입니다.
RPC 생성
NetworkObject의 NetworkBehaviour에서 RPC를 정의하려면 다음 단계를 따르세요:
- 반환 타입이
void또는RpcInvokeInfo인 일반 C# 메서드를 선언합니다(아래 문서화됨). - 메서드 이름 앞뒤에 "RPC"를 추가합니다(대소문자 구분 없음).
- 메서드 선언 앞에
[Rpc]속성을 추가합니다. RpcSources및RpcTargets매개변수를 설정하여 RPC 호출 위치와 실행 위치를 제어합니다.
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color){
playerName = name;
playerColor = color;
}
RPC는 작동하려면 메서드 이름에 "RPC" 접두사 또는 접미사가 필요합니다.
정적 RPC
정적 RPC는 약간의 다른 규칙을 따릅니다:
RpcSources및RpcTargets매개변수를 무시합니다.메서드의 첫 번째 매개변수는
NetworkRunner여야 합니다.특정
NetworkObject에 묶이지 않고, 모든SimulationBehaviour에서 구현할 수 있습니다.
정적 RPC는 소스와 대상 필터가 없기 때문에 모든 클라이언트에서 호출될 수 있으며 모든 클라이언트로 전송됩니다. 그러나 특정 PlayerRef를 대상으로 지정하여 호출 대상을 제어할 수 있습니다(Targeted RPC 참조).
C#
[Rpc]
public static void Rpc_MyStaticRpc(NetworkRunner runner, int a) { }
RPC 속성 매개변수
Sources와 Targets
RpcSources와 RpcTargets는 필터 역할을 합니다. RpcSources는 RPC를 보낼 수 있는 피어를 정의하고, RpcTargets는 실행될 피어를 정의합니다.
All: 세션 내 모든 피어(서버 포함)에서 보낼 수 있으며, 실행됩니다.Proxies: 입력 권한(Input Authority)이나 상태 권한(State Authority)이 없는 피어에서 보낼 수 있으며, 실행됩니다.InputAuthority: 해당 객체에 입력 권한을 가진 피어에서 보낼 수 있으며, 실행됩니다.StateAuthority: 해당 객체에 상태 권한을 가진 피어에서 보낼 수 있으며, 실행됩니다.
중요: RPC는 명시적 상태를 가지지 않습니다. 늦게 접속한 클라이언트와 연결이 끊긴 후 다시 연결된 클라이언트는 RPC가 발생한 사실을 잊게 됩니다. 따라서 RPC는 반드시 다음 중 하나를 보장해야 합니다:
- 실제로 상태를 가지지 않는 일시적인 작업(예: 채팅 메시지)일 것.
- 또는, 간접적으로
[Networked]속성에 효과를 기록할 것.
C#
public class Player : NetworkBehaviour {
[Networked] public string playerName { get; set; }
[Networked] public Color playerColor { get; set; }
[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color) {
playerName = name;
playerColor = color;
}
}
선택적 RPC 속성 매개변수
RpcSources와 RpcTargets 외에도 [Rpc] 속성은 몇 가지 선택적 매개변수를 제공합니다:
Channel(기본값Reliable): RPC가 전송 중 손실되어도 되는 경우Unreliable로 설정합니다.InvokeLocal(기본값 true): RPC가 로컬 클라이언트에서 호출되는지 여부를 나타냅니다.TickAligned(기본값 true): RPC가 전송된 틱 이후에 실행을 지연하지 않으려면 false로 설정합니다.
C#
[Rpc (RpcSources.All, RpcTargets.All, InvokeLocal = true, TickAligned = false )]
void RpcStartBoost(){
m_BoostAnim.StartBoostAnimation();
}
RPC 메소드 매개변수
RPC는 런타임에 직렬화됩니다. 따라서 Fusion 전용 타입(e.g., NetworkBool)보다는 일반 CLR 타입(e.g., bool)을 사용하는 것이 권장됩니다.
지원되는 타입
RPC에서 지원되는 타입은 다음과 같습니다:
- 기본 타입(Primitives)
- byte, sbyte
- Int16, Int32, Int64
- UInt16, UInt32, UInt64
- float
- double
- float
- double
- Unity 구조체 타입 (ILWeaver.cs에 정의됨)
- Vector2, Vector3, Vector4
- Quaternion
- Matrix4x4
- Vector2Int, Vector3Int
- BoundingSphere
- Bounds
- Rect
- BoundsInt
- RectInt
- Color, Color32
- System.Guid
- 사용자 정의
INetworkStructs - Fusion 정의
INetworkStructs- NetworkString<IFixedStorage>
- NetworkBool
- Ptr
- Angle
- BitSet64, BitSet128, BitSet192, BitSet256
- PlayerRefSet
- NetworkId
- NetworkButtons
- NetworkRNG
- NetworkObjectGuid
- NetworkPrefabRef
- NetworkObjectHeader
- NetworkPrefabId
- SceneRef
- TickTimer
- IFixedStorage (_2, _4, _8, _16, _32, _64, _128, _256, _512)
- Fusion 타입
- NetworkObject (직렬화 시
NetworkId로 변환) - NetworkBehaviour (직렬화 시
NetworkId와NetworkBehaviour인덱스로 변환) - PlayerRef (직렬화 시
PlayerRef.PlayerId로 변환)
- NetworkObject (직렬화 시
- 문자열 (Strings)
- 위에 나열된 타입의 배열
RpcInfo
RPC 메서드 선언에는 선택적으로 RpcInfo 타입의 매개변수를 추가할 수 있으며, 이를 통해 RPC에 대한 다음과 같은 메타 정보를 제공합니다:
Tick: RPC가 전송된 틱.Source: RPC를 보낸 플레이어(PlayerRef).Channel: RPC가Unreliable로 전송되었는지Reliable로 전송되었는지 여부.IsInvokeLocal: RPC가 로컬 플레이어에 의해 호출되었는지 여부.
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color, RpcInfo info = default){
playerName = name;
playerColor = color;
}
매개변수는 항상 RpcInfo info = default로 선언됩니다.
{% if Fusion_v2 %}
서버와 호스트 소스
Fusion이 ServerMode로 실행 중인 경우, 서버에서 보낸 RPC의 RpcInfo.Source는 PlayerRef.None으로 설정됩니다. 이는 서버가 플레이어로 간주되지 않기 때문입니다.
Fusion이 HostMode로 실행 중인 경우, 호스트-클라이언트는 서버와 플레이어 역할을 모두 수행합니다. 기본적으로, 호스트가 보낸 RPC는 서버와 동일하게 작동하며 RpcInfo.Source는 PlayerRef.None으로 설정됩니다. 호스트의 로컬 PlayerRef를 포함하려면 HostMode 속성을 RpcHostMode.SourceIsHostPlayer로 설정해야 합니다.
HostMode는 두 가지 모드로 설정할 수 있습니다:
RpcHostMode.SourceIsServer(기본값):RpcInfo.Source는PlayerRef.None으로 설정됩니다.RpcHostMode.SourceIsHostPlayer: Fusion이HostMode로 실행 중일 때RpcInfo.Source는 로컬PlayerRef로 설정됩니다.
호스트의 PlayerRef를 RpcSource.Info에 포함하려면 아래와 같이 코드를 조정할 수 있습니다:
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority, HostMode = RpcHostMode.SourceIsHostPlayer)]
public void RPC_Configure(string name, Color color, RpcInfo info = default){
playerName = name;
playerColor = color;
}
RpcInvokeInfo
RPC 메서드는 선택적으로 반환값으로 RpcInvokeInfo를 정의할 수 있습니다. RPC 메서드가 호출될 때, RpcInvokeInfo 반환값은 RPC 호출 및 전송 작업에 대한 정보를 제공합니다.
LocalInvokeResult: 로컬 호출 동작의 성공 또는 실패 원인을 나타내는RpcLocalInvokeResult열거형 값.SendCullResult: 원격 피어에 대한 RPC 호출 성공 또는 실패 원인을 나타내는RpcSendCullResult열거형 값.SendResult: RPC 전송 작업에 대한 메타 정보를 포함하는RpcSendResult구조체.Result: 이 RPC 메시지 전송 작업의 결과 플래그(RpcSendMessageResult).MessageSize: RPC 패키지 크기.Receivers: 이 RPC 작업의 수신자로 포함된PlayerRef의 컬렉션.CulledReceivers: 이 RPC 전송 작업에서 제외된PlayerRef의 컬렉션.
참고: 이는 전송 성공 여부에 대한 정보가 아니라, 호출 및 전송 작업의 결과만 제공합니다.
C#
[Rpc]
public RpcInvokeInfo RpcFoo() {
// RPC 작업
return default;
}
public override void FixedUpdateNetwork() {
var info = RpcFoo();
Debug.Log(info);
}
타겟팅 된 RPC
특정 플레이어의 기계에서만 실행되도록 RPC를 설정하려면 타겟팅 된 RPC를 사용합니다. 인스턴스 RPC와 정적 RPC 모두 PlayerRef 매개변수를 추가하고 [RpcTarget] 속성을 사용하여 타겟팅 된 RPC로 전환할 수 있습니다. 일반적인 사용 사례는 팀 채팅으로, 메시지가 자신의 팀원에게만 전달되는 경우입니다.
[RpcTarget] 매개변수에 PlayerRef.None을 전달하면 서버를 대상으로 지정합니다!
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.All)]
public void Rpc_TargetedInstanceMessage([RpcTarget] PlayerRef player, string message){}
또는
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.All)]
public static void Rpc_MyTargetedStaticMessage(NetworkRunner runner, [RpcTarget] PlayerRef player, string message) { };
메서드 내에서 사용하는 [RpcTarget] 속성은 메서드 선언 앞에 있는 [Rpc] 속성의 RpcTargets 매개변수와는 다릅니다.