Mommy's Best Games, Inc. is an independent game developer founded in 2007. This is a view behind the scenes of our game development and marketing!


Wednesday, April 9, 2014

Recursion Regret and Command Prompt Rescue

Our current game in development, Pig Eat Ball, is written in Java and uses a game development framework called LibGDX (which also uses LWJGL). The game's not been formally announced yet as I'm still getting it's pretty face ready for prime time, but I've been talking about the development along the way.

It's been running at a good framerate and seemed to run fine on many machines, except the one computer on which we really needed run well--our level builder's computer!
For reasons I couldn't figure out, Andrew's computer would crash with *no crash file* saved. We knew it was when he built a very big level and then tried to save it, or if he tried to play a big level from within the game (I can make big levels fine and I've made some which he couldn't run).

I try-catched and wrapped all the Save and Load functions tighter than a Christmas present, but I couldn't get the crash log to save. How was I to fix this if I couldn't get it to happen on my machine, and couldn't get any information out of his machine other than "it crashes here and here"?

Until I had a thought! Probably an obvious thought to some devs reading! I was already printing a log of certain actions in the game (when things saved, loaded, etc). But that was not saving correctly, especially not when I printed the callstack.

Command Prompt Rescue

So instead--I'd just have him run it from the command prompt! Yes, open a command prompt, run the game (set it to our new 'verboseLog' setting) and walla! Information from the game is shown in the prompt that can't be lost.
Except it can! Once I started printing each object loaded by the level, we quickly ran out of space in the prompt. The solution was to right-click the top bar, open the Properties, and select the third tab to the right--Layout. There, we could change Screen Buffer Size - Height to 9999. That gave us enough space to see the callstack during the crash!

Adding more "lines" to your command prompt.

And what was the crash? Well a StackOverflow of course! I think that makes sense now why it wasn't able to catch the crash--if the stack had already run out of memory. The good news was I got to see the callstack now in the command prompt (I had Andrew copy and send me the contents from his computer).

Recursion Abuse

And the problem was, I was using recursion to traverse the tree of objects to save in the level.
I had a nested tree system, in which there could be a 'child' which would branch the tree, and a 'next' which would simply continue the length of that branch.

From our Level Editor--here's how the broken version worked, with the lazy rescursion on every object.

Foolishly I just called the recursion function on both types--Child and Next, and let it do all the work. When a thousand-long branch of Next objects would be processed, that would be where the crash could happen. The callstack would have literally thousands of objects on the stack and on some computers it could crash.

Fixed version, in which I loop through most objects.

Simple Solution

The solution was simple, recurse into the branch (via the child) but simply LOOP through the Next objects! Just handle each one, then progress to the Next object, which means only one of those objects is on the stack at one time! Simple and the callstack is nice and happy.

Why didn't I do that in the first place? Pure laziness, but I wish I had known it was going to cause this much trouble or I'd have done it the more stack-friendly way the first time!