" Binary Save" Stuff - Workaround for Vector3 Serialization

Hi there! I’m editing my original question because I was just looking at the tip of the iceberg and thus formulated a too much open/broad/generic question two days ago.

I’m using procedural generation to build the scenes/levels in which my buggy game takes place.
It went all good until I decided that’d have been awesome to force the machine to remember those scenes.

Now I’m fighting against the limits of the engine because it seems that, even if Vector 3 should now be a serializable class, many classes I’d like to save into a binary file are not truly serialisable.

It seems that I’ve managed to get to the point where Unity doesn’t crash and executes everything, but the binary files I export are messed up because an error keeps showing up: SerializationException: Type UnityEngine.Vector3 is not marked as Serializable.

Here’s what I need:

  1. To Serialize a custom class, MatrixMaster, which is a class that handles all the things procedurally generated in the scene, from the props ( Game Objects) to the grid ( custom class) used by agents to move around
  2. To Deserialize that class
  3. To do it with the type of Serialization I’m most " proficient" with, which is the one with BinaryFormatter

This is, so far, the chunks of code about my custom class I’ve got:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization;

//using System.Diagnostics;

[Serializable]
public class MatrixMaster : ScriptableObject, ISerializable {

	#region Fields

   //A bunch of fields, custom class ones are Serializable
   //GameObjects are comprised

	#endregion

	#region Properties

    //A bunch of properties...

	#endregion

	// Implement this method to serialize data. The method is called on serialization. 
	public void GetObjectData (SerializationInfo info, StreamingContext context)
	{
		info.AddValue("ScriptableType", this.GetType().AssemblyQualifiedName, typeof(string));
		foreach(FieldInfo field in this.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance))
		{
			info.AddValue(field.Name, field.GetValue(this), field.FieldType);
		}
	}
	
	public void SerializeThisToBinary (){
		
		// To serialize the MatrixMaster and its values, we must first open a stream for writing
		FileStream fs = new FileStream(Application.persistentDataPath + "/matrix_" + this.associatedLevel.ToString() + ".dat", FileMode.Create);
		
		// Construct a BinaryFormatter and use it to serialize the data to the stream.
		BinaryFormatter formatter = new BinaryFormatter();
		try 
		{
			formatter.Serialize(fs, this);
		}
		catch (SerializationException e) 
		{
			Console.WriteLine("Failed to serialize. Reason: " + e.Message);
			throw;
		}
		finally 
		{
			fs.Close();
		}
	}
	
	/// <summary>
	/// Deserializes a matrix saved into a binary file to an instance of that class.
	/// </summary>
	/// <returns>Returns a matrix with the values cached inside the binary file.</returns>
	/// <param name="matrixScene">The number of the scene with which the matrix to load was saved.</param>
	/// <param name="matrix">The instance of the matrix to write into.</param>
	public MatrixMaster DeserializeTo (int matrixScene, out MatrixMaster matrix){

		//This is written poorly by me, or a more competent approach see this: https://msdn.microsoft.com/it-it/library/b85344hz(v=vs.110).aspx
		//I like the Try Catch Finally thing

		//Construct a BinaryFormatter and use it to deserialize the data to the stream
		BinaryFormatter formatter = new BinaryFormatter();

		//Open the file containing the data we want to deserialize
		FileStream file = File.Open(Application.persistentDataPath + "/matrix_" + matrixScene.ToString() + ".dat", FileMode.Open);

		//Declare the instance reference
		matrix = ScriptableObject.CreateInstance<MatrixMaster>();

		// Deserialize the MatrixMaster from the file and assign the reference to the local variable
		matrix = (MatrixMaster) formatter.Deserialize(file);

		//Close the stream
		file.Close();

		//Return
		return matrix;
	}
}

I’ve referenced a lot of stuff to get to this point ( I’m quoting all links because I’d like question to be helpful to others too and this sets everybody on the same page):

ISerializationSurrogates are what you want. Even though Unity-internal, Vector3 is serializable, this has nothing to do with Serializable as NET understands it; these are two completely different things unfortunately using the same term. That being said, implementing ISS is pretty easy. I posted the required code in the comments below my answer in this thread. As an added note, You will most likely encounter further serialization problems when trying to serialize GameObject variables (and other Types specific to Unity, like Transform, Texture2D, …). You can create a custom attribute to skip this field, but then you will again encounter the error if you serialize a variable of type ClassXY which itself has a variable of type GameObject. For these cases, I recommend creating ISS for each Type that gives an error you can’t avoid, and just pass no values inside the ISS, like this:

using System.Runtime.Serialization;
using UnityEngine;

sealed class GameObjectSerializationSurrogate : ISerializationSurrogate {
	
	// Method called to serialize a GameObject object
	public void GetObjectData(System.Object obj,
	                          SerializationInfo info, StreamingContext context) {
		
		GameObject go = (GameObject) obj;
		//Debug.Log(go);
	}
	
	// Method called to deserialize a GameObject object
	public System.Object SetObjectData(System.Object obj,
	                                   SerializationInfo info, StreamingContext context,
	                                   ISurrogateSelector selector) {
		
		GameObject go = (GameObject) obj;
		
		//obj = go;
		return obj;   // Formatters ignore this return value //Seems to have been fixed!
	}
}

GameObject Serializer Pro includes many of the commonly needed surrogates out-of-the-box (Transform, Texture, Mesh, Vector3, etc… full list is here) that way you won’t need to write them. It can serialize and deserialize entire GameObjects and preserve references where subclasses of UnityEngine.Object are used.

It’s also built on top of protobuf-net, making it forward-compatible with future versions of .Net/Mono (unlike BinaryFormatter) and much more efficient than XMLSerializer.

If you need more types that are not listed in the supported types list I would be glad to add them.

A Generic BinarySerializer tool , Easy to use.
Supports : Vectors, Colors, and Quaternions too.

PACKAGE: GitHub - herbou/Unity_GenericBinarySerializer

TUTORIAL: Unity 💾 Save your game data as binary, 2 lines of code📄 - YouTube