Out of order deserialization of TextAsset

I have a binary text asset that contains a “level” created in an external .net app (a “level” editor if you will). The serialization/deserialization of the “level” works perfectly in the external .net app, across different versions, etc.

I added the “level” .net assembly and the “level” .bytes file to my Assets folder. I’m using the TextAsset → MemoryStream approach for deserialization:

using MyLevelLib;
...
Stream s = new MemoryStream(File.bytes);
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new VersionDeserializationBinder();
myLevel = (Level)bf.Deserialize(s);

File is the TextAsset. I’m using a VersionDeserializationBinder that avoids issues w/ assembly names and changing version numbers.

The problem:
The result is that myLevel is null. Stepping through VersionDeserializationBinder.BindToType, the types that are being returned for deserialization are correct (never null), BUT, they are being encountered out of order. In my external “level” editor, the Level type (there is only one instance of Level in the file) is hit first, while in Unity it tries to start deserializing with a Grid[ ] (the Level has a Grid[ ]). Eventually the Unity code will hit the Level type, but the wrong ordering seems to cause problems even though all initialization is done in OnDeserialization methods.

The MemoryStream contains the correct number of bytes and is at position 0 before Deserialize is called.

I’m stumped and can’t find anyone else with the same issue, though there are a half dozen seemingly unresolved TextAsset deserialization issues on Unity Answers! I’m using Unity 3.4 pro and the ext assembly is built for .net 3.5.

Can you serialize to XML as well as Binary in your .NET level editor to verify the output? And can you write a Unity XML deserializer to verify your results? I have had similar issues with external level editor tools or externally processed data and a good sanity check is to try and load it two different ways in the debug builds, and then only load the optimal version in the release build.

At the moment, no, but that’s something I could add. I can verify that the binary data deserializes 100% correctly when the level is loaded into the external level editor.

I’ve also tried:

  • in the level editor, deserializing from a MemoryStream instead of from a file. Works correctly.
  • in Unity, deserializing from a file instead of a TextAsset + MemoryStream. Still deserializes out of order.

Hmm, then that sounds like a possible problem with the Mono deserializer. I hesitate to point any fingers in that direction at this time as it is used on a regular basis by people developing for and on top of Mono. So just to be clear, you have used System.File.IO under Unity to read in a binary file and deserialize, and it returns an incorrect result, is that correct?

Yes, binary serialization returns a null object with no exceptions via both MemoryStream of a loaded TextAsset and a FileStream of the asset directly from disk.

I think I can confirm that it is not an issue w/ TextAsset. Took the TextAsset byte buffer and dumped it back to disk - it deserialized without incident in the level editor.

Realized I’ve been using a stand-alone install of MonoDevelop to build the external assembly + level editor app. Rebuilt both in the Unity install. Levels deserializes just fine in the level editor app no matter where it’s built!

The Unity code isn’t spitting out any exceptions, it just fails to create the data structures correctly because of the out-of-order deserialization.

Thanks for your suggestions so far. Any ideas on how I could enforce a specific ordering? or why a class that extends MonoBehavior would cause .net deserialization to behave differently? I can actually serialize and deserialize a simple class just fine in Unity using .net binary serialization/deserialization. But it chokes on the order of nested classes.

Understood.

Just as an addendum, I know in the past that TextAsset had an issue with handling a NUL byte (zero byte) when you accessed the binary bytes directly. I think this has been fixed now, and for quite a few version, but I cannot find where the bug patch was posted.

Unfortunately I have no insight in to this issue. It is certainly intriguing. If I get time this week I’ll set up a test project that does some simple binary serialization from an external application and deserializes it in Unity as the issue intrigues me. Cannot promise anything though.

Thanks for all the info. I ended up bailing and using XML instead