The following is a guest post by Chris Wade. Originally posted on the TIGForums Devlog.
Hi all! I’m Chris Wade.
I’ve been helping Willy out with Relativity! To give some background, I’m a contract game programmer (mostly around Chicago) and recent graduate of DePaul University’s game development program. At school, I learned to design and develop games from scratch in C++ and using pre-made kits like Unity. During school I worked at local studios (Robomodo, Phosphor and NetherRealm Studios) in internships and contract jobs doing a mix of game design and programming work. I also have and continue to work on a lot of side projects, which you can check out over here:http://christopherwade.co/
My job on Relativity is make all the game systems work, interact and feel polished. So far, I’ve overhauled the cube and tree systems to be more robust while adding some more functionality and lately I’ve also been adding a bunch of small, editor-focused tools to help improve Willy’s level design workflow. Today I want to share a wild bug we ran into that halted our productivity for a few days. This specific bug caused the editor to crash whenever trying to load certain scenes that meet certain conditions. It’s fixed now, but it’s an interesting case that brings up some questions about how Unity operates and highlights the dangers of incomplete engine documentation.
First, some information about our system’s setup:
In the game we have a singleton setup, RelativityUtils where a bunch of colors and game feel tweak variables are held when multiple things need to get access to it at once. Some examples include cube colors, wall colors and button color. This isn’t a great way to do things if you’re sticking strictly to object-oriented design, but it makes it easy to change things in the inspector and have them be updated in the game.
Next, several objects in the game can be in any of the 6 gravities and look different between them. Gravity cubes, trees and color change beams are all like this. To improve workflow for Willy, I made it so changing an enum in the inspector of any of these objects changes their color to match. This is done in each scripts OnValidate method.
With this system in place, the editor started crashing on the load of our main testing scene. Cue panic. Every time we deleted our library files, the scene would load again but only once. After reloading the scene or re-opening the editor, we’d get a crash. After spending (probably) too much time changing one or two things in the scene and retrying, I moved onto reading crash logs.
So this looks pretty gross and on first it was total information overload, but after looking around a bit online it came to my attention that there’s a stack trace at the bottom. A stack trace is just an ordered list of as many commands as Unity can hold in reverse chronological order. Looking at this file, we can see all the steps taken leading up to the crash. Super helpful!
A good first step when looking at the stack is to find the most recent code that you wrote. Although Unity has it’s problems it’s much more likely for me to have messed up. So the first thing I wrote was OnValidate being called on the color changing beams in order to set their colors to match the set gravity direction. That process requires a call to our singleton, RelativityUtils which hasn’t been set as an instance yet. Here’s some code from the version of that singleton which was causing our crash:
When stepping through this code as the editor is starting, I noticed that OnValidate was being called just after the constructor of each class (as they’re being added to the scene in editor mode) which means that the scene has only partially been set up so far. In the color change beam’s OnValidate, we set the color with a value we get from RelativityUtils. Look again at the code for our singleton instance. If we haven’t assigned an instance of the class, then we try and use FindObjectOfType to search through the scene and check for that type of object! This is hugely problematic because we’ve only partially setup the scene and this is the cause of our editor crashing bug.
This is also where my questions start. How does Unity set up the scene graph at the start of a scene? Does it wait for all objects in the scene to load before assembling the hierarchy? Does it add them as we go through and instantiate objects? In cases like this where we’re given useful, but poorly documented functions like OnValidate. If I had source access or more filled out documentation, I could have more easily found the answer to this problem and saved more than a day’s work. Anyways, frustration aside, onto the solution.
The big problem here is that OnValidate is called when the editor is in the process of loading up a scene. That was unexpected behaviour, but now we know. What’s the solution? Add a check to not try and execute our OnValidate code if the scene is currently loading!
You’ll notice that my singleton code also removes the bit about creating a new object if there are none to find in the scene and that’s just to make sure we remember to add managers to our scenes. Otherwise the color and game feel variables on RelativityUtils will just be set to their default instead of the handpicked values they should be. Otherwise this is a very simple solution to an obscure and annoying problem.
Let me know if you have any questions about debugging in Unity or if you want to talk about our used of singletons or anything else game-related either here or on twitter: @cjacobwade