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).
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.
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.
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.
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”.
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.