I happen to use Parse as a Cloud datastore and highly recommend it if you want to bootstrap a feature or app quickly. The goal for this post is to offer an example of how to work with parse to store any serializable type.

Farther down I will briefly explain a few benefits of this approach, but I will leave some of that to a future post.


key points

  1. We will be subclassing ParseObject. This will add alot of boilerplate in the form of Parse attributes but our queries throughout the app become much cleaner.
  2. There will be two classes:

    • ExampleObject - The object our game uses
    • ExampleObjectWrapper - The object that we store in parse

    There will also be some example usage.

  3. When we want to save to parse we will serialize the ExampleObject to an array of bytes and store that in the wrapper.
  4. When querying parse we will deserialize the byte[] into an ExampleObject.

code

ExampleObject is the object that our game cares about. The properties in this class are to make the example more interesting. At the bottom of this class are some helper methods to serialize and deserialize the data.

using UnityEngine;

//  only
[System.Serializable]
public class ExampleObject  
{
   public string Name { get; set; }
   public Vector3 Position { get; set; }
   public string ParseObjectId { get;set; }
}

ExampleObjectWrapper is a container for our ExampleObject. I've added an extra property Version for both examples and what I consider a best practice.

using UnityEngine;  
using Parse;  
using System.Runtime.Serialization.Formatters.Binary;  
using System.IO;

[ParseClassName("ExampleObjectWrapper")]
public class ExampleObjectWrapper : ParseObject  
{
   // example metadata that will help us in the future
   [ParseFieldName("Version")]
   public int Version
   {
      get { return GetProperty<int>("Version"); }
      set { SetProperty<int>(value, "Version"); }
   }

   // Our object will be serialized to this field
   [ParseFieldName("SerializedExampleObject")]
   public byte[] SerializedExampleObject
   {
      get { return GetProperty<byte[]>("SerializedExampleObject"); }
      set { SetProperty<byte[]>(value, "SerializedExampleObject"); }
   }

   // convenience property to aid with serialization and deserialization
   public ExampleObject ExampleObjectValue
   {
      get { return (ExampleObject)ByteArrayToObject(SerializedExampleObject); }
      set { return ObjectToByteArray((object)value); }
   }

   // This will convert any object to an array of bytes
   private static byte[] ObjectToByteArray(object obj)
   {
      if (obj == null)
      {
         return null;
      }

      BinaryFormatter bf = new BinaryFormatter();
      MemoryStream ms = new MemoryStream();
      bf.Serialize(ms, obj);
      return ms.ToArray();
   }

   // This serialize an array of bytes into an object
   private static object ByteArrayToObject(byte[] arrBytes)
   {
      MemoryStream memStream = new MemoryStream();
      BinaryFormatter binForm = new BinaryFormatter();
      memStream.Write(arrBytes, 0, arrBytes.Length);
      memStream.Seek(0, SeekOrigin.Begin);
      return binForm.Deserialize(memStream);
   }
}