After University I worked with 3 brothers. They’d written the software for an ISDN (remember that?) test system called the A8619. It was basically a PC, with a custom card in it, which contained (amongst many other things) another x86 processor. There was another team having trouble programming the x86 on the card. You wrote software for the card in C, compiled it to a binary, burnt it onto a prom, put it in the card, rebuilt the PC. It hurt; they were getting nowhere fast. So these chaps wrote a simple program for the card. It just sat there waiting for the host PC to send it another program.
Whenever host PCs program was restarted it would send the latest binary down to the card. Suddenly the development cycle became compile and run. I often felt that games I’ve worked on needed this – big titles take an age to load and then navigate to the area you’re trying to test. Only then do you find out that it works or not. Rubbish!
We can do better. Unity does – it supports live code reloading while running the game in the editor. There’s limits, of course, so code reloading broke at some point while we were developing Monkey Slam, and never got fixed. Next time I want to understand what’s acceptable, and keep it going all the way through. The code reloading uses Unity’s underlying serialization mechanism to preserve state while code is unloaded and reloaded. The only difference between ‘editor’ serialization and the normal case turns out to be that private variables are serialized for code-reloads.
This makes total sense to me intuitively. When you did a little deeper it become clear why Awake() is used instead of a constructor. The constructor is called after every code reload; Awake() is only called when the object is created. The correct values are serialized into each object after code-reload after each object is constructed. Breaking the game on code-reload simply means that something in the run-time state is not being correctly serialized. The Unity documentation covers the basics, but left me with a bunch of questions. Here’s a few more details:
- Statics: are not serialized at all. Initial assignment and static constructors will re-run on code-reload.
- Properties: all properties are not serialized. Counter-intuitively that’s what you want. Properties are code – they will work after code-reload as long as the object state is correctly serialized. For auto-generated properties the private backing field is serialized fine.
- Collections: arrays and List are serialized are documented as being the only serialized collections. They work, but Queue and Dictionary do not. The loss of Dictionary is the biggest roadblock for me. Add Dictionary and I could imagine writing a game. Without Dictionary that’s … hard.
The good news is though that you can nest one of the supported collections within a class of your own and have it serialize correctly. So it’s perfectly possible to implement Queue on top of List and have Unity code-reload it. You could also do that for Dictionary if you’re prepared to settle one of the performance compromises possible implementing it while relying on List serialization. I suspect in many cases one of these implementation strategies and compromises would be acceptable:
- a linear search over unsorted List. For relatively small numbers of entries this is probably fast enough. Assuming List uses a contiguous block of memory internally it may even faster for less than about 100 items as it’s cache friendly.
- maintain a sorted List. In this case lookup is fast, but insertion is linear as list entries after the insertion point need to be moved. Great for read-only data.
- use a contained Dictionary and in the Unity editor maintain a backing List which all Dictionary entries are appended to. You can avoid slow lookups on the List by blinding appending new values. On code reload you take the last value for a given key from the list and insert it into a clean Dictionary. To avoid an arbitrary size overhead of the List you could “garbage collect” the List if it’s size became bigger than a certain multiple of the Dictionary size.
All of the above would make a great projects for GitHub. I’d be tempted just to implement the Dictionary with a linear search over a List first, until there was a clear performance reason for other solutions. Years ago, when people wrote their own collections routinely I wrote a lot of software that just used lists and it was almost always fine!
I guess the question is whether that’s all worth it to maintain code-reloading? Alternately @Unity3D could we get Dictionary serialization working please?
Recently there have been a couple of great blog posts about Unity serialization, both worth checking out. The main Unity blog has a lot of serialization details posted, and Jacob Pennock wrote a great post on leveraging Unity serialization for game configuration. I’d love to see all this detail wound into the Unity documentation.