mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
167 lines
8.2 KiB
Markdown
167 lines
8.2 KiB
Markdown
# OOB
|
|
|
|
OOB, or Out-Of-Band, means sending data between Evennia and the user's client without the user
|
|
prompting it or necessarily being aware that it's being passed. Common uses would be to update
|
|
client health-bars, handle client button-presses or to display certain tagged text in a different
|
|
window pane.
|
|
|
|
## Briefly on input/outputcommands
|
|
|
|
Inside Evennia, all server-client communication happens in the same way (so plain text is also an
|
|
'OOB message' as far as Evennia is concerned). The message follows the [Message Path](./Messagepath.md).
|
|
You should read up on that if you are unfamiliar with it. As the message travels along the path it
|
|
has a standardized internal form: a tuple with a string, a tuple and a dict:
|
|
|
|
("cmdname", (args), {kwargs})
|
|
|
|
This is often referred to as an *inputcommand* or *outputcommand*, depending on the direction it's
|
|
traveling. The end point for an inputcommand, (the 'Evennia-end' of the message path) is a matching
|
|
[Inputfunc](../Components/Inputfuncs.md). This function is called as `cmdname(session, *args, **kwargs)` where
|
|
`session` is the Session-source of the command. Inputfuncs can easily be added by the developer to
|
|
support/map client commands to actions inside Evennia (see the [inputfunc](../Components/Inputfuncs.md) page for more
|
|
details).
|
|
|
|
When a message is outgoing (at the 'Client-end' of the message path) the outputcommand is handled by
|
|
a matching *Outputfunc*. This is responsible for converting the internal Evennia representation to a
|
|
form suitable to send over the wire to the Client. Outputfuncs are hard-coded. Which is chosen and
|
|
how it processes the outgoing data depends on the nature of the client it's connected to. The only
|
|
time one would want to add new outputfuncs is as part of developing support for a new Evennia
|
|
[Protocol](./Custom-Protocols.md).
|
|
|
|
## Sending and receiving an OOB message
|
|
|
|
Sending is simple. You just use the normal `msg` method of the object whose session you want to send
|
|
to. For example in a Command:
|
|
|
|
```python
|
|
caller.msg(cmdname=((args, ...), {key:value, ...}))
|
|
```
|
|
|
|
A special case is the `text` input/outputfunc. It's so common that it's the default of the `msg`
|
|
method. So these are equivalent:
|
|
|
|
```python
|
|
caller.msg("Hello")
|
|
caller.msg(text="Hello")
|
|
```
|
|
|
|
You don't have to specify the full output/input definition. So for example, if your particular
|
|
command only needs kwargs, you can skip the `(args)` part. Like in the `text` case you can skip
|
|
writing the tuple if there is only one arg ... and so on - the input is pretty flexible. If there
|
|
are no args at all you need to give the empty tuple `msg(cmdname=(,)` (giving `None` would mean a
|
|
single argument `None`).
|
|
|
|
Which commands you can send depends on the client. If the client does not support an explicit OOB
|
|
protocol (like many old/legacy MUD clients) Evennia can only send `text` to them and will quietly
|
|
drop any other types of outputfuncs.
|
|
|
|
> Remember that a given message may go to multiple clients with different capabilities. So unless
|
|
you turn off telnet completely and only rely on the webclient, you should never rely on non-`text`
|
|
OOB messages always reaching all targets.
|
|
|
|
[Inputfuncs](../Components/Inputfuncs.md) lists the default inputfuncs available to handle incoming OOB messages. To
|
|
accept more you need to add more inputfuncs (see that page for more info).
|
|
|
|
## Supported OOB protocols
|
|
|
|
Evennia supports clients using one of the following protocols:
|
|
|
|
### Telnet
|
|
|
|
By default telnet (and telnet+SSL) supports only the plain `text` outputcommand. Evennia however
|
|
detects if the Client supports one of two MUD-specific OOB *extensions* to the standard telnet
|
|
protocol - GMCP or MSDP. Evennia supports both simultaneously and will switch to the protocol the
|
|
client uses. If the client supports both, GMCP will be used.
|
|
|
|
> Note that for Telnet, `text` has a special status as the "in-band" operation. So the `text`
|
|
outputcommand sends the `text` argument directly over the wire, without going through the OOB
|
|
translations described below.
|
|
|
|
#### Telnet + GMCP
|
|
|
|
[GMCP](https://www.gammon.com.au/gmcp), the *Generic Mud Communication Protocol* sends data on the
|
|
form `cmdname + JSONdata`. Here the cmdname is expected to be on the form "Package.Subpackage".
|
|
There could also be additional Sub-sub packages etc. The names of these 'packages' and 'subpackages'
|
|
are not that well standardized beyond what individual MUDs or companies have chosen to go with over
|
|
the years. You can decide on your own package names, but here are what others are using:
|
|
|
|
- [Aardwolf GMCP](https://www.aardwolf.com/wiki/index.php/Clients/GMCP)
|
|
- [Discworld GMCP](https://discworld.starturtle.net/lpc/playing/documentation.c?path=/concepts/gmcp)
|
|
- [Avatar GMCP](https://www.outland.org/infusions/wiclear/index.php?title=MUD%20Protocols&lang=en)
|
|
- [IRE games GMCP](https://nexus.ironrealms.com/GMCP)
|
|
|
|
Evennia will translate underscores to `.` and capitalize to fit the specification. So the
|
|
outputcommand `foo_bar` will become a GMCP command-name `Foo.Bar`. A GMCP command "Foo.Bar" will be
|
|
come `foo_bar`. To send a GMCP command that turns into an Evennia inputcommand without an
|
|
underscore, use the `Core` package. So `Core.Cmdname` becomes just `cmdname` in Evennia and vice
|
|
versa.
|
|
|
|
On the wire, a GMCP instruction for `("cmdname", ("arg",), {})` will look like this:
|
|
|
|
IAC SB GMCP "cmdname" "arg" IAC SE
|
|
|
|
where all the capitalized words are telnet character constants specified in
|
|
`evennia/server/portal/telnet_oob.py`. These are parsed/added by the protocol and we don't include
|
|
these in the listings below.
|
|
|
|
Input/Outputfunc | GMCP-Command
|
|
`[cmd_name, [], {}]` | Cmd.Name
|
|
`[cmd_name, [arg], {}]` | Cmd.Name arg
|
|
`[cmd_na_me, [args],{}]` | Cmd.Na.Me [args]
|
|
`[cmd_name, [], {kwargs}]` | Cmd.Name {kwargs}
|
|
`[cmdname, [args, {kwargs}]` | Core.Cmdname [[args],{kwargs}]
|
|
|
|
Since Evennia already supplies default inputfuncs that don't match the names expected by the most
|
|
common GMCP implementations we have a few hard-coded mappings for those:
|
|
|
|
GMCP command name | Input/Outputfunc name
|
|
"Core.Hello" | "client_options"
|
|
"Core.Supports.Get" | "client_options"
|
|
"Core.Commands.Get" | "get_inputfuncs"
|
|
"Char.Value.Get" | "get_value"
|
|
"Char.Repeat.Update" | "repeat"
|
|
"Char.Monitor.Update" | "monitor"
|
|
|
|
#### Telnet + MSDP
|
|
|
|
[MSDP](http://tintin.sourceforge.net/msdp/), the *Mud Server Data Protocol*, is a competing standard
|
|
to GMCP. The MSDP protocol page specifies a range of "recommended" available MSDP command names.
|
|
Evennia does *not* support those - since MSDP doesn't specify a special format for its command names
|
|
(like GMCP does) the client can and should just call the internal Evennia inputfunc by its actual
|
|
name.
|
|
|
|
MSDP uses Telnet character constants to package various structured data over the wire. MSDP supports
|
|
strings, arrays (lists) and tables (dicts). These are used to define the cmdname, args and kwargs
|
|
needed. When sending MSDP for `("cmdname", ("arg",), {})` the resulting MSDP instruction will look
|
|
like this:
|
|
|
|
IAC SB MSDP VAR cmdname VAL arg IAC SE
|
|
|
|
The various available MSDP constants like `VAR` (variable), `VAL` (value), `ARRAYOPEN`/`ARRAYCLOSE`
|
|
and `TABLEOPEN`/`TABLECLOSE` are specified in `evennia/server/portal/telnet_oob`.
|
|
|
|
Outputfunc/Inputfunc | MSDP instruction
|
|
`[cmdname, [], {}]` | VAR cmdname VAL
|
|
`[cmdname, [arg], {}]` | VAR cmdname VAL arg
|
|
`[cmdname, [args],{}]` | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
|
|
`[cmdname, [], {kwargs}]` | VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
|
`[cmdname, [args], {kwargs}]` | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE VAR cmdname
|
|
VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
|
|
|
|
Observe that `VAR ... VAL` always identifies cmdnames, so if there are multiple arrays/dicts tagged
|
|
with the same cmdname they will be appended to the args, kwargs of that inputfunc. Vice-versa, a
|
|
different `VAR ... VAL` (outside a table) will come out as a second, different command input.
|
|
|
|
### SSH
|
|
|
|
SSH only supports the `text` input/outputcommand.
|
|
|
|
### Web client
|
|
|
|
Our web client uses pure JSON structures for all its communication, including `text`. This maps
|
|
directly to the Evennia internal output/inputcommand, including eventual empty args/kwargs. So the
|
|
same example `("cmdname", ("arg",), {})` will be sent/received as a valid JSON structure
|
|
|
|
["cmdname, ["arg"], {}]
|
|
|
|
Since JSON is native to Javascript, this becomes very easy for the webclient to handle.
|