Friday, August 15, 2014

GuildCraft Dev Diary: Part IX

This post is about a particularly annoying problem that I encountered with Unity. It relates to C# type initializers (static constructors) and scripts in the Unity editor.

I was working on the task of adding serialization to my character class. (This is a feature that will be needed eventually anyway, and adding it now will make testing the combat engine easier.) Progress was better than expected, considering this meant adding serialization to all classes related to character creation: race, class, skills, the effects they apply, etc.

As I added serialization to new data types, I wrote tests to ensure they deserialized properly. Finally, I added a bit of custom logic and the [Serializable] attribute to my character class, expecting everything to work brilliantly.

Instead, when I ran the editor I was greeted by this:
NullReferenceException: Object reference not set to an instance of an object
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for Namespace.DurationType.

Yay. An exception without a line number.

One that disappears when I comment out the [Serializable] attribute on my character class. One that also causes a NullReferenceException every time I try to access a member of my other data types that were previously working.

After experimenting with a variety of approaches I eventually came to the conclusion that this problem was caused by Unity. The script initialization order was changing when the [Serializable] attribute was applied to that specific class.

Unity was creating an instance of my Character class in order to add it to the UI script in the editor. It was doing this before the type initializers on types the Character class refers to had a chance to run. I'm not even sure how that is possible, since those static lines of code are supposed to execute immediately before a class is first accessed.
Aside: Mono bug? I've never seen this while using .NET or XNA.
Changing the Edit -> Project Settings -> Script Execution Order settings did not change the script execution order.

The workaround I am using involved removing all references to my character class in scripts attached to the editor scene. I found that when I removed the character sheet UI in my scene the project would play properly. (But only if Unity was restarted first! First documented case of successful use of the ragequit programming methodology?) As a result, my character sheet UI needs to be added by this lovely piece of code in a start-up routine:

Every professional piece of software has hacks. This is now a professional piece of software.

I reported the bug to Unity while seriously considering moving my code back to XNA.


No comments:

Post a Comment