This document is about: SERVER 5
SWITCH TO

This page is a work in progress and could be pending updates.

Serialization in Photon

This page is not relevant for the JavaScript SDKs since they use JSON serialization and not the binary protocol. This makes the JavaScript SDKs have limited data types, at least compared to the other SDKs. Consider this especially if you want clients built with the JavaScript SDK to communicate with clients built with other SDKs.

Photon and its clients are using a highly optimized binary protocol to communicate.
It's compact, yet easy to parse.

Photon must convert all data into this binary protocol before it can be sent.
This is done automatically for a range of commonly used data types.
On most client APIs, you can also register your custom serialization methods for other classes you might need.
See below.

Photon Supported Types

Each Photon supported type needs some reserved bytes for the type_info.

  • Primitive types need 1 byte for type_info.
  • Most collections need 1 extra byte for the type of the collection.
    This is not the case for Hashtable, Object array and Byte array as the collection type is part of the type_info.
  • Strongly typed collections send the element type once instead of sending type_info per element.
  • All collections need 2 bytes to store their length. This is because the type of the length is short.
    Byte array is the exception to this rule. Its length is of type int
    and it needs 4 bytes to store the length.
  • A string[] can't contain null values. Use empty instead.

The following types are generally supported and known by Photon's binary protocol.
As some languages don't provide every listed type, some SDKs support less types.

Type (C#) Size [bytes] (photon_sizeof) Description
byte 2 8 bit unsigned
2 = type_info(byte) + sizeof(byte)
bool (boolean) 2 true or false
2 = type_info(bool) + sizeof(bool)
short 3 16 bit
3 = type_info(short) + sizeof(short)
int (integer) 5 32 bit
5 = type_info(int) + sizeof(int)
long 9 64 bit
9 = type_info(long) + sizeof(long)
float 5 32 bit
5 = type_info(float) + sizeof(float)
double 9 64 bit
9 = type_info(double) + sizeof(double)
String 3 + sizeof( UTF8.GetBytes(string_value) ) length ≤ short.MaxValue
3 = type_info(String) + length_size;
length_size = sizeof(short)
Object[] (Object-array) 3 + photon_sizeof(elements) length ≤ short.MaxValue
3 = type_info(Object[]) + length_size;
length_size = sizeof(short)
byte[] (byte-array) 5 + length length ≤ int.MaxValue
5 = type_info(byte[]) + length_size;
length_size = sizeof(int)
array (array of type T, T[]) 4 + photon_sizeof(elements) - length * type_info(T) length ≤ short.MaxValue
T-type can be any of the types listed in this table except byte.
4 = type_info(array) + type_info(T) + length_size;
length_size = sizeof(short)
Hashtable 3 + photon_sizeof(keys) + photon_sizeof(values) pairs count ≤ short.MaxValue
3 = type_info(Hashtable) + length_size;
length_size = sizeof(short)
Dictionary<Object,Object> 5 + photon_sizeof(keys) + photon_sizeof(values) pairs count ≤ short.MaxValue
5 = type_info(Dictionary) + 2 * type_info(Object) + length_size;
length_size = sizeof(short)
Dictionary keys should not be of type Dictionary.
Dictionary<Object,V> 5 + photon_sizeof(keys) + photon_sizeof(values) - count(keys) * type_info(V) pairs count ≤ short.MaxValue
V-type can be any of the types listed in this table.
5 = type_info(Dictionary) + type_info(Object) + type_info(V) + length_size;
length_size = sizeof(short)
Dictionary keys should not be of type Dictionary.
Dictionary<K,Object> 5 + photon_sizeof(keys) + photon_sizeof(values) - count(keys) * type_info(K) pairs count ≤ short.MaxValue
K-type can be any of the types listed in this table.
5 = type_info(Dictionary) + type_info(K) + type_info(Object) + length_size;
length_size = sizeof(short)
Dictionary keys should not be of type Dictionary.
Dictionary<K,V> 5 + photon_sizeof(keys) + photon_sizeof(values) - count(keys) * (type_info(K) + type_info(V)) pairs count ≤ short.MaxValue
K- and V-types can be any of the types listed in this table.
5 = type_info(Dictionary) + type_info(K) + type_info(V) + length_size; length_size = sizeof(short)
Dictionary keys should not be of type Dictionary.

Custom Types

For any type not listed above, Photon will need your help to de/serialize important values.

The basic idea is that you write two methods to convert your class to a byte-array and back, then register those with the Photon API.
When that's done you can include instances of that type in any message you send.

Custom types have 2 bytes for type_info:
one byte to tell that it's a custom type plus one more for the custom type code.
Photon supports up to 256 custom types. We recommend choosing custom type codes from 255 and downward.

Photon will call the serialization methods for a registered type and automatically prefix the created byte-arrays with 4 bytes:
2 bytes for the necessary type information and 2 bytes for payload length.
Due to the 4 bytes overhead, you might want to avoid registering types that are just a few bytes of data.

The Photon Server is able to forward unknown custom types "as is".
This is why you don't need to register your types in the Photon Cloud.

Make sure to register your custom types on all communicating clients.
Register custom types on server side or on plugins when needed.

RegisterType method returns a boolean result, which tells you if the type could be registered.
If any error occurs during custom type registration the method will return false and nothing will be changed.
Otherwise registration should be successful and the returned value is true.
If the custom code is already used the registration will fail and the method will return false.
Overriding registered serialization and deserialization methods for a same custom type will fail and the old ones will still be used.

Registering Custom Types on the Server

To register any unknown type for serialization in Photon Server, you have to use TryRegisterCustomType.

C#

    Protocol.TryRegisterCustomType(typeof(MyCustomType), myCustomTypeCode, MyCustomType.Serialize, MyCustomType.Deserialize);

You need two methods that write the type into a byte-array and re-create it on the receiving end.
As example, we implemented MyCustomType:

C#

public class MyCustomType
{
  public byte Id { get; set; }
 
  public static object Deserialize(byte[] data)
  {
    var result = new MyCustomType();
    result.Id = data[0];
    return result;
  }
 
  // For a SerializeMethod, we need a byte-array as result.
  public static byte[] Serialize(object customType)
  {
    var c = (MyCustomType)customType;
    return new byte[] { c.Id };
  }
}
Back to top