MUD tech is fun/cool, but…

As software development evolves, there are an ever-expanding number ofways to put together very complex, elaborate systems that are fun to geek out on. Multi-processing is becoming increasingly prevalent, distributed systems are a boon to cases with massive scalability or reliability requirements, and there are all kinds of neat data stores available. These are all definitely things that have a place in software.

But what does this mean, in the context of a MUD?

Honestly, very little. Even a very large MUD with hundreds of connected players can be ran on a very pedestrian machine with a modest amount RAM, and very little bandwidth. Multi-threading is not a requirement for performance (and can often work against it). Highly distributed, multi-server setups are hitting nails with jackhammers. After all, we’re talking about a genre that primarily features smaller (<100 connected players) games.

An important thing to keep in mind when developing a MUD is that simple, well-thought-out MUD architectures have a huge advantage over those their more complex kin: They are easier to develop, and they are a lot more likely to ever see the light of day.

MUDs are a labor of love

Although you’ll hear people crying about the demise of the text-based genre, there will always be a niche out there for our kind. However, the vast majority of the games in our space are going to remain non-commercial, and mostly developed by volunteers on their spare time.

By making simplicity a high priority, we make sure that it’s easier to make progress when you do have a few moments to sit down and work on your game. While you could write a super-distributed, super-fault-tolerant MUD server, it’s probably going to make future development more complicated, and you may run out of steam before you get anywhere close to being “done”. As someone who would love to see more great MUDs out there, this makes me sad!

Developing and launching a MUD is a labor of love, and it has to be fun and interesting to you. You have a finite amount of time to get your game launched before you probably lose interest and move on to other things. This “time limit” varies from person to person, and some possess the rare ability to regularly, routinely work on a game for years before going public, but those types are very rare now. Your goal should be to open to the public before your “ok, time to move on” timer goes off. Simplicity is one of your biggest allies while pursuing this goal.

But… there are always caveats

A very valid counter-point to this argument for simplicity is that MUDs are a great way to learn new technologies, to experiment, to do things one might not normally do. If one’s goal is to tinker more so than to actually release a game to the world, you can throw this all out the window. Get as complex/geeky/sexy as you’d like, and have a blast. Who cares if you never ship? That’s not the point for you, anyway.

For those that are most concerned with actually “shipping”

Focus on your core functionality. What is your “minimum viable product?” What is the most direct way to get to your opening day? Avoid unnecessary complexity, and remember that you can always refactor and improve performance/scalability as you grow. Nothing is set in stone.

Avoid traps like multi-threading (unless you really have to have it), super scalability, and elaborate distributed setups unless you just really want to play. You’re designing a Gocart, not an IndyCar.

Simplicity. Clarity. Focus. Oh, and ship the damned thing!

Magnificant MUDdy Musings

The Evennia MUD Server has been progressing through beta at a goodclip, with much effort spent on fine-tuning existing features, and expanding on the already excellent pile of documentation. Much to my delight, the current maintainer, Griatch, has started to blog about Evennia development. If you are at least somewhat interested in keeping an eye on a Python+Twisted+Django MUD server, consider taking a peek at Griatch’s Evennia Musings.

While the blog details Evennia development, there is a lot of valuable general-purpose stuff as well. Especially for those writing, or considering writing, a MUD server using some or all of the same building blocks.

For those who would like to harass the man (or the other users/developers) in person, stop by #evennia on FreeNode.

Sphinx and Design Documents

As I’ve matured as an individual and a developer, I find that I like tospend longer and longer amounts of time in the planning phase before writing too much code. I’ll tinker with some of the technical problems I’m very concerned about, make sure my idea is even feasible, then jump into design doc mode.

Depending on the complexity of the project, this can be as simple as a Google Doc (especially if collaborating with less technical people), or as “fancy” as Sphinx documentation. I find the latter to be strangely therapeutic, though (I don’t pretend to be normal).

What is Sphinx?

Sphinx is a wonderful tool used for writing documentation for software. In addition to being able to generate documentation from docstrings (autodoc) for API references, it also makes it really easy to write user/admin guides, and design docs. Your documentation can refer to individual functions, methods, classes, and modules (if they are autodoc’d), and you have the full power and ease of reStructuredText at your fingertips.

You may have seen Sphinx in action if you’ve browsed Django or Python’s documentation. While the most avid users are Python projects, other languages are now supported.

What does the end result look like?

In the case of my latest project, a MUD named Dawn of the Titans, the end result looks like this.

I tend to start out with high-level scribbling in a Scratch Pad section, and just brain dump high level stuff, even if it doesn’t make 100% sense.

As things solidify, they end up graduating to their final homes in the Administrator or Player Documentation sections (in this project’s case). So I am effectively writing much of the guides before I write the actual code. As the code falls into place, my developer documentation references autodoc’d functions/methods/classes/modules, and etc.

reStructuredText is about as simple as Wiki markup, and is really similar to how developers have traditionally formatted comments and READMEs. It’s not much extra burden to write in reST as opposed to just doodling in a text editor.

When does it make sense to use Sphinx?

  • When you don’t mind spending the initial time to get Sphinx set up.
  • You either know, or want to know, reST.
  • The ability to gradually shift to “final” documentation without changing formats is appealing.
  • You value Sphinx’s autodoc and other extensions for API references, and cross-referencing such API documentation throughout your user/admin/dev guides is appealing.

When does it not make sense to use Sphinx?

  • You are in a huge hurry.
  • People without the time or knowledge to write reST or use version control need to be able to update the documentation.
  • The project is simple enough that a Google Doc won’t be too clumsy.

Why so complicated?

You do indeed need to learn some basic reStructuredText in order to go the route that I have, and there is some initial setup work that can be avoided with something like Google Docs. However, the great thing about using something like Sphinx is that my design docs gradually morph into very complete, thorough user/administrator/developer guides. Due to Sphinx’s autodoc extension, I also have API reference generation baked in, for my user/admin/dev guides to reference. A better example of what one of my more mature projects that was designed and eventually documented in Sphinx is media-nommer. See that for a good example of what the Dawn of the Titans documentation may eventually resemble.

There are a few moving pieces (Sphinx+reST+Revision Control), but each one is reasonably simple to work with. You can expect to be reasonably proficient within a day or two, if you go through First Steps with Sphinx. There are some quirks, and the error handling isn’t wonderful, but the end product is great.

Use Read the Docs

The other thing that makes this absolutely wonderful is Read the Docs. This lovely service compiles and hosts your final documentation for all to see. You can even hook in a GitHub (or other service) post-commit signal to cause it to automatically pull and re-compile your docs after each commit.

Here is my workflow for most tinkering:

  • Navigate to a file on GitHub, hit the “Edit this file” button.
  • Make my changes.
  • Enter commit message, hit “Commit Chanes”.
  • Read the Docs gets the post-commit notification from GitHub, re-compiles the docs.
  • After a 15-30 second delay, my docs are updated on the web for all to see and comment on.

I can, of course, still edit all of the docs locally in my favorite editor, and compile everything locally to review before committing (for more major edits).

CouchDB as a MUD server data store

I’ve been using CouchDB as the data store for my in-developmentMUDDawn of the Titans. So far it’s been very enjoyable to work with, through the CouchDB Python module. I’ll take a moment to share my experiences, for those who might be interested.

To provide some background, my MUD server is built specifically for the game I’m working on, but I’ve been developing it in the open on GitHub. The whole thing is built on Twisted, and is loosely styled after TinyMUX 2 (with Python in place of C++ and SoftCode).

Why CouchDB?

This is probably the first question on most people’s minds. There was nothing overly scientific about the choice of CouchDB. For me, this was a very uninteresting choice. I wasn’t really interested in querying whatever DB I used, as I wanted to keep almost everything memory-resident. I didn’t need much scalability at all, and I didn’t really need a relational database. The only thing I really needed a DB for was persistence.

In the end, I thought CouchDB’s use of JSON documents was pretty neat, and figured they’d allow for a really simple way to store objects. It was also a chance to learn something new (which was the biggest factor of all).

The Perks

So far, CouchDB has been a joy to work with. I realize that almost all of these are possible with X relational/non-relational DB, but I still give an approving nod to CouchDB in these cases.

The biggest benefit to using CouchDB is that my in-game object loading code looks something like this (pseudocode):

# Retrieve the object's document from CouchDB. This is a JSON
# dict, whose keys are the object's various attributes (name,
# description, location, etc).
object_doc = self._db[doc_id]
# A simplified example of how a Room is loaded. The CouchDB's keys
# are expanded as kwargs to the Room's __init__. Presto, loaded object.
loaded_object = RoomObject(**object_doc)

This may not seem like anything earth-shattering (it really isn’t), but it makes things very simple to manage and expand on. RoomObject’s __init__ method knows exactly what to do with a CouchDB object document.

Since CouchDB just deals with JSON documents, I can add/remove keys (which become object attributes in-game) without hassling with schema modifications or explicitly specifying fields. I’ve been surprised at how little time I spend mucking with the DB. I’m free to just focus on dealing in the realm of my MUD server, without worrying too much about my data store.

Another great thing about CouchDB is Futon, the web-based management console for CouchDB. It has made editing objects a breeze. I do this constantly when tinkering with objects. My set of in-game building commands is currently very limited, so this helps me keep getting things done while those materialize.

The last cool thing I’ll mention is that saving objects to the DB can easily be made asynchronous, and you can bulk submit objects (instead of saving one at a time). While async DB operations are expected for most DBs, CouchDB’s calls/queries are really easy to work into a Twisted project (without resorting to threads/processes), since the calls are all just HTTP requests (that can be deferred via Twisted’s HTTP client). Take a look at Paisley for an example of how simple it is to perform non-blocking queries.

The downsides

There is only really one downside (for what I’m doing) to CouchDB, and many non-relational stores in general: I have to manually assure that all ‘fake relations’ stay valid, and fail gracefully if they end up invalid. For example, let’s say I have an Exit that leads to ‘Test Room’. If said room is deleted, the exit should be un-linked or deleted. Leaving the exit in place means that someone attempting to travel through it (to the now non-existant room) would see an error message, since the ‘destination’ attribute points to an invalid object ID.

Most MUD servers have to do this kind of cleanup on their own anyway, I’m just somewhat spoiled from my time spent with Postgres/MySQL/SQLite on Evennia, which cleaned up after me (CASCADE!). So this is far from a show-stopper, just something I’m not used to.

The only other thing that could possibly be construed as a down-side is that querying CouchDB feels clumsy to me. This is almost certainly due to knowledge gaps on my end. I didn’t really need this in my case anyway, so no harm here.

In summation

Used in the context of a MUD, CouchDB has been awesome to work with. I’ve enjoyed it much more than my last MUD server projecet using relational DBs. In the end, the choice of data store should be made based on what lets you spend more time on your game, rather than your serialization/persistence/object saving. For any sanely designed MUD, you’re not likely to hit performance issues, and it all comes down to a matter of preference.

Over the speed bumps

One of the worse parts about writing a codebase from scratch for aspecific game is the staggering amount of foundation work that has to happen before you can really start making visible progress. Database layers, object representation and manipulation, account management, exits, and a basic set of global commands are all necessary before much of anything ‘visible’ can happen. Plus, these are only just going to get you started in breaking ground on your world.

I know right now that my project (Dawn of the Titans) lacks such basics as a communication system, a full set of builder commands, the ability to IP ban and flood control, and a sane way to handle color. Furthermore, I have yet to dig room 1 of my world, or start writing the fun stuff like combat and space flight systems.

It’s easy to look at my mile-long to-do list and get intimidated/psyched out, and at times, I have. In particular, the tasks that are either extremely uninteresting, tedious, or require a lot of re-arranging tend to really make me cringe. I end up putting these off, and further progress slows or comes to a halt.

Speed Bumps

There are probably much better terms for this, but I call issues on a to-do list that I dread the most “Speed Bumps”. Sometimes this is due to complexity, other times due to being very uninteresting or tedious. More often than not, these items are required for progress to continue. Unfortunately, these are also the most likely to go neglected.

By putting off these “Speed Bumps”, our progress is slowed, morale may drop, and motivation might go with it. Development momentum slows, and we may even come to a complete stop for periods. This is not good, given that you probably have at least a year’s worth of work to get a 100% custom MUD in playable shape.

Flying through the Speed Bumps

I have found that the best way to get past my cringeworthy tasks is to try to find something really simple and quick that I can do to at the start of a development session. It could be fixing a spelling error or writing a paragraph or two of documentation. It lets me get a commit under my belt, and I feel rewarded for making progress.

From there, the most “dreaded” of my tasks is where I start. After thinking, doodling, and writing a line or two of code, I lose the concrete shoes and I’m off to the races. The hardest part of getting past speed bumps is getting motivated enough to start working.

Attack the things you’re dreading; try to find some way to get excited about them. If it’s a particularly boring task, try to make it interesting by thinking of what you’ll be able to do down the road with what you’re working on.

Also…

For those masochistic enough to write an entire codebase for their particular game in mind, keep one very important thing in mind: You knew going into this that it was going to be a very long road. Don’t be discouraged by this, and instead be happy that you’ve got a great project to poke at when you feel like it over a year or two, or five. If it makes it out the door to live players, wonderful. If it doesn’t, hopefully you at least enjoyed working on it.