Skip to content
Candoran2 edited this page Jul 19, 2021 · 25 revisions

NifTools XML format

This project is used to describe the Nif, Kf, and Kfm file formats used by Niftools projects. These XML files are central to our efforts to understand the file formats and create tools that support as many games as possible. The XML files also contain our human-readable documentation of the format, serves as the source for our HTML version of the file format specification.

Several Niftools projects use these format description internally to read and write files.

NifLib is a C++ library for reading and writing nif files. Python scripts read the XML file and generate some of the source code used by Niflib to read and write Nif files.

Pyffi is a pure python implementation that allows dynamic reading of the formats to expose a read/write library. Additional tools enable modification, sanitising, regex replacement and more on the files.

NifSkope uses these files directly using an internal file library to read the files. Almost any new discoveries about the format can be enabled in NifSkope by editing the nif.xml file included in its install directory.

The Basics

If you've never heard of XML before, you may want to check out a few of these informational links borrowed from Wikipedia:

If you've ever worked with HTML, XML will look very familiar to you. Basically, instead of working with tags like # <B>, <IMG>, and <TABLE>, you will be working with special tags designed to describe the Nif file format such as <basic>, <compound>, and <niobject>.

Every XML file starts with a basic heading. Following is the heading for the NifTools XML format. It doesn't really do anything important other than tell you that this document is in the NifTools XML format, and it has to be there:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE niftoolsxml>
    <niftoolsxml version="0.7.0.0">
        'XML File contents go here'
    </niftoolsxml>

Also, like in HTML, plain text can appear between the start and end version of a tag. Similarly, plain text enclosed in NifTools XML tags contains the human readable documentation about what this Nif structure does. This is completely plain text... no HTML tags are allowed. Here's an example:

    <field name="Name" type="string">
        Name of this object. This is also the name of the action associated with this file.
        For instance, if the original Nif file is called `demon.nif` and this
        animation file contains an attack sequence, then the file would be called
        `demon_attack1.kf` and this field would contain the string `attack1`.
    </field>

There are also certain characters which are not allowed in XML plain text. These must be replaced with special codes. Some examples:

Character Replace with this
" &quot;
< &lt;
> &gt;
& &amp;

Some attributes may accept lists of things (for example integers or strings). In this case, they are space-separated. So an example of an attribute with a list of strings would look like this:

<sometag attr="string1 string2 string3" />

Organization

The Nif XML file is divided into sections based around the five main tags. These are; <version>, <basic>, <enum>, <bitflags>, <bitfield>, <compound>, and <niobject>. At the top of each section is an XML comment. Just like in HTML, a comment is text that is ignored by the program reading the XML file.

For example: <!--This text is for informational use and will be ignored by parsers-->

Tags

This section will introduce each tag and explain how to use it. Tags which appear inside other tags will be grouped under the tag which they are most likely to appear inside of

<niftoolsxml>

The <niftoolsxml> tag is the root tag, and everything else in the file goes inside it. There is exactly one of these tags in a NifTools XML document. This is similar to the way the <HTML> tag works for HTML documents.

Attributes:

Name Format Description
version #.#.#.# Used to specify the version of the NifTools XML format being used.

Tags Which can appear inside this one:

<version>, <module>, <token>, <basic>, <enum>, <bitflags>, <bitfield>, <compound>, and <niobject>

Example:

    <niftoolsxml version="0.7.0.0"></niftoolsxml>

<version>

The <version> tag is a hint to NifSkope about which versions of the Nif format we currently support. Basically, if you try to open a file of a version that doesn't have a tag, NifSkope will tell you that that version is not supported. Adding a version tag makes that error message go away so you can start figuring out any other changes you might have to make so that all the files from that new version number can be opened. For informational purposes, each version tag contains description text which lists the games that are known to use that version. When that <version> is the default for a game, that game will be surrounded by double curly brackets {{}}. For expansive explanation/discussion, see #69.

Attributes:

Name Format Description
id V#_#_#_#, but can be any text Unique identifier for this combination of version, user version and bsver. Generally speaking, this is V, followed by the num attribute (but with the dots replaced by underscores). If user version and bsver are specified for this tag, they may follow after a double underscore, or a game abbreviation if that is more appropriate.
num #.#.#.# The Nif version to be flagged as supported by NifSkope.
supported true/false False if the XML does not fully support reading of this version.
user list of integers User version for this version id.
bsver list of integers Bethesda-specific extra user version for this version id.
custom true/false If this attribute is true, it denotes that it is not an official Gamebryo version and has customization of one or more blocks. If user or bsver is specified, this is assumed to be true.
ext list of strings Any custom NIF extensions associated with this version (e.g. .bto and .btr files can both be read as nifs).

Tags Which can appear inside this one:

None.

Example:

    <version num="20.0.0.4">Civilization IV, Oblivion</version>

<basic>

The <basic> tag specifies a new simple data type, one that holds just one piece of data. For example, a number, a string, etc. The main reason to add a new basic data type would be to allow NifSkope or Niflib to treat it differently. At this point most basic data types that you need should already have been created and it's probably best to ask if it's necessary to create a new one. You should know what the basic data types are, however, because you will refer to them often in other tags. For expansive explanation/discussion of the tags, see #76.

Attributes:

Name Format Description
name text This is the name of this basic data type. It is used to refer to this type in other tags.
boolean true/false Whether it is a data type that can be used as a boolean.
integral true/false This determines whether it is a data type that can be added (bit-wise, i.e. floats do not have integral=true)
countable true/false This determines whether a basic data type can be used as a count (e.g. for array size). Only data types that store unsigned integers can be used as a count. Is implied to be false if integral is false.
size integer How large this data type is in bytes.
convertible list of strings What other basic types this converts to without losing data.

Tags Which can appear inside this one:

None.

Example:

    <basic name="short" integral="true" countable="false" size="2" convertible="int int64">
        A signed 16-bit integer.
    </basic>

<enum>

The <enum> tag specifies a data type which consists of a list of options. Each <enum> tag will contain two or more <option> tags which specify the choices available in this collection. Each option corresponds to an integer value which is given a name and can have a description.

Attributes:

Name Format Description
name text This is the name of this enum data type. It is used to refer to this type in other tags and will be the name of the C++ enum in Niflib.
storage text This specifies the data type used to store the enum value in the Nif file. Generally, this will be uint, ushort, or byte. It must exist as the name of a <basic> tag somewhere else in the file.

Tags Which can appear inside this one:

<option>

Example:

    <enum name="ChoiceType" storage="uint">
        Specifies a type of choice.
        <option value="0" name="CHOICE_YES">An affirmative choice.</option>
        <option value="1" name="CHOICE_NO">A negative choice.</option>
        <option value="2" name="CHOICE_MAYBE">A noncommittal choice.</option>
    </enum>

<option>

The <option> tag describes a choice that is part of an enum data type. Enums store the choice as a number, so each <option> tag contains that number and a name so people can understand what the number means. It can also contain descriptive text explaining what the option is for. The name should be in all capital letters with spaces replaced by underscores(_) because it will be used as a constant name in Niflib.

Attributes:

Name Format Description
value integer This is the number that is stored in the Nif file when this choice is selected. There should be only one <option> tag per number.
name text This is the short name of this choice. It should be in all capital letters with no spaces and should start with an abbreviated form of the enum name. It must be unique; no choice name can be the same as any other choice name anywhere in the XML file.

Tags Which can appear inside this one:

None.

Example:

   <option value="0" name="ANIMAL_DRAGON">Indicates that this object is a dragon.</option>

<bitfield>

The <bitfield> tag denotes a data type spans 1 or more bytes, but which actually contains sub-fields, each of which can have their own data type and size (including sizes which are not whole bytes).

Attributes:

Name Format Description
name text This is the name of this bitfield data type. It is used to refer to this type in other tags.
storage text This specifies the data type used to store the value of the bitfield in the Nif file. Generally, this will be uint, ushort, or byte. It must exist as the name of a <basic> tag somewhere else in the file.

Tags Which can appear inside this one:

<member>

Example:

    <bitfield name="TimeControllerFlags" storage="ushort">
        Flags for NiTimeController
        <member width="1" pos="0" mask="0x0001" name="Anim Type" type="AnimType" />
        <member width="2" pos="1" mask="0x0006" name="Cycle Type" type="CycleType" default="CYCLE_CLAMP" />
        <member width="1" pos="3" mask="0x0008" name="Active" type="bool" default="1" />
        <member width="1" pos="4" mask="0x0010" name="Play Backwards" type="bool" />
        <member width="1" pos="5" mask="0x0020" name="Manager Controlled" type="bool" />
        <member width="1" pos="6" mask="0x0040" name="Compute Scaled Time" type="bool" default="1" />
        <member width="1" pos="7" mask="0x0080" name="Forced Update" type="bool" />
    </bitfield>

<member>

The <member> tag is used to describe a part of a bitfield data type. It specifies exactly which bits of the bitfield belong to a specific sub-field, what that sub-field should be named and what kind of data are stored in there.

Attributes:

Name Format Description
width integer This is the number of bits that this member takes up in the bitfield.
pos integer This is the bit where this sub-field starts in the bitfield, counting from the right, where the right-most bit is bit 0.
mask hexadecimal, preceded by 0x This is a hexadecimal representation of all the bits in the bitfield belonging to this member. It is obtained from the binary representation of the same thing, where a 1 means that the bit in that location belongs to the member. The mask can also be inferred from the width and pos attributes.
name text This is the name of this member.
type text This is the name of the type which this member uses. This type can normally be larger than what would fit in the bits covered by this member. In the example below, the "CycleType" type is used in a member which covers only two bits, even though CycleType is normally stored as a uint (which takes up 32 bits).

Example:

    <member width="2" pos="1" mask="0x0006" name="Cycle Type" type="CycleType" default="CYCLE_CLAMP" />

<bitflags>

The <bitflags> tag can be seen in two different ways.

  1. It is specialization of an <enum> which allows for the type to hold multiple options instead of just one. The syntax is identical except for the tag name, so please refer to the above <enum> documentation. What differs is the semantics of the <option>, specifically the bit attribute. The integral value of each option is not the value but 2^bit.
  2. It is a specialization of the <bitfield>, which uses the <option> tag instead of member. width is implied to be 1 and type is implied to be "bool" for every option, and bit is the equivalent of the pos attribute.

Example:

    <!-- BitFlagsType can hold the value 0, 1, 2, 4 and also 3 (A+B), 5 (A+C), 6 (B+C), 7 (A+B+C)  -->
    <bitflags name="BitflagsType" storage="uint">
        Specifies a type of choice.
        <option bit="0" name="CHOICE_A" /> <!-- 2^0 = 1 -->
        <option bit="1" name="CHOICE_B" /> <!-- 2^1 = 2 -->
        <option bit="2" name="CHOICE_C" /> <!-- 2^2 = 4 -->
    </bitflags>

<compound>

The <compound> tag defines a new data type which contains several instances of other data types. Compounds are analogous to C/C++ structs or classes in that they contain several variables in a certain order. These other data types can be specified in preceding <basic>, <enum>, or other <compound> tags. Basically, a compound data type is like a list of data that will be found in a Nif file in the order given. It is useful to create a compound when a complex part of another data type is repeated many times, such as in an array. The compound tag should contain a plain text description in addition to any <field> tags to document its purpose.

Attributes:

Name Format Description
name text This is the name of this compound data type. It is used to refer to this type in other tags and will be used for the name of the C++ struct for Niflib. The first letter of each word should be capitalized and it should contain no spaces or underscores.
generic true/false Optional. This determines whether this compound can be used as a template for various types. 0 is false, 1 is true. If absent, false is assumed.

Tags Which can appear inside this one:

<field>

Example:

    <compound name="LODRange">
        The distance range where a specific level of detail applies.
        <field name="Near Extent" type="float">Beginning of range.</field>
        <field name="Far Extent" type="float">End of Range.</field>
    </compound>

<field>

The <field> tag is used to add a variable to a <compound> or <niobject> tag. Like a declaration within a class or struct in C++, this new variable has a name and a storage type. A description should also be added between the beginning and end tag to describe the purpose of this attribute. These tags are considered sequentially and should be placed in the same order that these pieces of data appear in a Nif file.

The <field> tag also has a few extra features that make it a bit more complex than other tags. Not only can it be used to specify a single piece of data, but it can be used to define a 1 or 2 dimensional array of the same data as well. The size of these arrays can be fixed, or can come from a preceding variable by name. Most programmers will recognize this concept.

A variable can also have a template type specified. A template is a way, in C++, to have a single generic set of code apply to many different types. The biggest example of this in the Nif format is the Ref type, which points to another object somewhere else in the file. It's important to know what kind of object can be referenced here, so in addition to specifying the type, Ref, we also specify the template, say "NiNode." There are few other examples of templates, and you probably won't have to worry too much about them.

The Nif format also changes with time. Some variables disappear or move to another location, while new ones crop up all the time, often between existing ones. To take care of this, the field tag has attributes to specify the beginning and end version where that variable appears. Also, if you add a variable with the same name and type, but different version spans, it is considered to be the same variable for the purposes of Niflib. Only the order it is written to the file changes.

There are also many times when the existence of one variable is conditional on the value of a preceding one. To allow for this, a syntax using boolean operators can refer back to previous variables by name. If the condition ends up true, the variable is read or written from the file, if not it isn't.

Finally, to make things easier on everyone, it is often a good idea to have default settings. This way, new objects created with Niflib or NifSkope can be used right away without lengthy, repetitive setup routines. The field tag allows for this as well.

Attributes:

Name Format Description
name text This is the name of the variable/attribute to add. It is used to refer to this variable in subsequent tags and will be used for the name of the C++ struct for Niflib. The first letter of each word should be capitalized and separated by spaces.
type text This refers to the name of a <basic>, <compound>, <enum>, or <bitflags> tag. It is the data type that will be used for this variable/attribute and determines the size of the data on the disk as well as the operations that will be available from either NifSkope or Niflib. If this is part of a template compound, the type “TEMPLATE” can be used to make this variable take on the dynamic type specified in the variable that creates a template.
arr1 integer/var name This is the optional first array dimension for this variable/attribute. It can either be an integer or the name of a preceding count type variable.
arr2 integer/var name This is the optional second array dimension for this variable/attribute. arr1 must be specified for arr2 to be given a value. It can either be an integer or the name of a preceding count type variable.
template type name This is the optional template type for this variable/attribute. It can be the name of a <basic>, <enum>, <bitflags>, <compound>, or <niobject> tag.
cond expression If this expression evaluates to true, this data is assumed to be present in the file, otherwise it is not. The expressions follow C/C++ format and can include names of preceding variables.
ver1 #.#.#.# Optional. The first Nif file version where this variable appears. If absent, it is assumed that this variable appears in the earliest Nif files.
ver2 #.#.#.# Optional. The last Nif file version where this variable appears. If absent, it is assumed that this variable appears in the most recent Nif files.
ver #.#.#.# Optional. An exact match to the Header version. This is identical to writing vercond="Version == X.X.X.X" or ver1="X.X.X.X" ver2="X.X.X.X" with the same version in both.
binary true/false Optional. Whether this type (typically an array of bytes) should be treated as a binary data blob. Implies each array member should not be treated individually (e.g. editor UI).

Tags Which can appear inside this one:

None.

Example:

    <field name="Triangles" type="Triangle" arr1="Num Triangles" cond="Num Strips == 0">
        The triangles.
    </field>

<niobject>

The <niobject> tag defines a new Nif objects. These are the core building blocks of a Nif file. Like compounds, they can contain <field> tags which insert new variables, but unlike compounds, they can inherit from each other. When one Nif object inherits from another, it gains all its variables, and any new variables added appear below these. For example, NiObjectNET has the Name variable, and NiAVObject inherits from NiObjectNET. While the <niobject> tag for NiAVObject makes no mention of the Name variable, all NiAVObject objects start with the Name variable that they inherited from NiObjectNET. Sometimes a <niobject> will have no <field> tags in it at all; all its variables coming from its ancestors.

The name of a <niobject> tag should be taken directly from a Nif file whenever possible. These are non-abstract types... in other words you're allowed to use these types in a Nif file. Abstract types, on the other hand, are only used as ancestors, and can not actually appear in Nif files. Whenever possible, the names of these should be determined from the SSG command in Morrowind or Oblivion. If we must invent a name ourselves for an abstract type, we previx it with a capital A.

Determining the proper inheritence structure of Nif objects can be one of the fastest ways to figure out what they are. An object that consists of severl hundred bytes of information could be as simple as adding one new value on the end of an existing object. It also means that, in Niflib, the new object will inherit all the special functions that make it possible to work with that object. So figuring out the way Nif objects inherit from each other is very important.

Attributes:

Name Format Description
name text This is the name of this compound data type. It is used to refer to this type in other tags and will be used for the name of the C++ struct for Niflib. The first letter of each word should be capitalized and it should contain no spaces or underscores.
abstract true/false This determines whether this Nif object is abstract.
inherit Nif object name The name of the Nif object that this one inherits from. All Nif objects inherit from another except NiObject, which is the basis for all other Nif objects.
ver1 #.#.#.# Optional. The earliest Nif file version that this Nif object is known to appear in. If absent, it is assumed that this Nif object can appear in the earliest Nif files.
ver2 #.#.#.# Optional. The last Nif file version that this Nif object is known to appear in. If absent, it is assumed that this Nif object can appear in the most recent Nif files.

Tags Which can appear inside this one:

<field>

Example:

    <niobject name="NiObject" abstract="1">
        Abstract object type.
    </niobject>
Clone this wiki locally