[Edit: There’s an update to this post – Disabling Assembly Reload While in Play Mode]
As you can probably tell by now, I think Unity is great. I’ve never had such awesomely short edit & test cycles on a games project and I really value them. However like almost everything, Platonic Solids aside, it’s not perfect.
There’s one situation in-particular where Unity does something entirely unexpected (at least to me) and quite annoying:
- You’re debugging an issue, sitting at a breakpoint and you work out what the problem is (Yay!)
- You make a quick edit of the code, save the change and return to the Unity editor
- All is good. Things seem to be running happily again and then…
- BAM! There are loads of unhandled (mainly null-dereference) exceptions and you can’t seem to skip past enough of them (all your want to do is get out of play mode) so you eventually give up and just detach the debugger.
This happens because Unity hot-reloads the code (also known as ‘live compilation’) when you make changes. The process goes something like this:
- Unity notices that the code has changed and tries to recompile it
- If the recompilation if successful Unity does the hot-reload which:
- Serialises everything it can
- Tears down the managed (Mono) runtime
- Starts a new managed (Mono) runtime with the new code
- Deserialises everything it can back into the new runtime
As you can imagine, there are loads of reasons why this might go wrong:
- Anything which can’t be serialised… won’t be serialised so won’t make it through the process (leading to null-dereferences)
- Static class members aren’t serialised (leading to null-dereferences)
- Name changes to serialised fields won’t make it through to the new runtime (leading to null dereferences)
Unity sometimes seems to crash at this point but if you’re lucky enough to get through it you can exit play mode, reattach the debugger and continue where you left off…
After a while this really started to annoy me so I put together an Editor script (which evolved from some of the suggestions I found here) to stop it from happening. The basic idea is to detect a script compile and immediately exit play mode. This means that the hot-reload doesn’t happen anymore (as the editor isn’t in play mode when the compilation finishes).
So here’s the code…
ExitPlayModeOnScriptCompile.cs
Note: It needs to be inside an Editor folder in your project to work.
I’ve been developing with this script in-place for a few weeks now and am loving just being able to leave the debugger attached all day and editing the code without fear. Yay!
If you’re interested in how Unity serialisation actually works, there’s a really good Unite talk on the subject.
Edit: Also, there’s another interesting solution by Mark Currie here if you’re willing to use Console Enhanced (which is a pretty cool replacement for Unity’s standard console window with lots of extra features – I’ve been using it for a while and now find Unity can feel a little clunky without it!)