Multi User Domain

Using semantic web technologies to build an "infinite" text-based adventure game

April 23, 2021

Did you ever play a Fighting Fantasy book ? Roughly they are these role playing games where you are given a choice, say “help the man?” and if you choose “Yes” then it directs you to a page number, where it will describe the outcome of your choice. It’s a popular and early form of Role-Playing Game (RPG) which inspired subsequent games like Dungeons & Dragons and helped shape the RPG genre as we know it.

The front-cover of 'The Warlock of Firetop Mountain', a Fighting Fantasy book

On PC it’s notable that Fighting Fantasy’s designs gave rise to the text-based and the point-and-click adventure game which continue to be popular to this day.

A promotional image of Telltale Games 'The Walking Dead', a popular point-and-click adventure game first released in 2012

A Multi-User Domain is a real-time multiplayer virtual world and it’s usually text-based. It’s a concept deployed to various different domains including gaming, where players share a virtual world in which they might “choose their own adventure”.

Since the age of about 5 I’ve been fascinated by the idea of making a game with infinite choices. I made a game in which I was the server. I’d say “so what do you want to do?” and what the player said, I’d draw it. It had awful rendering time but great gameplay. Whenever I tried to write it into a book like Fighting Fantasies, I ran into a simple mathematical problem and couldn’t finish it. The truth is that writing a storytelling adventure game like The Walking Dead is the art of giving the illusion of choice. Giving real choice, you’ll find that the tree of possible outcomes grows exponentially and quickly becomes unmanageable. You must truncate outcomes and make choices lead to the same storyline until the very end.

Not so with the Multi User Domain.

A Very Brief Intro to the Semantic Web

For the unitiated I’ve prepared a brief intro on the basics of the semantic web (in particular on RDF data), but you may prefer to skip ahead.

The essential information is that with RDF, our data is modelled in graphs. It means that data can be more flexible than a table (I can add new properties to a resource at any time without adding a column to every row in a table), and by making the properties themselves URIs which can be followed, schema can also be discoverable as a web resource. By doing this in the right way, semantic web applications can become interoperable, which means that my application and yours can share data with eachother, without needing to plan for this at programmer-time.

In the regular web most data is served as human-readable content. In HTML the machine knows how to display the text to you, but it doesn't understand the knowledge that's is contained within the text. In applications the logic is written to neatly define what the machine should do with the data from the server, but it's the application programmer who understands the shape of the data it the server will send and what knowledge is contained within it. The machine just knows "robot do". In the semantic web we are almost always serving some type of RDF data. RDF data includes the "semantics", or meaning, of the data being served, so that instead of serving a wall of text about Barack Obama it will return something like ``` :Barack-Obama a :Person ; # Barack Obama is a person :name "Barack Obama" ; :hasSpouse :Michelle-Obama . ``` There are different formats for expressing RDF, here I'm using one called "Turtle" because it's popular. Notice that the data being communicated comes in **triples**: * "Barrack Obama - is a - Person" * "Barrack Obama - has a spouse - Michelle Obama" To make things clearer let me draw the same triples in a Graph, since that's what they represent: A graph showing a node, Barack Obama. An edge labeled 'rdf:type' leads to Person, an edge labeled 'has spouse' leads to Michelle Obama, and an edge labeled 'name' leads to the text 'Barack Obama' The nodes of the Graph are **resources**, kind of like objects, except his name which is a **literal** - a simple string value. The edges on the graph are always called **properties**. ### Why did I write ":Person" and not "Person"? The short answer is that I wrote this because it's easier to read than what I might really have written: ``` <https://example.org/#Barack-Obama> a <https://example.org/#Person> <https://example.org/#name> "Barack Obama" . ``` (It's all about URIs!) So if `https://example.org/#Barack-Obama` points to the graph we're defining here, the graph which defines Barack Obama, then it follows that `https://example.org/#Person` points to the definition of a **Person**, and `https://example.org/#name` points to the definition of a **name**. Note that we're not just serving data about Barack Obama, we're also serving the schema of what that data _is_. ### Vocabularies make everything interoperable The "schema" parts of that graph which describe what a Person is, what a name is, are known as a "vocabulary" or an "ontology". We're supposed to share these and reuse them so that my application and Bob's application can be interoperable, they can understand each other ``` <https://example.org/#Barack-Obama> a <http://xmlns.com/foaf/0.1/Person> <http://xmlns.com/foaf/0.1/name> "Barack Obama" . ``` Re-writing the data to use the popular [Friend-of-a-Friend](http://xmlns.com/foaf/spec/) ontology above, I can write my application to work with this representation of a `Person`, and then I can use it to publish this data, knowing that Bob's application can read it, and so can Alice's, without the need for bespoke application logic. We can all choose our own applications and we're not tied to a service because it holds our data prisoner.

The Infinite Text-Based Adventure Game

Where SQL data is characterised by its constraints on data, RDF data is characterised by its openness. I can add a canFly property to a Car storage, without needing to perform a database migration or define this property on any other car.

So at this level the Multi-User-Domain project is an effort to define a shared specification on a virtual world, which developers can extend and build on to infinity.

There is a lot of fun to be had in the building of a world, even without any “text-based adventure”, simply by creating a village, coming back in 6 months to find that your village is now a city, or that the bartender at the saloon you visited last week is complaining about another player who came in and challenged them to a duel. The world server doesn’t have to define what a duel is, what a saloon is or what a memory is, it just needs to allow players and machines to write to it in RDF. By defining common specifications for the interoperability of services, the client can discover a service which allows them to challenge bartenders to duels and expose this to the player.

a screenshot of a dialogue choice from Assassin's Creed Valhalla in which there are only two choices, 'Give it to the merchants' or 'Fund Halfdan's War'. A very restricted range.

No more choosing the lesser of two role-breaking choices! I want to give the silver to the peasants!

Building on the open and interoperable properties of semantic data, and defining common specifications for the interoperability of services, we can build a decentralised game, extended on the fly and bursting with life. It can continually surprise the players and architects of the worlds which compose it, forever evolving and forever changing. A community of worlds for humans and web crawlers to interact with.

Of course this implies that the game’s stories need to be decentralised, open to the twists and turns of player choices. Anyone who’s been “Dungeon Master” in Dungeons and Dragons knows the perils of players derailing quests with their unpredictable behaviour, but often that unpredictability is what makes it so fun and it’s what makes every campaign unique. Because of this open property at the heart of the MUD experiment, writing stories will be less “one big tree” like a Fighting Fantasy and more loose connections and federations of short and flexible event trees, changing on the fly like the game itself. But let’s find out while we write them!

I’m interested, what’s the next step?

Join our Discord server and say hello! https://discord.gg/sauZA3jCK7. We want to build an inclusive community which is accomodating for developers of any skill level and background :-)

Useful links