This document is about: PUN 1
SWITCH TO

PUN Classic (v1)、和 Bolt 處於維護模式。 PUN 2 將支援 Unity 2019 至 2022,但不會添加新功能。 當然,您所有的 PUN & Bolt 專案可以用已知性能繼續運行使用。 對於任何即將開始或新的專案:請切換到 Photon Fusion 或 Quantum。

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.

Additional Types in Photon Unity Networking

Photon Unity Networking (PUN) supports a few additional types.
They are implemented as "Custom Types", which are explained below.

You might notice that Transform and PhotonView are not present in this list.
Transforms can't be sent "as whole" so you must send Position, Rotation and Scale individually.
PhotonViews are usually referred to by their (short-typed) viewId.
This is unique in a networked-game and cheap to send.

Type (C#) Sizeof [bytes] Code Description
Vector2 12 23 (W) 2 floats
Vector3 16 22 (V) 3 floats
Quaternion 20 17 (Q) 4 floats
PhotonPlayer 8 16 (P) integer (PhotonPlayer.ID)

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.

When choosing the code for your custom type, take into consideration that PUN registers 4 types by default as shown here.

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.

Back to top