Categories
Uncategorized

Epic saga of Unity3D deserialization of arbitrary Objects/Classes

(a summary writeup of the things I tried – based on this Unity blog post: blogs.unity3d.com/2014/06/24/serialization-in-unity/ – to get Unity 4.5 to correctly serialize/deserialize simple object graphs)

UPDATE: I belatedly discovered that EditorUtility.setDirty() is fundamental to Unity; if you have even one single call of this missing, Unity will corrupt data when you save the project. In some of the cases below, where everything was fine EXCEPT on fresh startup, I suspect that was the real problem: a missing setDirty(). I thought this method was cosmetic, but tragically: no.

This is not easy to read, it’s bullet points summarising approximately 2 weeks of testing and deciphering (plus a month or so spent learning-the-hard-way the things that are in the Unity blog post above. Note that the blog post only came out very recently! Until then, you had to discover this stuff by trial and error)

Serializable-thing:

– example on blog won’t work if e.g. your Class is an object graph.
– e.g. class Room { List doors; }. class Door { Door otherDoor; }
– …can’t be serialized. Can’t be stored as a struct, unless you have a GUID per “Door” instance. That’s no surprise, didn’t bother me: This is standard in most serialization systems.
– So we go on a quest to create a GUID…

GUID1:

– class Door : ISerializeCallback { Door otherDoor; public string guid = Guid.NewGuid().ToString(); /* use OnBefore / OnAfter callbacks to store the guid of the other door / find the door from guid */ }

Unity inspector lists:

– if you add an item to the list, 2 things corrupt your data:
1. all existing objects are NOT MOVED, but are CLONED into new list. This breaks our GUID.
2. the new item is a carbon-copy clone of the old – so it ends up with the SAME GUID (ouch)

GUID2:

– class Door { [SerializeField]private string _guid = Guid.NewGuid().ToString(); }
– now the inspector no longer clones the guid … BUT … instead it sets it to null.
– it seems to run the constructor, then use serialization to delete all values it finds

GUID3:

– class Door { private string _guid = Guid.NewGuid().ToString(); public string serializedGuid; /** use serialize callbacks to maintain serializedGuid */ }
– Disable the Editor’s list-renderer: it has at least two major bugs that corrupt data. Use the UnityEditorInternal.ReorderableList.
– NB: ReorderableList – with no customization – does not have either of the two bugs I saw with built-in Inspector’s lists.
– NB: as a bonus, with RL, we can avoid the “run constructor, delete all data, deserialize, reserialize” cycle, and directly create a new, blank instance with a safely generated – FRESH! – Guid.

Ctrl-D in Editor:

– breaks this, because we have no idea if a deserialize event comes from “ctrl-d” or from “read back from disk” (or from a prefab instantiating into the scene).

GUID4:

– class Door { public Room serializedRoom; private string _guid; /** use callbacks to peek into the serialized room, and use the guid as a “local ID within this room” */ }
– Because we’re now leaning on Room (which is a GameObject) to provide part of our GUID, in theory we don’t care about prefab/ctrl-d/etc — the code inside MonoBehaviour will automatically separate-out those cases for us.

Work with everything except prefabs, I think

– eventually gave up, removed the GUID completely, and changed game design to only allow ONE door to connect any pair of rooms. Yes, I was desperate!

THIS WORKS! Until you restart Unity:

– restarting unity causes this to deserialize on a different thread, and now you’re NOT ALLOWED to peek into the serialized room. You cannot use it as a substitute ID. You get crashes at load-time).
– …apart from that, this works fine. We have a solution that worked for ctrl-D, for prefabs.

GUID5:

– class Door { public Room serializedRoom; private bool _isUnityStillOnBackgroundThread; /** use the bool to say “deserialize happened but the data is NOT VALID, DONT RUN ANY METHODS” */ }
– …also use an AutoRun script with [InitializeOnLoad] and “EditorApplication.update += RunOnce;”
– …the autorun script waits for Unity to startup, then goes and Finds all objects, and finds all Rooms, all Doors — and does the fixup.

Fail, but can’t be debugged:

– I have no idea why this failed. It appeared perfect. Simply moving code that worked inside the deserialize (but crashed because it was run on “wrong” thread) out into the post-launc RunOnce method … silently fails. No errors, but no data.
– NB: this is impossible to debug, because we can’t even call ToString() on the deserialize method :(.

Conclusion

Give up. Make 10,000’s of Component instances instead. Waste memory, kill performance (especially at runtime: imagine how bad the AI’s going to be iterating over this!) but hey – IT WILL WORK. Because it leans on the built-in hacks that MonoBehaviour has had for years (which we’ve all been using millions of times a day without realising / appreciating ;)).

Categories
Uncategorized

Upgrading your Makerbot Replicator2 – 2014

3D printers are almost unique as a product: they can upgrade themselves. The Rep2 is one of the most popular/successful “production ready” printers out there. This post looks at what to do when you get a new one to upgrade it to the latest, bestest it can be.

Categories
games design programming Unity3D Unity3D-tips

Debugging A* Pathfinding in Unity

I needed fast, efficient, … but powerful, adaptable … pathfinding for my hobby project. My minions have to fly, walk, crawl, teleport, tunnel their way across a procedural landscape. Getting to that point has been tricky, but the journey’s been interesting.

We want something that intelligently routes creatures around obstacles, and picks “shallow” routes instead of scaling cliffs (or vice versa for Giant Spiders etc). Something like this:

Screen Shot 2014-08-10 at 20.09.36

Categories
iphone programming

OpenGL ES 2 – Video on iPhone in 3D, and Texture-Map sources

This is a blog post I wrote 6 months ago, and my life got too busy to finish it off, finish testing the code, improving the text. So I’m publishing this now, warts and all. There are probably bugs. There are bits that I could explain better – but I don’t have time. Note that the code is ripped from apps where I ACTUALLY USED IT – so I know it does work, and works well!

In brief:

  1. Using different “sources” of textures in OpenGL, not just images!
  2. Using CALayer’s as a source — allows for video in 3D!
  3. Using “Video straight from the video decoding chip” as a source – faster video!