[MUD-Dev] DevMUD - thoughts.1
cg at ami-cg.GraySage.Edmonton.AB.CA
Sat Oct 24 22:58:41 New Zealand Daylight Time 1998
Well, instead of working on my own MUD, I've decided to put down some
thoughts about DevMUD. I find that I think best about something when I
can understand how its going to work, in terms of possible code. So,
some of the stuff here will be at a lower level than you might expect
for this stage of design. Don't worry about it, that's just me thinking
Some random thoughts:
- it has been suggested that it would be nice if modules could be either
native code (C, C++, whatever) or MUD-language code, and that the
two ways of writing them would be interchangeable. That could be a
problem. There would almost certainly have to be some glue code
to convert between the two. The previously suggested method, was,
I believe, to have the linkage convention defined to be the one
that the MUD-language uses, and require that native code convert
as needed. That works for me.
Note, however, that both C and C++ are essentially strongly typed
languages. If a function is written to accept a character pointer
argument, then you had better not pass it an arbitrary integer!
I take this as an argument that the MUD-language be strongly typed,
or at least be able to export strongly typed function declarations.
There are ways around this, but are there any non-ugly ones?
Alternatively, we could drop the requirement that modules be allowed
to be native or MUD-language, interchangeably? That would at least
allow native modules to communicate by direct function calls, which
is the most efficient.
I'm flexible on this - to me it makes sense that all server stuff be
written in the native language, and only scenario (world definition)
stuff needs to be in the MUD-language. Thus, the expense of using
the MUD-language interface would only be needed for scenario-level
stuff, and that would only need to be native code if it was *very*
expensive, and that expense would hide the cost of using the
- there was some talk about matching up the interfaces of the modules
based on function type and parameters. I think instead we need to
define a set (which can grow as needed) of interface kinds, which
give a purpose to a given exported definition or reference. Those
kinds implicitly include the required function prototype. This
will hopefully be clearer in some examples.
- threads. My current server isn't threaded, but that doesn't stop me
from believing that DevMUD should be threaded. I believe I saw a
suggestion that each module should have a thread. That doesn't
work too well if the inter-module interface is a function call. That
only works if all data going into a module is copied into a record
and queued, ready to be processed by the thread of that module.
That is imposing unneeded inefficiency. Some modules (e.g. a
socket module) will need internal queues (when sockets fill up),
but it would be better to not impose that on all modules from the
Having said that, I don't have any good suggestions for a general
method of deciding how threads should be used. One possibility is
that each input is run in a thread (the thread can be re-used when
it is done with that input). Then, it would be input-generating
modules that did thread control. Other modules might choose to
use threads internally - that would be their business. A prime
example would be an event handler (which in some senses is just
OK, now to get into a bit more detail for my thought experiment.
- some module interface kinds that I think a MUD-type game needs:
input - a source of input (typically from a user). This will come
with an identification of where the input came from, so that output
that needs to go back to the same place can be properly routed.
In my system I've found it useful to have more than one kind of
input, (e.g. text, keypad presses, mouse-clicks, etc.), so I suggest
that the prototype for an input handler be something like:
void inputHandler(void *source, uint kind, void *data, ulong len)
Alternatively, we could make the kind of input be part of the
interface kind, so that, potentially, different modules could
handle different kinds of input. E.g.
textInput - void textInputHandler(void *source, char *data, ulong len)
output - a place to send output so that it goes back to the place that
generated the input that triggered the output. (I don't say user
here, since this could be a way to do robots.)
Note that output exports a function, whereas input requires a
function to call.
inputFilter - this kind exports the same kind of function that input
requires, but also requires another function of that same kind.
The low-level system, when told to load a module that wanted to
do input filtering, would have to (atomically!) break any
connections between inputs and input consumers, and insert the
filter calls into that "pipe".
passwordChecker - (this could be part of a parser, or could be done
separately. A trivial one would accept anything, and would always
bool passwordChecker(char *characterName, char *password)
An input generator would require such a routine so that it could
validate new clients coming in.
passwordEncryptor - this could be a filter for a passwordChecker. It
just encrypts the password and passes the pair on. The goofy US
rules on export of encryption technology make this a good thing
to have as a module, so that there can be different ways of doing
More complexity: what if we wanted to have multiple input sources? E.g.
a telnet module and a binary connection module for graphical clients?
Then, any modules that accept input would have to have an identifier
of the module as well as an identifier of the specific connection within
that module. Perhaps just the two combined into a structure.
This is a tricky issue. There is a whole range of ways that parsing can
be done. For example, in LPC, a lot of parsing is done by the individual
objects in the world. How does that fit into the module scheme? I'll
let others suggest how other schemes might fit in - I don't know enough
about them to say anything reasonable.
I *do* know what my system is, however, so I can talk about how it would
fit into this scheme. In my scheme, there are things call "grammars"
that describe how to handle text input. (Is a parser required for
non-text input?) Each grammar contains a table of words and their
synonyms. Words which are verbs describe what the structure of a
command starting with that word looks like (so, this doesn't extend
to other languages than English very well). This description is just
a selection of one of:
- no other words in the command
- a possible extra specific word, then a noun phrase
- a noun phrase, a specific word, a second noun phrase
- uninterpreted - pass the word list on
It's a bit more complicated than that, but I hope you get the idea. A
very simple structure, but it handles most input reasonably well. The
key is, that associated with each verb word is a reference to a
MUD-language function to call to process the commands that match that
verb specification. (The same word can be the verb word for more than
one specification - the specific extra words are used to choose among
So, initially, the parser module exports an input handler routine, and
a routine by which other modules can tell it about verb forms and what
to do with them. As modules are loaded which handle various verbs, they
call that second routine in the parser, which then builds up internal
structures about the new verb forms. When a module is about to be
unloaded, it would have to tell the parser to remove its entries for
the verbs forms that are going away.
How do we handle ambiguity? Is a system of separate modules like this
going to limit the sophistication of the parsing, simply because of
the structure imposed by having these inter-module interphases? Can
there be multiple parser modules loaded? If so, perhaps each client
or robot connection that provides an input has a parser selection
associated with it, and it is that parser's input handler that is
used. That requires that the input generators explicitly know about the
existence of parsers. Perhaps that sort of thing could be done in an
input filter, which just maintained a mapping between input streams
and parsers, and the main parser input handler is never directly called
from an input generator, but only indirectly via that filter module.
How would that affect other filter modules - they would have to be
inserted *before* the parser-chooser filter, else they would never
see any data!
Where in all of this have we switched from native code to MUD-language
code? In my system, its done when going from the filtered input into
the parser, but, with loadable parsers, it could also be done at
the point of the callouts from the parser to other (scenario) modules.
Does it make any sense for there to be more than one database module
loaded? How would anything choose which one to use for something?
Because all of this is so different from what I've currently got, I
have trouble convincing myself that it won't be too restrictive. I
Chris Gray cg at ami-cg.GraySage.Edmonton.AB.CA
More information about the MUD-Dev