I have mentioned that I am really excited about our rewrite several times, but I haven’t ever gone into much detail about why that is. I hope that we have learned from what worked and what didn’t work in the old Crown and Cutlass code, and applied those lessons to the new Protocce code. I’m sure there are still things that we will realize are not well done, but this is a much more stable base for future work. Here are several specific things I’m excited about:
Exception – We implemented the pcce::Exception class which we now use consistently for error reporting. Coupled with our greater focus on RAII (see below), I think we have made some serious progress. We used to use error codes sometimes and throw other times. Unfortunately, sometimes we threw strings, sometimes we threw char *’s, sometimes we threw ints, etc. This is much better. It does not descend from std::exception at the moment, but we are thinking about doing that.
Greater focus on RAII – RAII is really a great idiom for resource management in C++, especially when coupled with smart pointers like boost::shared_ptr. We have design for RAII from the start, so that should make things much more manageable. Again, I’m sure we have more to do in this area, but we have a good start.
Variant – At work, I have gotten used to using the Win32 Variant class in Delphi. While it certainly has its drawbacks, it sure can be helpful for doing things like reading text from a config file. Our variant class is cross platform, and based on boost::variant. I think it will change a little as we use it, but I’m pretty happy with it now. You wouldn’t want to use it when a statically typed variable will do, but for example the config system was really easy to do using Variant.
PropertyBag – Again, at work I got used to using “property bags” which are basically just a map from a string to a variant value. You wouldn’t want to replace all of your normal classes with a property bag (static typing can be nice!), but it can be really useful. For example, our configuration system is an INI file. That gets loaded into a property bag. When you initialize a subsystem, you pass its settings as a property bag. That way, you can change the config options around without changing the config object or the method signature. We have also used property bags to create “game objects” which are just property bags with a couple of predetermined fields for model name, texture, etc. The game programmer can put whatever else he wants in there.
Consistent use of shared_ptr – I really don’t mind managing my own memory, but once you start talking about exceptions and RAII, using some kind of smart pointers really makes sense. We are making pretty serious use of boost::shared_ptr, which has made a lot of things easy. No need to worry about who owns an object, as long as you have a shared_ptr to it, it will stay valid. Of course, we have to think about circular references, but overall I think using smart pointers is a big win.
OGRE – I think it’s pretty clear why I am excited about OGRE. Originally, the project was just an excuse to do OpenGL programming. I enjoyed that, but now I am more interested in other things. I’m a little sad not to get to try that from the ground up, but eventually we can revamp Protocce to use a custom engine if we want. Until then, using OGRE will simplify our code, standardize our models (our old model loading code was really picky), and open up the doors to easily implementing graphical improvements. It will also allow us to focus on the game itself, rather than the details of the graphics.
EventSystem – Our old code used to be very tightly coupled (see the SailingState for an example), so minor changes could not only cause a large number of units to need to be rebuilt, but also end up causing a large number of code changes. The event system is based on what is mentioned in Game Coding Complete and allows us to significantly decouple our code. Once an event is defined, you can register a boost::function to receive that event. Events can be dispatched immediately, or queued to be dispatched once per frame. I expect the way that will work is that game events will be queued, while internal “plumbing” type stuff will be sent immediately. As an example, the input subsystem needs a window handle to receive input. Rather than connecting it directly to the render subsystem (which would force you to initialize the entire render subsystem if you wanted to use the input subsystem), the input subsystem just sends an event that the render system receives. If you don’t want to use the render subsystem for some reason, you could just register a different handler for that event. Collin actually does that in the input test. As I mentioned in my previous post, the sound system is also event driven. It is running in its own thread, and all the main thread does is send an event that says “play sound X” or “stop sound Y”. That data is easily sent out to the other thread, where the actual sound code handles it. We can totally revamp the sound implementation and not touch client code at all. I think the event system is a much more flexible system and I think it will open up a lot of doors for us.
Improved resource management – I mentioned this a little in my last post too. Between the release of Alpha 1.4 and the decision to start the rewrite, I wrote a resource management system. It was pretty good. It would make sure that only one copy of a texture, sound file, or model was loaded at a time and used reference counting to automatically unload the model when it was finished. I have further refined it (partially based on the OGRE resource system) and posted a reply on gamedev explaining the Protocce resource system.
Anyway, there are other things but that is a decent explanation of the things that I am excited about.