Saving, Loading, and Serializing Data

One thing I've been wondering about while reading the book is how to I save persistent game data. Well luck would have it that chapter 12 is all about saving and loading game data.

Filesystem

When developing a game, you often need to store data locally on the filesystem running the game. To do this, Unity and C# have great integrations with the host using the System.IO name space. System.IO provides all the necessary API calls to provide you information about the filesystem. To store assets on the local host, Unity uses the Application.persistentDataPath followed by other directories of your choosing. Application.persistentDataPath returns a different persistent data folder depending on what operating system is in use.

Windows Store apps points to: %userprofile%\AppData\Local\Packages\<productname>\LocalState

Windows Standalone Player points to: %userprofile%\AppData\LocalLow\<companyname>\<productname>

Mac points to: ~/Library/Application Support/company name/product name

There are persistent data path locations for WebGL, Linux, iOS, tvOS, and Android as well. You can check them out at https://docs/unity3d.com/ScriptReference/Application-persistentDataPath.html

The System.IO namespace provides you with all the necessary calls to add, delete, and list files, directories, and file system info using the File class.

The File class takes advantage of a technology called a stream. When we read, write, or update a file, the data is first converted into an array of bytes, that are then streamed using a Stream call. This stream is responsible for carrying the bytes to or from a file acting like a translator between the game and the files.

FileStream, MemoryStream, NetworkStream, and GZipStream are all subclasses used for different functionality.

XML

XML is a special format consisting of an opening, a closing tag, and supports tag attributes. A basic XML document looks like:

<?xml version="1.0" encoding="utf-8"?>
<root_element>
  <element_item>element 1</element_item>
  <element_item>element 2</element_item>
  <element_item>element 3</element_item>
</root_element>

To work with XML documents the use of a XMLWriter is used. When XMLWriter is used it applies XML formatting, and dumps out the information as an XML file. To use XML in C# and Unite the System.Xml namespace is required. A call to XMLWrite would look something like this: R

public void WriteToXML(string filename){
  // checks to see if the file already exists
  if (!File.Exists(finelanem)){
  	//creates new filestream using the new path variable
    FileStream xmlStream = File.Create(filename);
    
    //Creates a XMLWriter instance and pass our new FileStream
    XmlWriter xmlWriter = XmlWriter.Create(xmlStream);
    //Creates the start of the XML document
    xmlWriter.WriteStartDocument();
    //Creates the root element
    xmlWriter.WriteStartElement("Level Progress");
  	// adds individual elements to the document
    for (int i = 1; i < 5; i++){
      xmlWriter.WriteElementString("Level", "Level-" + i);
    }
    // Closes the root element
    xmlWriter.WriteEndElement();
    // Closes the xmlWriter
    xmlWriter.Close();
    // Closes the xmlStream
    xmlStream.close();
  }
}

Reading from and XML file is no different that reading any other document. A call to readfromfile() or readfromstream() will read the XML file. In the above code example near the bottom we have two calls to close(). This can be handled automatically by using a "using" statement seen below.

using(streamWriter newStream = File.CreateText(filename))
{
	newStream.WriteLine("<Save Data> for HERO BORN\n");
}

As soon as the code block finishes the outer using statement automatically closes the stream.

Serializing Data

Serializing data is all about translating an objects entire state to another. To deserialize, you do the reverse. Take the data an return it to its former state. An objects state includes properties or fields that are reference types, when serializing or deserializing, those properties should still be recognized. An important note; keep an eye to make sure that the objects properties match the dat from the file and vice versa or you may end up with an empty object.

To use serialization with XML a new namespace is needed; System.Xml.Serialization. This namespace allows you to designate what objects can be serialized. This done using the [Serializable] attribute.

JSON Serialization

C# and Unity have two separate ways to work with JSON. When working on Unity projects, the JsonUtility serializer class needs to be used. The JsonUtility class is available using the namespace System.Text. The coding is similar to the way the XML serializer works until you get to where you want to use lists or arrays. Unity's JsonUtility needs to have lists and arrays as part of a class object for them to be recognized and handled correctly.

There are many different ways to load, store, and work with files and directories in Unity and C#. Each method; text, XML, or JSON have their strengths and weaknesses. Its up to us as the developer to pick which way or several ways to use in our apps and games.