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 Vector3, Quaternion, 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!