Developing Games with Unity – Serialization (Part I)

in #unity8 years ago (edited)

For every grain of sand on this planet there are different ways of approaching a challenge. I have always preferred a systematic approach that focuses on building a firm foundation. 

In the case of game development, for me it always starts with getting serialization out of the way, so that's what I'll discuss in this post, and then in an upcoming post (or set of posts depending on how long it gets) I will walk through creating the serialization system based on what I discuss here. 

The great thing about these foundational systems like serialization is that once you write it, you will be able to reuse it on all of your future projects. There may be some slight tweaking here and there, but in general it will be something that will be with you throughout your life as a coder. 

This post won't go over any code, but will introduce you to the concept of serialization and the options you have with Unity. 

Part II: https://steemit.com/unity/@therajmahal/developing-games-with-unity-serialization-part-ii

Part III: https://steemit.com/unity/@therajmahal/developing-games-with-unity-serialization-part-iii

Part IV: https://steemit.com/unity/@therajmahal/developing-games-with-unity-serialization-part-iv

Serialization 
When developing any type of application, whether it is a game in Unity, a mobile app or desktop app serialization is one of the first things that comes to mind that needs to be addressed. Serialization is the process of taking an object in memory and storing its state (by state I mean the current values the object's member variables hold) to a file or stream. Deserialization is the reverse process, reading data from a file or stream and re-creating an object with the data from that file or stream. 

A Note about Unity and .NET
Unity technically doesn't use .NET; it uses an open source version of .NET called Mono. Additionally, Unity has made some modifications to the vanilla version of Mono so it makes upgrading the version of Mono a more involved task than usual. In fact, the modified version of Mono that Unity uses is based on .NET 2.0 (the latest version of .NET is 4.5). Newer versions of .NET have more serialization options, but we will have to make do with what Unity comes with. 

Serialization in .NET 2.0
Even in .NET 2.0, the .NET API provides two intrinsic forms of serialization; binary and XML. Binary takes an object in memory and represents it as an array of bytes in a binary file or stream. XML takes an object in memory and represents it as XML in a text file or stream. When writing data to a text file it is important to consider the encoding of the text; the most common type of encoding is UTF-8.

JSON Serialization
Today, a popular serialization format is JSON. The reasons are obvious; JSON stands for (J)ava(S)cript (0)bject (N)otation. JavaScript can read and interpret JSON strings and parse them into JavaScript objects automatically. The trouble is, at least with .NET 2.0, is that there is no intrinsic JSON serializer and while there are many third party options some of them don't handle derived classes or other things, so its pretty hit or miss out there in general. 

Fortunately, there is one that seems to do a really, really good job that is also open source, used with an MIT license. The project is called FullSerializer, created by Jacob Dufault. The Full Serializer code can be downloaded or cloned from here: 

https://github.com/jacobdufault/fullserializer 

Choosing a Serializer 
In development, Full Serializer is the serializer that my colleagues and I prefer. You may ask why we don't prefer XML. There are two primary reasons: first, we believe that JSON is easier to read than XML. Second, we use a node.js backend for projects that require a backend. Having data being transmitted in JavaScript Object Notation (compressed as bytes or plain text) makes it easy to work with on the backend as our server can parse the strings and objects intrinsically. 

Scriptable Objects 
Unity itself does provide an alternative called a Scriptable Object. The benefits are that it can serialize and deserialize any class in the Unity API. Binary and XML serialization can't. Additionally, binary and XML serialization (at least in .NET 2.0) don't not intrinsically support serialization and deserialization of classes using the IEnumerable<T> interface. 
 
The catch with Scriptable Objects is that you can't, at least by normal means, save data to a Scriptable Object at runtime. This makes it unusable for a player save game feature, for example. Another drawback would be if the game design calls for an in-game editor; the player will not be able to save their data to a Scriptable Object. 

A Scriptable Object is fine if you only need to read data in at runtime. In our judgment, however, it makes no sense to use Scriptable Objects for this one scenario and another system for the rest (like saving and loading a game). 

Our Choice 
We are big fans of Full Serializer. It is open source, licensed under the usual MIT license and we have not run into anything that it hasn't been able to serialize and/or deserialize. It really is impressive. 

For binary data, we run the object through Full Serializer to get a JSON string representing that object, then convert the string to an array of bytes. The binary serializer may not be able to serialize every type of object, but it can always serialize a string which is what Full Serializer gives us. 

Why am I Writing about this Now and not Later? 
So why am I writing at length about serialization first? Because having a plan for serialization is part of the foundation of any application that will be saving data, loading data or transmitting data. If you can take your objects in memory and convert them to data that can be saved (serialized) and loaded (deserialized) you are well on your way to being able to create not only your game but custom editors as well. You are also on your way to being able to create your own high level networking system utilizing Unity's low level API or a completely different system (in the case you want to use websockets instead of UDP, for example). It is an important step. We consider it a foundational step before doing anything else. 

What's Next?
So the first thing we are going to do is we are going to write a Serialization Manager, that will serialize objects into JSON strings using Full Serializer and then either save that string out to a file or convert it to a byte array and save that out to a binary file. Likewise, the Serialization Manager will be able to read those files from disk and create those objects with their values in tact. 

We haven't gotten to the code yet but after this primer on serialization we will jump right in, so stay tuned.