[MUD-Dev] TECH DGN: a few mud server design questions (long)

Caliban Tiresias Darklock caliban at darklock.com
Tue Jul 24 01:08:34 New Zealand Standard Time 2001

On Mon, 23 Jul 2001 09:57:00 -0500 (CDT), Robert Zubek
<rob at cs.northwestern.edu> wrote:

> these issues seemed fundamental to the design of any multiplayer
> engine, and i hoped there may be some canonical ways of dealing
> with them - some analysis of the tradeoffs they introduce, and
> perhaps standard solutions. but i've been unlucky trying to find
> any online documentation about mud server design.

You and me both, buddy. I spend a lot of time crawling through the
source to other MUD engines and asking myself deep moral and ethical
questions about whether it makes my server a derivative work. Then I
ask myself deep moral and ethical questions about whether I
personally would ever in a million years have let code this terrible
go out on a public FTP site.

I also spend a lot of time wishing other programmers knew how to
write comments. ;)

I can give you a basic description of how *I* handle various
things. I don't know if it's canonical, because to be honest I
haven't found much intelligible source that relates to these
questions so I've had to develop each of them from scratch.

(We REALLY need a design pattern web site for this sort of thing;
gamedev.net is trying to build one, but so far they just have
pattern definitions and no patterns. Maybe this would be an
interesting sort of community project; we certainly have enough
people on the list who could ramble about their ideas, and we'd only
need a couple who could collect it into something concrete and pass
it on to a web developer.)

>  assuming that each event in the world gets parsed down to a
>  standard representation

[nod] I'm doing something similar, but not *quite* the same.

>  now, how should these events get handled? presumably there's a
>  big switch statement somewhere (or better yet, a data-driven
>  dispatch table) directing the messages to subroutines that handle
>  them - but what would be a good first-cut division of how these
>  messages should be handled? ie., should the agent who performs
>  the action have the code that actually performs the action? 
>  should the recipient (ie. patient) handle the action it receives? 
>  or maybe all actions should be handled by global handlers? 
>  perhaps a mixture of all three?

I handle it as a mixture. When a player enters a command, several
events end up being generated, the first of which is a "command"
event. This command event instructs the server to parse and validate
the command, potentially halting the process for syntax errors or
incomplete directions.

Once a complete command is formulated and accepted, a "direction"
event is passed to the subject, the character which has been
directed to act.  The character inspects the situation, and
potentially halts the process as impossible or inadvisable.

If the direction event is acceptable, an "action" event is generated
by the subject, which the server further validates and then passes
on to the appropriate target if it is accepted. (My system has an
inherent notion of context which simplifies this. In most cases, the
target of an action is selected by the server, not the player --
because there exists only one valid target.)

The target performs yet *more* validation on the event, modifies
itself if necessary, and then generates two events: a "notify"
event, which directs the server to send a report to the target's
client, and a "reaction" event.

The reaction event is validated by the server and passed to the
original subject, which inspects the event and potentially modifies
its own data further before generating its own "notify" event to the
server so it will message the subject's client.

In short, the server is responsible for determining whether a
command is valid; the acting character is responsible for
determining whether it can be completed; the server is responsible
for determining whether it actually *is* completed; and the target
is responsible for determining whether it succeeds. The target is
then responsible for modifying its own state, while the acting
character is responsible for modifying its own state. All of this is
done on the server, NOT the client, so integrity is (hopefully)
guaranteed by the design.

>  for the first example, we may wish to hang event handlers off of
>  the patient of the action - so that when i hit another player,
>  their handler will subtract the appropriate amount of hit
>  points. this makes it very easy to add new objects that support
>  novel kinds of actions (eg. adding a beverage to drink), but
>  breaks in case of actions that have no patients (such as emotes:
>  wave, say, etc.)

The multiple event system works well with this, because if there is
no target and the character is irrelevant, the entire process can be
short-circuited by simply handling the command event as soon as no
further objects are necessary.

>  which of these gets used most often in actual muds? my suspicion
>  is that it would be the last one (mix of global and local
>  actions) - but wouldn't it also complicate extending the world?

In my experience, the vast majority of MUDs use a command routing
structure in which the world tries to handle the command, and if it
can't, it passes it along to other objects to see if they can handle

>  somewhat related to the above is the technical side of how to
>  handle events. what i *think* is the standard approach is that
>  there's one global event queue from which events get popped off
>  and dispatched to the appropriate handler (global or local).

Reasonably standard, yeah. Like a Windows message queue.

>  in this architecture, how does one elegantly handle temporally
>  extended events - for example, a spell that takes several minutes
>  to cast? the handler obviously can't block while waiting for the
>  event to finish.

Don't have them. That was my solution. Of course, I doubt that will
work for you... ;)

>  one could imagine a number of solutions inspired by operating
>  systems research - perhaps implementing a fake
>  continuation-passing style (as a kind of non-preemptive
>  multitasking: a temporally-extended action would be expected to
>  initialize itself, do a fraction of the necessary processing,
>  then put a new fake event on the queue saying "continue the spell
>  event", and exit).

This is the normal response. If I were implementing something like
this, I'd place these events into a time-sorted queue which popped
events off when they became due and passed them along. In the
meantime, I'd set a state on the appropriate objects that caused
other events to either fail or force the failure of the pending

>  but once the handler figures out the return value for the event,
>  what are some standard ways of propagating this value? does the
>  handler send the result to the closest binding container (such as
>  current room) that propagates it among its elements? does it
>  return it to the agent and the patient, who propagate it
>  themselves? or would the handler actually manually figure out the
>  list of proper recipients for this message, and hand it to them
>  individually?

I do a bit of both, but I'm having some difficulty culling out
redundant messages. If you have a trace beacon on both characters
and are in the same sector, for example, you get:

  Joe is attacked by Bob.
  Bob attacks Joe.
  Bob attacks Joe.

This rather odd response order is a consequence of the target
knowing what happened before the world, which in turn knows before
the acting character. Ideally, I should strip out the trace beacon
output when you're in the same sector, but I haven't really figured
out how best to do this yet. I also think my player notifications
are pretty badly written, so I may rework this.

>  each has a drawback: for the first (container passing the message
>  to its elements), there are cases when these messages should be
>  propagated further down to elements-of-elements (eg. people in a
>  cage in a room should be able to see what the people in the room
>  around them are doing),

Agreed. My system doesn't have that sort of thing, though; it has
single-containment only, and containment precludes
notification. Rather simplifies the tasks. I made a lot of design
decisions that restrict player activities to a domain that's easier
to handle. Sometimes "don't do that then" really *is* the best
medicine. ;)

MUD-Dev mailing list
MUD-Dev at kanga.nu

More information about the MUD-Dev mailing list