Photon Realtime and protobuf-net serialization (without garbage collection problems)

I costs me a lot of time to find a good way to use Photon Realtime with a simple to use and easy serializing framework like protobuf-net. Here are some issues that I had:
- Garbage Collection everywhere
- Slow and runtime consuming LoadBalancingClient.Service() calls
- Huge garbage creation in OpCustom
- Everything resulted in: Got a unexpected Disconnect in LoadBalancingClient State: Disconnected.

Here is my Solution:
I created a base message class that is used to register all the subclasses to photon and protobuf-net. The most important thing is, that you nest the protobuf serialization inside the photon serialization:
namespace MyGame
using ExitGames.Client.Photon;
using ProtoBuf;

[ProtoInclude(1, typeof(GameInfoMessage))]
[ProtoInclude(2, typeof(ClientJoinMessage))]
[ProtoInclude(3, typeof(ClientPlayerUpdateMessage))]
//[ProtoInclude(#no, typeof(YourType))]
public class NetMessageBase
static NetMessageBase()
PhotonPeer.RegisterType(typeof(GameInfoMessage), 1, Serialize, Deserialize);
PhotonPeer.RegisterType(typeof(ClientJoinMessage), 2, Serialize, Deserialize);
PhotonPeer.RegisterType(typeof(ClientPlayerUpdateMessage), 3, Serialize, Deserialize);
//PhotonPeer.RegisterType(typeof(YourType), #no, Serialize, Deserialize);

private static object Deserialize(StreamBuffer inStream, short length)
return Serializer.Deserialize(inStream);

private static short Serialize(StreamBuffer outStream, object customobject)
var positionStart = outStream.Position;
Serializer.Serialize(outStream, customobject);
return (short)(outStream.Position - positionStart);

After that you simply call:
OpRaiseEvent(1, message, reliable, RaiseEventOptions.Default);
And OnEventAction you get it as a response:
Hope that helps! And I hope that google takes me here if I have this problem in the future!


  • MBPPedro
    edited August 2018
    Thank you in advance for your attention. :)
  • If you're looking for a way to reduce garbage from calling LoadBalancingClient.Service() - there is a much simpler way.

    • Set LoadBalancingPeer.ReuseEventInstance to true => this is a free optimization that doesn't cost you anything or require any maintenance. It will make sure EventData is reused, rather than new'd every time.
    • Set LoadBalancingPeer.UseByteArraySlicePoolForEvents to true => this requires you to bundle all data you send in a byte[] format and send it by using a ByteArraySlice. You can read more about how that's done here:

    Hope this helps.