Skip to content

Doc_Code_Postmortem

Noah Sherwin edited this page Feb 9, 2023 · 3 revisions

Introduction

For those of you who don't know, OpenSauce is an open source project1 for the modification of Halo, primarily Halo 1's Custom Edition (the real Halo CE). Our modifications are not just about changing values in the game's level files. The majority of our code is for changing and extending the actual engine's code.

The goals of the project when it started off in 2004/05 (back then only known as Project Yelo) were to create a sort of 'Garry's mod' for Halo CE2. A simple tool3 that allowed you to manipulate objects in-game, plus a few other utilities like switching to third person (the main Halo series is a FPS after all).

However, the project really started to explode in growth

Words I've cut for inclusion later/elsewhere

All the project consisted of was a VC++ project (not source controlled!) and a couple of messy source files.

One of the main reasons we've stuck with HaloCE as our primary development target is due to how 'simple' the engine is and because its editors were released. I mean 'simple' in terms of generated code. Halo1's engine was programmed in C, with its editors being mostly C++ (via MFC/ATL). The engine, other than in its world editor, has no fancy templates, STL, or polymorphic C++ classes (with vftables) complicating the generated code or the code's overall structure. HaloCE's editors are almost the exact same ones used in the development of HaloPC. This was not the case of Halo2 Vista, which shipped with a stripped down version of the tools.

Footnotes

1. Initially our codebase was entirely open source, but we've since closed public access in between major releases. We've also been re-evaluating switching from a GPLv3 license to something more like MIT.
2. I can't claim credit for the initial idea of Project Yelo. A guy in the community named bitterbanana was the one who came to me and purposed working on a Garry's mod-type tool for HaloCE. All I had to do was say 'yes' and share my reverse engineered knowledge of the engine, which had been accumulating since 2002.
3. Implemented via a DirectX hook.

Outlining

What went right

  • Project team started out small, with devs mostly focusing on entirely different areas of engine development
  • Reverse engineering the game before features are decided and made. New features/ideas are rarely given much weight or time until the engine components which they affect are RE'd fully.
  • Reverse engineering newer Halos for feature\ideas consideration. Bungie made feature X work in Halo #Y, so why can't we literally reverse engineer it into HaloCE? Information learned from the later engine builds supports modding of those engines and may shed further light on older builds due to having more usage context. RE'd features don't always map 1:1, but that's part of the fun, making it something based on your own design than just 'cut and pasted' logic/setup.
  • Choosing to be additive, not 'invasive'. Most features can happily co-exist with the game and tools because they essentially use 'gaps' in the game (sometimes literally, where game content has unused padding in their structs) that the stock code can cycle over without issue.
  • Using our own file extension, .yelo, instead of .map for level files. Stock game won't touch anything that's not a .map. It will violently crash (instead of peacefully ignore) .maps with values outside of normal patterns (eg, different version number)

What went wrong

  • Project team continues to stay small, limiting resources. Many features once deemed 'not possible' without source access are becoming more a potential reality, all while many key lowlevel and glue systems need to be implemented
  • Most that want to contribute aren't familiar with the inner workings or design of the engine. Game content is designed and used in a very specific way. Game state is handled in a very specific way. Etc. All of which is undocumented, so it's to no real fault of these contributors. They either reverse engineer the game too, or we take time out of development to try and document pieces of the engine (which may rely on other systems needing documentation; enter the rabbit hole)

Evolving goals

  • Project started out as a "Garry's mod"-esque game add-on. Funny enough, we no longer support (or even have in the main branch) the 'gravity gun'.
  • Code has always been written/designed to be as close to that of the original code base (as far as reverse engineering can tell us). This sort of impacted some code design, due to the original code base being in C, thus not having much in the way of dynamic initializers, so almost everything is deterministically and explicitly initialized. We kept this pattern, even though we're a C++ project, where no global objects are to be dynamically initialized. Dynamic memory allocation (DMA) was also kept to a very strict minimum in the game mod.
  • Proof-of-concept project (known today as CheApe) for adding new tag_groups to the editing kit eventually saw the project evolve into an entire engine mod (so both the games and tools)
  • Started fixing workflow issues and bugs in the editor
  • Used our new found editor abilities to create new game interfaces for map makers to use (new script functions, gameplay tweaks, etc)
  • Also allowed us to address hard coded limitations set in the engine. We could build and use larger game files, and address more game memory
  • After upgrading the build files from VS2008 to 2013 we started working on using more C++11 features and designs in our code. Majority of the stock engine was written in C, and a lot of our code reflects these C structs and functions, but we end up writing them in a way that is either C++ friendly or build more abstract wrapper utilities to promote C++ code (simple example: we've added ranged for support to many of the engine's data structure types)
  • The upgrade to 2013 also saw more STL use. It wasn't really used before hand due to it not being used much in game dev to begin with, but also because we used to keep DMA to a minimum

FS Thoughts

  • There has been a lack of code maintenance and updating to create consistent design across the project. A lot of code gets written and working, then left without being touched whilst better methods are used in other systems that come later. KM00: Is there a clear example of this? "code written...left untouched...better methods used in other systems"
  • Focus tends to be on implementing a feature straight way rather then planning, designing and documenting a system before writing any code. This leaves us with a deficit of documentation and a myriad of systems that all use different methods that don't mesh well together. This has also meant that there is rarely contribution to a feature from more than one person since the implementation plan is in someones head rather than shared with the group. KM00: Is this really the case? I know we lack a formal documentation path, but I don't think much of the systems we've had were made like blindly throwing paint (code) on a wall (the project). Some features are taken as requests, eg from CMT. Initial implementation of the scripted object property getter/setters was trivial, but as more properties and use cases (non-networked properties) were requested a more formal system was implemented. Most of the time I'd say we're trying to prototype requests or ideas. Sometimes it doesn't make sense to dedicate time to a full documentation path to an untested idea (ie, something that may not work with the engine's current design). However, this has conflicted with other work items. Like the Faux Zones and the new lightmapping system.
  • There is little use of code review and unit testing. The lack of a code review process is understandable due to the small team and mix of skill levels, but unit testing should be worked on to try and avoid breaking code. Because we do not have a dedicated test team, it is unlikely that everything we write is fully tested before release so creating a test framework to validate everything possible should be a priority. KM00: One of the problems with adding unit testing to the tools is that the majority of the code is dependent on the engine's code. Some of that code is only present in the editor or game builds. Thus, there's no One Way to test things in OS. Each build of the editor/game hooks would require a "unit testing" build. Another major problem is that we essentially have to also add code coverage to existing engine APIs that we change the internals to. I don't even think Bungie had any real unit testing in Halo1's codebase.
  • Support for public releases has been lacking, with releases largely being fire-and-forget and bug fixes not becoming available until months after a release. This is generally a project management issue where there are no plans for when releases will be made, what features need to be worked on, the time things will take and such. KM00: This also has something to do with little source control branching. A new public release will be made, and then new changes will be made to the master branch (where development is made).
  • Working code seems to take priority over good performance code which has left the game with framerate issues that have not been worked on in favour of adding more features to the engine. KM00: This stems from having no usable code tools for perf testing. Normally we hook/use the engine's existing frameworks, but this doesn't help in the case of the game build, which contains little to no real 'utility' code like perf measurements.

What needs improving

  • Google code was a good code hosting provider initially, offering (for free) an Issue system (which anyone with a google account can use!!), Wiki, and most importantly, downloads. Now downloads are closed and due to be dropped. We need to find a new public alternative for project hosting
Clone this wiki locally