codethrasher

Galactic-level Management

I’ve always been interested in simulations. In college I would write very simple simulations, graph the output and marvel at the patterns that would emerge from things like the periodic oscillations of a predator/prey population set given a stable environment. It was so much fun to do that even if I knew the outcome. It was sort of my way of playing a game without actually playing a game.

I wasn’t ever really a massive gamer. I had my various love affairs with a few games when I was in middle/high school (Age of Empires, Command & Conquer, and Zelda come to mind), but they were frequently put to the side in favor of being out skating with my friends. In college the only game I had any fascination with was Dwarf Fortress. It absolutely blew my mind when I found it (which was before its Steam release). The ASCII art felt indecipherable the first few times I eyed the screen and simply trying to understand what each little symbol represented was like learning a new language, to say nothing of the insane complexity of it.

Dwarf Fortress

A few years ago I stumbled on Aurora 4X, which had the same effect on me as Dwarf Fortress did when I first discovered it. If you’ve never played that game and you like to micromanage everything, check it out. It’s free, but it is finicky and it refuses to hold your hand. Imagine a super-complex spreadsheet with multiple tabs barely given a UI. The game has its problems. It was originally written in VBScript (~2005) then ported to C# years ago by one person (Steve Walmsley, the sole author). No disrespect to Mr. Walmsley, but it has some fairly massive performance issues in its late-game stages. That being said, I haven’t really had a chance to see them yet as I haven’t played a campaign (if you can call them that) long enough to experience the lag. Nonetheless, they’re well documented in the subreddit and other various forums.

Aurora UI

The game is brutal. Both in its style and its mechanics. I can handle the latter, but the former has me craving something a bit more modern and more OS agnostic. Aurora can be played in non-Windows environments, but it takes some tweaking. I’ve always been interested in making a game heavily inspired by Aurora, but in a moden framework and less performance issues. My problem has always been time. Aurora is 20+ years old. Its depth has been something added over time. To match that depth, in a new framework, and not completely lose touch with my family, hobbies, and physical health I’d have to put this fantasy project off until retirement. I don’t have the patience for that. With the accuracy of LLMs being what they’ve been the last year (or less), I’ve finally been given a chance at taking on this behemoth, and so I have.

My attempt at Aurora, which I’m calling Expanse, is being written in the Tauri engine. That gives me the familiarity of React for the UI and the performance of Rust for the backend. I’ve always loved Rust so this has also been a cool/legitimate excuse to use it. As I’m deeply aware of Aurora’s perf. issues, it has been imperative that I constantly check where the bottlenecks sit and try to minimize them as much as possible.

To do this I’ve followed two familiar patterns:

  1. A sim and ui separation dilineated by a transport (IPC) to prevent the UI from ever actually touching the @tauri-apps/api directly. I’ve defined the transport as such
invoke<T>(cmd, args?): Promise<T>                   // UI -> sim (command)
listen<T>(event, handler): Promise<Unlisten>        // sim -> UI (subscribe)
emit<T>(event, payload?): Promise<void>             // UI -> sim (fire)

These messages are passed back and forth as JSON.

  1. Rust Sqlite is the source of truth. emit() carries a StateDelta which is merged into Zustand. This means the UI never reads game state directly. The management of the varying changes in the game state are handled via dirty-flag monitoring. I didn’t approach it this way at first, but as I was staying mindful of the possible perf. issues and adding more and more economic complexity, it became way too expensive to not do this.

To be honest, the hardest part in all of this has been creating the interface. I’m not the most aesthetically-oriented developer. I’ve been relying on inspiration from other games and AI to get to where I think it should be. Despite this work, I keep finding myself “refactoring” the UI. It’s difficult to make something look good and be functionally appropriate.

I’m pretty proud of the game itself. It’s not quite at the same level of depth as Aurora, but it’s definitely not shallow. Right now I have a few things that make the mechanics quite interesting:

  • Culture per colony: an empire (managed by the player) can have multiple colonies and if those individual colonies are not managed correctly (or kept in the trade system appropriately) their culture will diverge from the empire’s and potentially break off.

  • Class-based population dynamics: revolutions, politics, propaganda…just like real life!

  • Communication/Diplomacy: if you find another empire in the galaxy you have to work and research communication strategies with this foreign species. Low communication will result in poor diplomacy which is lost money or lost lives (war).

Everything else is standard space/Aurora/4x mechanics: trade, design fleets, discovery…it’s quite complex. I’ve been working on it now for 6+ months and I’m hoping I can have a version to start passing out to play testers by the new year, but we’ll see.

I’ve found this project refreshing from my normal “day job”. It’s satisfied by neverending technical curiosities and has been really cool playing something complex that I’ve built.

← The Feynman Technique