Serializing data on mobile devices with protobuf (C#)

Jun
17

Serializing data on mobile devices with protobuf (C#)

When it comes to serialize data on Unity, the built-in serializer maybe is a bit slower on mobile devices, specially if you have a lot of data to serialize. To achieve better performance we can serialize our data with protobuf. In this tutorial I’m going to explain how to install and serialize/deserialize data with protobuf on Unity.

Protobuf is known as Protocol Buffers, the Google’s data interchange format. Protocol Buffers are a way of encoding structured data in an efficient yet extensible format. Google uses Protocol Buffers for almost all of its internal RPC protocols and file formats. The official library does not support C#, fortunately there is a project called protobuf-net to implement protobuf on C#, it’s really an amazing project and it’s really faster. Is it quick? Yes, a lot! In case of doubt check some performance tests their author published here: protobuf-net performance.

Setup

Steps to integrate protobuf-net into our Unity project.

1. Download latest protobuf-net version from the protobuf-net project website.
2. Create a new library dll with the model you want to serialize. Remember you need to link the library: protobuf-net-version/Full/unity/protobuf-net.dll in order to use the protobuf attributes. Let’s assume this is our library:

using ProtoBuf;

namespace protolibrary
{
    [ProtoContract]
    public class ProtoData
    {
        [ProtoMember(1)]
        public string name;

        [ProtoMember(2)]
        public float health;
    }
}

Build this library and save it with the name you want. I’m going to use the name myprotolib.dll and will save the generated dll on the same folder where the protobuf-net precompiler is located to make this tutorial easier to undertand: protobuf-net-version/PreCompile.

3. Create the serialization/deserialization classes with the protobuf-net precompiler. Go to protobuf-net-version/Precompile folder and execute the following command on a console:

precompile.exe myprotolib.dll -o:Serializer.dll -t:MySerializer

This will output Serializer.dll with the class name MySerializer. This is the class we’re going to use on C# to serialize our data.

4. Copy the files: protobuf-net-version/Full/unity/protobuf-net.dll, your serializer: Serializer.dll and the library myprotolib.dll to your Unity project folder: Assets/Plugins/Android
5. You’re ready to work with protobuf-net on Unity!

Serializing and deserializing

Once we’ve our setup ready, serialize and deserialize data with protobuf it’s pretty easy on Unity.

using protolibrary;
using System.IO;
using System;

public string GetFilePath()
{
    return Application.persistentDataPath + "/serializedata.bytes";
}

public void SerializeData()
{
    ProtoData data = new ProtoData();
    // Fill your data. The following values are for demonstration purposes only
    data.name = "codestalkers";
    data.health = 100.0f;

    MySerializer mSerializer = new MySerializer();
    using (FileStream file = File.Create(GetFilePath()))
    {
        mSerializer.Serialize(file, data);
    }
}

public IEnumerator DeserializeData()
{
    // Did you know you can use the file schema on the WWW Unity class? Works like a charm!
    WWW file = new WWW("file://" + GetFilePath());
    yield return file;

    using (MemoryStream memStream = new MemoryStream(file.bytes))
    {  
        MySerializer mSerializer = new MySerializer();
        ProtoData mData = (ProtoData) mSerializer.Deserialize(memStream, null, typeof(ProtoData));

        Debug.Log("Name: " + mData.name);
        Debug.Log("Health: " + mData.health);
    }
}

We’re almost done! Now let’s see how we can serialize Unity classes.

How to serialize Unity classes

If we want to serialize classes like Vector3Quaternion, etc. will not work by default. To make it work, we need to make use of the implicit operator. In the following example I’m going to integrate Vector3 and Quaternion in our protobuf library, do the same on the Unity classes you want to serialize.

using ProtoBuf;
using UnityEngine;

[ProtoContract]
public class ProtoData
{
        [ProtoMember(1)]
        public string name;
  
        [ProtoMember(2)]
        public float health;
  
        [ProtoMember(3)]
        public MyVector3 position;
  
        [ProtoMember(4)]
        public MyQuaternion rotation;
}

[ProtoContract]
public class MyVector3
{
        [ProtoMember(1)]
        public float x;
   
        [ProtoMember(2)]
        public float y;
   
        [ProtoMember(3)]
        public float z;
   
        public MyVector3()
        {
              this.x = 0.0f;
              this.y = 0.0f;
              this.z = 0.0f;
        }
   
        public MyVector3(float x, float y, float z)
        {
              this.x = x;
              this.y = y;
              this.z = z;
        }
   
        public static implicit operator Vector3(MyVector3 v)
        {
              return new Vector3(v.x, v.y, v.z);
        }
   
        public static implicit operator MyVector3(Vector3 v)
        {
              return new MyVector3(v.x, v.y, v.z);
        }
}

[ProtoContract]
public class MyQuaternion
{
        [ProtoMember(1)]
        public float x;
   
        [ProtoMember(2)]
        public float y;
   
        [ProtoMember(3)]
        public float z;
          
        [ProtoMember(4)]
        public float w;
   
        public MyQuaternion()
        {
              this.x = 0.0f;
              this.y = 0.0f;
              this.z = 0.0f;
              this.w = 0.0f;
        }
   
        public MyQuaternion(float x, float y, float z, float w)
        {
              this.x = x;
              this.y = y;
              this.z = z;
              this.w = w;
        }
   
        public static implicit operator Quaternion(MyQuaternion v)
        {
              return new Quaternion(v.x, v.y, v.z, v.w);
        }
   
        public static implicit operator MyQuaternion(Quaternion v)
        {
              return new MyQuaternion(v.x, v.y, v.z, v.w);
        }
}

I hope this tutorial has been helpful and can help someone.

Thank you for reading! 🙂