Moo Database Browser

* DB File Format

Moo databases are written to disk using a text-only format. Despite being text, it is a challenging format to read and edit due to the lack of internal signposts. This page attempts to document the format so that compatible or interfacing applications may be written.

Alternatives

Before diving into parsing the database file, it is worth taking a step back and asking if this is what one really wants to do. Most Moos run continuously and their database files are written to disk every hour or so. The file on the disk is just a snapshot of the Moo's database at the point it was written. Which means it is out of date. It also means that any changes to this file won't affect the Moo, and will just be overwritten next time the Moo saves itself. The only time when the disk file is considered authoritative is when the Moo is shutdown. Therefore if one is dealing with an executing Moo, one probably wants to open a network connection to it and query the database that way.

Another reason one probably does not want to use this specification is that there already exist a collection of tools which read the database:

  1. The first tool is the Moo server itself. The server can be started in regular mode (network ports open, everything running normally) or in emergency mode (single user, only your tasks).
  2. The second tool is the Moo Command Line Browser which can quickly extract information from a database file. This browser is compatible with a friendly web interface which makes browsing the database as easy as pointing and clicking.
  3. The third tool is the Moo to XML converter. XML is a lot easier to parse than the database format. If one wants to parse the database, why not convert it to XML first then use an off-the shelf XML parser?

Ok, you still want to play with the raw Moo Database file? The above three tools are good starting points. They are written in C++, C and Python respectively. The specification below describes the format in detail.


Intro Block

The first line of the database file specifies the version. Modern Moo databases start with:
** LambdaMOO Database, Format Version 4 **
This format has remained stable for over ten years.

The version string is followed by four integers, each on their own line:

  1. Total number of objects, e.g. 95 (this may not equate to max_object() due to hard-recycled objects)
  2. Number of verbs, e.g. 1698
  3. Dummy number, e.g. 0 (presumably used in a previous database format)
  4. Number of players, e.g. 4 (same as length(players()))

Player Block

Next are the numbers of every object which has a player flag. The content and the order is the same as the players() function. These are raw integers, one per line, with no '#' symbols. This list must be the same length as the number of players listed in the intro block. e.g.
2
71
36
38

This block is required but redundant as the player flag is also specified on each object's definition (below).

Object Block

Next is all the data to define the objects and their properties. There are two classes of objects, recycled and created. A recycled object is simple, just one line containing the object number and the word 'recycled', e.g. #123 recycled  A created object is more complicated, each such object starts with the following data, one per line:

  1. The object's number, e.g. #5 (this is the only place where a '#' is used)
  2. The object's name, e.g. generic thing
  3. Dummy line, normally blank (a "handles string" used in a previous database format)
  4. Integer representing the flags, e.g. 152 (see explanation below)
  5. The object's owner, e.g. 2
  6. The object's location, e.g. -1
  7. The first object in the object's content list, e.g. -1
  8. The next object in this object's location's content list, e.g. -1 (see explanation below)
  9. The object's parent, e.g. 1
  10. The first object in the object's child list, e.g. 8
  11. The next object in this object's parent's child list, e.g. 6 (see explanation below)

The flag integer is made by adding the following:

Thus in the above example, 152 = 128 + 16 + 8

The contents lists and child lists are encoded in a linked-list format. The parent links directly to the first child, then that child links to its next sibling, and so on until one hits -1. Likewise a container links to the first object in the contents list, then that object links to its next neighbour, and so on until one hits -1.

Verb Definitions

Each object has a list of all verbs defined on it. The definitions start with the number of verbs, e.g. 6 This is followed by that number of verb definitions. Each definition has four lines, which defines everything about the verb except the verb code itself:

  1. Verb name, e.g. g*et t*ake
  2. Verb owner, e.g. 2
  3. Verb perms, e.g. 45 (see explanation below)
  4. Verb preposition, e.g. -1 (see explanation below)

The perms integer is made up by adding the following:

Thus in the above example, 45 = 32 + 8 + 4 + 1

The preposition integer is one of the following:

This is the standard list of prepositions, any changes would be made in db_verbs.c

Property Names

Each object also has a list of the names of all properties defined on it. This section starts with the number of new properties, and is followed by exactly that number of property names. e.g.
4
drop_failed_msg
drop_succeeded_msg
take_failed_msg
take_succeeded_msg

Property Definitions

This section contains the perms and values of every defined or inherited property for this object. As usual, the block starts with the total number of properties to be defined, e.g. 12. The properties are then listed, starting with the ones on this object (as named in the previous section), then the properties from the parent, grandparent, etc. Each of these properties contains the following three elements:

  1. Property type and value, e.g. 2 and You can't seem to drop %t here. (see explanation below)
  2. Property owner, e.g. 2
  3. Property perms, e.g. 5 (see explanation below)

The perms integer is made up by adding the following:

Thus in the above example, 5 = 4 + 1

The type and value section is a bit more complicated. The type integer is one of the following:

# Type Example (File) Example (Moo)
0 integer 0
123
123
1 object 1
5
#5
2 string 2
Hello!
"Hello!"
3 error 3
10
E_RANGE
4 list 4
2
9
3.14
2
Pi
{3.14, "Pi"}
5 clear 5 N/A
9 float 9
2.5
2.5

The type integers are the same ones returned by the Moo's typeof() function. The odd one out is 5, clear. If the property is clear, then 5 is all that is printed, there is no value. In order to retrieve the value one would have to dig back through the object's ancestors until one found a non-clear property.

The other odd one is 4, list. A list starts with the number of elements within the list, followed by the the types and values of each element (which may themselves be lists).

The error value is indexed into the Moo's list of errors (starting with index zero). The standard list of errors is {E_NONE, E_TYPE, E_DIV, E_PERM, E_PROPNF, E_VERBNF, E_VARNF, E_INVIND, E_RECMOVE, E_MAXREC, E_RANGE, E_ARGS, E_NACC, E_INVARG, E_QUOTA, E_FLOAT}

Some Moos may have non-standard data types (such as WAIFs) which would have their own type integer and value formats.

Verb Block

This block is very simple, it is a list of every verb in the database. The total number of verbs was already defined in the intro block. Each verb starts with the object number, a colon and the number of the verb (zero based). The verb is listed without indentation. It is terminated with a line containing only a dot ('.'). e.g.
#5:0
this:moveto(player);
if (this.location == player)
player:tell(this:take_succeeded_msg() || "Taken.");
if (msg = this:otake_succeeded_msg())
player.location:announce(player.name, " ", msg);
endif
else
player:tell(this:take_failed_msg() || "You can't pick that up.");
if (msg = this:otake_failed_msg())
player.location:announce(player.name, " ", msg);
endif
endif
.

Status Blocks

At the very end of the database file are four optional blocks containing clocks, queued tasks, suspended tasks, and active connections. Databases saved while executing may have entries here, but in most core databases these would be empty. e.g.
0 clocks
0 queued tasks
0 suspended tasks
0 active connections with listeners

I have no interest in these status blocks, so I haven't decoded their formats. If you would like to submit documentation for this section, feel free to mail me.

-------------------------------------
Last modified: 8 June 2005