Fixed all links

This commit is contained in:
Griatch 2020-10-11 19:31:05 +02:00
parent d4f1733bc7
commit 26f8ba3f71
175 changed files with 11972 additions and 4443 deletions

View file

@ -1,7 +1,10 @@
# Messagepath
The main functionality of Evennia is to communicate with clients connected to it; a player enters commands or their client queries for a gui update (ingoing data). The server responds or sends data on its own as the game changes (outgoing data). It's important to understand how this flow of information works in Evennia.
The main functionality of Evennia is to communicate with clients connected to it; a player enters
commands or their client queries for a gui update (ingoing data). The server responds or sends data
on its own as the game changes (outgoing data). It's important to understand how this flow of
information works in Evennia.
## The ingoing message path
@ -40,47 +43,72 @@ depends on the [Protocol](./Custom-Protocols) used:
### Portal Session (ingoing)
Each client is connected to the game via a *Portal Session*, one per connection. This Session is different depending on the type of connection (telnet, webclient etc) and thus know how to handle that particular data type. So regardless of how the data arrives, the Session will identify the type of the instruction and any arguments it should have. For example, the telnet protocol will figure that anything arriving normally over the wire should be passed on as a "text" type.
Each client is connected to the game via a *Portal Session*, one per connection. This Session is
different depending on the type of connection (telnet, webclient etc) and thus know how to handle
that particular data type. So regardless of how the data arrives, the Session will identify the type
of the instruction and any arguments it should have. For example, the telnet protocol will figure
that anything arriving normally over the wire should be passed on as a "text" type.
### PortalSessionHandler (ingoing)
The *PortalSessionhandler* manages all connected Sessions in the Portal. Its `data_in` method (called by each Portal Session) will parse the command names and arguments from the protocols and convert them to a standardized form we call the *inputcommand*:
The *PortalSessionhandler* manages all connected Sessions in the Portal. Its `data_in` method
(called by each Portal Session) will parse the command names and arguments from the protocols and
convert them to a standardized form we call the *inputcommand*:
```python
(commandname, (args), {kwargs})
```
All inputcommands must have a name, but they may or may not have arguments and keyword arguments - in fact no default inputcommands use kwargs at all. The most common inputcommand is "text", which has the argument the player input on the command line:
All inputcommands must have a name, but they may or may not have arguments and keyword arguments -
in fact no default inputcommands use kwargs at all. The most common inputcommand is "text", which
has the argument the player input on the command line:
```python
("text", ("look",), {})
```
This inputcommand-structure is pickled together with the unique session-id of the Session to which it belongs. This is then sent over the AMP connection.
This inputcommand-structure is pickled together with the unique session-id of the Session to which
it belongs. This is then sent over the AMP connection.
### ServerSessionHandler (ingoing)
On the Server side, the AMP unpickles the data and associates the session id with the server-side [Session](./Sessions). Data and Session are passed to the server-side `SessionHandler.data_in`. This in turn calls `ServerSession.data_in()`
On the Server side, the AMP unpickles the data and associates the session id with the server-side
[Session](./Sessions). Data and Session are passed to the server-side `SessionHandler.data_in`. This
in turn calls `ServerSession.data_in()`
### ServerSession (ingoing)
The method `ServerSession.data_in` is meant to offer a single place to override if they want to examine *all* data passing into the server from the client. It is meant to call the `ssessionhandler.call_inputfuncs` with the (potentially processed) data (so this is technically a sort of detour back to the sessionhandler).
The method `ServerSession.data_in` is meant to offer a single place to override if they want to
examine *all* data passing into the server from the client. It is meant to call the
`ssessionhandler.call_inputfuncs` with the (potentially processed) data (so this is technically a
sort of detour back to the sessionhandler).
In `call_inputfuncs`, the inputcommand's name is compared against the names of all the *inputfuncs* registered with the server. The inputfuncs are named the same as the inputcommand they are supposed to handle, so the (default) inputfunc for handling our "look" command is called "text". These are just normal functions and one can plugin new ones by simply putting them in a module where Evennia looks for such functions.
In `call_inputfuncs`, the inputcommand's name is compared against the names of all the *inputfuncs*
registered with the server. The inputfuncs are named the same as the inputcommand they are supposed
to handle, so the (default) inputfunc for handling our "look" command is called "text". These are
just normal functions and one can plugin new ones by simply putting them in a module where Evennia
looks for such functions.
If a matching inputfunc is found, it will be called with the Session and the inputcommand's arguments:
If a matching inputfunc is found, it will be called with the Session and the inputcommand's
arguments:
```python
text(session, *("look",), **{})
```
If no matching inputfunc is found, an inputfunc named "default" will be tried and if that is also not found, an error will be raised.
If no matching inputfunc is found, an inputfunc named "default" will be tried and if that is also
not found, an error will be raised.
### Inputfunc
The [Inputfunc](./Inputfuncs) must be on the form `func(session, *args, **kwargs)`. An exception is the `default` inputfunc which has form `default(session, cmdname, *args, **kwargs)`, where `cmdname` is the un-matched inputcommand string.
The [Inputfunc](./Inputfuncs) must be on the form `func(session, *args, **kwargs)`. An exception is
the `default` inputfunc which has form `default(session, cmdname, *args, **kwargs)`, where `cmdname`
is the un-matched inputcommand string.
This is where the message's path diverges, since just what happens next depends on the type of inputfunc was triggered. In the example of sending "look", the inputfunc is named "text". It will pass the argument to the `cmdhandler` which will eventually lead to the `look` command being executed.
This is where the message's path diverges, since just what happens next depends on the type of
inputfunc was triggered. In the example of sending "look", the inputfunc is named "text". It will
pass the argument to the `cmdhandler` which will eventually lead to the `look` command being
executed.
## The outgoing message path
@ -109,7 +137,11 @@ The call sign of the `msg` method looks like this:
msg(text=None, from_obj=None, session=None, options=None, **kwargs)
```
For our purposes, what is important to know is that with the exception of `from_obj`, `session` and `options`, all keywords given to the `msg` method is the name of an *outputcommand* and its arguments. So `text` is actually such a command, taking a string as its argument. The reason `text` sits as the first keyword argument is that it's so commonly used (`caller.msg("Text")` for example). Here are some examples
For our purposes, what is important to know is that with the exception of `from_obj`, `session` and
`options`, all keywords given to the `msg` method is the name of an *outputcommand* and its
arguments. So `text` is actually such a command, taking a string as its argument. The reason `text`
sits as the first keyword argument is that it's so commonly used (`caller.msg("Text")` for example).
Here are some examples
```python
msg("Hello!") # using the 'text' outputfunc
@ -117,39 +149,144 @@ For our purposes, what is important to know is that with the exception of `from_
msg(mycommand=((1,2,3,4), {"foo": "bar"})
```
Note the form of the `mycommand` outputfunction. This explicitly defines the arguments and keyword arguments for the function. In the case of the `text` and `prompt` calls we just specify a string - this works too: The system will convert this into a single argument for us later in the message path.
Note the form of the `mycommand` outputfunction. This explicitly defines the arguments and keyword
arguments for the function. In the case of the `text` and `prompt` calls we just specify a string -
this works too: The system will convert this into a single argument for us later in the message
path.
> Note: The `msg` method sits on your Object- and Account typeclasses. It means you can easily override `msg` and make custom- or per-object modifications to the flow of data as it passes through.
> Note: The `msg` method sits on your Object- and Account typeclasses. It means you can easily
override `msg` and make custom- or per-object modifications to the flow of data as it passes
through.
### ServerSession (outgoing)
Nothing is processed on the Session, it just serves as a gathering points for all different `msg`. It immediately passes the data on to ...
Nothing is processed on the Session, it just serves as a gathering points for all different `msg`.
It immediately passes the data on to ...
### ServerSessionHandler (outgoing)
In the *ServerSessionhandler*, the keywords from the `msg` method are collated into one or more *outputcommands* on a standardized form (identical to inputcommands):
In the *ServerSessionhandler*, the keywords from the `msg` method are collated into one or more
*outputcommands* on a standardized form (identical to inputcommands):
```
(commandname, (args), {kwargs})
```
This will intelligently convert different input to the same form. So `msg("Hello")` will end up as an outputcommand `("text", ("Hello",), {})`.
This will intelligently convert different input to the same form. So `msg("Hello")` will end up as
an outputcommand `("text", ("Hello",), {})`.
This is also the point where [Inlinefuncs](./TextTags#inline-functions) are parsed, depending on the session to receive the data. Said data is pickled together with the Session id then sent over the AMP bridge.
This is also the point where [Inlinefuncs](./TextTags#inline-functions) are parsed, depending on the
session to receive the data. Said data is pickled together with the Session id then sent over the
AMP bridge.
### PortalSessionHandler (outgoing)
After the AMP connection has unpickled the data and paired the session id to the matching PortalSession, the handler next determines if this Session has a suitable method for handling the outputcommand.
After the AMP connection has unpickled the data and paired the session id to the matching
PortalSession, the handler next determines if this Session has a suitable method for handling the
outputcommand.
The situation is analogous to how inputfuncs work, except that protocols are fixed things that don't need a plugin infrastructure like the inputfuncs are handled. So instead of an "outputfunc", the handler looks for methods on the PortalSession with names of the form `send_<commandname>`.
The situation is analogous to how inputfuncs work, except that protocols are fixed things that don't
need a plugin infrastructure like the inputfuncs are handled. So instead of an "outputfunc", the
handler looks for methods on the PortalSession with names of the form `send_<commandname>`.
For example, the common sending of text expects a PortalSession method `send_text`. This will be called as `send_text(*("Hello",), **{})`. If the "prompt" outputfunction was used, send_prompt is called. In all other cases the `send_default(cmdname, *args, **kwargs)` will be called - this is the case for all client-custom outputcommands, like when wanting to tell the client to update a graphic or play a sound.
For example, the common sending of text expects a PortalSession method `send_text`. This will be
called as `send_text(*("Hello",), **{})`. If the "prompt" outputfunction was used, send_prompt is
called. In all other cases the `send_default(cmdname, *args, **kwargs)` will be called - this is the
case for all client-custom outputcommands, like when wanting to tell the client to update a graphic
or play a sound.
### PortalSession (outgoing)
At this point it is up to the session to convert the command into a form understood by this particular protocol. For telnet, `send_text` will just send the argument as a string (since that is what telnet clients expect when "text" is coming). If `send_default` was called (basically everything that is not traditional text or a prompt), it will pack the data as an GMCP or MSDP command packet if the telnet client supports either (otherwise it won't send at all). If sending to the webclient, the data will get packed into a JSON structure at all times.
At this point it is up to the session to convert the command into a form understood by this
particular protocol. For telnet, `send_text` will just send the argument as a string (since that is
what telnet clients expect when "text" is coming). If `send_default` was called (basically
everything that is not traditional text or a prompt), it will pack the data as an GMCP or MSDP
command packet if the telnet client supports either (otherwise it won't send at all). If sending to
the webclient, the data will get packed into a JSON structure at all times.
### Client (outgoing)
Once arrived at the client, the outputcommand is handled in the way supported by the client (or it may be quietly ignored if not). "text" commands will be displayed in the main window while others may trigger changes in the GUI or play a sound etc.
Once arrived at the client, the outputcommand is handled in the way supported by the client (or it
may be quietly ignored if not). "text" commands will be displayed in the main window while others
may trigger changes in the GUI or play a sound etc.
### Full example of Outgoing Message
For a full outgoing message, you need to have the outgoing function defined in the javascript. See
https://evennia.readthedocs.io/en/latest/Web-Client-Webclient.html for getting set up with custom
webclient code. Once you have a custom plugin defined and loaded, create a new function in the
plugin, onCustomFunc() for example:
```javascript
var onCustomFunc = function(args, kwargs) {
var = args.var
console.log(var)
}
```
You'll also need to add the function to what the main plugin function returns:
```javascript
return {
init: init,
onCustomFunc,
}
```
This defines the function and looks for "var" as a variable that is passed to it. Once you have this
in place in your custom plugin, you also need to update the static/webclient/js/webclient_gui.js
file to recognize the new function when it's called. First you should add a new function inside the
plugin_handler function to recognize the new function:
```javascript
var onCustomFunc = function (cmdname, args, kwargs) {
for( let n=0; n < ordered_plugins.length; n++ ) {
let plugin = ordered_plugins[n];
if( 'onCustomFunc' in plugin ) {
if( plugin.onCustomFunc(args, kwargs) ) {
// True -- means this plugin claims this command exclusively.
return;
}
}
}
}
```
This looks through all the plugins for a function that corresponds to the custom function being
called. Next, add the custom function to the return statement of the plugin handler:
```javascript
return {
add: add,
onKeydown: onKeydown,
onBeforeUnload: onBeforeUnload,
onLoggedIn: onLoggedIn,
onText: onText,
onGotOptions: onGotOptions,
onPrompt: onPrompt,
onDefault: onDefault,
onSilence: onSilence,
onConnectionClose: onConnectionClose,
onSend: onSend,
init: init,
postInit: postInit,
onCustomFunc: onCustomFunc,
}
```
Lastly, you will also need to need to add an entry to the Evennia emitter to tie the python function
call to this new javascript function (this is in the $(document).ready function):
```javascript
Evennia.emitter.on("customFunc", plugin_handler.onCustomFunc);
```
Now you can make a call from your python code to the new custom function to pass information from
the server to the client:
```python
character.msg(customFunc=({"var": "blarg"}))
```
When this code in your python is run, you should be able to see the "blarg" string printed in the
web client console. You should now be able to update the function call and definition to pass any
information needed between server and client.