WebAssembly in the Cloud - Will it MUD? ⚔️
Tags: webassembly, mud, rust, wascc
Published: 2020-05-22 23:58:48

# Overview of MUDs

Throughout my career, one of the first things that I've done when encountering a new technology is ask myself whether this technology can be used to create a [MUD](https://en.wikipedia.org/wiki/MUD), a _multi-user dungeon_ (or _dimension_). MUDs, at least historically, are multi-user, online, text-based adventure games. It's quite possible that there are some MUDs that are older than some of the people reading this post. _Just because a technology is old doesn't mean it's bad_. I'm going to over-simplify a bit, but MUDs tend to come in two flavors:

* Data-Driven - an _engine_ presents a gaming experience by reading from a fixed-schema set of data
* Code-Driven - a _driver_ (what we nowadays would call a _virtual machine_) loads user/wizard-supplied code files on demand to provide the gaming experience.

I personally have no interest in the former. For the latter, the best example of a code-driven MUD is the famous [LPMud](https://en.wikipedia.org/wiki/LPMud). An LPMud has 3 core components:

* **The game driver (virtual machine)** - This is a stateful process that runs on a host, providing a network interface and exposes a suite of "efuns" (external functions) to LPC code.
* **The mudlib** - Code written in [LPC](https://en.wikipedia.org/wiki/LPC_(programming_language)) that provides the foundation of the game, e.g. weapons, objects, economy, guilds, magic, rooms, etc.
* **User (wizard) Code** - Code written in LPC by players of the game. This code utilizes the mudlib to create the virtual world in which players inhabit.

LPC is a _blueprint_ or _prototype_ based language. Every file (e.g. `lib/weapons/sword.c`) is a game object. If a game object can be _cloned_, then multiple instances of the blueprint can exist in memory. In the case of a sword, the blueprint object is `lib/weapons/sword` and a specific instance of a sword (the one my character is wielding that is worn and about to break, for example) might be `lib/weapons/sword#127`.

Before I get into how any of this relates to WebAssembly, let's take a look at a sample bit of LPC code:

```c
inherit "/lib/room";

void create() {
    ::create();
    set_short("a simple room");
    set_long("A simple room in a simple building.");
    set_description("This is a simple room in a simple building.  It is very nice.");
    add_exit("north", "/realms/descartes/north_room");
}
```

This code might exist in a file like `areas/kevin/simple_room.c`. It should be fairly obvious the benefits of having user-created code like this rather than admin-defined fixed data. This lets the game evolve over time and get more and more features that can be supplied by users rather than a single core developer.

# waSCC Overview

[waSCC](https://wascc.dev), _WebAssembly Secure Capabilities Connector_, is a WebAssembly host runtime that dynamically binds cloud native capabilities to _actors_ (WebAssembly modules). The goal of waSCC is to let developers define pure business logic and deploy it in a small, secure WebAssembly module that is completely decoupled from the capabilities that satisfy non-functional requirements.

As I was developing waSCC, one thought kept gnawing at the back of my brain: _can I use waSCC to let people write MUD code as wasm actors?_

I think the answer is **_yes_**.

# waSCC as an Evolution of LPMud

Back in the good old days, an LPMud was a single process running on a machine to which players would `telnet` in order to play. If we're going to build a modern MUD, then it needs to be a distributed, cloud-native system that can dynamically scale to handle changes in load. Thankfully, this is precisely what **waSCC** is designed to do.

Recall the 3 components of an LPMud:

* Game Driver (VM)
* Mudlib (LPC)
* User Code (LPC)

waSCC is a WebAssembly host, and as such is a _virtual machine_ that executes wasm modules. This means we can probably use waSCC runtime hosts as components of a distributed game driver.

A **mudlib** is a core set of functionality that is securely exposed to user code that provides foundational building blocks for creating virtual worlds and game experiences. A waSCC _capability provider_ seems like an ideal way to provide a mudlib. User code could make requests of the mudlib to do everything from set state (remember this is a distributed system, state isn't local to a process) to communicate with players, trigger weather events, initiate combat, and much more.

Finally, **user code** in an LPMud is written in LPC. User code in a waSCC-based MUD would be written in _any language_ that compiles to a waSCC-compliant actor `.wasm` file. 

As a thought experiment, let's take a look at what it might look like to re-write the previous LPC example as a Rust-based waSCC actor (for information on creating waSCC actors, check out [this tutorial](https://wascc.dev/tutorials/first-actor/).

```rust
#[macro_use]
extern crate wasmud_mudlib as mudlib;

gameobject_handlers! { mudlib::msgs::CREATE => create }

fn create(msg: mudlib::msgs::CreateMessage) -> HandlerResult<()> {
    mudlib::room::create(); // Perform default room setup

    set_short("a simple room");
    set_long("A simple room in a simple building.");
    set_description("This is a simple room in a simple building.  It is very nice.");
    add_exit("north", "/realms/descartes/north_room");
}
```

It looks pretty similar to the original LPC code, but what you _don't_ see here is that because this is a WebAssembly module running under a waSCC host, it's automatically getting enterprise-grade scalability and security and a pile of other features.

We can continue down this road and see what it might look like for the room to clone an NPC and move it into the room upon creation:

```rust
fn create(msg: mudlib::msgs::CreateMessage) -> HandlerResult<()> {
    mudlib::room::create(); // Perform default room setup

    set_short("a simple room");
    set_long("A simple room in a simple building.");
    set_description("This is a simple room in a simple building.  It is very nice.");
    add_exit("north", "/realms/descartes/north_room");

    let dragon = clone_object("/npcs/dragon");
    dragon.move(this_object())?;
}
```

The cool new stuff here is `clone_object` and the `move` function on the `dragon` variable. In traditional LPC, since it was running in a single monolith, code like this would directly instantiate the `dragon.c` file by running it through the VM interpreter and then immediately add the dragon _reference_ (e.g. `/npcs/dragon#1284`) to the room's `_inventory` field.

This code, by virtue of running under waSCC, is _far more powerful_. The `clone_object` function will ask the mudlib provider to instantiate another actor (`/npcs/dragon.wasm`). Our user code does not care _where_ or _how_ this dragon is instantiated. Next, calling `move` on the dragon will ask the (distributed) mudlib to move the dragon into this room, triggering all appropriate real-time events and dealing with all the ugly things in the background like replication, eventual consistency, etc.

# Summary

In conclusion, it is my hypothesis that we can use waSCC, actors, and secure capability providers to create a MUD that lets players write code that looks and feels as simple as the original LPC, but automatically deals with running in a distributed, dynamically scaling, multi-user environment in the cloud.

I would love to hear your thoughts on this as a potential project. Do you think it's a good idea? Should I continue a series of blog posts as I attempt to write some of this MUD in waSCC? Let me know!

To stay up to date, you can keep in touch with me on [Twitter](https://twitter.com/KevinHoffman) and you can check out the [waSCC](https://github.com/wascc) organization on GitHub.