- Home /
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:
Create a script TestSerializer.cs anywhere on your project
Assign script to an Empty GameObject
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?
Answer by BigBulle · Jun 26, 2011 at 08:46 PM
I've just tried your code in Visual Studio in a console application and it works perfectly :-)
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();
}
}
$$anonymous$$y objects (Network of Node and Links) are a bit more complicated than the attached example and I did not want to put everything in public members (that why I found the ISerializable to be useful).
I'll try to use a Proxy object that will be serialized using your method. Definitely better than saving/reading to file/resource.
In my example you have nothing in public and I've already used this method to save networks with nodes and links... The binary formatter is very powerfull, you only have to add the Serialize attribute above your class. Your class can be as complex as you want.
Please share if you get a nice implementation with Proxy
I'm playing with this as I'm writing this and I must say that I over-thought it. I still have to by-pass the Vector3 (since it "Type UnityEngine.Vector3 is not marked as Serializable.") with a dummy-object.
On a side note, where is the package for ZipOutputStream? Is it bundle with $$anonymous$$ono?
Why do you reference Vector3 in your class? Just use your method toVector3() when you need it. ZipOutputStream comes from here http://sharpdevelop.net/OpenSource/SharpZipLib/ I will add the reference in my code above.
I built quick-n-dirty proxy classes and it seems to work!
I don't know if it's a good practice to include a binder that "does no validation" (see DeserializationBinder line 70) but it allow the saved bytes to load even tho it is a "different assembly".
Answer by LucasMeijer · Jun 26, 2011 at 08:24 PM
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?
As you can read in my post on the forum, I built a navigation mesh. I'm trying to save some "precious" runtime initialization with serialization.
Your answer