[MUD-Dev] Re: Bruce Sterling on Virtual Community goals

Jon Leonard jleonard at divcom.slimy.com
Tue Oct 20 18:00:52 New Zealand Daylight Time 1998


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.)

The issues for these buzzwords as I see them:

Efficient:  May make the VM harder to understand.

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.

	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.).

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.

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.)

[environment for the language module: functions, callbacks, etc.]
> > Left to my own devices, I'd implement these calls as C functions.
> > Each module would have a structure listing the names of the functions
> > it exported and function pointers.  The structure might include stuff
> > about calling conventions, a documentation string, etc.  In my current
> > server, all functions take and return linked lists of arguments/results,
> > but that's not necessarily the best choice.
>
> Or you could implement this in C++, and you'd be doing some things a
> little different. I'm not about to start a religious language war here
> (hopefully), but I think the O-O nature of C++ lends itself perfectly to
> an object-oriented environment such as a MUD. When I did my first server
> effort in C, I found myself writing object-oriented C code most of the
> time :)

(Normally I'd just not comment on language issues, but in this case we do
need to pick an implementation language.  Our esteemed list owner may have
to tell us if we get too far off topic.)

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.

	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.

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.

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.

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++)

> This project (which actually strikes a chord for me), sounds in some
> aspects very similar to my own pet project. Why not use a dynamic loading
> scheme in conjunction with C++? Conceptually, we would view the modules as
> objects which support a few basic operations.  The individual modules
> would then be inherited versions of class Module with redefined
> functionality. New modules could be cleanly and easily be dynamically
> loaded from a shared lib, allocated by a factory function in the lib, and
> then added to the executable without ever having to restart it, much less
> recompile it. Using this scheme (it's called "external inheritance"), we
> would get true drop-in modules which can be whipped together and added to
> the running MUD without having to touch the server code at all.

I definitely like dynamic loading, and I think some sort of object model
is important.  I'd just do it without language support.

A proposed basic module interface:

With the exception of a bootstrap module, all modules can be loaded with
dlopen.

Modules export an array of structures, each containing the name of the
function exported, a pointer to the function, and possibly documentation,
argument information, etc., depending on the calling convention.  Modules
compiled to support more than one calling convention should export multiple
arrays, named appropriately.

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

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.

A (hypothetical) example:

A MUD is running as a hardcoded (Diku-style) mud, with a database of objects
that hasn't been completely loaded into memory.

A player wanders into a room that is still on disk, causing the database
module to retrieve the room from disk to memory.

The player gets moved into the room.  The location manager module notices
that the room has a script that should be run when a player enters it.

The location manager detects that the language for the script isn't loaded,
so it has the boot module load it.  It then passes the script to the
newly loaded language module, which executes it.

The language module may wind up calling other modules, doing whatever it
needs to to execute the script.

Modules involved:
	Boot
	Location manager
	Language
	Database manager

In-game entities involved:
	A player
	A room
	A script

Sound feasable?

> Since the individual modules have no way of knowing which other modules
> are present in the system, we would also need a decoupled way of passing
> information between them. One way of doing this would be to have some kind
> of message chain which the modules could connect to and listen on.  Any
> messages which are sent on this path can be intercepted and handled by
> modules on the path (the modules could be ordered by priority, allowing us
> to put default handlers at the very end (=lowest priority) of the chain).

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. 

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.

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.

> Of course, there is always the matter of having an adequate interface for
> the Module base class, and this is something which needs to be discussed
> in depth.

Indeed.

> > We might need to have (compile time option?) more than one calling
> > convention, and certain modules might use backdoor entry points
> > into other modules for efficiency.
> >
> > > I'm game.  :)
> >
> > Cool.
>
> I'm definitely ready to contribute! Why not build a website, draw some
> specifications, do some heavy designing (I'm deeply in favor of OO
> analysis & design with UML as the modelling language), create a CVS tree,
> etc?

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. 

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

> 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.

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

> (In that case, why don't we rename this thread "GNU Mud"? :)

The thread certainly needs renaming, but that's not it.

Jon Leonard




More information about the MUD-Dev mailing list