Manta-X Code (Part 5)

Unfinished Business

It’s been fairly cathartic to go back and clean some of this code up - almost feels like some unfinished business. Still not sure if I want to continue working on it, but I thought I’d at least cull some of the garbage in here to unmuddy the water a bit.

Let’s take away the easy stuff. All those classes that aren’t used or do nothing I’d want to take forward.

GUI Gone

First up, the GUI subsytem. It looks like I was building out a GUI system - it wasn’t hooked up to anything except an empty “editor game state” (or the code was commented out). The GUI system can handle bitmap font display, text labels and ‘windows’. I looked at the code and decided to remove it. The whole thing. If I need a GUI in the future (probably), there will be better solutions than this half finished thing - dear ImGui is one such system that I could pretty much drop into place when I need it.

That’s quite a lot of code to remove. Past-me would have kept it around because of that reason - current me thinks YAGNI and points out that it’s still in the git hitsory if I need it (I won’t).

Metaclass

The Entity subsystem had the DTIClass (from Game Programming Gems 2) and PropertySet stuff to provide a runtime type information and metaclass system. It was probably here for automating script binding and data loading. Well it’s not used, so it’s going.

I could pretty much delete this stuff straight up without affecting anything. Gone.

Path Navigation

I was building some rudimentary node-based path navigation system that’s not hooked up or used. By the looks of it, it wasn’t going to work anyway. Gone.

Exceptions

I had an exception handling system in here that seemed to track the callstack of methods to the site of the exception. Well none were thrown anyway and this looks like it is just going to be problematic. Gone.

Goodbye, IMMO

I thought I’d tackle the old nemesis, the IMMO & MMOPtr combo. The IMMO system is basically a simple reference counted pointer system that tracks all ‘managed’ objects in a global list (eg: if you inherit the IMMO base). The reference counter is incremented/decremented by the scoping of the MMOPtr object. Each frame, we ‘clean’ up the dead list by iterating it and deleting any objects.

There’s a couple of sets of problems with this system. The first is that the IMMO system itself has a few mechanical flaws:

  • global static list of objects
  • cleaning all dead on each frame
  • no custom allocation strategies (heap or gtfo)
  • and more fundamentally, an IMMO cannot be a stack object

The ‘easy’ route to fixing this would be a blanket find/replace of the IMMO system with something like std::shared_ptr.

However, the second set of problems is common to all smart pointer style systems (including std::shared_ptr):

  • easy to create circular reference groups of objects
  • easy to disregard object ownership and lifetime concerns

That second point is a huge one. You’ll recognise it when you see public method signatures that pass around std::shared_ptr for everything. What you’re essentially saying here is “I don’t know who owns this anymore” and as a result, an object’s lifetime becomes less deterministic.

In languages such as C# this is fine as the garbage collector is sophisticated and the memory is managed - C# was designed around this very concept. In C++, and in games specifically, this can become a problem.

The use of the IMMO system in Manta-X is a huge abuse of this type of pointer. Almost every method signature has an MMOPtr reference which means that every object in the game has this problem. Therefore a blanket replacement of the IMMO system with std::shared_ptr may address some of the mechanical problems with IMMO, it does not solve the architectural issues of the codebase. Instead, removing IMMO means going through each system, one at a time and making decisions about ownership and lifetime and changing it to reflect this.

So that’s what I did.

Removing IMMO

Over the course of 10 or so commits, I went through and extricated the IMMO system from the codebase. Here’s the order, from first to last:

  • GameState
  • Image Loading
  • Texture System
  • Model System
  • Ship ‘class’ system
  • Particle system (I discovered that this whole system was total junk)
  • GameData (analogous to UE4’s GameInstance)
  • Entity System
  • Remnants
  • IMMO deleted

What was very clear was that the use of IMMO in the majority of these systems was replaced by holding onto a std::unique_ptr and doling out a raw pointer to anything that needed it. In the future, this may get replaced in some systems with a handle, but right here, right now, this works.

Cleaning up

In removing IMMO, I ended up poking around almost everything in the project. As a result, I’ve decided that the next goal for me is to remove everything in the code that isn’t been exercised by the current running state. So if it’s not part of a live codepath, it’s going.

After this cleanup, cloc is 4168 (down from 5990) and compile times:

Time Elapsed 00:00:56.54

That’s down from 00:01:13:00.

Until next time.