Photonでのシリアル化

Photonとクライアントは、非常に最適化されたバイナリプロトコルを通信に使用しています。 このバイナリプロトコルは簡潔で、容易に解析できます。

Photonは送信前に、すべてのデータをこのバイナリプロトコルに変換する必要があります。 この処理は、通常使用されるデータ型について自動的に実行されます。 ほとんどのクライアントAPIでは、必要となる他のクラスに独自のシリアル化手順を登録することも可能です。 以下を参照してください。

Contents

Photonでサポートされている型

下記のタイプは通常サポートされていて、Photonのバイナリプロトコルとして知られています。
言語によってはリストにある全ての型を提供していませんので、SDKによっては型のサポートが少ないものもあります。

Type (C#) Size [bytes] Description
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
array of <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
additional size if K- or V-type is object

Back To Top

Photon Unity Networkingで追加された型

(英語版にはありませんでした)

(英語版にはありませんでした)

Type (C#) Size [bytes] Description
Vector2 12 2 floats
Vector3 16 3 floats
Quaternion 20 4 floats
PhotonPlayer 8 integer PhotonPlayer.ID

Back To Top

カスタムタイプ

上記リストに含まれていない型の場合、重要な値をシリアライズ化または非シリアライズ化する必要があります。

基本的には二つのメソッドを書いてクラスをバイト配列に変換してから戻します。その後にそれをPhoton APIに登録します。 登録が完了すれば、メッセージにその型のインスタンスを含むことができます。

Photonが登録された型のシリアライズ化メソッドを呼び、自動的に作成したバイト配列(4byte)と必要なタイプ情報をプリフィックスします。 4 byteのオーバーヘッドがあるので、byteの少ないデータの登録は避けた方が良いかもしれません。

Photon Serverは不明のカスタムタイプをそのまま転送することもできます。このため、Photon Cloudではタイプの登録をする必要がありません。

通信する全てのクライアントにカスタムタイプを登録してください。

Back To Top

C#でのカスタムタイプ

全てのC#ベースのAPIは(.NET, Unity, Xamarin, etc)同じ方法でクラスの登録を行います。 カスタムSteamクラスを使用するか、「普通」のbyte配列を使用するかによって2通りの方法があります。

Back To Top

Byte配列メソッド

コールの静的メソッド:

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

SerializeMethodDeserializeMethodは以下の各シグネチャで定義されたデリゲートです。

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

Back To Top

例として、基本的なMyCustomTypeを実装しました:

public class MyCustomType
{
  public byte Id { get; set; }

  public static object Deserialize(byte[] data)
  {
    var result = new MyCustomType();
    result.Id = data[0];
    return result;
  }

  public static byte[] Serialize(object customType)
  {
    var c = (MyCustomType)customType;
    return new byte[] { c.Id };
  }
}

これを登録するには以下を参照してください:

    PhotonPeer.RegisterType(typeof(MyCustomType), myCustomTypeCode, MyCustomType.Serialize, MyCustomType.Deserialize);

Back To Top

StreamBufferメソッド

StreamBufferStreamクラスのカスタム実装です。これを実行すると、byte配列ラッパーのメリットを存分に受けられます。また、Photonにビルトインのシリアライズ可能なタイプもサポートしています。

コールの静的メソッド:

    RegisterType(Type customType, byte code, SerializeStreamMethod serializeMethod, DeserializeStreamMethod deserializeMethod)

SerializeStreamMethod and DeserializeStreamMethod are defined delegates with the following respective signatures:

    public delegate byte[] SerializeMethod(StreamBuffer outStream, object customobject);
    public delegate object DeserializeMethod(StreamBuffer inStream, short length);

Back To Top

PUNがどのようにUnityのVector2に対応しているかを説明します。

PUNのカスタム実装タイプはすべて "Assets\Photon\PhotonUnityNetworking\Code\CustomTypes.cs"の下にあります。

Vector2にはxとyの二つのfloatがあり、それぞれVector2.xVector2.yです。 Photonはfloatには対応していますがVector2には対応していません。

基本的にはC#のどのような方法でfloat型を表す4byteを取得しても問題ありません。PhotonのProtocolクラスには効果的に複数のタイプをバイト配列に書き出すシリアライズ方法がいくつかあります。

    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タイプに投げる必要があります。

あとは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);

Back To Top

追加情報

複雑なデータのカスタムシリアライザーションを行う場合、データがどのように転送されるか、またどのようにトラフィックを監視して管理下に置いておくかを理解することが重要です。

ドキュメントのトップへ戻る