Xdata file format
Xdata (short for eXternal data) files provide a way for scripts to easily load settings that are stored externally. When readables were being coded, people requested that it be possible to load readable settings from an external file instead of being forced to store all readable information in the entity spawn-arguments. Since readables would need to load an arbitrary list of settings from a file, I figured I might as well make them use a general-purpose format. Xdata declarations were created as a result.
An xdata declaration is pretty much just a dictionary of strings, with a few extra features: precaching of referenced assets may be optionally done, and it's possible to inherit any number of other xdata decls. Xdata declarations are relatively similar to entity definitions (though their syntax is different), but I decided to keep them separate so as not to confuse or fill up the Doom 3 editor's entity list.
--Gildoran 09:32, 2 December 2006 (CST)
Creating Xdata Files
Xdata files are stored in xdata/ and end in .xd. Each xdata file may contain any number of xdata declarations. The basic format of an xdata declaration is as follows:
<asset name> { [data goes here] }
The <asset name> follows the normal rules for a Doom 3 asset name: It must be a unique identifier which may take the form of a relative path (it may contain slashes, but not as the first or last characters), but spaces are not allowed. For example, the following is a valid xdata declaration:
hello/world/blah { }
Inside the braces, whitespace (including newlines) is ignored, except in string literals. The xdata declaration is evaluated from top to bottom; later statements may override statements that occured earlier.
Key/value pairs
The primary feature of xdata declarations are their key/value pairs. The simplest way to define a key/value pair is:
<key string> :
The strings must be standard C-style strings (enclosed with with double-quotes and escaped with backslashes). Newlines (\n) are allowed. For example:
"name" : "BillyBob"
Like C preprocessor definitions, it is possible to break up a string into multiple lines by using a backslash. This is mostly useful for multi-line paragraphs.
"quote" : "To be or not to be,\n" \ "that is the question.\n" \ "\n -Hamlet\n"
For convenience and ease of reading, another syntax has been added to assist with multi-line paragraphs: (this example is semantically identical to the one above)
"quote" : { "To be or not to be," "that is the question." "" " -Hamlet" }
When values are stored using this format, there is an implicit newline at the end of each string.
Inheritance
It's possible to inherit key/value pairs from other xdata declarations. This is acheived with the import keyword. The simplest syntax is:
import <asset name string>
The <asset name string> should be a C-style string. All key/value pairs in the referenced xdata declaration will be copied to the current xdata declaration. In this example, the people/bill xdata declaration will end up with a name of "Bill" and an occupation of "guard":
people/bill { import "people/bob" "name" : "Bill" } people/bob { "name" : "Bob" "occupation" : "guard" }
You may only want to load specific keys from another xdata declaration. This is done with the following format:
import { <key string 1> <key string 2> ... <key string N> } from <asset name string>
For example, this will only import the key "jabberwocky" from the "entire_encyclopedia" xdata declaration:
import { "jabberwocky" } from "entire_encyclopedia"
You can also rename an imported key with this syntax:
import { <old key string> -> <new key string> } from <asset name string>
For example:
import { "description" -> "desc" } from "somedecl"
These last two methods of importing things can be combined:
import { "name" "occupation" -> "job" "birthplace" -> "origin" "hobby" } from "people/bill"
Precaching
If you use a sound or some other asset in a script, you need to tell Doom 3 to preload the sound by refering to it in an entity's spawn-arguments (such as "snd_turn_on" - note that the prefix snd_ is important), or the game will temporarily hang when the sound is first used. The same applies to xdata declarations; any xdata declarations used by a script need to be referenced in an entity's spawn-arguments or the game may temporarily hang when the xdata declaration is first used. The spawn-argument prefix for xdata declarations is xdata_.
Sometimes you'll want to use an xdata declaration to define what assets (such as models or sounds) something should use. However, assets referenced in an xdata declaration aren't preloaded by default. If the precache keyword occurs anywhere in an xdata declaration, then upon being loaded its contents will be preloaded as though they were an entity definition. It doesn't matter where the precache keyword is placed; the precaching occurs AFTER the entire xdata declaration has been constructed.
letter { precache // necessary because Bob's signature is an image "note" : "Dear Bill, HELLO!" "signature" : "guis/assets/bobs_signature.tga" }
Loading Xdata Files
A script may copy the contents of an xdata declaration into the spawn-arguments of an entity via the loadExternalData() script event. Its synopsis is as follows:
ent.loadExternalData( string declaration, string prefix );
ent is the entity to copy the key/value pairs to.
declaration is the name of the xdata declaration to copy the key/value pairs from.
prefix is prepended to the key names as they're being copied to ent. It's used to sandbox an xdata declaration and prevent its keys from overriding ent's keys.
This is effectively what occurs:
foreach key in declaration ent[ prefix + key ] = declaration[ key ];
For example,
$bill.loadExternalData( "people/bill", "personal_info_" );
will result in "personal_info_name" being set to "Bill" and "personal_info_occupation" being set to "guard".
Control Codes
Found precious little on this so far so needs expanding but I found the foreground colour command ineffective. Here are some colour codes that can be put in the text but unfortunately they are all bright so far and terminate at the end of the line as formatted in the game when it defaults back to the gui default thereafter...
- ^0 default
- ^1 bright red
- ^2 bright green
- ^3 bright yellow
- ^4 bright blue
- ^5 bright cyan
- ^6 bright magenta (pink)
- ^7 bright white
- ^8 light grey
- ^9 black
Example: "This is default black ^1This is bright red."