Archive for January, 2007

Building Assets

Saturday, January 20th, 2007

Building an entire game’s worth of source assets (from Maya, Photoshop, etc) into engine usable assets is a very time consuming process. It is a process ripe for automation.

During the development of PubCrawl we lacked the time and infrastructure to create a complete system for building assets, we were relegated to a manual build process. Tony would copy source assets from a network share on Denrei’s computer and build a game asset from each source asset using our command line tools. The game assets would then be copied into PubCrawl’s game file system. The entire process was horrendously error prone; it was not uncommon to spend precious time trying to figure out why something wasn’t showing up in the game only to discover that the wrong game asset had been copied into the game path.

A major factor preventing us from creating an asset build system was that our source assets were completely unmanaged. The source assets that Denrei created existed only on his computer. We tried checking source assets into our Subversion repository, a process which took nearly an hour any time they were checked in. Then we tried storing the source assets in a seperate repository from the source code. Tony tried valiantly to integrate it into our existing systems, but it was just not to be.

Then we discovered Perforce and all our problems evaporated. Now both code and assets are stored in one repository on our Linux server and the repository is easily accessible for scripting. The stage was set for an automated asset build system.

What I created was SNAX: the Stolen Notebook Automated eXporter. It is written in Python and designed to fit into our Buildbot/Perforce build system. It is also designed to be very extensible. I’ll get into how SNAX works, but first some background is in order.

Building Dependantly
Build systems generally work by explicitly defining dependencies between files and executing commands to resolve those dependencies. For example:

depgraph.gif

This graph is traversed from the ‘project1’ node down to find what dependencies are not met and what steps are necessary to resolve those dependencies. In this example if data.o were missing a command is executed to recreate it from data.c and data.h. The effect of this system is that only nodes that fail their dependency check are updated. If only one file has been modified only that file and those depending on it are processed.

However, a dependency based system requires that the dependency relationships for all files be completely defined. This is great for source code because a lot of files result in one executable. Assets, on the other hand, have a one-to-one or one-to-many relationship between game asset and source asset. Two source assets never result in one game asset.

Further complicating things, source assets can create arbitrarily named intermediate files. It is common in to define general dependency rules to simplify dependency definitions. A common rule for source code is that .o files depend on .h and .c files of the same name. This concisely defines a number of dependencies and also automatically handles new .h and .c files with out modifying the dependency definition. However, when the names of files are arbitrary it is impossible to use this rule. For example a Maya file named ‘level01.mb’ might produce materials named ‘wood.material’, ‘grass.material’, ‘rock.material’, etc. There is no simple way to define these dependencies, they must all be specified. It is as if the above dependency graph were reversed, with .c and .h files being produced from .o files and the names of files didn’t correspond. Each dependency has to be explicitly defined before any building could begin.

Creating and maintaining a dependency graph definition of source assets complicated by the explosion of game assets generated from source assets seemed like more trouble than it was worth… so I decided against dependency based building.

Forwards is Backwards
SNAX works in a forward direction as opposed to the dependency systems reverse traversal. Each node takes in a list of files, does a build operation, and outputs a list of built files which is passed to it’s child nodes, and so on.

buildnode.jpg

These nodes are linked together in a graph that is traversed forward. For example, to build materials and scenes from source assets a Maya binary is built into a collada file, materials and scenes are then exported from the collada file. It looks like this:

mayabuild.jpg

The advantage of this is the simplicity of defining the graph. It isn’t necessary to specify what files build to what files, only what file types build to what other types. The nodes themselves handle passing around the specific files. The definition for building scenes and materials from Maya binaries is simple:

<File filename="*.mb" builder="maya_to_collada">
  <File filename="*.dae" builder="collada_to_material"/>
  <File filename="*.dae" builder="collada_to_scene"/>
</File>

There are a couple cool features here. The builder names in the above XML correspond directly to python functions making it very easy to add new builder operations. Also, building only specific assets is easily handled by passing only the source files to be considered to the root of the forward builder. Tony used this to make the build server rebuild only the modified source assets after each check in to Perforce. Full rebuilds can also be forced from the buildbot web interface.

Conclusions
Building in a forward manner simplifies build definitions and reduces user error. In a dependency graph based system it would be easy to forget to update a dependency definition because they must be defined for each game asset file. Dependency based builds err towards doing too little whereas forward building may do too much. I prefer to do too much work to ensure that the latest game assets are always built.

For now forward building is the simplest method. We don’t have a huge number of source assets for our current project so even rebuilding all game asset takes under 3 minutes. For a larger project the limitations of forward building could become more problematic. In a project with many source assets a dependency based build system would allow very explicit definitions of what should be processed and what is output. The dependency build system can filter out unused source assets by not including them in the dependency graph. This could be emulated in the forward build system by explicitly maintaining a list of source assets and passing into the forward build system. But at that point it may be easier and more robust to simply use a dependency build system.

Perforce

Wednesday, January 3rd, 2007

During the primordial days of Stolen Notebook we decided that Subversion would be our source code management system (instead of CVS). Stolen Notebook was all but founded on Subversion. Atomic commits, the freedom to move files and directories, and global version numbers! What more could we want?

It’s hard to know what you want until you’re given it.

During programming SIG at IGDA Madison in November, Perforce was the hot topic in source control. However, at $800 per client we had some excuse for not having tried it.

Someone at Human Head discussed how they had been testing various systems for source control including Perforce and SVN. He thought Perforce and SVN were both excellent choices but Perforce won out because of it’s speed. He mentioned that Perforce is free for two clients, so there was no reason not to try it.

Over the Holidays Tony setup our server with Perforce and modified Trac to browse Perforce. I started using Perforce after I got back from the Holidays. It’s great. Combined with the Perforce SCC plugin for Visual Studio I can do all my coding, updating and checking in within the IDE. The perforce client also has loads of useful information at hand, including what other users have checked out and are working on. It’s a very powerful tool for project management.

Perforce is fast
Subversion used to take 5-10 minutes to checkout the Catharsis source code (about 150Mb). With Perforce it takes about 20 seconds. At one point we had source assets in SVN which took nearly an hour to check in and out. Perforce allows us to have our assets versioned along with source code without long checkout and update times.

Perforce is best on a LAN
The way perforce operates means that clients have to be in constant contact with the server. When a client opens a file for editing the perforce server is told. This is cool because it allows clients to see what files other users are working on. With SVN most communication with the server is done during checkout, update, or checkin. Subversion is great for use on the Internet but Perforce dominates the office. Make sure your internal network is secure, though, because Perforce itself isn’t very secure.

Perforce makes developers happy
So far I have been extremely happy with Perforce on the user end. I’ve heard from Tony that server side there are a few things that make you wonder what the Perforce guys where thinking (plain text passwords come to mind). Thankfully, they are not impossible to work out and the increased boost in productivity makes it well worth it.