The ToastStunt database file is a flat ASCII text file with relevant bits of information separated by newlines. This document will go over the structure of that file and explain how various values are derived. It’s unlikely you’ll be able to make more than minor changes to a database by hand, but this information should prove valuable if you need to parse or attempt to recover a database or data from a database.
The information below is written in the exact order you’ll encounter things in an actual database file. When a specific type of MOO value is expected, that item will link to a section explaining how to interpret that specific type in the database.
Those curious about the server source code should find these functions of particular interest:
write_db_file
in db_file.cc
: The entry point into database writing.It’s worth keeping a couple of things in mind when reading, parsing, or thinking about the database format:
typeof()
) immediately before their value.
CLEAR
or NONE
(5
or 6
), there will be no value after the type.Every database file begins with a recognizable, human-readable header. This is typically something like: ** LambdaMOO Database, Format Version 17 **
. This indicates that it’s a LambdaMOO database (of course) and the version of the format in use. The version is important because it tells the server which features are available at the time the database is written, which affects how it gets read back. (For example, databases prior to format version 15 didn’t include the last_move
property for every object. Without a proper version, the server would assume this database has that property and attempt to read it, which would fail.) (See version.h
if you’re curious to see what each database revision changed.)
X values pending finalization
: This header indicates the total number of anonymous objects that have been recycled but have not had their recycle()
verb called yet.
12
for ANON
)4
for #4
)0 clocks
: Now meaningless. This was a part of early MOO task handling that is now obsolete. Any database with clock information will be using the LambdaMOO database format version 4 or lower, in which case you should reference Anatomy of a LambdaMOO db fileX queued tasks
: This header indicates the total number of queued (forked) tasks.
X suspended tasks
: This header indicates the total number of suspended tasks.
X interrupted tasks
: This header indicates the total number of interactive tasks that were interrupted (e.g. read()
or read_http()
X active connections with listeners
: This header indicates the total number of active connections at the time of shutdown. The next X lines consist of:
max_object()
plus one for #0)#5 recycled
). Done with this object.#
) and the object’s number. (e.g. #5
)
chparents()
and a single parent) and is formatted as a list.properties(object)
. This includes all properties defined on the object and properties defined on every ancestor. (When multiple inheritance is involved, it follows the order of parents()
for each object.) For each property:
0
verbs(object)
minus 1 (verb numbers start at 0). (e.g. #0:0
).
) on a single line.For each forked task, the following will be written:
0
task_id()
for the forked taskX variables
: This header indicates the total number of variables in the verb that forked the task. For each variable:
NUM
, player
, caller
, etc.0
for INT
)For each suspended task, the following will be written:
-1
if the task was suspended indefinitely.)task_id()
of the suspended taskresume()
that hasn’t had a chance to execute yet. If there is no return value, the type will be 0
(INT
).resume()
. Most of the time this will be 0
task_local()
variable.max_stack_depth
language version 17
)X variables
: This is a header for the variables section. It indicates the total number of variables for this frame.
NUM
, player
, caller
, etc.)0
for INT
)X rt_stack slots in use
: A header indicating the number of activation stacks in use.
6
for NONE
)eval
)register_function_with_read_write
in the server source, find your MOO built-in function, find its C write function (6th argument to register_function_with_read_write), and read the source code there.-111
this
fork()
)1
for threading enabled or a 0
for threading disabled."toast":explode()
), this will be the object number of the handler for the primitive value (e.g. $str_proto
). Otherwise it’s the value of this
.-7
-8
-9
-10
No
More
Parse
Infos
verb
variable. (e.g. shr
if you typed that to invoke the shr*iek
verb)shr*iek
)The object flag integer is obtained by adding one or more of the values from this table together:
# | Value | Flag |
---|---|---|
0 | 1 | Player |
1 | 2 | Programmer |
2 | 4 | Wizard |
3 | 8 | |
4 | 16 | Read |
5 | 32 | Write |
6 | 64 | |
7 | 128 | Fertile |
8 | 256 | Anonymous |
9 | 512 | Invalid |
10 | 1024 | Recycled |
For example: If you want an object to be a player, a programmer, and a wizard, you would add together the ‘Value’ column for each to get: 1 + 2 + 4
for a total value of 7
.
If you’re trying to decipher a flag, it’s slightly more complicated. Without going too deeply into bits, you can accomplish this with a MOO eval. Instead of looking at the ‘Value’ column, look at the ‘#’ column. Our eval will be: FLAG &. (1 << #) != 0
Say we have an object with a flag of 7
. To see if that object is a wizard (# 2 in the table), we plug it into our eval: 7 &. (1 << 2) != 0
If it returns 1, the object has the flag. In our case, yep, it’s a wizard! Just remember, use the number from the ‘#’ column, not ‘Value’.
Verb permissions are obtained by adding one or more of the values from this table together:
# | Value | Flag |
---|---|---|
0 | 1 | Readable (+r) |
1 | 2 | Writable (+w) |
2 | 4 | Executable (+x) |
3 | 8 | Debug (+d) |
Strangely enough, dobj
and iobj
are also part of a verb’s permission flags:
# | Value | Flag |
---|---|---|
4 | 16 | dobj = any |
5 | 32 | dobj = this |
6 | 64 | iobj = any |
7 | 128 | iobj = this |
For example: If you want a verb to be readable (+r) and debug (+d) with arguments {"any", "out of/from inside/from", "this"}
, you would add together the ‘Value’ column for each to get: 1 + 8 + 16 + 128
for a total value of 153
.
If you’re trying to decipher a flag, it’s slightly more complicated. Without going too deeply into bits, you can accomplish this with a MOO eval. Instead of looking at the ‘Value’ column, look at the ‘#’ column. Our eval will be: FLAG &. (1 << #) != 0
So if you have permission flags with a value of 9
, you can check if it’s writable by plugging it into our eval: 9 &. (1 << 1) != 0
If it returns 1, the permission bit is set. In this case, nope, not writable!
The preposition flag is simply a number corresponding to a value. The standard prepositions are listed here. Should your server be weird and add more, you can find them in db_verbs.cc
Value | Preposition |
---|---|
-2 | any |
-1 | none |
0 | with/using |
1 | at/to |
2 | in front of |
3 | in/inside/into |
4 | on top of/on/onto/upon |
5 | out of/from inside/from |
6 | over |
7 | through |
8 | under/underneath/beneath |
9 | behind |
10 | beside |
11 | for/about |
12 | is |
13 | as |
14 | off/off of |
# | Value | Flag |
---|---|---|
0 | 1 | Readable (+r) |
1 | 2 | Writable (+w) |
2 | 4 | Chown (+c) |
For example: If you want a property to be readable (+r) and writable (+w), you would add together the ‘Value’ column for each to get: 1 + 2
for a total value of 3
.
If you’re trying to decipher a flag, it’s slightly more complicated. Without going too deeply into bits, you can accomplish this with a MOO eval. Instead of looking at the ‘Value’ column, look at the ‘#’ column. Our eval will be: FLAG &. (1 << #) != 0
Say we have a property with a flag of 7
. To see if that property is writable, we plug it into our eval: 7 &. (1 << 1) != 0
If it returns 1, the property has the flag. In our case, yep, it’s writable! Just remember, use the number from the ‘#’ column, not ‘Value’.
5
6
2
"Hello world!"
2
Hello world!
1
#2
1
2
3
Integer | Error |
---|---|
0 | E_NONE |
1 | E_TYPE |
2 | E_DIV |
3 | E_PERM |
4 | E_PROPNF |
5 | E_VERBNF |
6 | E_VARNF |
7 | E_INVIND |
8 | E_RECMOVE |
9 | E_MAXREC |
10 | E_RANGE |
11 | E_ARGS |
12 | E_NACC |
13 | E_INVARG |
14 | E_QUOTA |
15 | E_FLOAT |
16 | E_FILE |
17 | E_EXEC |
18 | E_INTRPT |
E_ARGS
3
11
0
123
0
123
14
1
if true, 0
if false.7
8
9
123.45
9
123.45
10
For each key in the map…
["source" -> #123, "time" -> 1670634392]
10
2
2
source
1
123
2
time
0
1670634392
4
{#2, "Hey, that's wizard!", 2, 2.22, {"A list in a list, oh NO!"}}
4
5
1
2
2
Hey, that's wizard!
0
2
9
2.22
4
1
2
A list in a list, oh NO!
12
max_object() + 1
).When looking for property values on anonymous objects, you have to look for the object created in this step. It will appear in the standard object list as any other object.
*anonymous*
12
5
13
If the waif is a reference to an existing waif:
r
and ending with the numeric reference to the waif in the waif index..
)If the waif is new:
c
and ending with a numeric reference to a waif in the waif index.:
) on the waif’s class and all ancestors of that class.-1
.
)We have two waif classes:
#4: Waifilicious
with one property: :flavor
#5: Waiftastic
with one property: :activity
Waif #5 is a child of waif #4. Our waif is an instance of #5 with the .flavor
property set to "toast"
:
[[class = #5, owner = #2]]
13
c 0
5
2
2
1
2
toast
-1
.
Last Updated: 2022-12-15 for Database Version 17
Corrections? Comments? Wild bursts of irrational hatred? Contact me: lisdude@lisdude.com