There are times when infrastructure work can feel like a tax that you have to get through in order to get to the really fun coding; you do a ton of work but don’t necessarily get a “look at what I did!” moment at the end of it.  But when the infrastructure is either (a) cleaning up and refactoring (aka removing code you now know isn’t needed any more; oh it feels good), or (b) enabling yourself to create new features with considerably lower effort, then it becomes more fun.  And when it’s both, it’s definitely fun; that’s what last night and tonight were.

Here’s the net result of all that work:


Before explaining what’s cool about that picture, here’s what’s new in the code:

  • Major cleanup and refactoring of the persistence code.  I had been storing game state as a single monolithic file; since players can go up and down levels, I need to keep all of them around – that meant the gamestate file was eventually going to get unacceptably large.  Also, I didn’t want to store static definitions in the save file since I want the ability to change them in updates.  There are now three sets of files; “gameDefinitions.dat” which stores all ‘immutable definitions’ (mobDefn, lightDefn, cellDefn, and 15 other definition classes), “gameSlot#.dat” which stores data that spans characters (discovered recipes, total mobs killed count, settings, etc), and “level#.dat” which stores the instantiated models for a specific level (mobs, objects, etc).  Much cleaner split of persisted data
  • The problem with that is that while Protobuf-net serializes references without complaint, it can’t do it across files.  So when a model (from level#.dat) references a Defn (from gameDefinitions.dat), what protobuf actually does is store a complete copy of the defn rather than a reference to it.  This was fun to figure out since it’s practically impossible to tell that a copy was created and not a reference.  This is not what I want because I want to be able to change definitions (e.g. tweak fields) in updates, and I can’t do that if the definitions are baked into the level data.  So; Defns can safely reference Defns since both are in one file, and Models can safely reference Models since both are in one file; however, Models cannot reference Defns.  So I went through and added load-time fixups for all instances of Defns and persist the Defn Id instead of the Defns themselves. On the plus side, in the future I can update the game and modify games that are already in progress.
  • ParticleDefn and LightDefn now read from the Xlsx; itemdefns can specify up to three of each and the code handles creating them.
  • I added the concept of ‘adornment items’; in the xlsx, CellDefns can specify inclusion of an item that will automatically be created in the cell – e.g. a Brazier or a poison pit.

Mix those together and now I can define what you see in the above picture just by adding to the xlsx:

* The green circles in the upper left are slightly glowing poison pits with particle “bubbles” and a celleffect that does 1 damage when you step in it

* the burning squares in the top middle are bright glowing firepits with a fire particle effect and a celleffect that adds a debuff that does 2 damage to the actor for 3 turns

* The smaller orange fire in the center left is a new “Brazier” adornment that includes a couple of lights and three particle effects (smoke, fire, and sparks) – all defined in the xls

* The smaller orange/green fire in the center right is a new “campfire” adornment that includes its own light and a different particle effect (cylcing through colors to green as a test).  Again, all from the xls.

* As a test, I also added a dim green light and green particle effect to the skeleton mob (seen in the lower-middle), and again without touching code was able to create an entirely new and unique “poison zombie” mob.  Give it a “poison touch” skill, and you’ve got a totally brand new mob with almost no effort.

And that’s why this infrastructure work was fun