The typical computer game has a large number of assets files. Often a game will have thousands of tiny files, each file representing perhaps an animated character or a sound. Because directories containing lots of files are hard to manage, confusing to users, and on some platforms slow to load, it is customary to bundle assets into a "resource file". Early resource formats consisted merely of concatenations of assets, where each asset would be loaded by file number within the resource file. For example, one asset scheme I wrote in 1993 would generate a C header file whenever a new asset file was built. The C header file would contain a series of #define statements, one for each asset, which would allow the game programmer to load the asset by symbolic name. The limitations of this sytem were obvious - each time an asset was inserted into the file, the numbers would change and the program would have to be recompiled.
Many game companies have developed sophisticated tool suites for managing assets, which are often considered part of the key intellectual property of the company. In 1995 I co-wrote a "resource compiler", similar to the utility Rez on the Macintosh, which would not only allow binary files to be incorporated by name into the resource file, but declarations of arbitrary structures and data initialization, including non-uniform arrays and other complex data structures which are hard to declare in C. However, this environment was quite complex, especially when faced with extremely large numbers of assets. Rebuilding the asset files for Faery Tale 2 (which took up most a CD as I recall) took roughly two hours on a Pentium 90. This meant that each time the artists made a change, it would take two hours before those changes could be previewed in the game. Breaking up the project into a smaller number of asset files didn't help, because so many of the assets had interdependencies which meant that when, for example, a sprite animation file changed, many other assets (such as frame ordering tables, scripts, etc.) would also have to be rebuilt.
It seems to me now that the best approach to the asset problem is not to develop a special suite of tools, but rather to leverage the existence of commodity tools which already exist. In particular, I have for a number of years felt that the best way to manage assets would be to simply store them in a zip file. The advantage would be that no special tools would be required to create, inspect, or modify game resource files. This was partly inspired by Java's use of zipfiles to store compiled classes. However, I wasn't able to implement this idea until about June of 1999, simply because the directory format of zip files is somewhat complex and a little bit crufty, and I didn't have the time available to puzzle it all out.
libasset is the result of this idea. In basic terms, it's just a random-access zipfile reader. When I say "random access" I mean that you can read the individual zipped files in arbitrary order. The actual files themselves must still be decompressed and read sequentially.
libasset has a number of features designed to make the game developer's life easier.
First, the directory of the zipfile is cached in memory, so assets can be located relatively quickly.
Second, libasset supports a "classpath" or in this case "asset path", which allows more than one archive of assets to be searched. Each element on the asset path can either be a zipfile or a real directory. When an asset is requested (by giving the filename path of the asset) the elements of the asset path are searched in order.
The advantage of this scheme is that an artist can easily replace individual assets without having to re-zip the asset file. Simply place the artist's working directory on the asset path in front of the main resource file for the game. Any elements placed in that directory will override assets with the same name.
In addition, the working directory can be zipped and distributed, allowing "packages" or "add-ons" to the game without having to distribute the entire set of assets for the game.
One issue that this scheme does not address is the issue of cross-linkage of assets. Early game platforms were memory tight - there was no room in memory for string-based dictionaries of assets. Instead, each asset which contained a reference to another asset had to do so via an integer, which indexed into a table of offsets. This structure was very difficult to maintain, so often sophisticated languages and build procedures were invented to describe the relationships between assets.
However, memory and CPU speed are no longer so constrained, so it's perfectly feasible to describe the relationship of assets as strings of ASCII text, which are in turn also stored as assets. The game can parse these strings at runtime without too much performance penalty. Thus, the interrelationships between assets can be described in a high-level symbolic manner, and in a way which won't break when the ordering of assets changes.
For example, the aninmation editor Anima that I am currently writing will store the frame relationships (i.e. which frames constitute a "walk sequence") as text comments in the PNG file which contains the actual frames themselves. Other assets can describe which game characters have a particular animation file, palette, sound, behavior, etc.
Send any comments, bug reports, or feedback to Talin.
You can also download via FTP from here, but please note that my firewall doesn't allow passive-mode connections, so if you are behind a firewall (or you're using a browser to download) it probably won't work.
cvs -d :pserver:firstname.lastname@example.org:/usr/local/cvspub login
<enter return for password>
cvs checkout libasset
Return to Talin's project page.
Return to Talin's home page.