ISerialization madness

I’m having a hard time with ISerialization process. Related to my post on the forum, I built a simple example to reproduce my problem.

Steps to reproduce:

  1. Create a script TestSerializer.cs anywhere on your project
  2. Assign script to an Empty GameObject
  3. Press play

Console output:

Serialization Test: myTest (12.0, 12.0, 12.0) (12, 12, 12)
Serialization Vec3: (12, 12, 12)
Deserialization Test: myTest (0.0, 0.0, 0.0) (0 0, 0, 0)
Deserialization Vec3: (12, 12, 12)
Result: myTest (0.0, 0.0, 0.0) (12, 12, 12)

Should have outputted:

Serialization Test: myTest (12.0, 12.0, 12.0) (12, 12, 12)
Serialization Vec3: (12, 12, 12)
Deserialization Vec3: (12, 12, 12)
Deserialization Test: myTest (12.0, 12.0, 12.0) (12, 12, 12)
Result: myTest (12.0, 12.0, 12.0) (12, 12, 12)

Problem:

I do understand that this process seems to be asynchronous since my t.vec3 is modified internally to the correct value at a different time. But since I’m converting Vec3 to Vector3 before that internal magic happen, my Vector3 is always (0,0,0).

To me, deserialization process seems to be reversed: Vec3 should be deserialized before Test. So I must did something wrong?

It indeed looks like the .net deserializer only deserializes the vec3 after your GetObjectData() finishes. One workaround you could do is have your Vector3 nested in your Vec3, and handle the creation of it in the vec3 deserialize method.

The (to me) more interesting question here is: why do you need to do this?

I’ve just tried your code in Visual Studio in a console application and it works perfectly :slight_smile:

From my past experience with Unity, do only use the internal serialization system of Unity.

If you want to serialize a personal object, you can also define a byte array as a public member of a MonoBehaviour. Then just serialize/desarialize to/from this byte array with the binary formatter.
Do not implement the ISerialize interface, just use the Serialize attribute it works fine.
The byte array itself will be saved by UNity because its a public member.

Here is an example of implementation:

using System.ComponentModel;
using ICSharpCode.SharpZipLib.Zip;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour 
    {
    // Keep it private instead of public to hide it in the inspector and to other scripts
    [SerializeField, HideInInspector]
        private byte[] m_BackupArray;
    
        private MyClassToSerialize m_MyClassToSerialize;
    
    	// Restore your class
    	void Awake () 
        {
    	    RestoreChanges();
    	}
    
        public void StoreChanges()
        {
            // Save your class with compression
            var saveStream = new System.IO.MemoryStream();
            using (var stream = new ZipOutputStream(saveStream))
            {
                stream.PutNextEntry(new ZipEntry("My backup"));
                var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                binaryFormatter.Serialize(stream, m_MyClassToSerialize);
                stream.CloseEntry();
            }
            saveStream.Close();
            m_BackupArray = saveStream.GetBuffer();
        }
    
        public void RestoreChanges()
        {
            if (m_MyClassToSerialize != null)
            {
                using (var stream = new ZipInputStream(new System.IO.MemoryStream(m_BackupArray)))
                {
                    stream.GetNextEntry();
                    var binaryReader = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    m_MyClassToSerialize = (MyClassToSerialize) binaryReader.Deserialize(stream);
                }
            } 
            else
            {
                m_MyClassToSerialize = new MyClassToSerialize();
            }
    
            // One way to keep track of the changes
            m_MyClassToSerialize.PropertyChanged += OnMyClassToSerialize_PropertyChanged;
        }
    
        void OnMyClassToSerialize_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            StoreChanges();
        }
    }