Describes the file format of the bot navigation files .nav used by the Quake 2021 Re-Release version.
Introduction
This guide will describe and explain the .nav files. These are the files that save all the bot navigation data (eg: waypoints). This guide is intended for programmers.
It’s a binary format but it’s relatively simple. I’ve written the format into Kaitai – [kaitai.io] . Download the KSY file here – [pastebin.com] and you can try it at their online IDE – [kaitai.io] . From there you’re able to upload .nav files and see the contents or generate file readers for multiple programming languages.
Some important info
All offsets are relative to the beginning of the structure or sub-structure, not the file. The file is variable length so it’s not possible to do that anyway.
Here’s the types and their length in case there’s any confusion:
Type | Size (bytes) | Comment |
---|---|---|
int | 4 | |
short | 2 | |
float | 4 | |
vector3 | 12 | XYZ coordinates, 3 floats |
Diagram
This is a diagram generated from the Kaitai struct file. It doesn’t correspond 1:1 to what is in this guide but all the fields are there.
File Structure
The file is divided into 6 structures.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Header | Header | Header of the file. Contains some important info. |
20 | Nodes | Node[] | Info about the nodes |
… | Node origins | NodeOrigin[] | 3D coordinates where nodes are placed |
… | Links | Link[] | Info about the links between nodes |
… | Traversals | Traversal[] | Info that helps bots on how to traverse big gaps between nodes |
… | Edicts | Edicts | Info about connection of links to edicts |
Header
The header of the file contains mostly counters that tell you how much data to expect.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Magic Number | char[4] | Always ‘NAV2’ |
4 | Unknown | int | Always 14. Probably version indicator. |
8 | Node count | int | How many nodes exist in the file |
12 | Link count | int | How many links exist in the file |
16 | Traversal count | int | How many traversals exist in the file |
After the header comes the Node structure.
Nodes
The node structure contains info related to each node, but surprisingly not the position as that is contained inside a separate structure.
There are as many sequential nodes here as specified in the header.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Flags | short | The type of node. See table below |
2 | Connection count | short | How many outgoing connections this node has. |
4 | Connection start index | short | In which index in the connection array the connections for this node begin. |
6 | Radius | short | Radius of the node |
After this array, the file continues with Node origins structure.
Node flags
This is a bit flag enum.
Bit flag | Description |
---|---|
1 | Teleporter |
2 | Pusher |
4 | Elevator Top |
8 | Elevator Bottom |
16 | Underwater |
32 | Hazard |
Nodes origins
The nodes origin coordinates are stored in a separate array. There is as many as there are Nodes and they correspond by index. So for example, Node[53] will be NodeOrigin[53].
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Origin | vector3 | XYZ coordinates |
After this, comes the Links structure.
Links
The links connect all nodes together and provide pathing for the bots, however this array is quite bare.
As with Nodes, there are as many Links as defined in the Header.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Destination | short | Target Node index where this link leads to |
2 | Type | short | What type of link this is. See table below. |
4 | Traversal index | short | Index of the traversal info to use for this link. 0xFFFF if not used. |
The file continues with the Traversals structure.
Link types
A link can only be 1 type.
Value | Name |
---|---|
0 | Walk |
1 | Long Jump |
2 | Teleport |
3 | Walk Off Ledge |
4 | Pusher |
5 | Barrier Jump |
6 | Elevator |
7 | Train |
8 | Manual Jump |
9 | Unknown (literally) |
Traversals
This is probably the most surprising thing from the file, as it contains pre-computed helping coordinates to tell the bot how to traverse gaps like long jumps.
There as many Traversals as specified in the Header.
For simplicity sake I’ll condense XYZ float coordinates into a ‘vector3’ type.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Node exit | vector3 | Where the bot should leave the node. Coordinate is at the radius edge. |
12 | Jump start | vector3 | Where the bot should start jumping. |
36 | Jump end | vector3 | Where the jump ends / lands. |
The file continues with the Edicts structure.
Edicts
The final structure of the file is the Edicts. It appears to be kind of independent of the other structures as it links Nodes to Edicts.
Header
The structure begins with a small header that indicates how many ‘Edict’ entries come after.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Edict count | int | How many edicts are contained in the file. |
Edict
There are as many Edict as specified in the Edict header.
Rel. Off. | Name | Type | Description |
---|---|---|---|
0 | Link id | short | Which link this belongs to, connected via it’s index |
4 | Mins | vector3 | The world coordinates for the target edict ‘mins’ |
16 | Maxs | vector3 | The world coordinates for the target edict ‘maxs’ |
28 | targetname | int | Engine string index for the targetname of the target edict. |
32 | classname | int | Engine string index for the classname of the target edict. |
A little explanation
So the way this structure works is a bit weird but at the same time it also makes it pretty reliable in some ways.
You’ll notice that there’s no entity index here, and you might think that it links to the entity via the targetname. But if that’s the case how can it work with buttons which have no targetname?
The answer is via the mins and maxs. Even if you remove the targetname and classname from the file, it will automatically find the entity contained within that box and fill up the information. I suspect if you remove the mins and maxs it might use targetname and classname to find it as well, but this hasn’t been tested.
However… You can’t really use the targetname and classname yourself. As they’re not strings but instead engine strings. Engine strings are assigned an index and they’re allocated at the beginning of the map and are different for each map. But in sum, if you’re pointing to the same entity, it’ll be the same id.
I hope you enjoy the Guide we share about Quake – Details about Bot Navigation Data & File Format; if you think we forget to add or we should add more information, please let us know via commenting below! See you soon!
- All Quake Posts List
Leave a Reply