8sync participates in the Lisp Game Jam with Mudsync

-- Wed 11 May 2016

Hello, hello! Over the last week and a half, 8sync participated in the Spring 2016 Lisp Game Jam. In short, I had ten days to build a game, so I decided to build a MUD on top of 8sync. And so, mudsync was born!

> go east **Smoking Parlor** This room looks quite posh. There are huge comfy seats you can sit in if you like. Strangely, you see a large sign saying "No Smoking". The owners must have installed this place and then changed their mind later. There's a door to the west leading back to the grand hallway, and a nondescript steel door to the south, leading apparently outside. You see here: a comfy leather chair, a plush leather sofa, Ford Prefect and a bar stool. > sit in the chair You sink into the comfy leather chair. > say Ahhhhhh, this is the life! paroneayea says: Ahhhhhh, this is the life!

How'd it go?

I'm happy to say that mudsync was successful overall. The end released project includes a fairly solid, live hackable game engine for multiplayer interactive fiction. This ended up being more of a piece of infrastructure to build games rather than being a nice game itself, but it does ship with a mini-world called "Hotel Bricabrac" which has some interesting things, but is more of a tech demo. Most importantly, I feel like mudsync is a really nice foundation for future games, and the amount of world building I did do in it was a joy to put together. So! More of that in the future?

Mudsync also made great use of 8sync's new actor model subsystem, which will publicly premiere in the upcoming 0.2.0 release.

Why participate in the game jam?

At first participating in the game jam may sound merely like an exercise in fun, and of course it was this too, but greater ambitions were also at play. I have plans to use 8sync for some larger projects involving federated networks, and I wanted to be sure that the technology worked well enough to invest my time by building something more complicated. Happily, all seems to have gone well; I am feeling much more confident in 8sync now having completed the jam and am looking forward to my larger projects with it. And along other federation-related lines, I've long been interested in the overlap between the type of federation-related work I am persuing with the ActivityPub standard MUDs, and the actor model of programming. MUDS, the actor model, and ActivityStreams (the syntactic basis upon which ActivityPub rests) all share a subject-predicate-object syntax and use message passing as a primary communication mechanism. And lest it sound like I've gone completely off my rocker (maybe I have, of course) I might note that research in MUDs as a decentralized mechanism of communication was very high before the web took over everything, and even an active topic in a couple of research labs! (I recommend checking out the Design Requirements for Network Spaces document to get a sense of this.) So I figured implementing a MUD might help me better think through some of this space, and it did!

Furthermore, 8sync itself owes part of its existence to a much older interest of mine in creating networked games. XUDD, the actor model system I wrote in Python and which preceded my thoughts on how to build 8sync, originally stood for "eXtensible User Dungeon Design" (but I gave it a sillier acronymn when its goals shifted). I haven't lost interest in how to design such systems, and the implications of them fueled a lot of my reading in this area.

Plus, it sounded like a whole lot of fun!

What does it look like?

From a player's perspective, mudsync is your classic MUD-over-telnet. There are some things missing, but it works: you can walk around from room to room, interactive with objects and other players, and so on.

From an administrator / hacker's perspective, mudsync is much more interesting. You write out a "game spec" like the following (which is borrowed from real game code):

(define lobby (lol ; just a simple 'list of lists' macro ;; Starting place for players ('room:lobby <room> #f #:name "Hotel Lobby" #:desc " You're in some sort of hotel lobby. You see a large sign hanging over the desk that says \"Hotel Bricabrac\". On the desk is a bell that says \"ring for service\". Terrible music plays from a speaker somewhere overhead. The room is lined with various curio cabinets, filled with all sorts of kitschy junk. It looks like whoever decorated this place had great ambitions, but actually assembled it all in a hurry and used whatever kind of objects they found lying around. There's a door to the north leading to some kind of hallway." #:exits (list (make <exit> #:name "north" #:to 'room:grand-hallway))) ;; Summons a clerk if a player does 'ring bell' ('thing:lobby:bell <summoning-bell> 'room:lobby #:name "a shiny brass bell" #:goes-by '("shiny brass bell" "shiny bell" "brass bell" "bell") #:desc " A shiny brass bell. Inscribed on its wooden base is the text \"ring me for service\". You probably could \"ring the bell\" if you wanted to." #:summons 'npc:break-room:desk-clerk)))

This builds the kind of world you might expect from the above:

> look **Hotel Lobby** You're in some sort of hotel lobby. You see a large sign hanging over the desk that says "Hotel Bricabrac". On the desk is a bell that says "ring for service". Terrible music plays from a speaker somewhere overhead. The room is lined with various curio cabinets, filled with all sorts of kitschy junk. It looks like whoever decorated this place had great ambitions, but actually assembled it all in a hurry and used whatever kind of objects they found lying around. There's a door to the north leading to some kind of hallway. You see here: a curio cabinet, a shiny brass bell, the Hotel Bricabrac sign, a frumpy fellow and sign-in form. > look at bell A shiny brass bell. Inscribed on its wooden base is the text "ring me for service". You probably could "ring the bell" if you wanted to. > ring the bell *ring ring!* You ring the bell! Suddenly, a uniformed woman rushes into the room! She's wearing a badge that says "Desk Clerk". "Hello, yes," she says between breaths, "welcome to Hotel Bricabrac! We look forward to your stay. If you'd like help getting acclimated, feel free to ask me. For example, 'ask clerk about changing name'. You can ask me about the following: 'changing name', 'common commands', and 'about the hotel'."

(I inserted the ">" characters to make where the input was a bit clearer, but otherwise that's verbatim output from the game.)

What's nice is that you can live hack everything that's going on. And by that of course I mean the kind of usual nice live hacking you have going on with 8sync and Guile... but it's not only that! Consider the following challenge: you've just tweaked the description of the room your friends are hanging out in, but you already have a room set up in the game's universe, so how on earth can you replace it? Luckily Mudsync provides a nice protocol for replacing objects, and even provides a nice utility to inject it into the currently running game (the actors know how to "transfer important details", in this case, the participants in the room):

(inject-gameobj! game-spec 'room:lobby)

Obviously, you don't want to do this for anything other than live hacking. But it is nice that you can live modify how things are running in the game. For example, at one point a player asked me how they could "emote" in the game, and we didn't have an emote command, so I added it and told them, and then we all happily did some emote'ing. At another point a player said they felt bad for the desk clerk and wanted a way to dismiss her so she wouldn't have to hang around the desk, so I added a dismiss command where she'll thank the player and "run off to do something important" (as it turns out, doing something important means to go smoke in the employee break room).

A story about stories

So, speaking of that, the "main game" that ships with Mudsync right now is a little mo... hotel named "Hotel Bricabrac" full of various strange and fun things (though, not as many as I would like). Unfortunately, it lacks any significant story. There's something that almost resembles a story, and which players seemed to like: the desk clerk, upon ringing the bell, arrives, but quickly becomes bored, starts fidgeting distractedly, and eventually leaves. When I first started coding this, I had envisioned the character as perhaps a disaffected and incompetent teenager, but as I was playing around I started to feel empathy for them... it really was a boring job that they had, and newcomers ringing the bell all the time would get annoying. Thus, if you explore well enough, you might find the "employee break room", a cage affixed to the exterior of the building. Whenever the clerk leaves her post, she goes here to smoke and check her phone and slack off. But if you talk to her enough in this off-duty space, she'll tell you that she's a student studying high energy particle physics, that she's underpaid, but she's working the job because she doesn't have many other options and her student loans are crushing her. So she was never really incompetent after all, just overqualified, bored, and, well, still disaffected. Some players seemed to enjoy that and expressed empathy for the character (though it didn't seem to stop them from ringing the bell to provoke a response from her). I was glad about that, and I wish I had more time to script in more things like this.

Indeed, my original ambitions were to build a full and immersive game as part of the game jam. I sketched in a notebook a layout for a haunted mansion or college campus. My original vision for the jam was that players would be collaborating in exploring an area on figuring out how to help various ghosts be put to rest. You'd find out what's binding them to this world and help them resolve their problems, and you as a player would have an "achievements" list showing off just how many interesting things you had done in the world. Unfortunately (though not surprisingly), building the engine itself ended up being enough work that I didn't have a lot of time for content. Thus the experimental little world where I was testing various game mechanics became the actual deliverable of a demo-world to be played.

In the end, that's probably not the worst situation. I feel I have a good design on which future games could be built. And despite the chaos of it, players did seem to have a lot of fun (I think at one point we had about 8 players or so on the game who were hanging out and mostly socializing). The chaotic gathering place on some mysterious property atmosphere looks a lot like LambdaMOO, and as LambdaMOO enthusiast Rob Myers said to me at one point, "Themeliness is next to timeliness." It's not such a bad start! Though I do hope to have more interesting worlds to show in the future.


No sprint like this is without its challenges. Here were mine:

  • It was really hard to decide what "flavor" of sentence parsing to go with. Basically you can either have more rich sentences which require a lot of complicated parsers, but then you can say complicated things like "Put the melon in the fruit basket." (Zork/ZIL/Z-Machine type single-player interactive fiction games tend to go like this.) Or you can go with more predictable but limited parser and parse more basic sentences like "put melon in fruit basket". The former lends itself to more immersive gameplay. The latter is faster, more predictable, and works better for either combining with non-text interfaces (maybe a web UI) and could concievably work with a federated game. I spent some time agonizing over this. In the end I built kind of a hybrid: actors select from a few prebuilt "rich" command processors which handle all the basic cases you might want.
  • 8sync relies heavily on delimited continuations. However, sometimes if scheme calls C which then calls out to scheme again in Guile, things break. A few things caused this, including using the "@@" special form to try to get around dependency loops lazily. Most significantly, since 8sync's actor model system uses GOOPS, I learned the hard way that GOOPS being very C based in Guile 2.0 means that I had to forego many interesting GOOPS features, like generic methods or accessors. Once I realized this, things went a lot more smoothly, and I didn't really need these features... but sometimes I wished I had them.
  • You might say, "but Guile 2.2's GOOPS was rewritten in scheme!" And you'd be right. Unfortunately, I uncovered a pretty critical bug with GOOPS and Guile 2.2, and didn't have time to look into it seriously. Again, not a huge deal, but it did take up some time to look into.
  • I hit a really weird SIGABRT issue in 8sync's actor model. Initially I thought it was a Guile issue, but it turned out I just didn't understand some things about how prompts and exceptions work.
  • I really wanted to have a nice text formatter, but I ran out of time to integrate one. (If you talk to the hotel owner in the lobby of Hotel Bricabrac, you'll find he complains about this kind of indirectly, expressing my wishes to explore something along the lines of Skribilo or fmt. Alas! No time for it...)
  • Again, I would have loved to have more time to build a more coherent story. But time is always a challenge in these things!

What's next?

So mudsync will be a background hacking task for me probably for a while, something to hack on for my and friends' amusement every now and then. I may end up writing some small and interesting stories. But it won't be my main project.

But it probably will be a basis for research (and fun) for me. It's a nice system to test out ideas in. And I'll probably add some cool optional components, like persistent-world-supporting databases. (Maybe even player-scripted items? Unlikely in that it would require a carefully crafted sandboxed execution environment, but don't think I haven't been thinking about it...!)

In the meanwhile, if you want to check it out, the source is available. Patches most welcome! And if you hop in #8sync on irc.freenode.net, maybe you can find the address of the current dev server!

Thanks to Rob Myers and Jason Self, who both know a lot more about interactive fiction than I do and answered a lot of questions and offered ideas. Thanks also to everyone who gave the game a try. I hope it was as fun for you as it was for me!

Happy hacking...