Looped live code

30 Sep 2015

Today’s update is a little lighter on text compared to the previous posts, as all the groundwork on which the main new feature was built has been done and documented previously. The feature I’ve been working on is looped live code, where ‘looped’ refers to replaying the same action replay over and over again, and ‘live code’ means modifying the game code while we’re doing the looping, Makes sense, right?

Looped live code

The first time I saw an implementation of looped live code was in Casey Muratori’s entertaining and informative Twitch/YouTube show Handmade Hero, where he codes a complete game from scratch, broadcasting every second of it. While I don’t always agree with Casey’s coding style, he’s a veteran in the game industry and has been working as a developer on Jonathan Blow’s upcoming and highly anticipated game The Witness, so he knows a thing or two about game development. Be sure to check out his YouTube archive of Handmade Hero episodes, and his blog to read his diary developing The Witness, if you are interested in game development!

Looped live code is not just a gimmick, but a very useful tool for prototyping new gameplay features or debugging existing gameplay. By looping some section of the game over and over again while tweaking or adding game logic, the effect on gameplay become immediately visible. Particularly hard sections can be tuned until they are just about right, bugs can be reliably reproduced, and the feature could be used to build a live level editor, the possibilities are limitless. So when I saw Casey Muratori’s implementation of looped live code in Handmade Hero, I decided I had to implement something similar into 2k14: The Game.

The thing I don’t really like about Casey’s looped live code implementation in Handmade Hero is that it’s a bit too ghetto to my taste, and that it can’t do the things I’d like to be able to do with 2K14: The Game. Which means: updating game code running on an iOS device or the simulator, without requiring recompilation. Looped live code in Handmade Hero works by basically writing a memory dump of the complete game state to disk along with the inputs during received while recording. When the replay is (re-) started, all game state is read back from the replay file and overwritten in memory, down to the last bit. To allow live code updates, Handmade Hero moves all game code into a DLL, which is reloaded automatically whenever it is recompiled, by means of a file timestamp check inside the main game loop.

The advantage of Handmade Hero’s method is simplicity. The disadvantages are multiple, but I’ll just list the three most relevant for our purposes: First of all the replay file has to be huge, as it has to cover the total memory footprint of the game. Second, the replay file will break, possibly crashing the game if it was running, if the in-memory layout of the game state changes, which is every time some field of a structure is changed, moved, added or removed. Third, the live code updating requires recompilation and dynamic linking. All of these three limitations are prohibitive for an iOS application, but fortunately, now that we have a scripting engine, we can do better :-)

Looped replays

The first thing that needed to get sorted out was looped replays. Everything was already in place to implement this feature, so the implementation effort was minimal. Whenever gameplay recording starts, a snapshot of the current game state is made, which can be used to reproduce the start state of the replay. Note that this is not a memory dump like in Handmade Hero, but just the minimum amount of information required to re-create the game, planet, and entities at the time recording started. You could view it as a ‘recipe’ or a ‘collection of parameters’ from which the start state can be reproduced. While recording, all gameplay inputs are serialized, and after recording stops the start state and inputs are bundled together and written to a file.

Replaying is just a matter of re-creating the game, planet and entities from the start state snapshot, and simulating the inputs as if someone was playing the game. All of this has been working for a while, including storing/re-creating Lua VM state when recording/replaying. The single thing missing was to reset game state to the start-state snapshot whenever the replay ended, and ‘rewinding’ the captured inputs. Nothing groundbreaking.

To make looped replays a little more interesting, I added a ‘start/stop recording’ button to the in-game controls. This allows recording gameplay at any point in the game, instead of just from the beginning. To maximize the usefulness for rapid prototyping or debugging the game, this is a must-have feature, as the bit of gameplay you’d like to modify or debug might only get activated after a long sequence of actions.

Live code

Similar to the looped replay feature, live code updating required minimal effort, thanks to all the work that went into the scripting engine. One of the main advantages of scripting languages is that it’s almost always trivial to execute arbitrary code fragments inside an existing VM, without requiring offline compilation: just feed the fragment to the scripting engine as a string, which will usually compile it on-line to some kind of bytecode, and inject this bytecode into the VM. Lua is no different, it’s native API has functions like ‘luaL_dostring which does exactly this.

The missing piece of the puzzle is how to get new code fragments into a game that’s already running. Since we cannot directly access or modify on-device storage, we need a way to push code to the device using some alternative medium. Like, for example, the network ;-)

The solution may sound a lot more complicated than it actually is in practice: just embed a web server into the application! The webserver can listen for incoming POST requests, and whenever it receives one, interpret the request body as Lua code and source it into the running VM using luaL_dostring.

Obviously we don’t need a full-blown webserver like Apache to push some code fragments, just something that listens at a port and parses HTTP requests. After some searching around I found the terrific GCDWebServer, which is actually an already very capable web-server that supports many things we don’t need, but at the same time is very lightweight and ridiculously easy to integrate. The whole process of downloading GCDWebServer, adding it to the project, and starting the webserver when the game starts, only took about 10 minutes, it’s really that easy. GCDWebserver makes great use of modern Objective-C and Cocoa features, which means adding handler code to process incoming requests can be done using an inline code block occupying a single line of code. Kudos and thanks to GCDWebServer’s author, Pierre-Olivier Latour, aka swisspol!

GCDWebServer uses Grand Central Dispatch to handle incoming requests on dedicated GCD threads, which means some care was needed to prevent concurrent access to the Lua VM, which is not thread-safe. I solved this by queuing up fragments using a locked NSArray, which is emptied and processed inside the game update loop. Code fragments are stored in a dictionary, using a key derived from the URL that was used to push them, so they can be made ‘sticky’ and overwritten with new versions. Whenever the replay ends and is re-started the code fragments for each key are re-sourced, to override entity state that may have been restored from the replay start state snapshot.

To simplify pushing code fragments to a replay running on an actual device, the level select screen now displays the device IP address and post URL. POST-ing fragments to this URL can be done using an HTTP tool like cURL, which is installed by default on any decent OS you would want to use for development, ie: any Linux distro or other Unix-based OS, and Mac OS X. But I’m sure getting cURL or something similar on Windows should be a breeze too, just don’t ask me because I wouldn’t know ;-)

Video

The best way to explain the usefulness of looped live code is using a video. In the video below, you can see the feature in action. I pre-recorded a bit of gameplay on my iPhone, and copied the replay file to the simulator to capture the video.

Note: the video is best watched full-screen at HD quality on desktops, or inside the YouTube player on mobile. In the embedded player the code pushed to the game is almost unreadable.

Note 2: there’s some brightness flickering visible in the video, which is some weird software problem on my computer but unrelated to the game ;-)

While the replay is looping in the simulator, a few simple code modifications are pushed to the game. First I change the planet tint color, by getting the planet through the global variable game, which is set automatically when the game starts. The second code fragment pushes a new step method for the Bullet entity, which will pulsate the size of bullets using a sine function that takes the elapsed game time as an input. The last code update changes the planet gravity by adding a non-zero x-component, which will cause the player ship to veer left.

While these may not be the most advanced use cases of the looped live code feature, you can imagine that when we start to add some actual gameplay features to 2k14: The Game, looped live code will be an extremely useful tool to try, tweak and debug the new features, as it removes the need to rebuild, deploy and restart the application whenever some piece of gameplay logic is changed.

Next steps

I haven’t decided what to work on next. Maybe I’ll refactor the way levels (planets) are represented to allow more interesting planets, for example adding support for switches, moving surface edges, etc. But I also feel like doing some graphics stuff on the side again, maybe some support for sprite animations, explosions, or configurable sprite color palettes.

The looped live code feature needs a little cleanup as well, one thing I don’t like about it right now is that the code fragments are stored inside the K14ScriptableGame instance, which sources them every time the game is reset from a snapshot. Since we have to source all pushed code fragments on every reset anyway, maybe it’s a better idea to store the fragments with the view controller, and create a whole new K14ScriptableGame instance with a fresh Lua VM every time the replay is restarted.

Development scoreboard

Implementing looped replays, integrating the webserver, and supporting live code updates together took a little over 2 hours. Unfortunately I did spend over 5 hours debugging a stupid bug in my Lua VM interface class, which had a Lua stack underflow bug that resulted in really weird random crashes that were almost impossible to trace to the actual code problem (decoding a Lua table value to an NSDictionary incorrectly popped one item too many from the Lua stack). This brings the total implementation time to about 238 hours. Native code SLOC count went up by 191 to 5904, a not insignificant amount of which went into boilerplate initializers I had to add to silence XCode 7, which has a much higher warning level when you are using NS_DESIGNATED_INITIALIZER (which is a good thing, by the way). Lua SLOC count increased by a grand total of 8, and now sits at 649.