|
For technical aspects of the project, this largely happened. Problems we encountered when trying to design for stability or puzzle out a particular quirk of the 360 never held us up for long. Process and design were another story. Communication between team members was infrequent, the master design document was never fully fleshed out, and many functional areas of the game were laid out by individuals working in a virtual vacuum.
The audio system was the work of a single coder, as was network session management, the menu interface, and user profile data. As these largely complete units began to be integrated, poor communication led to duplication of effort and an inability to keep up with changing spheres of responsibility. Many hours were lost when it was discovered that two programmers had been working on the same code -- optimizing the Shapes loader cost nearly an entire extra man-day for this reason.
Another problem caused by this deficiency was that due to different coding styles and lack of a comprehensive design, many areas of the code could only be efficiently debugged by the person who had created them. The audio system in particular involved multiple threads and extensive use of the Xbox 360’s audio library, which no one except the coder directly responsible for it was sufficiently familiar with.
As a result, it continued to produce bug reports caused by subtle race conditions throughout practically the entire project -- reports which most of the team couldn’t address. Even when singular code like this wasn’t producing bugs, it was causing coders to run into trouble and waste time wrestling with largely undocumented APIs and quirks when their work brought them into contact with another functional area.

Drop-in libraries are not a magic spell. For our network code, we hired an experienced programmer who provided us with his pre-existing network library. We expected that adding it to the project would take minimal effort. Unfortunately, this was not the case. Despite being a very flexible and powerful system, it had still been built with certain expectations in mind and made assumptions about the code it would interact with. It relied on constructors and destructors to perform much of its work, while our game used statically allocated arrays of objects to build the game world. The first time we attempted to invoke the network code while running the game, it simply exploded. Determining why this happened took several days, since the flaw was in such a fundamental area.
The eventual solution was to establish a system of proxy objects whose creation and deletion followed the rules the network library expected, and which manipulated the static arrays to control entities in the world. This was far from an ideal solution, as innumerable bugs appeared in the synchronization between the two objects, and it removed a major advantage of the static array design -- a completely predictable memory layout.
Overhauling very old code is difficult. Marathon was written in straight C, which does not lend itself to good software engineering (and that’s not even considering the requirements of high-performance 3D graphics in 1994). Most interaction between different functional areas was accomplished by direct manipulation, not accessors. The life cycle of particular parts of the world was quite difficult to puzzle out in many cases. Quite often, the limitations of the original 68K Macintosh platform had been worked into the gameplay in subtle ways.
Multiplayer scoring was a particularly hairy section to overhaul. The original game had used a pure peer-to-peer network architecture that only transmitted raw user input -- usually passable in a LAN environment, unworkable on the internet. Since the game did not differentiate between remote and local players in any meaningful way, scorekeeping was implemented simply by giving each player a table of which opponents they had beaten or fallen to and having each player grant points to the appropriate enemy (through a direct write to his internal table, naturally) when dying.
When the model was changed to transmit absolute states over a client-server network, this had to be replaced with a message-passing system that informed remote players of their earned kills -- more accurately, it informed a remote player of his kill and then propagated his updated score to every other client in the game, to satisfy Xbox Live’s requirements for verifying game coherence.
|