serialization of Gameobjects with c#

I’m working on a serializer to store values for the different “mats” in a game. Everything works good except for the link to the mats gameobject. I get an error on the gameobject. All the other values store fine though. The goal is to actually edit the values in a window which I built.

InvalidCastException: Value is not a convertible object: System.Boolean to UnityEngine.GameObject
System.Convert.ToType (System.Object value, System.Type conversionType, IFormatProvider provider, Boolean try_target_to_type)

  1. Create a emptyGameobject and name it dummy. Create a folder in assets called data.
  2. Open the editor window. You’ll get an error since a matdata file dosn’t exist yet.
  3. Click any button and it’ll save the file. Do to a Debug you’ll get another error that you don’t need to worry about.
  4. Open the window again and when it loads it’ll create a few blank records.
  5. Click save and close. Now the matdata file should be completely good.
  6. Open the window again and when it tries to load the file the error occurs.

Now the classes. I cut out the code thats not needed to make it easier to read.

The Editor window.

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class IT_MatMaint : EditorWindow
{		
	[MenuItem("RRD Tools/Mat Maintenance")]
	public static void ShowWindow()
	{
		EditorWindow.GetWindow(typeof(IT_MatMaint));
	}
	
	void Awake()
	{
		IT_DataCore_SaveLoad.Load ();
	}
	void OnGUI()
	{
		//Menu buttons across top
		EditorGUILayout.BeginHorizontal("Box");
		if(GUILayout.Button("Metal"))
		{
			IT_DataCore_SaveLoad.Save();	
		}
		if (GUILayout.Button("Wood"))
		{
			IT_DataCore_SaveLoad.Save();
		}
		if (GUILayout.Button("Bone"))
		{
			IT_DataCore_SaveLoad.Save();
		}
		if(GUILayout.Button("Leather"))
		{
			IT_DataCore_SaveLoad.Save();
		}
		if(GUILayout.Button("Cloth"))
		{
			IT_DataCore_SaveLoad.Save();
		}
		if(GUILayout.Button("Gems"))
		{
			IT_DataCore_SaveLoad.Save();
		}
		GUILayout.EndHorizontal();
	}
}

And here is the class that is being stored in an array, again cut out the stuff thats not needed. Left one other field in as example of it working.

using UnityEngine;
 
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
 
using System;
using System.Runtime.Serialization;
using System.Reflection;
 
[Serializable]
public class IT_DataCore_physMatRecords : ISerializable
{
	public string matName="Void";
	public GameObject matSkin=GameObject.Find("dummy");

	public IT_DataCore_physMatRecords(){}
	public IT_DataCore_physMatRecords (SerializationInfo info, StreamingContext ctxt)
	{
		this.matName=(string)info.GetValue("matName",typeof(string));
		this.matSkin=(GameObject)info.GetValue("matSkin",typeof(GameObject));
	}
	public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
	{
		info.AddValue("matName",matName);
		info.AddValue("matSkin",(matSkin));
	}	
}

This is the final class that gets serialized out.
using UnityEngine;
using System.Collections.Generic;

using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
 
using System;
using System.Runtime.Serialization;
using System.Reflection;
 
[Serializable]
public class IT_DataCore_MatRecords : ISerializable {
	
	
	public List<IT_DataCore_physMatRecords> metalMats=new List<IT_DataCore_physMatRecords>();
	
	public IT_DataCore_MatRecords () {}
	public IT_DataCore_MatRecords (SerializationInfo info, StreamingContext ctxt)
	{
		this.metalMats=(List<IT_DataCore_physMatRecords>)info.GetValue("metalMats",typeof(List<IT_DataCore_physMatRecords>));
	}
		public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
	{
		info.AddValue("metalMats",metalMats);
	}
}

This is the class that actually saves and loads the binary.

using UnityEngine;
 
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
 
using System;
using System.Runtime.Serialization;
using System.Reflection;

public class IT_DataCore_SaveLoad :MonoBehaviour{
	public static string currentFilePath = "Assets/Data/BasicMats.rrd";
	public static IT_DataCore_MatRecords matData= new IT_DataCore_MatRecords();
	
	public static void Save () 
	{
		Save (currentFilePath);
	}
	public static void Save (string filePath)
	{
		
		Stream stream = File.Open(filePath, FileMode.Create);
		BinaryFormatter bformatter = new BinaryFormatter();
		bformatter.Binder = new IT_DataCore_VersionDeserializationBinder(); 
		bformatter.Serialize(stream, matData);
		stream.Close();
		Debug.Log ("Mat Record Saved");
	}
	public static void Load ()  { Load(currentFilePath);  }
	public static void Load (string filePath) 
	{
		//data = new IT_DataCore_MatRecords();
		Stream stream = File.Open(filePath, FileMode.Open);
		BinaryFormatter bformatter = new BinaryFormatter();
		bformatter.Binder = new IT_DataCore_VersionDeserializationBinder(); 
		matData = (IT_DataCore_MatRecords)bformatter.Deserialize(stream);
		stream.Close();
		if(matData.metalMats.Count==0)
		{
			for (int a=0; a<5; a++)
			{
				Debug.Log ("adding dummy record");
				IT_DataCore_physMatRecords mat= new IT_DataCore_physMatRecords();
				matData.metalMats.Add(mat);

			}
			Debug.Log (matData.metalMats[0].matSkin);
		}
		Debug.Log ("Mat Record Loaded");
	}
}

And finally a class that keeps the file name consistent.

using UnityEngine; // For Debug.Log, etc.

using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

using System;
using System.Runtime.Serialization;
using System.Reflection;

// === This is required to guarantee a fixed serialization assembly name, which Unity likes to randomize on each compile
// Do not change this
public sealed class IT_DataCore_VersionDeserializationBinder : SerializationBinder
{
public override Type BindToType( string assemblyName, string typeName )
{
if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) )
{
Type typeToDeserialize = null;

    assemblyName = Assembly.GetExecutingAssembly().FullName; 

        // The following line of code returns the type. 
        typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); 

     return typeToDeserialize; 
    } 

    return null; 
} 

}

Do I need to store the gameobjects in a different way or did I goof up somewhere with the gameobjects? I’m thinking if I can’t get this to work I might just store the value as a string but not sure if I will be able to easily convert a prefab name to a string or vice verse.

Thanks in advance and sorry for the wall of text :slight_smile:

I ended up just storing the asset name as string in the file and swapping back and forth between string and Gameobject as needed. Everything working now :slight_smile: