RPC

개체의 속성과 상태, 위치를 동기화하는 것은 정확하고 자연스러운 멀티플레이어 환경 확보를 위해 중요합니다. 그러나 플레이어가 행하는 동작도 동기화해야 합니다.

값이 특정 동작을 표시하기 위해 변하는지 폴링할 수 있지만 대부분은 동작을 다른 플레이어에게 전달하여 관련 함수를 호출하게 하는 것이 더 좋습니다.

RPC는 함수 시그니처와 옵션 인수를 포함하고 있는 플레이어 간에 주고 받는 메시지입니다. 이것으로 다른 플레이어의 월드에 있는 개체에 바로 메서드 호출이 가능합니다.

Strix는 각종 RPC 관련 함수로 이것을 지원합니다.

등록

참고

RPC의 등록은 소유자와 레플리카 GameObject 모두에서 일어나야 합니다.

메서드를 RPC로 바꾸기 위해서는 그것을 StrixRpc 속성으로 표시해야 합니다.

[StrixRpc]
void MyRPCMethod()
{
    // ...
}

StrixBehaviour에서 유래한 클래스의 메서드만 RPC가 될 수 있습니다. 메서드를 StrixRpc 속성으로 표시하면 그 메서드에 절차 코드를 할당합니다. 이 코드는 호출할 때 메서드를 식별하는 역할을 합니다. 이 코드는 속성의 ProcedureCode 특성을 이용하여 직접 지정할 수 있습니다. 그렇지 않다면 메서드 이름의 해시를 이용합니다.

RPC 전송

Strix는 여러 가지 방법으로 RPC를 보냅니다. 이러한 방법은 RPC를 보내는 멤버가 다릅니다. 특정 멤버로 전송된 RPC는 그 RPC가 등록된 개체에서 해당 클라이언트의 인스턴스에 호출됩니다.

RPC를 호출할 때는 대상의 타입을 몇 가지 지정할 수 있습니다.

  1. 특정 방 멤버에 RPC 호출

void Rpc(UID to, string rpcName, params object[] args)
void Rpc(UID to, string rpcName, RpcSuccessEventHandler successHandler, FailureEventHandler failureHandler, params object[] args)
  1. 이 멤버에 RPC 호출

void Rpc(string rpcName, params object[] args)
void Rpc(string rpcName, RpcSuccessEventHandler successHandler, FailureEventHandler failureHandler, params object[] args)
  1. 현재 방장에만 RPC 호출

void RpcToRoomOwner(string rpcName, params object[] args)
void RpcToRoomOwner(string rpcName, RpcSuccessEventHandler successHandler, FailureEventHandler failureHandler, params object[] args)
  1. 현재 멤버를 제외하고 멤버 전체에 RPC 호출

void RpcToOtherMembers(string rpcName, params object[] args)
void RpcToOtherMembers(string rpcName, RpcSuccessEventHandler successHandler, FailureEventHandler failureHandler, params object[] args)
  1. 자신을 제외하고 방 멤버 전체에 RPC 호출

void RpcToAll(string rpcName, params object[] args)
void RpcToAll(string rpcName, RpcSuccessEventHandler successHandler, FailureEventHandler failureHandler, params object[] args)

호출할 RPC의 이름을 가져올 nameof:

nameof(MyRPCMethod);

RPC 인수

모든 RPC 전송 함수에는 몇 가지 인수가 있습니다.

참고

Strix는 RPC를 보낼 때 특정 함수 시그니처에 대해 인수 배열이 유효한지 확인하지 않습니다. 인수 시그니처가 올바른지 주의해야 합니다. 바르지 않으면 RPC 수신에 실패할 수 있습니다.

args의 배열은 특정 함수의 인수를 순서대로 나타냅니다. 함수에 인수가 하나뿐이어도 인수는 배열 안에 있어야 합니다.

Strix는 이들 인수 중에서 몇몇 타입을 직렬화할 수 있습니다.

직렬화 가능한 타입

원시 타입

  • bool

  • char

  • byte

  • sbyte

  • short

  • ushort

  • int

  • uint

  • long

  • ulong

  • float

  • double

  • byte[]

  • string

  • DateTime

  • Enums

컨테이너

  • Arrays

  • List<>

  • LinkedList<>

  • HashSet<>

  • Dictionary<,>

  • ICollection 또는 ICollection<>에서 상속된 모든 컬렉션

  • IDictionary 또는 IDictionary<,>에서 상속된 모든 컬렉션

참고

요소(딕셔너리용 키 포함)는 모두 이 섹션에 명시된 직렬화 타입이어야 합니다.

Unity 타입

  • Vector2

  • Vector3

  • Vector4

  • Vector2Int

  • Vector3Int

  • Quaternion

  • Matrix4x4

  • Color

  • Color32

  • Rect

  • RectInt

  • Bounds

  • LayerMask

커스텀 클래스

ObjectFactory.Instance.Register()로 등록하면 커스텀 클래스도 직렬화가 가능합니다. 모든 필드의 타입과 이 클래스들의 속성도 직렬화해야 합니다. 즉, 위에 명시된 타입 중 하나이거나 미리 수동으로 등록된 것이어야 합니다.

RPC 예시

코드 안에 캐릭터가 입는 데미지를 설명하는 구조가 있다고 가정하겠습니다.

struct DamageInfo
{
    public int Points;
    public Vector3 Direction;
}

이것을 RPC 메서드 안에서 매개변수로 이용하고 싶다면 먼저 등록해야 합니다. 등록은 한 번만 하면 되며 등록하기 좋은 곳은 게임 초반쯤입니다.

public class SomeGameManager : MonoBehaviour
{
    public void Start()
    {
        ObjectFactory.Instance.Register(typeof(DamageInfo));
    }
}

이 라인은 이 타입의 인수가 있는 RPC를 호출하기 전에 송신 클라이언트와 수신 클라이언트 양쪽에서 모두 실행되어야 합니다.

그러고 나면 다음과 같이 이용할 수 있습니다.

public class Character : StrixBehaviour
{
    [StrixRpc]
    public void MakeDamage(DamageInfo damageInfo)
    {

    }
}
gameObject.GetComponent<Character>().Rpc(
    nameof(Character.MakeDamage),
    new DamageInfo {
        Points = 10,
        Direction = (transform.position - gameObject.transform.position).normalized
    }
);

RpcContext

수신한 RPC에 관한 메타 정보도 얻을 수 있습니다. 그 후에는 메서드의 마지막 인수로 StrixRpcContext를 추가해야 합니다. 주의: 메서드 시그니처만 변하며 호출은 변하지 않습니다. RPC를 보낼 때는 컨텍스트 자체를 제외하고 인수를 모두 제공해야 합니다. 컨텍스트는 RPC가 호출되면 SDK가 자동으로 제공합니다. 거기서 방 멤버와 RPC를 보낸 클라이언트에 관한 정보를 추출할 수 있습니다.

[StrixRpc]
public void MakeDamage(DamageInfo damageInfo, StrixRpcContext strixRpcContext)
{
    Debug.Log("Received " + damageInfo.Points + " damage from " + strixRpcContext.sender.GetName());
}

경고 로그

RPC 이용 중에는 여러 가지 경고 메시지를 받게 됩니다. 해당 메시지의 의미와 원인, 수정 방법이 아래에 정리되어 있습니다.

  • Can't use RPC when not joined to room

    가능성이 있는 원인: 아직 방에 입장하지 않았거나 방에 들어왔지만 연결이 끊어졌습니다.

    수정 방법: 방에 입장 또는 재입장한 후 RPC를 다시 이용해 보십시오. 또, 방을 나온 후 로직이 제대로 작동하는지 확인하십시오.

  • Can't use RPC for %target% because it does not have StrixReplicator attached

    가능성이 있는 원인: RPC 함수를 호출하고 있는 개체에 Strix Replicator 요소가 없습니다.

    수정 방법: RPC를 호출하고 있는 개체에 Strix Replicator가 있어야 합니다.

  • Can't use RPC for %target% because networkInstanceId is not assigned yet.

    가능성이 있는 원인: RPC 함수를 호출하고 있는 개체에서 Strix Replicator가 동기화하지 않고 있습니다.

    수정 방법: RPC 실시 전에 Strix Replicator가 연결되어 동기화하고 있는지 확인하십시오.

  • StrixReplicator not found for instanceId: %instanceId%

    가능성이 있는 원인: Replicator가 예기치 않게 삭제되었습니다.

    수정 방법: Replicator가 삭제되지 않게 하십시오.

  • RPC method not found for object type: %objectType%

    가능성이 있는 원인: RPC가 이 클라이언트에 등록되지 않았을 수 있습니다. 또, RPC를 받는 개체가 올바르지 않을 수 있습니다.

    수정 방법: 클라이언트가 보내거나 받는 RPC는 모두 등록해야 합니다. 호출할 개체는 동기화해야 합니다.

  • RPC method not found: %rpcHash%

    가능성이 있는 원인: RPC가 이 클라이언트에 등록되지 않았을 수 있습니다.

    수정 방법: 클라이언트가 보내거나 받는 RPC는 모두 등록해야 합니다.

  • RPC Component not found for type %Type%

    가능성이 있는 원인: 해당 메서드를 호출하는 스크립트가 삭제되었을 수 있습니다.

    수정 방법: RPC 호출 전에 스크립트가 삭제되지 않도록 하십시오.

  • Failed to invoke Rpc: %name%. %message%

    가능성이 있는 원인: 인수 비직렬화 중에 또는 RPC 호출 중에 오류가 발생했습니다.

    수정 방법: 인수가 바르게 직렬화되고 비직렬화되는지 확인하십시오. 피호출자도 유효해야 합니다.