{"id":54,"date":"2019-05-20T22:31:06","date_gmt":"2019-05-20T21:31:06","guid":{"rendered":"https:\/\/joshtest04.wordpress.com\/2019\/05\/20\/enhancing-my-pet-game-project-with-castledb\/"},"modified":"2025-05-05T20:23:51","modified_gmt":"2025-05-05T19:23:51","slug":"enhancing-my-pet-game-project-with-castledb","status":"publish","type":"post","link":"https:\/\/fevered.earth\/index.php\/2019\/05\/20\/enhancing-my-pet-game-project-with-castledb\/","title":{"rendered":"Enhancing my pet game project with CastleDB"},"content":{"rendered":"\n<p>Using static databases and simple code generation to describe almost-dynamic game content.<\/p>\n\n\n\n<p><em>I\u2019m a solo indie dev working on my magnum opus of undisputed genius, <\/em><strong><em>_space_train<\/em><\/strong><em>. The daily grind of handling all aspects of game development is my burden, except when I\u2019m not doing that because I have a regular job as a software developer instead. The major flaw with <\/em><strong><em>_space_train <\/em><\/strong><em>is that there\u2019s no compelling reason to play it, and that that will continue to be the case for the foreseeable future. Nonetheless, if you want to follow development and watch as I slowly descend into madness and ignominy, it has an <\/em><strong><em>itch.io <\/em><\/strong><em>page <\/em><a href=\"https:\/\/josh04.itch.io\/space-train\" target=\"_blank\"><em>here<\/em><\/a><em> with a downloadable build and a <\/em><strong><em>Twitter<\/em><\/strong><em> <\/em><a href=\"http:\/\/twitter.com\/_space_train\" target=\"_blank\"><em>here<\/em><\/a><em>.<\/em><\/p>\n\n\n\n<p>I had an issue building <em>_space_train<\/em>, my magnum opus of undisputed genius. The path to complex user interactions lay in the direction of adding \u2018content\u2019 for prospective users to engage with. In material terms, this meant adding more of the things that people do in the game: items to pick up and use. The problem was, adding new items was proving a surprisingly laborious task for me, the developer. Items in <em>_space_train <\/em>are represented by unique id numbers associated with an entry into a centrally managed map which has an id, a type, and a \u2018display modifier\u2019, a bitfield which specifies the appearance. The list of possible item types is represented with an <code>enum<\/code>, and a separate mapping exists to convert between the <code>enum<\/code> value for each type name and the string name for each type\u200a\u2014\u200athe string value being necessary for accessing external resources for each item type, specifically Lua scripts which say what they do in various scenarios.<\/p>\n\n\n\n<p>Adding a new item then, means adding both to the <code>enum<\/code>, and then to the name map, the name of the new item. In addition, over on the client side, the item type then needs to be associated with coordinates into the item texture, represented in another <code>enum<\/code>. All this before any actual material properties of the new item can be expressed!<\/p>\n\n\n\n<figure class=\"wp-block-image wp-caption\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/1*W9FSNkWCP1zxI6NzT1cE1g.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">A player standing by a handful of items in <strong><em>_space_train<\/em><\/strong>.<\/figcaption><\/figure>\n\n\n\n<p>The elephant in the room is the possibility of loading and representing item types at runtime. This would necessitate separating items into some extra-compilatary zone where they can be manipulated distinct from the game code, all together all in one place. This was appealing in some ways\u200a\u2014\u200ait would remove business data from the scrappy C++ engine I\u2019ve insisted on building and relocate it, in a potentially more manageable format. I didn\u2019t want to give up, however, on the ease of referring to item types directly in code, or take on the overheads of runtime look-up.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Around a year ago, I became aware of a software development tool called CastleDB (www.castledb.org), which appeared to do something to do with static data. The website described it thus: \u201c<strong>CastleDB<\/strong> is a structured static database easing collaboration.\u201d<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/1*KBFD8dn8495iXY6Yvzr0sw.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Structure sounds good. Static sounds good. Unfortunately there\u2019s only me working on <em>_space_train <\/em>so the collaboration might go a little under-utilised, but I was still excited.<\/p>\n\n\n\n<p>Unfortunately, at the bottom of the page, castledb.org also says this: \u201cCastleDB was created using the <a href=\"http:\/\/haxe.org\" target=\"_blank\">Haxe<\/a> technology, it also allows some Haxe-specific integration.\u201d I\u2019ve heard of Haxe, and <a href=\"https:\/\/haxe.org\/\" target=\"_blank\">the website<\/a> for it only really confused me more as to what it does, I\u2019m aware it\u2019s some sort of web-development-y thing. And I myself, a terrible C++ programmer, don\u2019t understand the first thing about it\u200a\u2014\u200aor any other webdev library. Thrown into confusion like this, unclear over whether or not CastleDB was something only web developers got to use, I did what any good programmer ought to do: I left the tab open for a full year and skim-read the page again, once every other month.<\/p>\n\n\n\n<p>Eventually, I decided to go one step further: I downloaded the damn thing. Inside the zip there was an <code>index.html<\/code>, which loaded into a blank spreadsheet with buttons that didn\u2019t work and an error in the console saying \u201cCONSOLE ERROR HERE\u201d. It turns out CastleDB is bundled as some kind of self-hosting web executable, and I was supposed to go against years of instinct and open <code>cdb.exe<\/code> rather than the enticingly-named <code>index.html<\/code>. Never grow complacent.<strong> <\/strong>With CastleDB opened properly, I found that it was actually exactly what I wanted: for want of a simpler phase, it\u2019s Excel but not dynamic. It\u2019s phpmyadmin but not php or mysql. It\u2019s hand-editing JSON but without any hand-editing JSON. You enter static data in a familiar-ish interface (minor gripe\u200a\u2014\u200acopy and paste doesn\u2019t work on MacOS, but I\u2019m narcissistic enough to enjoy retyping my own work) and it comes out in JSON. This was the start of something good.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>What I wanted, was to enter data using this convenient interface, and have it represented in code for me to use when designing game elements (in theory the bulk of game development; in practise I merely add more engine features and release nothing). This necessitated some kind of transformation of the data into code, either at compile time or at runtime. As discussed earlier, I\u2019m loath to defer this process to runtime for several reasons, most of which boil down to wanting to pretend my program is less complicated than it is. If elements are loaded at runtime, then all references discovered while debugging are contingent on that load, and it\u2019s harder to have good instincts about what is out of place or unusual. So I wanted this to happen at compile time.<\/p>\n\n\n\n<p>The missing link here for C++ development specifically, is some kind of all-constexpr JSON processing library that can automatically infer data structures from some input. I am not the person to write that library though, and decided to make do with some homegrown codegen.<\/p>\n\n\n\n<p>Codegen is the art of code which produces code, and often leads to some of the worst abominations of programming imaginable. All the personal terribleness of the programmer who wrote it, combined with a computer\u2019s indefinite ability to spew vast reams of procedural content. Nonetheless, codegen has a proud history in games: in the <em>Wolfenstein 3D Black Book<\/em>, Fabien Sanglard describes how iD used codegen to produce (and patch!) code for transformation tables for sprites at distance at runtime, in order to minimise the size of the executable shipped. If it\u2019s good enough for shooting Nazis, it\u2019s good enough for me.<\/p>\n\n\n\n<p>JSON was originally invented to serve as a serialisation format for Javascript, so I immediately decided the best tool for this job would be Python. Python has a first-class JSON loading library, and very simple string manipulation functions (compared to working directly in C++ for this). Using a Python script to write some simple C++ types and functions into a header and cpp couldn\u2019t have been simpler, and I very quickly had a working <code>enum class<\/code> generated, included and compiled.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-caption\"><img decoding=\"async\" src=\"https:\/\/cdn-images-1.medium.com\/max\/800\/1*D6bV4E8TTd3MRLoBs9cpJg.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">My simple database of space-tomatoes.<\/figcaption><\/figure>\n\n\n\n<p>From this quickly thrown-together table of existing content, a handful of Python lines in the fashion of the ones below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">output_h.write(\"\"\"<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">enum class list {<br>\"\"\")<br>for item in item_db_items:<br>  output_h.write(\"            \"+item['type']+\",\\n\")<br>output_h.write(\"\"\"<br>};<br>\"\"\")<\/pre>\n\n\n\n<p>Were able to throw out a quick enum:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>enum<\/strong> <strong>class<\/strong> list {<br>  none,<br>  tile,<br>  ticket,<br>  food,<br>  screwdriver,<br>  shovel,<br>  terminal,<br>  pickaxe,<br>  access_card,<br>  hat,<br>  corpse,<br>  fuel_brick,<br>  mug,<br>  oxygen_mask,<br>  urine,<br>};<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>My enthusiasm for this approach quickly snowballed. Not only was I now generating the enum and the static constexpr map from the JSON file, I added a column for the item descriptions, making them easy to read altogether and also amend, and also for the short descriptions used when the items are hovered over.<\/p>\n\n\n\n<p>Then I went one step further and moved a function from the engine client that selected an image to pair with each item, and had that generated from the JSON too. CastleDB has built in support for (varyingly-sized) tiles and will handily display them inline for easy glancing. I didn\u2019t need the relative path to the image, both because resources in the <em>_space_train<\/em> engine come from specific named textures, and because the directory structure from compile-time has changed by runtime, but were that not the case it would have been easy to pull it out of the provided \u2018tile\u2019 data type in CastleDB.<\/p>\n\n\n\n<p>With this under my belt, I drove further forward and converted the floor tile types and image mappings too, as well as room bounds (which are done under the hood in an extra layer of tiles. Three whole compile units are now being generated! I made myself feel extra professional by abstracting common functionality, mainly related to the opening of files, into a python module called <code>codegen.py<\/code>. I refrained from getting too smart and making a special python class with scoped constructors and destructors which would function to emulate C++ namespaces and other cleverness like that, because down that road lies madness and the aforementioned template-based constexpr JSON library.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Since adding the codegen functionality to <em>_space_train<\/em> I\u2019ve identified several other candidates for static codegen, including a table of sound effects and a table of background music entries. If you made it this far, thank you for reading and I hope you enjoyed my terrible programmer jokes.<\/p>\n\n\n\n<p><em>If you want to look at the codegen Python in more detail and send me a message about how bad it is, it can be viewed in a pair of gists <\/em><a href=\"https:\/\/gist.github.com\/josh04\/2a05b251562fa1b990490cae2a060778\" target=\"_blank\"><em>here<\/em><\/a><em> (codegen.py) and <\/em><a href=\"https:\/\/gist.github.com\/josh04\/260154\" target=\"_blank\"><em>here<\/em><\/a><em> (item_codegen.py).<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using static databases and simple code generation to describe almost-dynamic game content. I\u2019m a solo indie dev working on my magnum opus of undisputed genius, _space_train. The daily grind of handling all aspects of game development is my burden, except when I\u2019m not doing that because I have a regular job as a software developer [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[94,97],"tags":[38,39,40,41,29],"class_list":["post-54","post","type-post","status-publish","format-standard","hentry","category-article","category-gamedev","tag-c-programming","tag-codegen","tag-game-development","tag-humor","tag-programming"],"_links":{"self":[{"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/posts\/54","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/comments?post=54"}],"version-history":[{"count":1,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/posts\/54\/revisions"}],"predecessor-version":[{"id":142,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/posts\/54\/revisions\/142"}],"wp:attachment":[{"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/media?parent=54"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/categories?post=54"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fevered.earth\/index.php\/wp-json\/wp\/v2\/tags?post=54"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}