[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