The Message path¶
> look
A Meadow
This is a beautiful meadow. It is full of flowers.
You see: a flower
Exits: north, east
When you send a command like look into Evennia - what actually happens? How does that look string end up being handled by the CmdLook class? What happens when we use e.g. caller.msg() to send the message back?
Understanding this flow of data - the message path is important in order to understand how Evennia works.
Ingoing message path¶
Internet│
┌─────┐ │ ┌────────┐
┌──────┐ │Text │ │ ┌────────────┐ ┌─────────┐ │Command │
│Client├────┤JSON ├─┼──►commandtuple├────►Inputfunc├────►DB query│
└──────┘ │etc │ │ └────────────┘ └─────────┘ │etc │
└─────┘ │ └────────┘
│Evennia
Incoming command tuples¶
Ingoing data from the client (coming in as raw strings or serialized JSON) is converted by Evennia to a commandtuple. Thesa are the same regardless of what client or connection was used. A commandtuple is a simple tuple with three elements:
(commandname, (args), {kwargs})
For the look-command (and anything else written by the player), the text commandtuple is generated:
("text", ("look",), {})
Inputfuncs¶
On the Evennia server side, a list of inputfucs are registered. You can add your own by extending settings.INPUT_FUNC_MODULES.
inputfunc_commandname(session, *args, **kwargs)
Here the session represents the unique client connection this is coming from (that is, it’s identifying just who is sending this input).
One such inputfunc is named text. For sending a look, it will be called as
text(session, *("look",), **{})
What an inputfunc does with this depends. For an Out-of-band instruction, it could fetch the health of a player or tick down some counter.
For the text inputfunc the Evennia CommandHandler is invoked and the argument is parsed further in order to figure which command was intended.
In the example of look, the CmdLook command-class will be invoked. This will retrieve the description of the current location.
Outgoing message path¶
Internet│
┌─────┐ │
┌──────┐ │Text │ │ ┌──────────┐ ┌────────────┐ ┌─────┐
│Client◄────┤JSON ├─┼──┤outputfunc◄────┤commandtuple◄───┤msg()│
└──────┘ │etc │ │ └──────────┘ └────────────┘ └─────┘
└─────┘ │
│Evennia
msg to outgoing commandtuple¶
When the inputfunc has finished whatever it is supposed to, the server may or may not decide to return a result (Some types of inputcommands may not expect or require a response at all). The server also often sends outgoing messages without any prior matching ingoing data.
Whenever data needs to be sent “out” of Evennia, we must generalize it into a (now outgoing) commandtuple (commandname, (args), {kwargs}). This we do with the msg() method. For convenience, this methods is available on every major entity, such as Object.msg() and Account.msg(). They all link back to Session.msg().
msg(text=None, from_obj=None, session=None, options=None, **kwargs)
text is so common that it is given as the default:
msg("A meadow\n\nThis is a beautiful meadow...")
This is converted to a commandtuple looking like this:
("text", ("A meadow\n\nThis is a beutiful meadow...",) {})
The msg() method allows you to define the commandtuple directly, for whatever outgoing instruction you want to find:
msg(current_status=(("healthy", "charged"), {"hp": 12, "mp": 20}))
This will be converted to a commandtuple looking like this:
("current_status", ("healthy", "charged"), {"hp": 12, "mp": 20})
outputfuncs¶
Since msg() is aware of which Session to send to, the outgoing commandtuple is always end up pointed at the right client.
Each supported Evennia Protocol (Telnet, SSH, Webclient etc) has their own outputfunc, which converts the generic commandtuple into a form that particular protocol understands, such as telnet instructions or JSON.
For telnet (no SSL), the look will return over the wire as plain text:
A meadow\n\nThis is a beautiful meadow...
When sending to the webclient, the commandtuple is converted as serialized JSON, like this:
'["look", ["A meadow\\n\\nThis is a beautiful meadow..."], {}]'
This is then sent to the client over the wire. It’s then up to the client to interpret and handle the data properly.
Components along the path¶
Ingoing¶
┌──────┐ ┌─────────────────────────┐
│Client│ │ │
└──┬───┘ │ ┌────────────────────┐ │
│ ┌──────┼─►│ServerSessionHandler│ │
┌──────────────────┼──────┐ │ │ └───┬────────────────┘ │
│ Portal │ │ │ │ │ │
│ ┌─────────▼───┐ │ ┌─┴─┐ │ ┌───▼─────────┐ │
│ │PortalSession│ │ │AMP│ │ │ServerSession│ │
│ └─────────┬───┘ │ └─┬─┘ │ └───┬─────────┘ │
│ │ │ │ │ │ │
│ ┌────────────────▼───┐ │ │ │ ┌───▼─────┐ │
│ │PortalSessionHandler├──┼──────┘ │ │Inputfunc│ │
│ └────────────────────┘ │ │ └─────────┘ │
│ │ │ Server │
└─────────────────────────┘ └─────────────────────────┘
Client - sends handshake or commands over the wire. This is received by the Evennia Portal.
PortalSessionrepresents one client connection. It understands the communiation protocol used. It converts the protocol-specific input to a genericcommandtuplestructure(cmdname, (args), {kwargs}).PortalSessionHandlerhandles all connections. It pickles thecommandtupletogether with the session-id.Pickled data is sent across the
AMP(Asynchronous Message Protocol) connection to the Server part of Evennia.ServerSessionHandlerunpickles thecommandtupleand matches the session-id to a matchingSessionSession.ServerSessionrepresents the session-connection on the Server side. It looks through its registry of Inputfuncs to find a match.The appropriate
Inputfuncis called with the args/kwargs included in thecommandtuple. Depending onInputfunc, this could have different effects. For thetextinputfunc, it fires the CommandHandler.
Outgoing¶
┌──────┐ ┌─────────────────────────┐
│Client│ │ │
└──▲───┘ │ ┌────────────────────┐ │
│ ┌──────┼──┤ServerSessionHandler│ │
┌──────────────────┼──────┐ │ │ └───▲────────────────┘ │
│ Portal │ │ │ │ │ │
│ ┌─────────┴───┐ │ ┌─┴─┐ │ ┌───┴─────────┐ │
│ │PortalSession│ │ │AMP│ │ │ServerSession│ │
│ └─────────▲───┘ │ └─┬─┘ │ └───▲─────────┘ │
│ │ │ │ │ │ │
│ ┌────────────────┴───┐ │ │ │ ┌───┴──────┐ │
│ │PortalSessionHandler◄──┼──────┘ │ │msg() call│ │
│ └────────────────────┘ │ │ └──────────┘ │
│ │ │ Server │
└─────────────────────────┘ └─────────────────────────┘
The
msg()method is calledServerSessionand in particularServerSession.msg()is the central point through which allmsg()calls are routed in order to send data to that Session.ServerSessionHandlerconverts themsginput to a propercommandtuplestructure(cmdname, (args), {kwargs}). It pickles thecommandtupletogether with the session-id.Pickled data is sent across across the
AMP(Asynchronous Message Protocol) connection to the Portal part of Evennia.PortalSessionHandlerunpickles thecommandtupleand matches its session id to a matchingPortalSession.The
PortalSessionis now responsible for converting the genericcommandtupleto the communication protocol used by that particular connection.The Client receives the data and can act on it.