Serializing data on mobile devices with protobuf on C#

http://www.codestalkers.com/blog/protobuf-net

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. You need to link the library of folder: protobuf-net-version/Full/unity/protobuf-net.dll in order to use the protobuf attributes. Let's assume this is our library:

1
2
3
4
5
6
7
8
9
10
11
12
namespace protolibrary
{
     [ProtoContract]
     public class ProtoData
     {
         [ProtoMember(1)]
         public string name;
 
         [ProtoMember(2)]
         public float health;
     }
}

Let's build this library and save it with the name you want. I'm going to use the name myprotolib.dll and I'm going to 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:

1
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/deserialize our data. 
4. Copy the files: protobuf-net-version/Full/unity/protobuf-net.dll, your serializer: Serializer.dll and your protobuf library myprotolib.dll to Unity 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using protolibrary;
using System.IO;
using System;
 
public string getFilePath()
{
     return Application.persistentDataPath + "/serializedata.bytes" ;
}
 
public void SerializeData()
{
     ProtoData protoData = new ProtoData();
     // Fill your protoData values
 
     MySerializer mySerializer = new MySerializer();
     using (FileStream file = File.Create(getFilePath()))
     {
         mySerializer.Serialize(file, protoData);
     }
}
 
IEnumerator DeserializeData()
{
     WWW file = new WWW( "file://" + getFilePath());
     yield return file;
 
     using (MemoryStream memStream = new MemoryStream(file.bytes))
     {  
         MySerializer mySerializer = new MySerializer();
         ProtoData myData = (ProtoData) mySerializer.Deserialize(memStream, null , typeof (ProtoData) );
         // Your data is loaded on myData
     }
}

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 to serialize the rest of Unity classes you want to serialize.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
[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!


你可能感兴趣的:(Serializing data on mobile devices with protobuf on C#)