logo to emphasize the application of in-game analytics for MUDs

DevOps like It’s 1999 with


· · ·

Anyone who has ever met me knows that online text-based roleplaying games, called Multi-User Dungeons (or MUDs for short), are the entire reason I became a programmer. Despite the fact that many of these games predate the HTTP protocol by a few years, there is still a small, but thriving, community devoted to building and playing these games. Unfortunately, due to licensing restrictions, many MUD codebases are prohibited from commercial use, which has resulted in relatively little innovation over the past several decades. It is because of this fact and the fact that MUDs are built on a volunteer basis, that there is very little opportunity to monetize, which has left a pretty big gap in third-party tools and resources.

This is the first article in an ongoing series I intend to write about integrating modern DevOps tools into my own version of an Eye of the Storm MUD (my favorite derivative of the original DikuMUD codebase) called OASIS. Now, analytics are huge these days. From understanding everything about your customers and their behavior, to the behavior and patterns of your servers, data is king. This is one area where many MUDs are lacking. While some games have their own custom-built in-game analytics, they aren’t near as verbose and accessible as analytics provided by (which is the tool I will be integrating, in case you haven’t guessed it yet).

EOS is a relatively new codebase (“relatively” meaning it is 15 years old and written in C) which presents us with the fun task of consuming’s API without a pre-written SDK. This is where libcurl comes in, a “C-based multi-platform file transfer library.” Libcurl will allow us to send raw data up to from directly within the game, allowing us to monitor everything from player data to game statistics in the dashboard. This is also an appropriate time to mention the libjansson, a C-based library that we will use to easily build JSON objects (which is a requirement of any API worth using).

Installing and linking libcurl and libjansson can differ from implementation to implementation, but at a general level it’s best to use pkg-config to generate the appropriate compilation flags. In the OASIS codebase, I added the following to the compiler command in my makefile:

`pkg-config --cflags --libs jansson libcurl`

If you are working with any DIKU derivative, it is important to note that many modern libraries have worked with have issues with the static linking that is often configured in the makefile. While little else changed in the OASIS makefile, I did also remove the -static flag in order to get everything to compile properly.

Now, installing and linking the necessary libraries is only one part of the solution. The second part is actually utilizing them. Luckily, has incredibly thorough documentation for recording data to the platform using raw curl requests. Following their documentation (plus some of libcurl’s and libjansson’s documentation) I cobbled together a function that allowed me to post analytics data to

void write_analytics( json_t* obj, const char* collection ) {
   CURL *curl;
   CURLcode res;
   char *payload;
   char url[MAX_STRING_LENGTH];
   struct curl_slist *headers = NULL;


   if ( curl = curl_easy_init() ) {
     sprintf(url, "", KEENIO_PROJECT_ID, collection, KEENIO_API_KEY);

     headers = curl_slist_append(headers, "Content-Type: application/json");
     payload = json_dumps( obj, 0 );

     curl_easy_setopt(curl, CURLOPT_URL, url);
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);

     curl_easy_perform( curl );



Using this function, we are able to then write analytics data easily by building a JSON object and passing it into the method. For example, I configured OASIS to keep a note of every player login using the following snippet:

json_t *obj = json_object();
json_object_set_new(obj, "player_name", json_string( ch->name ));
write_analytics(obj, "logins");

By inserting this piece of code in the right place, we immediately start seeing login analytics data every time a player logs into the game:


While I only included the player name in this example, you could conceivably put any relevant information in the request. The more data you upload to, the more analysis you can do on it using their awesome project explorer. As a quick (and boring) example using the simple integration above, I can build an embeddable (!!!) widget that shows the number of player logins within the past week.

The beauty of the project explorer is that the analysis is limited only by the data we provide, which means that the more data we give, the more insight we have into our system (and the more insight the non-developers of any organization can have into the inner-workings of a system).

I know that integrating DevOps tools like into a decade(s) old computer game isn’t the most sought after use-cases, but I think it is by far one of the most fascinating. Keep an eye out for the next article in this series, where I will integrate PagerDuty with the built-in critical bug reporting method.

Zachary Flower (@zachflower) is a freelance web developer, writer, and polymath. He has an eye for simplicity and usability, and strives to build products with both the end user, and business goals, in mind. From building projects for the NSA to features for Buffer, Zach has always taken a strong stand against needlessly reinventing the wheel, often advocating for using well established third-party and open source services and solutions to improve the efficiency and reliability of a development project.

Zachary Flower is a freelance web developer, writer, and polymath. He has an eye for simplicity and usability, and strives to build products with both the end user and business goals in mind. Zach is a regular contributor at Fixate IO.


Leave a Comment

Your email address will not be published. Required fields are marked *

Skip to toolbar