Phantasmal MUD Lib for DGD

Phantasmal Site > DGD > The Kernel Library > Extending the Kernel

Modifying the DGD Kernel Library

An alternative to this document would be just getting going fast with Shevek's simple MUDLib BBLib v1.0b building on the Kernel MUDLib.

Paths in this document will often be given relative to the dgd directory. So the Kernel MUDLib will be in the directory "/mud", the top-level docs in "/doc", and the "mud.dgd" file is "./mud.dgd". Also, the paths given tend to only be valid in the source distribution. If you're hacking a MUDLib, you did get the source distribution rather than binary, right?


Getting Started with the Kernel MUDLib

You've probably got a head full of ideas about all the cool stuff you're going to have on your MUD. Good for you! Write it all down somewhere safe, because there's a lot of work between now and when you start building things like that. But do keep it in mind -- you'd like your MUD's MUDLib and architecture to fit your eventual goals. Never use anything from this page or anyplace else blindly, always look at it and figure it out first.

First, you'll need to compile DGD and run it with the Kernel MUDLib. If you don't run it unmodified, you don't know whether you broke anything. You'll need to build the DGD driver binary, which will probably be called "driver". You'll need to modify "/mud.dgd", mainly to give it the absolute (not relative) path of your MUDLib. To begin with, you can build right on top of the Kernel MUDLib in your DGD directory, so use a path like "/home/mudMaster/dgd/mud" (that's if you installed DGD in "/home/mudMaster/dgd"). Finally you'll want to run the driver with the path (it can be relative) to mud.dgd as an argument. Be careful of symbolic links in all this, they can sometimes cause problems — make sure your setup works without them first.

Once you've got it running, you'll want to log in as admin by telnetting to the machine running the MUD (127.0.0.1 if it's the local machine) and typing "admin" in response to the login prompt. I recommend you do it all lower case, at least to start out with -- the Kernel MUDLib has some problems along these lines which you'll be fixing for your own MUDLib.

You can change the password with the passwd command, but with the plain vanilla Kernel lib, only Wizard accounts can use their passwords. Now log in with a couple of other accounts and start typing things like "say Hello?" and "emote grins." If you're at all used to MUDs, this'll look a lot like a gossip channel. The admin character can do some pretty spiffy stuff, which you can find out more about here.

Incidentally, yes, the preceding is incomplete and vague. That's because if you're not good enough to build and play with the Kernel MUDLib in the first place and without my help (you have read Dworkin's docs already, right?) then you probably shouldn't be here. At least, not yet. Do that first, then come back here and grin about how easy it's all become.


The Kernel MUDLib and File Layout

The Kernel MUDLib, out of the box, ships with a little directory structure for you to use. It looks like this:

doc/ include/ kernel/ log/ txt/ usr/

I'm putting the little slashes after each name to mean it's a directory. On Unix, if you type "ls -F" you'll see the same thing. It just distinguishes the file type visually, which happens to be convenient for me.

The doc directory is for you to put documentation on the MUDLib you're building. If you ever plan to have another human being work on your MUD it's vitally important that you do that. You may believe you can just hack some quick docs together when you need them, but you're the only one who believes it. Write them. Write lots. And put them in "/doc".

The include directory is for headers. This includes some headers DGD generates automatically for you like type.h and float.h. It includes some headers you'll probably want to edit, like config.h. It includes a whole subdirectory, kernel, which you shouldn't touch under pretty much any circumstances. Which brings me to another point.

This document assumes that, like Skotos, you've got the presence of mind to leave the Kernel MUDLib absolutely intact. That's not saying you have to keep your MUDLib down to just that -- the Kernel MUDLib has lots of hooks to let you entirely customize what it does. But, the underlying library itself stands inviolate, not unlike your Operating System underneath the program you're running. Even if it would be easier for you to just tweak the OS to add a feature instead of adding it to your program, it's just not a good idea. The Kernel MUDLib should be treated the same way.

That brings us to the kernel directory. In this directory, the Kernel MUDLib itself resides. The auto and driver objects you've heard so much about reside under "/kernel/lib/auto.c" and "/kernel/sys/driver.c", respectively. The rest of the Kernel MUDLib can be thought of us just providing support for what those files do, and what you ask for. This is the directory you don't want to change stuff under. Just to drive the point home, the Kernel MUDLib makes it much harder for your MUD to change stuff under here. I'll explain how when I explain security.


Getting your MUDLib Set Up

First, you'll want to read some documentation. Starting to notice a theme here? That's because well-written, secure, tight, careful MUDLibs are in short supply, and I'm willing to browbeat you throughout this document if there's a chance it'll give us all just one more of those. MUDLibs like that are written by, coincidentally, people who read lots of documentation. Now go ahead and grin, you.

That documentation would be "/mud/doc/kernel/overview". It's the best documentation currently available (except, I hope, these pages) on how to build your own MUDLib on top of the Kernel MUDLib. And it ships with - drum roll please - the Kernel MUDLib. Is Dworkin on top of things or what?

Remember hooks from before? You're going to need to make some objects with very specific functions in them for the Kernel MUDLib to call. The overview mentions this, especially in section 9. Let's get started.

Open up a text editor and create the file "/mud/usr/System/initd.c". If you're looking at the right place, the "mud/usr/System" directory should already be there waiting for you, you'll just create a new empty file.

In that brand spanking new file, put the following:

static int create(varargs int clone) {

}

Now run the MUD again. Nothing changes, nothing breaks, right? Now add a line inside the create function above. Make it look like this:

static int create(varargs int clone) {
  write_file("/log.txt", "Successful initd.c test\n");
}

After that, you should find a file in "/mud/log.txt" that says "Successful initd.c test". And you just created it by starting up the MUD. That's how cool you are. This new file of yours is how you're going to set up all the cool stuff that makes your MUDLib different from the Kernel MUDLib. And the way you're going to do that is by returning a network connection object that you wrote and that you control.

The way you're going to do that is to add a Telnet Manager object in your initd.c, which will return your connection, not the default system one. So let's make a telnetd.c that'll do just exactly that. After you've looked over the docs on the Telnet Manager in "/mud/doc/kernel/userd", you'll realize what kinds of functions your telnet manager will have to have. You can start with one in "/usr/System/sys/telnetd.c" that looks like this:

#include <kernel/user.h>
#include <config.h>

static void create(varargs int clone) {
  if(!find_object(DEFAULT_USER)) { compile_object(DEFAULT_USER); }
}

object select(string str)
{
  return clone_object(DEFAULT_USER);
}

int query_timeout(object connection)
{
  return DEFAULT_TIMEOUT;
}

string query_banner(object connection)
{
  return "Welcome to BoboMUD!  What's yer name? ";
}

DEFAULT_USER is the user object that the Kernel MUDLib supplies you with from the get-go. Later you'll be supplying your own user object, but first you'll figure out what the telnetd object is and what it does. On that note, you'll also need to make some changes to your initd.c to make it recognize and use your lovely new telnetd.c, which is otherwise just another lonely, untouched file on your hard drive. To do that, fix up your initd.c to look like this:

#include <kernel/kernel.h>
#include <config.h>

static int create(varargs int clone) {
  object driver;
  object telnet_manager;

  write_file("/log.txt", "Successful initd.c test\n");

  /* For later, when you start setting more managers */
  driver = find_object(DRIVER);

  if(!find_object("/usr/System/sys/telnetd")) {
    compile_object("/usr/System/sys/telnetd");
  }
  telnet_manager = find_object("/usr/System/sys/telnetd");
  "/kernel/sys/userd"->set_telnet_manager(0, telnet_manager);
}

Start the MUD up, telnet to it and - rapture! - it says "Welcome to BoboMUD! What's yer name?" just like it's supposed to.

(If it doesn't, make sure you're running a *very* recent experimental version of Phantasmal. The line with "set_telnet_manager" above used to not require that zero in front, but now it does. That could screw you up)

But all is not well in paradise. Tell it your name is Bob (or Sam, or Frederick, or a name of your choice) and it'll tell you that Access is Denied, and give you a stack dump. You should read it: the dumps read bottom to top, which is to say that the function you actually crashed in is the lowest line, the one that called it is one line above that, its caller is one line higher and so on.

If you actually check out "/kernel/lib/auto.c" (line 400 for my version of the MUDLib) you'll find that access is denied because only Kernel objects can clone other Kernel objects. So you'll need your own non-kernel User object to clone and return. That's okay, you'll need to make your own user object before long anyway since that's how you add new commands and otherwise change behaviors.

Start by copying the DEFAULT_USER -- that's "/kernel/obj/user.c". You'll want to put it in "/usr/System/obj/user.c". You'll need to change a few things to get this to work.

First, go into /include/config.h and add a line like:

# define SYSTEM_USER  "/usr/System/obj/user"

This will allow you to refer to your spiffy new user object. Then, in the user object itself look for places it says DEFAULT_USER and change it to SYSTEM_USER. Don't change DEFAULT_USER_DIR to anything else, though, keep it the same for now. It may be a good idea to change later (see Adding Stuff to your MUDLib), but for now keep it the same.

You'll also need to change your telnetd.c file to say SYSTEM_USER wherever it used to say DEFAULT_USER, so that it clones your user and not the Kernel MUDLib one.

Now log in with a couple of players and start using the say and emote commands. Looks a lot like before you modified anything, doesn't it? Nonetheless, it's now using your user. You win!

You're not out of the woods yet, though. Try logging in as admin. Type anything for the password. It'll give you an Access Denied, which will look like you got the wrong password. You didn't. Instead, that Access Denied is because you're trying to clone the Kernel MUDLib wiztool instead of one of your own, just like the problem with your user object. You'll solve it the same way, pretty much. Start by copying /kernel/obj/wiztool.c to /usr/System/obj/wiztool.c.

You won't need to modify the wiztool object, but you *will* need to add a line like

#define SYSTEM_WIZTOOL "/usr/System/obj/wiztool"

to /include/config.h. Then you'll need to change DEFAULT_WIZTOOL to SYSTEM_WIZTOOL in two places in /usr/System/user.c. You'll also need to find the create() function and either inside or outside the if (doesn't matter) put the line:

if(!find_object(SYSTEM_WIZTOOL)) compile_object(SYSTEM_WIZTOOL);

That's because anything you want to clone you'll need to have compiled first. One reason you might get "Cannot clone XXX" errors is having not compiled the object you're trying to clone.

Having done all that, go ahead and log in. As a little celebration you can type "compile /usr/System/obj/user.c" and watch it come back with something like "$0 = </usr/System/obj/user>". This means it's successfully recompiled that file on the fly. How cool does that make you?

You've now got something almost entirely comparable to Shevek's BBLib. That's a good start, and it's nice to know. So you can move on to adding more stuff to your MUDLib. The "Adding Stuff" documents on my pages will do their best to show you how.