[MUD-Dev] TECH DGN: a few mud server design questions (long)
Robert Zubek
rob at cs.northwestern.edu
Mon Jul 23 09:57:00 CEST 2001
hi all,
i've been toying with the idea of building my own lisp-based mud
server for doing AI experimentation - nothing fancy or
industrial-strength, but i figured it would be nice to have the AI
agents be native to the server, rather than runing through some
clunky text or foreign-function-call interface. :) however, as i
started working out the design of such a beast, a number of design
questions immediately popped up, and i wasn't quite sure how to
address them this early in the design process.
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.
so i thought to myself - what better place to ask about this? :)
perhaps the kind mud-dev folk may help illuminate some of these
issues. in particular, these are:
1. how to handle events
assuming that each event in the world gets parsed down to a
standard representation, such as: { action: HIT, agent: PLAYER123,
patient: NPC456, modifiers: ... } (not necessarily as a data
structure, but in that the relevant information gets extracted on
what the action is, who performs the action, and what/who the
action is performed on.)
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?
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.)
having event handlers hooked to the agent will solve the problem
of patient-less actions, but complicates the object model - now
when i add a new target object with a novel action (such as a
beverage), i also have to go and change all the classes that can
use it. in addition to imposing unnecessary code dependencies,
this also encourages me to cut up the object hierarchy according
to the differences of which objects can perform what actions - and
i'm not convinced that's a good way of organizing an ontology.
finally, selecting the event handler based on just the action is
probably the simplest, but i would imagine has the worst effect on
extensibility - since now we have to change all actions when we
add new types of possible agents or patients. perhaps some sort of
mix is in order - global actions for certain general types of
events (such as combat), and then action handlers local to the
agent (or the patient) for the more specialized actions.
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?
2. how to handle long-lasting events
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).
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.
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). or, if threads were cheap on that system, one
might consider actually spawning a new thread for each call to the
handler, and let those that take a while just run quietly in the
background until they finish.
temporally extended events is just one thing that's likely to
cause event processing problems - i'd be curious to hear what are
some other problems? what are the practical implementations of
event handling? how well do they work?
3. propagating messages
i'm also curious what are some standard ways of propagating
messages in a mud engine. for example, when the player performs an
action, the engine processes the event, returning some result
value. at that point the involved parties (agent, patient) will
need to be informed of the result of the action and then, if
applicable, others in the area may be informed of what happened as
well.
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?
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), but it could grind the server to a halt if
all of the contents of everyone's pockets would be getting all the
messages about what's going on in the room. for the second one
(agent doing the propagation) and the third one (handler manually
propagating the result to relevant parties), it's a matter of
maintaining abstraction boundaries - the agent and the event
handler really shouldn't be worrying about making sure everybody
saw what happened, it should be handled by some separate
component.
but how does this actually end up getting implemented in practice?
i suppose i'll start with these three topics - and let's see if
these spark any discussion. i'm looking forward to what you might
think of the above. :)
rob
--
Robert Zubek
rob at cs.northwestern.edu
_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://www.kanga.nu/lists/listinfo/mud-dev
More information about the mud-dev-archive
mailing list