fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
[NOTE: Almost ALL of the information in this file is out of date and
 is no longer correct.  All the suggested modifications have already
 been made, or their features are implemented in different ways.
 This document is provided only as an interesting historical note on
 the developement of TinyMUCK.]

TinyMUCK 2.0 Technical Notes

Lachesis, June 1990

E-Mail: lachesis@belch.berkeley.edu

INTRODUCTION

The goal of this work was to give TinyMUCK a programming language.  I
had been playing around with MUCKs and MUDs for all of two weeks,
when, upon creating a movie theatre, I found the supporting world in
adaequte.

This note is intended for those who wish to add to the TinyMUCK code
some more.  (Especially the compiler and interpreter.)  It discusses
the design of the programming language, its implementation, and also
the possible extensions that would be welcome.

DESIGN

During the design stage, primary consideration was given to ease of
implementation, reliability, extensibility, and speed.  Secondary
considerations included ease of use and consistency with the rest of
the TinyMUCK paradigm.  In particular, I did not want the programming
language to seem like a kludge.  (By definition it *is* a kludge, but
I did want it to possess some elegance.)

First of all, I needed ways to add to an object's data fields without
having to change source code.  To facilitate this, I came up with the
concept of property lists --- basically character string pairs which
were settable by the user.  The data structure also included a hidden
integer field which could only be accessible through programs.  This
allows the programmer to make certain things inaccessible to the user
(except for examining)

Then, I had to decide on a programming language.  I observe that most
MUCKs use a sort of C-like language, which I don't really like. (though
I'm a fairly experienced C programmer)  Part of it is that C isn't
really all that great for prototyping, and its syntax isn't exactly
the easiest thing in the world to parse.  I hovered between LISP and
forth for a while, before coming down on the side of forth because
it's easier to write a byte-compiler for forth than it is to write one
for LISP.

Note that I had no experience with forth whatsoever, aside from a bit
of experience in thinking about stack machines, but I picked up the
language easily enough.  The syntax took all of 5 minutes to learn and
an hour to sink in.

I decided that I wanted an editor, (partly because lots of people on my
MUCK don't even have tinytalk) and went about implementing a
line-based editor.  The problem comes in, of course in reading input
--- how am I supposed to know that something is meant for the editor
(or a forth program) and something is meant for the command parser?
My solution was to add a flag called INTERACTIVE.  When this flag is
set on a player, I will pass the command to the editor or the forth
program depending on the state of the player.

I then added a few more fields to the player structure, and added a
new program type called TYPE_PROGRAM.  Each player also had a frame in
which to contain the forth program's execution image.

It turned out that for each player to have a frame permanently
allocated to him would take up too much space, so I made frame
allocation dynamic after loading up "Atlantis," my TestMUCK, and
finding that it took up 5 Megabytes of RAM.

IMPLEMENTATION

I implmented the editor and the compiler independently --- as far as
they are concerned, the only thing they have in common is the data
strucuture containing a program's text.

Together, the implementation took about 2 man days, or 1 weekend.
Testing and debugging then took another day.

The editor is a simple line editor, with each line held in a doubly
linked list.  Commands are available to list the lines, delete lines,
insert lines, compile the program, and disassemble.

The compiler was also simple --- it had no look ahead, (other than
recursive calls to itself) and was single pass --- all references were
resolved by a back-tracking mechanism, which basically left blanks in
the byte-code and filled them in as the answers became clear.  It was
at this stage that the ELSE clause of the IF was abandoned --- it is
still possible to implement it --- I simply did not feel the need, nor
did I want to take the time.

One of the more interesting aspects of the language, though, is that
recursion is supported.  As far as I know, most other MUD languages do
not implement recursion.  Given my stack based structure, however, I
knew that it would be impossible to hit an infinite loop without
overflowing the stack in a very short time, and therefore allowed
that.  In the future, tail-recursion elimination could be implemented,
though doing that means that a program would have to keep track of how
many cycles it has taken up and abort or suspend its operation after a
certain number of executed instructions.

The READ capability of MUF is, I believe, quite unique.  It means that
things such as the purity test can be implemented with little
difficulty.  (And even less inflexibly than you might think,
especially if the property list of a room was used to store the
questions instead of hard-coding them into the program.)

PUTTING IT IN

This part was harder than I thought, for there were many places where
things had to happen.  For instance, because the programming language
could do so many things, (including give players pennies or take away
pennies from players) I added a MUCKER bit to the flags so that only
MUCKERS or WIZARDS could program.  I also had to add to the database
routines the capability of reading in programs.  Here too, TinyMUCK is
unique in that it stores not the byte code, but the source code.  Each
MUF program is stored in a separate file, and while it takes extra
time to load the file, I considered the time spent quite worth while
--- in the event that a large forth package needs to be written or
added to a program, a player could mail the program to the wizard who
could just stick it in.

Furthermore, the primary Wizard can read the source code on-site and
modify it if she finds that it violates her guidelines or whatever it
is that she wishes to enforce.

Upon start up, each program encountered is loaded into memory and an
attempt to compile it is made.  Compile errors are sent to the
standard error at this point, since no players are on line.
Everything then proceeds as normal.

Programs are created using the @prog directive, which puts you
automatically into the line-editor.  Within this line editor, you may
compile, edit and disassemble code.  (Disassembly was really a
debugging patch put in so I could see the compiler output without
executing it.)

Actions or Exits can then be linked (but NOT meta-linked) to programs
by the usual means --- you must own a program or it must be LINK_OK
before you can link to it.  A successful use of the action/exit then
launches and executes the program.

Note that while you can see your own programs, you cannot see
another's programs, making programs effectively dark.

Programs can also be part of locks, in which case the program is
launched when a test is made.  Note that should a program attempt to
READ or causes an error during execution, the test is automatically
false.  (Or rather, the program part of the test is automatically
false.)

FUTURE ADDITIONS

I'm taking a break from hacking MUCK code after this, so this is a
list of what enterprising hackers might want to do with my code.
Please try to contact me before doing things so that I can help
coordinate all new MUCK features and modifications.

1.	Extend the compiler.

A hash table should be used for the primitives.  As the primitive list
gets longer and longer, the current method will no longer be
sufficient to guarantee speed.

2.	Add primitives to the interpreter.

This is the easiest to do transparently, as the only changes (if they
are non-drastic) would occur in get_primitive() in compile.c (which
has the list of primitives), and dispatch() in interp.c, which defines
each primitive.

A method for using exits would be nice, and would allow things
happening in UberMUD (like a remote-controlled tank), which aren't
allowed right now.  Part of the problem has to do with how to trigger
exits --- they shouldn't be links to programs, for instance, as it
might result in a recursive infinite loop or worse...

Before adding primitives, please contact me --- I will issue you a
range of numbers to use (if you know how many you intend to implement,
please state so --- but give yourself some room.) so that different
hackers don't wind up on each other's turfs.  Yes, I do know that with
#defines it is easier to rearrange things, but I'd prefer to have it
easy.

It would be nice to have a CALL that does not inherit variables.  (But
it MUST NOT have it's own stack, or launch another frame.)

Local primitives should always be 32000 or above.  (But below 32767,
the maxint for shorts)

3.	Extend the programming language's capabilities.

Adding primitives is one way, but if you look at the code, you will
notice a TYPE_DAEMON, which is a type of program that runs on time
rather than on user command.  If you can think of a good way to
implement it, do so and let me know when you're done.  It should not
be too hard, but does need some careful thinking.

4.	Write a meta-compiler to MUF

Write a front end to Forth to translate from, say, C to MUF.  I do not
ever intend to implement C in the server, as this takes up too much
time, but this translation to forth should be relatively
straight-forward, and takes lots of load off the server, which is
nice.

5.	Add a GLOBALIZE ACTION command

This will allow wizards to add actions that are accessible to everyone
implicitly.  This will allow new commands to be added to TinyMUCK by
writing MUF code and then globalizing an action linked to that code --
extending the compiler/interpreter further would make it at least
competitive with any UberMUD.  (By allowing programmed actions to
shadow built-in actions.)

ACKNOWLEDGEMENTS

Thanks and Kudos to Stephen White, James Aspnes, and other
TinyMUD/TinyMUCK contributors for making this possible.  Thanks to all
the programmable MUDS out there for giving me the incentive to come up
with something like this to keep MUDs/MUCKs alive if nothing else.
And finally, thanks to everyone on Atlantis, who kept my morale and
interest high even on the worst of days. (even during the crashes ---
you've been an exceedingly patient audience, and I hope that all the
feedback I receive from now on would be as constructive as that.)