Recent Posts

Elixir Cowboy Websocket Handler

Posted on 10 Aug 2018

For my side project Gossip I wanted to have a websocket connection for non-Phoenix connections. I did this by going straight to Cowboy and using a handler at that level. This explains how I did this for Gossip.

Gossip is a cross game chat service for MUDs, check it out.

The Handler

The full websocket handler is here on GitHub.

defmodule Web.SocketHandler do
  @behaviour :cowboy_websocket_handler

  def init(_, _req, _opts) do
    {:upgrade, :protocol, :cowboy_websocket}

  def websocket_init(_type, req, _opts) do"Socket starting")
    {:ok, req, %State{status: "inactive"}}

  def websocket_handle({:text, message}, req, state) do
    with {:ok, message} <- Poison.decode(message),
         {:ok, response, state} <- Implementation.receive(state, message) do
      {:reply, {:text, Poison.encode!(response)}, req, state}
      {:ok, state} ->
        {:ok, req, state}

      _ ->
        {:reply, {:text, Poison.encode!(%{status: "unknown"})}, req, state}

This is a snipped version of the full file, but the basics are here. This shows the websocket upgrading, a cowboy and websockets requirement. The init function upgrades to websockets and the websocket_init function is called after the upgrade.

The other function shown is when a new message is received. The message is JSON (or should be), so it gets parsed and then run through an implementation module elsewhere. Depending on the response from that submodule, different responses will get send back.

There are a few other cool things in the real module, so I encourage you to check it out.


One thing I had to add that I thought was included as part of the cowboy handler was a pong response to a client side ping. This actually crashed the websocket process a few times so I needed to add this as per the websocket spec:

def websocket_handle({:ping, message}, req, state) do
  {:reply, {:pong, message}, req, state}

Phoenix Configuration

Since we're using a lower level websocket (than Phoenix) we have to manually set up the cowboy dispatcher. This configuration shows the cowboy websocket handler along with a separate Phoenix channel, since I want to have both options.

If you go this route, you need to manually specify any Phoenix channels from here on out.

config :gossip, Web.Endpoint,
  http: [dispatch: [
    {:_, [
      {"/socket", Web.SocketHandler, []},
      {"/chat/websocket", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, {Web.Endpoint, Web.UserSocket, :websocket}}},
      {:_, Plug.Adapters.Cowboy.Handler, {Web.Endpoint, []}}


Setting up your own lower level websocket in Elixir/Phoenix turned out to be pretty simple. I am happy I went this route so I didn't have to worry about forcing the higher level Phoenix channels protocol on top of external clients.

If you're curious about more of the events Gossip sends, the docs are available here.

ExVenture Updates for July 2018

Posted on 25 Jul 2018

The last month of ExVenture has been pretty sparse compared to previous months. This has been due to me starting a new side service called Gossip. Gossip is a cross game chat network for MUDs.

Links for MidMUD & ExVenture:


Gossip has been rolling around in my head for a while while working on ExVenture, but there has always been more pressing matters. About a month ago we were talking on the MUD Coders Guild about cross game chat and that inspired me to kick this off.

Gossip is similar to the I3 Network except it uses more standardized technologies. Secure WebSockets are the transport layer and all events are in JSON. You can see the documentation on Gossip.

ExVenture Remote Channels

The first big feature of Gossip is remote channels. You can flag a channel as a Gossip channel and it will try to send all communications up to the network.

ExVenture Remote Player Status

When your game is configured for Gossip, all signed in players are pushed up to Gossip. This lets other connected games see your players sign in and out. Right now all notifications are displayed to users on ExVenture. This is an optional but highly suggested feature for games that are not based on ExVenture.

This should help make your game feel more alive by letting your small pool (maybe just 1!) of players see others on the network.

The local who list will also display remote players, so users can see who is on the network.

Remote player list

ExVenture Remote Tells

The final big feature for Gossip right now is remote tells. If you're syncing your local players up to Gossip (and ExVenture does) then remote games and send tells to your local players. ExVenture lets you initiate tells and also handles reply for remote players.

This degrades nicely for remote games that do not support tells. As part of connecting a Gossip client says what features they support. For games that are not built on ExVenture remote tells are optional, but highly suggested.

First set of remote tells

Gossip Games List

I definitely suggest you check out the Gossip Games list. So far we have 5 games connected, more seem to be checking out Gossip every day!

Gossip Clients

The Gossip client from ExVenture has been pulled out into it's own Elixir hex package. If you're developing your own Elixir MUD (and there are a lot of you out there) then come join the fun and add the package.

Right now you do need to implement the full set of callbacks for all of the features of Gossip, but I would like to let you dictate which features your game supports and slowly add them in.

There is also a Ranvier bundle that supports remote channels and player status updates.

Next Month

Next month I hope to start back on ExVenture more and leave Gossip to sit for a bit. I think Gossip has a good enough feature set to let other games implement what's there and get some more feedback from the community.

Elixir OTP Supervision Tether

Posted on 09 Jul 2018

I got to try out a new OTP Supervision tree pattern in ExVenture, that I am going to call a tether.


I started a new service, named Gossip, that ExVenture creates a persistent websocket connection to.

When this service dies or is not alive when the ExVenture server starts, the websocket connection will crash or refuse to start entirely. It crashes immediately and then cannot reconnect. This ripples up the supervision tree taking the entire application down in short order.

To get around this, I added a layer of supervision trees for just that socket process. My tree looks like this when fully booted:

- ExVenture
  - Gossip.Supverisor
    - Gossip.Monitor
    - Gossip.Supverisor.Tether
      - Gossip.Socket

The Process

The tether supervision starts with no childspecs. After boot the Monitor (or the cluster leader) will start the Socket inside the tether. When the socket process dies, it will eventually crash the tether supervisor causing it to restart.

When the tether supervisor restarts, it will restart with no children breaking the restart loop ("cutting the tether".)

Eventually the monitor process will try to restart the Gossip socket which may crash, causing the tether to crash and so on. Either way the crashing process was contained and the application stayed up.


The code for this was pretty simple, you can see it on GitHub in the gossip folder.

I learned of this at least part of this technique from Adam, over at the MUD Coders Guild. If you are interested in Elixir and multiplayer game programming, come check out the Slack and say Hi.

ExVenture Updates for June 2018

Posted on 29 Jun 2018

The last month of ExVenture was mostly the overworld, which I posted about previously. There were a lot of other smaller tweaks too.

Links for MidMUD & ExVenture:


The overworld is a new extremely large feature for ExVenture. Admins can "paint" an overhead map that players can wander around. Exits can be made to rooms in the "old world" for travel back and forth.

I was very happy to get this working, even if there is still a large TODO list.

Overworld movement


There was some conversation this week on the MUD Coders Slack that made me finally get around to a cross game chat network. I started the Gossip project for this. It's a simple Phoenix app that has a cowboy websocket handler to get around not using Phoenix channels.

I went with this route so others didn't have implement the Phoenix channels protocol in other languages. I also wanted something that was extremely stable, since Phoenix Channels has bumped versions fairly recently I don't want to have my library bump and break any existing connected game.

So far its been a fun exercise and it's currently working in a simple form of routing messages to connected applciations. I am in the middle of an ExVenture connect.

Mudlet Additions

When connecting via Mudlet, the package down auto downloads the world map. This should save a lot of wandering time for players to get a fully functional mapper.

I also got a patch into Mudlet based on some functionality I pulled out of the ExVenture package. This is available as part of Mudlet 3.10.

Mudlet has been working on Discord integration, and ExVenture is ready whenever that ships. I have basic status setting functionality set up at the moment.

Admin React

To sort of build myself up to what I thought I would need for the overworld, I started adding some nicer interfaces to the admin panel via React components. The first two I did were effects and quest scripts.

Effects are now done via a nice form that dumps to raw JSON. No longer do you need to edit that huge textarea by hand!

Quest scripts are now filled out by a nice form instead of of a text area and I also have a script tester right in the panel. You can see how the NPC would react without having to head in game.

Script Editor for Admins


Room exits got a massive overhaul in preparation for the overworld (and continued afterwards.) They are now one way, but the admin panel makes and destroys both directions. This drastically simplified the usage of exits inside of the code base.

The only tricky part was getting the reverse exit to be created for the overworld, but I will take one tricky spot over it being littered throughout the whole app.

As a bonus, this let me finally add in diagonal movement. You can go north east now.

Character Stats

I revamped the character stats. Movement points are gone, replaced with Endurance Points. They aren't used yet, but I would really like to let skills use Skill Points or Endurance Points. I might also rename Skill Points sometime in the future to better reflect the split. I want Endurance Points to be more physical based, and Skill Points to be more "mind" based.

The basic attributes have also been reworked. The new six attributes are:

  • Strength
  • Agility
  • Intelligence
  • Awareness
  • Vitality
  • Willpower

They all go in pairs of two to boost the HP, SP, and EP. Strength and Agility boost HP, Intelligence and Awareness boost SP, and Vitality and Willpower boost EP. This feels a lot better than how it was previously and has at least 100% more thought put into what they are and how they're named.

Web Client

The web client got a major face lift over the weekend. It now has a sidebar chat to track channel messages, so they don't get lost in the flow. I also tweaked the bottom bar to feel better, paddings and margins are now similar, along with font and font size. Some panels also got squeezed and moved around. Hopefully the new client looks much nicer to you as it does to me.

Web Client

Next Month

I hope to continue with the overworld and Gossip integration. These are both big features that will be fun to continue with in the coming months.

I am in the process of reading The Art of Game Design by Jesse Schell so I expect some changes to come from that. Namely I want to start thinking of how I want people to experience the game and start tweaking it to better reflect that. I expect this to be a slow process but highly worth the thought put into it.

ExVenture Overworld

Posted on 19 Jun 2018

This week I wrapped up the absolute basics of ExVenture's largest new feature, the overworld.

Overworld overview

This was a huge feature that's barely been scratched.

Map Editor

First up was I wanted to make a nice way to edit the overworld in the browser. This was my first big React app. You can see it in action below:

Overworld map editing

I have a lot of ideas on how to make this nicer, but the editor works for now. Things I want to add are: a nicer color picker, which will display the color instead of just using the word; and some way to paint bucket large areas with symbols and colors.

I may also set up a terrain swatch to bundle together a symbol and color (and eventually cell attributes) into a nice picker.

Exit Editor

After the map is created, you need to hook it up with rooms so players can move in and out of the map. This is another react page that does live API updates.

Overworld exit editor

Moving Around

Once exits are created, players will be able to move around freely between the room based zones and the overworld based zones.

Here is movement on MidMUD, going from the room based town of Milay to the countryside around it:

Overworld movement

Backing Architecture

Overworld zones are set up as a pool of Sector processes. Each sector handles a portion of the grid of cells in a map, 10x10 right now. The calling or casting process determines which sector to talk to so this should scale well.

Only minor updates for the commands were needed to get the overworld working. Mostly the updates were stripping functionality and making sure they did less on the overworld. Commands like involving items in particular were broken on the overworld, because I didn't want to implement item storage on the overworld quite yet.


I've started a GitHub issue to track all the things that are still missing. The big ones right now are:

  • Items in the overworld
  • NPCs in the overworld
  • Say communication should go further than your current cell
  • Seeing other players on the map

I am looking forward to seeing the overworld slowly fill out now that the basics of being able to get to it and move around are done. It is a huge relief to have this part over.

Links for MidMUD & ExVenture

Eric Oestrich
I am:
All posts
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.