NAV (file format)
A NAV file is a map specific Navigation Mesh file that defines the walkable space in a level for bots in GoldSrc (CS:CZ) and Source games. They usually reside in <game folder>/maps and can be integrated into BSPs in some Source games.[Clarify]
Games
In
Counter-Strike: Source and
Counter-Strike: Global Offensive, the file is generated automatically when bots are played or being added into a map for the first time on a specific map that doesn't have one.
Nav Mesh file write is open source in Source SDK 2013: https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/server/nav_file.cpp#L1071
Nav Mesh generation is also open source in Source SDK 2013: https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/sp/src/game/server/nav_generate.cpp#L3399
Left 4 Dead games appear to be based on an older branch of the nav mesh code, predating version 15. They use smaller integer types for counts and IDs than later versions.
File format
unsigned int magicNumber; // Magic number to check if the file is a .nav file (little endian 0xFEEDFACE)
unsigned int version; // Version of the .nav file, for example GMod and TF2 has 16
if ( version >= 10 ) {
unsigned int subVersion; // Sub version of the .nav file, for example GMod has 0, TF2 has 2. This is usedt
}
if ( version >= 4 ) {
unsigned int saveBspSize; // Size of source bsp file to verify that the bsp hasn't changed
}
if ( version >= 14 ) {
unsigned char isAnalyzed;
}
if ( version >= 5 ) {
// Callouts. Places data. This is the "Mid", "Banana", etc stuff that is used in this nav mesh
unsigned short count;
for( int i = 0; i < count; ++i ) {
unsigned short len; // length of the name
char name[len]; // The name. Maximum len is 256
}
if ( version > 11 ) {
unsigned char m_hasUnnamedAreas;
}
}
if ( subVersion == 13 || subVersion == 14 ) // L4D and L4D2
{
// The default zombie population. You can find the list within scripts/population.txt
char defaultZombiePopulation[];
unsigned short defaultZombiePopulationShort;
}
{
// PreLoadAreas( count )
// This is by default is completely unused, it is left for mods to store custom data
// Assuming that the data is per nav area
//for( int i = 0; i < count; ++i ) {
//}
}
unsigned int areaCount; // number of CNavAreas
area_t area[areaCount]; // Area Data
if ( version >= 6 ) {
unsigned int ladderCount; // number of CNavLadders
ladder_t ladders[ladderCount]; // Ladder Data
}
{
// Load Custom Data
// Again, by default this is unused
}
Area
A navigation area is a bounding square in which bots can move.
struct nav_area_t {
unsigned int ID; // Identifier of the navigation area.
union AttributeBitField {
unsigned char; // In NAV versions ≤ 8
unsigned short; // In NAV versions ≤ 12
unsigned int; // In NAV Versions ≥ 13
};
float nwCorner[3]; // North-West corner vector.
float seCorner[3]; // South-East corner vector.
float NorthEastZ; // Z coordinate of North-East corner.
float SouthWestZ; // Z coordinate of South-West corner.
connectionData_t connectionData[4]; // Connection data in NESW (North, East, South, West) order.
unsigned char hidingSpotCount; // Amount of hiding spots.
hidingSpot_t hidingSpots[hidingSpotCount]; // Hiding spot data.
if ( version < 15 || subVersion == 13 || subVersion == 14 )
{
// Todo: Unconfirmed. Approach spots were removed in NAV version 15. However L4D appear to retain a count byte that is always 0.
unsigned char approachSpotCount;
approachSpot_t approachSpotData[approachSpotCount];
}
// L4D/L4D2 use a byte count;
if ( subVersion == 13 || subVersion == 14 ) {
unsigned char encounterPathCount;
encounterPath_t encounterPaths[encounterPathCount]; // Encounter path data.
} else {
unsigned int encounterPathCount;
encounterPath_t encounterPaths[encounterPathCount]; // Encounter path data.
}
unsigned short PlaceID; // ID of place.
struct ladderIDSequence_t {
if ( subVersion == 13 || subVersion == 14 ) { // L4D and L4D2 use a byte count and unsigned short IDs
unsigned char ladderCount;
unsigned short ladderIDs[ladderCount];
} else {
unsigned int ladderCount;
unsigned int ladderIDs[ladderCount];
}
} ladderIDSequence[2];
if ( subVersion == 13 || subVersion == 14 ) { // L4D and L4D2
// Ladders usable by the common infected, stored in order of vertical direction (up then down).
struct zombieLadderSequence_t {
unsigned int ladderCount;
signed int ladderIDs[ladderCount];
} zombieLadderSequence[2];
}
float EarliestOccupyTimes[2]; // Earliest occupy times for teams.
float LightIntensity[4]; // Light Intensities for each corner.
if ( subVersion == 13 || subVersion == 14 ) { // L4D and L4D2
// Spawn attributes. See: https://developer.valvesoftware.com/wiki/List_of_L4D_Series_Nav_Mesh_Attributes
unsigned short spawnAttributes;
}
// Area-binds were added in version 16 and are not present in L4D/L4D2.
if ( version >= 16 && subVersion != 13 && subVersion != 14 )
{
unsigned int areaBindCount; // Amount of area-binds stored.
nav_area_bind_t areaBindSequence[areaBindCount]; // Sequence of area-binds stored.
}
unsigned int InheritVisibilityFromAreaID; // Inherit visibility from area.
if ( subVersion == 13 || subVersion == 14 ) { // L4D and L4D2
unsigned int visibilityCount;
struct vis_area_t {
unsigned int areaIndex; // Area index, not ID of the area.
unsigned char attributes;
} visibleAreas[visibilityCount];
// Todo: Unconfirmed. Appears to group nearby nav areas together
// Where one area in the group shares the same ID as the cluster (the "representative" area).
unsigned int clusterID;
}
void* customData; // Game-specific data.
}
Approach Spot
struct approachSpot_t {
uint approachHereId;
uint approachPrevId;
byte approachType;
uint approachNextId;
byte approachHow;
}
Area-bind
Area-binds are a structure type used in nav areas to determine the visibility between the parent area and another navigation area, based on area ID.
struct nav_area_bind_t {
unsigned int target_area_id; // Area ID of area.
unsigned char AttributeBitField; // Attribute flag field that determines the visibility type.
};
Area-binds were added in NAV version 16.
Connection
struct connectionData_t {
unsigned int count; // Amount of connections.
unsigned int AreaIDs[count]; // List of area IDs that each connection points to.
};
Hiding Spot
Hiding spots are data structures used to determine points in a nav mesh that bots can hide at.
enum Attribute : unsigned char // Hiding Spot attribute values.
{
IN_COVER = 0x01, // In a corner with good hard cover nearby
GOOD_SNIPER_SPOT = 0x02, // Had at least one decent sniping corridor
IDEAL_SNIPER_SPOT = 0x04, // Can see either very far, or a large area, or both
EXPOSED = 0x08 // Spot in the open, usually on a ledge or cliff
};
struct hidingSpot_t {
unsigned int ID; // Identifier of hide spot. Added in NAV version 2.
float position[3]; // Position of the hiding spot. Added in NAV version 1.
unsigned char Attributes; // Attribute field. Added in NAV version 2. Defaults to IN_COVER for version 1
};
| Game | Used For |
|---|---|
| Determines where Spy bots can lurk for targets. | |
| Determines where bots can take cover and shoot at. | |
| Determines where bots can take cover and shoot at. |
Encounter Path
Encounter paths are structures used to determine routes to take to get to certain areas.
struct encounterPath_t {
unsigned int EntryAreaID; // ID of the Area entered from.
unsigned char EntryDirection; // Direction of entry.
unsigned int DestAreaID; // ID of the Area destination.
unsigned char DestDirection; // Direction towards the destination area.
unsigned char encounterSpotCount; // Amount of encounter spots.
encounterSpot_t encounterSpots[encounterSpotCount]; // Encounter spots.
};
Encounter Spot
Encounter Spots (better termed waypoints) are data structures used in encounter paths to determine the order of area IDs in a route.
struct encounterSpot_t {
unsigned int AreaID; // The Area ID to go to.
unsigned char ParametricDistance; // Parametric distance in bytes.
};
Ladder
A navigation mesh ladder.
struct nav_ladder_t {
unsigned int ID; // Identifier of the navigation ladder.
float width; // extent of ladder
float top[3]; // top endpoint of ladder
float bottom[3]; // bottom endpoint of ladder
float length; // ladder length
unsigned int direction; // Direction of the ladder (NavDirType)
unsigned char bDangling; // if version 6, dangling status
unsigned int topForwardArea; // area ID
unsigned int topLeftArea; // area ID
unsigned int topRightArea; // area ID
unsigned int topBehindArea; // area ID
unsigned int bottomArea; // area ID
}
Custom Data
Some games store custom data in areas.
| Subversion | Data | Label |
|---|---|---|
| 2 | unsigned int | |
| 1 | char[14] |
Versions Used By Games
| Game | Version | Subversion |
|---|---|---|
| 16 | 2 | |
| 16 | 0 | |
| 16 | 14 | |
| 15 | 13 | |
| 9 | n/a | |
| 5 | n/a |
See also
NAV processors
- Nav file parser in C++.
- libSourceNav — a NAV parser in Common Lisp.
- Base NAV file format in Kaitai Struct.
- Nav file parser in Go. (Outdated)