Battlesnake protocol

Battlesnake communicates over @pemit, using strings broken up with multi-character delimiters for various purposes. While the protocol is crude and makes some assumptions, it is reliable enough for heavy usage.

Inbound vs Outbound commands

Battlesnake has a notion of inbound and outboud commands. Outbound commands are those performed by the bot, sending text to the game. Inbound commands are @pemit strings asking the bot to do something, typically from your softcode.

This document will mostly focus on inbound commands, as that is where most of the challenge is.

A high level overview of inbound command syntax

An simple inbound command @pemit syntax example:

<prefix_str><command_name><kwarg_delim><invoker_dbref>

Breaking this down by component:

<prefix_str>
A randomized multi-character string that is set on the bot’s player object when it connects. If the bot sees this at the beginning of a line of input, it knows to look command_name up in its command table.
<command_name>
This is the command name that Battlesnake will look up in its internal command table. For example, send_email.
<kwarg_delim>
This is another randomly generated multi-character string that is used to separate bits of input to send to the bot. Almost all data (save for the invoker’s dbref) is in key=value form, separated by this delimiter.
<invoker_dbref>
This is the object on the MUX that is sending the command. The most common use for this is to give the bot a way to reply to the invoker.

Here’s an example inbound command with no additional data:

PREFIXSTRsend_emailKWDELIM#212

<prefix_str> is PREFIXSTR, <command_name> is send_email, <kwarg_delim> is KWDELIM, and <invoker_dbref> is #212.

Sending key/value data with inbound commands

We know how to send inbound commands now, but this isn’t too useful unless we can also send in arbitrary bits of data. Expanding on our previous example, here’s how that works:

<prefix_str><command_name><kwarg_delim><invoker_dbref><kwarg_delim>key1=value1<kwarg_delim>key2=value2

As you can see, kwarg_delim is used to split up key/value pairs. On the Battlesnake side, we convert these into Python dicts. Here’s how the command parser would split this up:

{'key1': 'value1', 'key2': 'value2'}

But what if we omit a value for a key?

<kwarg_delim>key1=<kwarg_delim>
{'key1': ''}

Sending lists values

Sometimes we’ll need to send lists instead of individual values:

<kwarg_delim>key=item1<list_delim>item2

We’ve introduced a new delimiter, list_delim. Much like prefix_str and kwarg_delim, this is a randomly generated multi-character delimiter. The presence of a list delimiter in a kwarg’s value causes it to be converted to a list in Battlesnake. Let’s say we do something like this (omitted invoker/command name/prefix for brevity):

<kwarg_delim>key=item1<list_delim>item2<list_delim>item3

Within Battlesnake, this would be interpreted as:

{'key': ['item1', 'item2', 'item3']}

You can combine regular string values and list values without issue:

<kwarg_delim>key1=value1<kwarg_delim>key2=item1<list_delim>item2<list_delim>item3

In Python land, this would be interpreted as:

{
    'key1': 'value1',
    'key2': ['item1', 'item2', 'item3']
}

Protocol limitations

The Battlesnake protocol only knows of two different data types: strings and lists. Your logic on the Python side will need to know how to treat the data being passed in. If you need ints, you’ll need to cast them and potentially handle errors.

While the delimiter characters should be random enough to avoid collisions, if your softcode were to generate values that matched one of the delimiters, kwarg pairs could be discarded. The likelihood of this happening is incredibly low, though, unless your data is sufficiently random and large.