Photon의 직렬화(Serialization)

Photon과 클라이언트는 통신할 때 고도로 최적화된 바이너리 프로토콜을 이용합니다. 바이너리 프로토콜은 컴팩트 하지만 해석하기 쉽습니다.

Photon은 데이터가 전송되기 전 바이너리 프로토콜로 변환 되어야 합니다. 일반적으로 널리 사용되는 데이터 타입에 대해서는 자동 변환 됩니다. 필요시 대부분의 클라이언트 API에서 특정 클래스들만의 직렬화(serialization) 방식을 등록 할 수 도 있습니다. 아래를 참고 해 보세요.

Photon 에서 지원하는 데이터 타입

다음의 타입들은 일반적으로 지원되는 것으로 Photon 의 바이너리 프로토콜에서 알고 있습니다.
특정 언어에서는 나열한 모든 타입을 지원하지는 않습니다. 일부 SDK 에서는 몇 가지 타입만 지원 합니다.

타입 (C#) 크기 [bytes] 설명
byte
2
8 bit unsigned
boolean
2
true or false
short
3
16 bit
int
5
32 bit
long
9
64 bit
float
5
32 bit
double
9
64 bit
string
3 + size( UTF8.GetBytes(string) )
< short.MaxValue length
byte-array
5 + 1 * length
< int.MaxValue length
int-array
5 + 4 * length
< int.MaxValue length
<type> 배열
4 + size(entries) - count(entries)
< short.MaxValue length
hashtable
3 + size(keys) + size(values)
< short.MaxValue pairs
dictionary
3 + size(keys) + size(values)
< short.MaxValue pairs
K- 또는 V-타입이 객체인 경우 추가적인 크기

Photon 유니티 네트워킹의 추가 타입

Photon 유니티 네트워킹(PUN)은 몇 개의 추가적인 타입을 지원 합니다. 추가적인 타입들은 "커스텀 타입"으로 구현되어 있으며 아래에 설명되어 있습니다.

Transform 과 PhotonView 는 이 목록에 없습니다. Transforms 은 "전체"로 설정될 수 없으므로 Position, Rotation과 Scacle 을 각각 전송 해야만 합니다. PhotonViews 는 일반적으로 viewId(줄여서) 에 의해 참조 됩니다. viewId 가 네트워크 게임에서 유일한 것으로 전송하는데 가장 부담이 없습니다.

타임 (C#) 크기 [bytes] 설명
Vector2 12 2 floats
Vector3 16 3 floats
Quaternion 20 4 floats
PhotonPlayer 8 integer PhotonPlayer.ID

커스텀 타입

위에서 열거되지 않은 타입에 대해서는 Photon을 위해 중요 값들을 직렬화/비직렬화 해주어야 합니다.

기본적인 개념은 두 개의 메소드를 통해 클래스를 byte-배열로 그리고 byte-배열을 클래스로 해주는 것을 구현 하는 것 입니다. 그리고 이 클래스를 Photon API 에 등록 합니다. 이 작업이 완료되면 이 타입에 대한 인스턴스를 모든 메세지에 포함하여 전송 할 수 있습니다.

Photon 은 등록된 타입에 대해서 직렬화 메소드를 호출 하고 자동적으로 생성된 byte-배열에 프리픽스를 붙여 줍니다. 이 프리픽스에는 타입 정보가 들어있고 4바이트 크기 입니다. 4바이트 오버헤드로 인하여 타입을 등록하는것을 원하지 않을 수 있는데 겨우 4바이트 입니다.

"현재" Photon 서버는 알수 없는 커스텀 타입을 포워드 할 수 있습니다. Photon 클라우드 내에서 타입을 등록하지 않았기 때문 입니다.

통신하는 모든 클라이언트에게 커스텀 타입이 등록 되었는지 확인 해주셔야 합니다.

C# 의 커스텀 타입

모든 C#-기반 API(.NET, Unity, Xamarin 등)는 동일한 등록 클래스를 제공 합니다.

등록 정적 메소드의 호출은 다음과 같습니다:

    PhotonPeer.RegisterType(Type customType, byte code, SerializeMethod serializeMethod, DeserializeMethod constructor)

SerializeMethod 와 DeserializeMethod 에는 위임자(delegate)가 정의됩니다:

    public delegate byte[] SerializeMethod(object customObject);
    public delegate object DeserializeMethod(byte[] serializedCustomObject);

예제

유니티의 Vector2 를 PUN 이 어떻게 구현하는지 살펴 보겠습니다.

Vector2 는 2개의 float 값을 가지고 있습니다: x 와 y 입니다. float 는 Photon 이 지원 하나 Vector2 는 지원 하지 않습니다.

SerializeMethod 에 결과적으로 바이트 배열이 필요 합니다. 기본적으로 float 와 유사한 4바이트를 받는 어떤 C# 방식을 사용해도 좋습니다. Photon 의 프로토콜 클래스는 효율적으로 몇개 데이터 타입을 바이트 배열로 써주는 몇 개의 Serialize 메소드가 있습니다.

    public static readonly byte[] memVector2 = new byte[2 * 4];
    private static short SerializeVector2(StreamBuffer outStream, object customobject)
    {
        Vector2 vo = (Vector2)customobject;
        lock (memVector2)
        {
            byte[] bytes = memVector2;
            int index = 0;
            Protocol.Serialize(vo.x, bytes, ref index);
            Protocol.Serialize(vo.y, bytes, ref index);
            outStream.Write(bytes, 0, 2 * 4);
        }

        return 2 * 4;
    }

SerializeVector2가 객체를 받아서 Vector2로 우선 캐스트(cast)해야 하는 것을 주의 하세요. 반대로 DeserializeVector2 에서는 객체만을 리턴 하게 됩니다:

    private static object DeserializeVector2(StreamBuffer inStream, short length)
    {
        Vector2 vo = new Vector2();
        lock (memVector2)
        {
            inStream.Read(memVector2, 0, 2 * 4);
            int index = 0;
            Protocol.Deserialize(out vo.x, memVector2, ref index);
            Protocol.Deserialize(out vo.y, memVector2, ref index);
        }

        return vo;
    }

마지막으로 Vector2를 등록 해야 합니다:

    PhotonPeer.RegisterType(typeof(Vector2), (byte)'W', SerializeVector2, DeserializeVector2);

 기술문서 TOP으로 돌아가기