Quest Command

4-03-2022

Visual Log

Having started programming with visual basic for Oblivion and Skyrim, learning Java in order to mod a FTL save manager was a revelation. I remember reading Effective Java in the early years and learning the basics of more advanced programming. And so, while today I find java nearly unbearable to write, it will always hold a special place in my heart, and for a long time it was my favorite language.

Programming started as a hobby for me, and it's continued to be that ever since. After messing with an existing save editor, essentially my first java project was to spend six months, at least 20 hours a week creating a java space ship game (like FTL). It was terrible, and I committed every programing sin you could, and then felt the great pain of living with those errors (which is why Clean Code was such a revelation). In my early years I repeated a cycle of working on a project as long as I could until it's complexity and scope grew to a point where it wasn't feasible to continue to work on because the knowledge domain and many layers of coupling required too much research to get anything done. In effect, to work on any one part of the app, I'd have to remember how every part of the app worked. It was about this time I was considering to take yet another stab at my Stars Between game, and was planning to try an event based approach to see if I could minimize coupling.

Work allowed me to attend Code Mash and on a whim I signed up for a 'pre-compiler' (longer session that occurs the first day of the conference) that was on a language called Kotlin. I believe it was a four hour session that was followed by another four hour session in the afternoon. After the first session I dropped all the other talks I had planned to attend and spent the full day learning about Kotlin. It seemed like a revelation to me. (Ironically, I believe I also attended a talk on Elixir that week, and was unimpressed). To me, Kotlin is functional, except when it's convenient to be OOP, it's statically typed without being verbose or slow to write, and it's highly discoverable (I can follow methods and dig into source without having to abuse 'find'). It was probably within a week that I decided all my hobby projects going forward would uses Kotlin and that I'd convert anything I was currently working on over.

I quickly worked on converting my new, more event based version of Starship over to Kotlin (and then gave up, frustrated with the UI aspects). I also worked on creating my Palette Cycle app for Android. My third project was the culmination of several evolutions I was going through. I wanted to create a game that was as open and world interactive as games like Runescape, Skyrim, and Breath of the Wild, but I knew I'd never accomplish something with such a large scope, as a single dev, working as a hobby. I also knew that I continued to run into the complexity issue (but that an event based system seemed promising). Finally, I had tried enough front end systems (HTML, Angular, React, AWT, Swing, Tornado FX, etc) to know that I just didn't enjoy trying to make GUIs and that's where my efforts almost always ground to a halt. I thought about the evolution from Morrowind to it's sequel's sequel Skyrim. The latter game took many times the budget to make, but wasn't hugely more interactive than the earlier game; instead it seemed much of the budget went into graphic fidelity (coding, modeling, textures, voice actors, etc). This lead me to the third conclusion that formed my goal: what if I didn't do a gui at all?

Quest Command was born of those three goals: create an open, interactive world, use Kotlin and an event based system, and do so as a text only game. Quest Command has been my most active project since then; over the years I've produced over 800 commits on master and constantly refactored both small and large chunks of the game. It's scope grows as I feel like working on something interesting, and yet the event based system has worked well to prevent me from ever falling off due to complexity. (I think being a more mature developer has helped as well). On my work computer I keep the repo bookmarked as it constantly provides references of how I've solved a problem before or examples I can show a dev of how to approach a problem.

Quest Command and the Workplace.

Creating a long running, larger project has been instrumental in helping my work career. First, it's allowed me to explore concepts in a safe space where I'm not wasting company time. I often see less mature (though not necessarily less experienced) developers try out their latest interest at work not because it's the right fit for the task, but because they're curious and not doing this exploration in their free time. I also see developers not able to quickly discern a concept because they haven't practiced that exploration etc. Having a long running, non-trivial project allows you to explore concepts and still feel the effect of them in a way a trivial kata doesn't do. It also makes lessons more real as you have to actually deal with their consequences. I think this alone has driven me to be a more mature developer and allowed me to address leadership things at work instead of being stuck just trying to discern at the technical level.

Having a long running project is a great way to generate interesting talks. In the past I've talked about Quest Command itself as well as used it as an example to talk about Testing with Kotlin. Having talks that are portable across companies (that you don't lose when you change jobs) has allowed me to build a backlog so that I can jump into that space when opportunities arise, without needing to re-invent the wheel. Having presentations that focus on something I've spent time on and care about make it easy to be engaged in presentation and knowledgeable when asked questions.

Quest Command has been a blast to continue to tinker with. I highly recommend that a developer find something they really care about and stick with it over a long period of time. Doing so builds discernment, architectural intuition, and a storehouse of tools to bring to bear at the workplace. It grows both your skills and your career, while being enjoying and satisfying on it's own merits.

The Evolution of Quest Command

Quest Command has evolved significantly over time. One of the lessons I learned from one of the technically stronger devs I've ever worked with was a lack of fear to do large scale refactors when appropriate (which in itself requires discernment). In Quest Command I've done a number of larger scale refactors.

The first large one was to refactor my many types of 'targets' (things you could interact with in the game) to one large Target object. Initially I had separate Activators (things like levers or grain shutes), Actors (NPCs), and Items (things you could hold). As more and more of the behavior became the same (you can burn an NPC, or a pie, or a tree), it didn't make sense to use inheritance, composition with interfaces, etc. And so I consolidated all of them into a single Target (which I later renamed to Thing). This also lead to a recursive idea: my map was a network of locations. A body became a network of locations, each location being a body part. Any Thing could have a body, and any body part could have a (or more than one) Thing. This makes things like saving confusing, but means I can reuse traversal and path find for finding your way through the overworld, equipping a cloak, or climbing a large monster. Both Things and Locations become large objects, but can use composition to break out all their component pieces to still be manageable (and persistable).

I also spent a couple weeks at one point refactoring out all the hard coded calls to the game's singular player, and instead pass the player around in events. This opens the door for multiplayer, as a server and client only need to pass text back and forth and so long as we have a map of player id to Thing, there should be no other real work needed to suddenly have a server that would allow multiple players to play in the same world. (Security and not abusing the system are entirely different. Without a queue and internal clock, a user could submit a long list of commands and essentially hijack the server / kill everyone in one command etc, but that would be a concern for making an actual MMO, not a localhost friendly coop match).

Another large effort was spent in ripping out the months of work I had done on a json 'game inquiry and rules' system that let me create dynamic interactions in json by allowing the json to 'ping' the game state and depending on certain factors take different decisions. I replaced this by creating a Kotlin DSL. This means that modding will be trickier (I'll need to take the Minecraft Jar loading aproach over just grabbing static json files), but gave me a ton more power and convenience at the same time.

Finally, lately I've been working on removing the JVM specific code from the main app, so that I can wrap it with a multiplatform Korge 'terminal' and deploy the app to web and phones.