Skip to content
jonwd7 edited this page Feb 1, 2016 · 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 File contents go here'

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:

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`.

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;

Organization

The Nif XML file is divided into sections based around the five main tags. These are; , , , , and . 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 NifSkope-->

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

The 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 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>, <basic>, <enum>, <compound>, and <niobject>

'''Example:'''

The 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.

Attributes:

Name Format Description
num #.#.#.# The Nif version to be flagged as supported by NifSkope.

'''Tags Which can appear inside this one:'''

None.

Example:

Civilization IV, Oblivion

<basic>

The 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.

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.
count integer This determines whether a basic data type can be used as a count. Only data types that store integers can be used as a count. 1 is true, 0 is false.
niflibtype text This is the name of the type in Niflib that this basic data type will be mapped to. Usually it is the same as the name. It doesn't have to exist as a basic tag.
nifskopetype text This is the name of the type in NifSkope that this basic data type will be mapped to. Usually it is the same as the name. It must be the name of an existing basic tag.

'''Tags Which can appear inside this one:'''

None.

Example:

A signed 16-bit integer.

<enum>

The tag specifies a data type which consists of a list of options. Each tag will contain two or more 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 tag somewhere else in the file.

Tags Which can appear inside this one:

Example:

Specifies a type of choice. An affirmative choice. A negative choice. A noncommittal choice.

<option>

The tag describes a choice that is part of an enum data type. Enums store the choice as a number, so each 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 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:'''

Indicates that this object is a dragon.

<compound>

The 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 , , or other 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 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.
niflibtype text This is optional. Some special types are implemented by hand in Niflib to give them extra features. If this is the case, the name of the C++ class or struct is specified here. Normally you can ignore this.
istemplate integer 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:'''

'''Example:'''

The distance range where a specific level of detail applies. Beginning of range. End of Range.

<add>

The tag is used to add a variable to a or 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. As the name 'add' implies, these tags are considered sequentially and should be placed in the same order that these pieces of data appear in a Nif file.

The 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 add 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 add 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 , , or 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 , , , or 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.

'''Tags Which can appear inside this one:''' None.

'''Example:'''

The triangles.

<niobject>

The tag defines a new Nif objects. These are the core building blocks of a Nif file. Like compounds, they can contain 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 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 will have no tags in it at all; all its variables coming from its ancestors.

The name of a 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 integer This determines whether this Nif object is abstract. 0 is false, 1 is true.
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:'''

'''Example:'''

Abstract object type.
Clone this wiki locally