ProtoBuf-Net + Unity - Is It Worth It?

It’s been a while since I worked with unity but during that time I did experiment with JSON and ProtoBuf a little and I began to wonder if it was really worth trying to bring ProtoBuf to unity (JSON is a bit easy to implement IMHO). Then I did a small test with ProtoBuf using this:

[ProtoBuf.ProtoContract]
public class PBVector3
{
    [ProtoBuf.ProtoIgnore]
    public UnityEngine.Vector3 vector3 = new UnityEngine.Vector3();
    public PBVector3 (){}
    public PBVector3 (UnityEngine.Vector3 source)
    {
        vector3 = source;
    }
    [ProtoBuf.ProtoMember(1, Name = "x")]
    public float X
    {
        get { return vector3.x; }
        set { vector3.x = value; }
    }
    [ProtoBuf.ProtoMember(2, Name = "y")]
    public float Y
    {
        get { return vector3.y; }
        set { vector3.y = value; }
    }
    [ProtoBuf.ProtoMember(3, Name = "z")]
    public float Z
    {
        get { return vector3.z; }
        set { vector3.z = value; }
    }
    public static implicit operator UnityEngine.Vector3(PBVector3 i)
    {
        return i.vector3;
    }
    public static implicit operator PBVector3(UnityEngine.Vector3 i)
    {
        return new PBVector3(i);
    }
}

And this:

public class Test : MonoBehaviour {
    public int runs = 5000000;
    void Start () {
        Stream o = new FileStream("*path*", FileMode.Create);
        System.Diagnostics.Stopwatch a = new System.Diagnostics.Stopwatch();
        a.Start();
        for(int i = 0; i < runs; i++)
            Serializer.Serialize<PBVector2>(o, new Vector2(-3.4028234663852886E38f, 3.4028234663852886E38f));
        o.Close();
        a.Stop();
        Debug.Log(a.ElapsedMilliseconds);
        o = new FileStream("*path*", FileMode.Open);
        a.Reset();
        a.Start();
        for(int i = 0; i < runs; i++)
        {
            Vector2 v = (Vector2)Serializer.Deserialize<PBVector2>(o);
        }
        a.Stop();
        Debug.Log(a.ElapsedMilliseconds);
    }
}

So in essence, I just made a simple wrapper for Vector2 and casted it back and forth between it and the actual Vector2 struct. It’s about as close as I’ve gotten to seamlessly bringing in ProtoBuff but I will admit that it is somewhat clunky to me. However, I’m still in the process of testing other approaches such as extension methods and trying to compare this against other serialization methods.

So far, it seems that each Vector2 uses 10 bytes apiece; my assumption is that 8 of those are the data representing the values x and y and the other 2 bytes are for the field tag and type. Then that means that there’s nothing that explicitly states that it’s a Vector2?

I’ll take a good guess that this has long already been done I’ll just need to dig a little…

I don’t have the answer to your question, but want to point out that Protobuf-net doesn’t require such boilerplate for serializing other’s types (such as Unity Vector3).

E.g. see c# - Protobuf-Net serialize object with unaccessible to proto type - Stack Overflow

1 Like

It’s clunky because you aren’t using .proto files to define your messages. A standard protocol buffer message definition for a vector3 is 5 lines total. The standard way of doing this is you define your messages in a .proto file, and then use protoc to compile them. Then just use them like any other class.

Protobuf messages are not self describing which is a core feature.

Serialization performance is generally a non issue. Network/file latency dwarfs the actual serialization/deserialization times. If it’s not, I guarantee you are doing something wrong.

1 Like

In order to use protobuf with Unity, can i pick up the latest release from their site? or do i have to use some other “port” that works with Unity ?

NuGet Gallery | protobuf-net 3.2.30 still has the docs and there is a link tothe nuget page which I suggest for installing.

You can use protobuf-net as snacktime mentioned above, but it does not work out of the box. This instruction might be helpful for you:

https://medium.com/@datdeveloper/using-protocol-buffer-in-unity-ios-android-windows-phone-8-1-4a8ea18e082b

Ya if you like pain do that. If you don’t, just generate all your messages into a single .cs file and drop it into unity.

Also, if you have a serializer for each message type you probably forget you can nest messages. So when sending over the network use a container message. Then you only need to serialize/deserialize one message type in one place.

As I remember, you can use protobuf-net like that for desktop/android

But for iOS/windows Phone you have to do it the painful way. More details:

http://blog.marcgravell.com/2012/07/introducing-protobuf-net-precompiler.html?m=1

I’ve always used the portable library without issues. But even if you want to precompile like that no need for a dll per message, and you could automate the process.

His warnings about using the portable library are a bit short on why. I have a feeling the restrictions are mostly to do with his non standard features, because using just proto files and not any non standard features and I’ve had no issues.

1 Like

Oh yes we do not need a DLL/message, I think the example in the post causes misundestanding. We can use 1 DLL for all messages

Actually for something like a game, FlatBuffers are much better (also by Google, see here: FlatBuffers: FlatBuffers ). No marshalling overhead. You waste a lot of time and space using Protocol Buffers compared to “direct binary”.

E.g. check this out (Json vs Protocol Buffers vs FlatBuffers):
https://google.github.io/flatbuffers/md__benchmarks.html

E.g. from the first link:

1 Like

How much better depends on context and environment. I’ve done tons of stress testing of my Game Machine platform where pretty much 90% of the objects being created are protocol buffers. I regularly test the Game Machine client with where it’s getting updates for a couple of hundred entities in visual range, all of them protocol buffers. And yes object creation and memory allocation are an issue.

But most games don’t push that kind of volume, and would see little if any benefit in performance using flatbuffers.

That said I like how flatbuffers was architected. It is a better fit for games. I don’t see it being enough better to say switch a large project over to, but I’d definitely look at it for new projects.

Sorry for necro-ing the post but I have written a new Unity script that compiles/regenerates all of your .proto files in the project automatically. Some one might be interested in it : GitHub - 5argon/protobuf-unity: Automatic .proto files compilation in Unity project to C# as you edit them, plus utilities.

6 Likes