[MUD-Dev] PDMud (was Re: Bruce Sterling on Virtual Community goals)

Niklas Elmqvist d97elm at dtek.chalmers.se
Wed Oct 21 09:58:18 New Zealand Daylight Time 1998


I changed the topic to the suggested "PDMud". So sue me, this thread
sorely needed a name change. :)

On Tue, 20 Oct 1998, Jon Leonard wrote:
> On Tue, Oct 20, 1998 at 11:58:27AM +0200, Niklas Elmqvist wrote:
> > On Mon, 19 Oct 1998, Jon Leonard wrote:
> > > That said, I think some sort of byte-code machine makes a lot of sense
> > > as an option.  Which buzzwords do we want to start with?
> >
> > Umm, do I get to pick? :)
> 
> If no one else has an opinion, yup.  :-)
> 
> > Efficient and garbage collected are two, and
> > threaded should not be too hard to tack on... And a stack-based VM like
> > the JVM sounds pretty good.
> 
> I asked because I don't think it's obvious.  My current interpreter is
> neither threaded nor stack-based.  (It isn't efficient, either, but let's
> ignore that.)

Hehe.

I am not entirely sure about the focus for the virtual machine (and it's
language). As I see it, we basically have two options:

1) Use the VM (and language) to implement game systems as well as a "quest
and world programming language" (ala LPC or ColdC).

2) Use the VM (and language) as a "quest and world programming language".
Period.

One way to look at it is to ask ourselves this question: "Do we want to be
able to implement stuff like network code, DB handlers and event managers
with our VM?" If no, we'd go for option 2) and stick to putting this kind
of low-level/engine-specific code into dynamically loaded (there's that
word again :) modules. If yes, go for 1) and design an all-out .

Personally, I am all in favor of # 2. I believe that an internal language
for a MUD should be tailored for use when programming the behavior of the
MUD world, not the MUD engine. The engine is "nothing" more than a sandbox
for the VM (cf JVM in browsers) which provides engine primitives such as
event managing, data channels, security, etc.

> The issues for these buzzwords as I see them:
> 
> Efficient:  May make the VM harder to understand.

Right. Could maybe be done later. The optimizing step is "just" a filter
through which you pass the bytecodes before emitting them, after all.

> Garbage collected:  Some languages prefer the malloc/free model, and some
> 	run with static allocations.  These don't benefit from a garbage
> 	collector (but would benefit from resource tracking:  At end of
> 	thread, collect any malloced but unfreed space, etc.), and would
> 	pay a performance penalty if it were enabled.  Similarly, type
> 	taging for tracing pointers or some replacement technique is
> 	required.  (And anything better than reference counting can be
> 	fairly hard to follow.)
> 
> Threaded:  If we want the VM itself to be multithreaded, then we need
> 	locking for various parts of the VM.  There's a real performance
> 	cost there.  I'd like at least a compile time option to turn it
> 	off for uniprocessor machines.

Well, with a stack-based approach (can't speak for anything else as I am
quite new to compiler design and have only come in touch with stack-based
VMs) it's fairly easy to suspend execution of a Thread (an object which
contains thread-specific things such as the PC, stack frame, etc) in favor
of another in a single-threaded VM. 

But since I am no expert at compiler/VM design (as you may have noticed),
merely interested, I will leave these weightier decisions to others.

> 	Being able to run multiple threads of the bytecode is a must.
> 	This can be implemented using something like cooperative multitasking,
> 	or even just forcing each bytecode operation to complete before
> 	doing something else (interrupt, other thread, etc.).

Right. Cooperative multitasking is IMHO a little dated, and I (if I did
this myself) would allow each bytecode operation to finish before
switching to another Thread.

> Stack-based:  This does pointless, inefficient things to continuation-passing
> 	languages.  It also doesn't map well into superscalar hardware, but
> 	I don't forsee doing custom hardware for the bytecode.

Well, as I said, stack-based is all I know, and the fact that the Java
people used it says something, does it not? :)

> I'd recommend going for efficient, possibly GC'd, threaded in the bytecode
> model, and stack based.  (Leaving open the possibility of alternate VMs if
> we get tired of the first one.)

I agree. The GC-part is not a must, but would be nice. However, if we do
want it, it should be something we add from the beginning, yes?

[environment for the language module: functions, callbacks, etc.]
> I think some C++ charateristics are incompatable with what we want to do:
> 
> 1) The C++ object model is unique to C++, and using C++ objects from another
> 	language requires writing wrappers that use C bindings.  C++ naming
> 	conventions aren't even consistent between compilers, and prevent
> 	other languages calling objects directly.

Yes, I guess this is a problem, but only if we want to allow other
languages to use our objects. We can solve the naming scheme
incompatibilities between compilers by exporting factory functions from
the code modules which are marked #extern "C". You would have to do this
anyway if you want to use dlsym() on the factory function's real name
instead of the mangled name.

> 	If we're going to have C bindings for things, (necessary for
> 	supporting in-game languages like Perl, Python, TCL, etc.) then
> 	I don't see the point in building separate C++ interfaces.

Hmm. You have a point.

> 2) The C++ object model doesn't lend itself to mix and match components,
> 	in that it can require a recompile to change between logically
> 	equivalent interfaces ("fragile base class problem").  This
> 	prevents dynamic loading of modules, at least in some combinations
> 	that I want to use.

Hmm, I'm not entirely sure what you are refering to, but I think external
inheritance solves this. As long as you keep the base class (which should
be nothing more than an empty shell) the same, you can inherit from this
in the independant code modules and redefine it before reloading the
module and creating the object. No recompilation of the core executable is
necessary in this case, I assure you.

Of course, there is always the aspect of not having to change the base
class. This comes to down to good design and adequate interface, though.

> If there are good workarounds for these kinds of problems (and the consensus
> is that people want to use C++), then I'll ignore my distaste for C++
> (I've been burned more than once by C++isms on large projects) and use it.

Maybe this is a good time to survey how many people on this list are ready
to pitch in on a project like this and contribute? Oh, and the list will
be the perfect forum to tell our war stories as well as bounce some ideas
and design issues before implementing them. 

Btw, I've been with the list for a while and am surprised nothing like
this has happened before(?). It seems like an almost logical step. 

> I have no objections to modules being written in C++ (or some other language),
> but I prefer interfaces using C calling conventions.  (extern "C" in C++)

Well, how would you go about using C++ objects in a C++ module loaded by a
C program? Never mind, I assume you have the answer :)

> A proposed basic module interface:
> 
> With the exception of a bootstrap module, all modules can be loaded with
> dlopen.

Right. But would not the base server require some functionality besides
module handling? Off the top of my head (well, I've designed something
similar before), I come up with the following list:

 - event manager
 - decoupled message chain/channel system or something similar
 - module handler (loading/unloading of code modules)

I was about to add "virtual machine" to the list, but maybe even this
could be loaded as a module?

[snip]

> All modules should have in the exported structure functions for
> initializing, shutting down, getting the module's name, and getting the
> version.

Right, and maybe a short descriptive string or something. 

> If a module serves a standard purpose, it should export functions that
> match the definition for modules that do that.  A module may serve
> serveral purposes, in which case it should export the appropriate functions
> for all of them.
> 
> Modules may interact by other means as well.  This can be because they were
> compiled together, negotiated an additional interface, or whatever.

Okay, this is where my brain twists in on itself. How do modules
communicate with each other? How are they tied together? Me, I'd like the
modules to be completely decoupled, but I'm perverted in that sense :)

[snip (hypothetical) example]

> Modules involved:
> 	Boot
> 	Location manager
> 	Language
> 	Database manager

Right, this mirrors my thoughts pretty closely. I am, however, very
interested in how inter-module communication is carried out in this
example. Using a message/request-passing system, you would get something
like this (still hard-coded Diku mode):

The player enters "north" and the TelnetModule emits a request with this
message along with socket information. The ParserModule captures the
request, parses the text and then sends a new message to the request chain
about the parsed command. This one is picked up by the
CommandExecutorModule (kof) which moves the player to the new room and
requests a description text to be sent to the player. The DatabaseModule
captures this, sends a description message, etc...

Ok, maybe a little low-level/low-tech and maybe not very illustrative.
Comments? Better ways of doing this?

> In-game entities involved:
> 	A player
> 	A room
> 	A script
> 
> Sound feasable?

Yes, very.

> I wouldn't assume that modules can't know what other modules are present.
> The environment should probably provide functions to tell if a given
> module is present, and also to list all present modules.  Something in
> the code needs to know this, after all. 

Hmm... Yes, the module handler knows the names, filenames and pointers to
the dynamically loaded code modules, but do the individual modules know
this? Can you figure out what a module does just by looking at its name?
Maybe there could be several different implementations of the same kind of
module? What if someone creates a replacement for the "standard" 
MagicModule and wants it to work seamlessly by capturing all magic-related
requests and just not handling all of them (or handling *more* of them)? 
Having the modules know nothing about other modules is IMHO the most clean
solution. 

Admittedly, you need *some* kind of coordination between modules. The
ParserModule must know the acceptable commands supported by the
other modules (or does it? Maybe this could be polled by a message from
the ParserModule: "Okay, send me your command grammars along with a way of
packaging this into a request you can capture.").

> I like the "request to be notified when X happens" primitive.  Message
> chains are a possible way to implement this, but not the only way.

Roger. But I like it in the way that it is completely decoupled (there's
that word again ;). 

> I'm not sure about the need for default handlers, and I can think of cases
> where more than one thing needs to get notified when something happens.

Okay, my thought was on having the default handlers take care of requests
which are not captured by any of the modules attached to the message
chain. That is, if no one took care of a "MegaBoom Spell" Command request
(due to some glitch in the ParserModule versus the MagicModule), the
default handler would silently take dispose of the request and emit an
error message in the log or something. 

> I'll happily contribute a website, server space, accounts, etc. on
> frost.slimy.com.  (160 Kbit network connection, 600 MHz Alpha)
> Somewhere else might be better.  (Kanga.nu would be easiest to find,
> for example.)  There's nothing stopping us from having different modules
> living on different servers, with links and mirroring to make it easy to
> find stuff. 

Yes, but the main server/core/driver (maybe a convention would be in order
here) should reside somewhere nice. Slimy sounds just like what we need
(SlimyMUD? :). 

> I prefer having everything on my machine, but it really doesn't matter much.

Fine by me. My own server (486DX-100) is not anywhere powerful enough :)
(Although I do have a T1 to the net -- in Sweden). 

> > GNU Mud anyone?
> 
> Naming it GNU Mud is at least misleading if it's not GPL'd, and as much
> as I like the Gnu Public License, it doesn't fit this project.
> 
> I want code that I or anyone else can modify, experiment with, and even
> build commercial servers out of, without having to worry about what's
> permitted.  GPL may not necessarily prohibit running commercial services,
> but it might wind up forcing release of client source code (including
> signatures to prevent cheating clients?) and be otherwise unpalatable
> to commercial interests.

Ahh, you're right. Well, it sounded neat and official. 

> Public domain may wind up being the right license -- PDMud?

Henceforth, this project is named PDMud -- for the moment, at least. Being
on the other side of the Atlantic and posting when you guys are asleep (?) 
and not able to reply does have *some* advantages. 

> Jon Leonard

-- Niklas Elmqvist (d97elm at dtek.chalmers.se) ----------------------
  "Nanny Ogg looked under her bed in case there was a man there. 
   Well, you never knew your luck."
		-- Terry Pratchett, Lords and Ladies





More information about the MUD-Dev mailing list