The Tale Of The Tools That Made Dead Rising 2
April 5, 2011 Page 2 of 3
The Toolkit. Hubris is a trait of Real Programmers who are very susceptible to the "Roll Your Own" syndrome. It is often easier to write your own code than to read, understand the pile of spaghetti that someone else (perhaps even you two years ago) wrote. This often leads to code duplication, and incomplete functionality. Real Programmers are also lazy[iii].
To alleviate this syndrome, a template was created similar to the way the Visual Studio wizard creates a blank WinForms project. Now the tool had game connectivity built in and the toolkit library linked in; all that was left was to hook up the widgets and the tool was done.
t also made all of our tools look very similar (at least with the game connection side of things). The toolkit also contained an array of utility functions to deal with our database, console functionality (i.e. screenshots, deployment, etc), loading/saving user options, and a random assortment of helper functions.
Plug and Play. Armed with a database, a communications protocol, and a big toolbox, it was now time to make sure we could get data in and out of all of our systems. We instrumented our game engine so play session data could end up in our database.
A few dozen tables would store all the significant events in the game (game version, console playing, items picked up, zombies killed, doors opened, quests completed, Chuck's health changes, etc). This made it very easy for designers to see how our game was being played during development.
The logical extension was to add information that programmers were interested in. We tracked asserts that fired during play sessions, poor frame rate locations, and various memory metrics for different levels. In other words, to know how big some buffer needed to be, add a few lines of code, release it into the wild, and a few days later check what the high watermark was. The hardest part was figuring out the questions; the answers were a few lines of code and an SQL query away.
Next, our bug database was integrated into the fold. Our biggest breakthrough was to add a world location (x,y,z) to every bug. This changed our bug descriptions from "A little to the left of the big green thing, next to the stuff" to three numbers (it also didn't need to be translated).
The other great benefit now that the game talked to the tools -- which talked to the bug db -- was it was one click to teleport in game to the location of the bug. During development, duplicate bugs could be avoided by querying the bug db to see what was active at your location. Bug entry was further simplified by grabbing data (screenshots, inventory, location, etc) directly from the game without the person having to type that information in.
We can now look more in-depth at how our world was populated. Our level editing tool was aptly named Midden[iv]. It controlled all of the game object definitions, where they were placed in the world, our quests, the NPCs, and a few other odds and ends. We chose to control placement of items, triggers, and gameplay information in a tool rather than a 3D package so we could iterate live in-game.
Concurrent placement of items in the same zone would also be problematic (merging the data from 3D packages is not a trivial matter). At the end of Dead Rising 2, Midden controlled about 1000 data files that were edited by many people. There were around 18,000 items placed in the world picked from a palette of almost 2000 different objects.
The core of Midden was just a pretty way of viewing the massive collection of what we called "AFOs" (Asset Factory Objects). The AFOs are arranged in a rough tree form, so a hierarchy can be built up for a given level or quest. Each AFO has a name, a type (class) and one or more key/value pairs which make up the properties for the object. In object oriented fashion, all of the items can derive from their parent items as to not duplicate functionality. In this fashion we can define every entity in our world and build all of the levels, items, etc.
Because of this abstraction, Midden only needs to know how to manage the hierarchy, and how to process AFOs to nicely display its key/value pairs. This means adding more types of objects and extending the properties of an object is now a fairly painless process. The hierarchy management was a simple tree view control; we won't bother to talk about it there.
The interesting part was how we dealt with the AFO properties. All of the important information in an AFO was contained in the key/value pairs, the key was always a string, and the value would be one of a dozen types each with their own GUI control. If we look at our Food Item, the content creator would see this form:
The buttons at the top allow the content creator to select which attribute groups (sub class) they would like to edit[v]. Through the custom controls (dropdowns, checkboxes, etc) it is very easy for the content creators to do their work without needing a programmer (when Midden connects to the game the editing is live). In addition having widgets rather than text files has greatly reduced syntax errors (it is hard to make a typo when picking from a list, or ticking a box).
From the programming end, adding a new object is a bit of work; it requires a new class (mostly boilerplate code), and some registration code. However, adding new properties is usually one line of code. Because Midden parses our source code and builds up a list of classes, their properties and which display widgets should be used, adding new key/value pairs is all on the game side (Midden just needs to be restarted, no tool side coding needs to be done).
[iv] If you don’t know what a midden is it won’t be as funny.
[v] Windows seems to be very slow at creating custom panels with hundreds of widgets, by grouping the classes in this way we could significantly improve panel creation/deletion time.
Page 2 of 3