Skip to content
DummkopfOfHachtenduden edited this page Sep 25, 2023 · 12 revisions
// Header
1   byte    version     // expecting 1
4   uint    simpleDungeonDataOffset

//AI_NAVIGATION Data
//CRefDungeon
2   ushort  regionID
4   uint    blockCount
for (int i = 0; i < blockCount; i++)
{
    //CRefBlock
    4   uint    block.Index
    4   uint    block.CellCount     // number of refCells in this block
    4   uint    block.EdgeCount     // number of refEdges in this block

    // CellLookupTable
    // A table that when given a start and goal cell returns the index of the edge that should be used in order to reach the goal.
    for(int goalCellID = 0; goalCellID < cellCount; goalCellID++)
    {
        for(int startCellID = 0; startCellID < cellCount; startCellID++)
        {                  
            2   short   refEdgeIndex0;         // refEdge to use when pathing forwards (start cell to goal cell)
            2   short   refEdgeIndex1;         // refEdge to use when pathing backwards (goal cell to start cell)
        }
    }

    // Links
    4   uint    linkCount
    for (int i = 0; i < linkCount; i++)
    {        
        4   uint    link.ID                     // same as CellID
        2   ushort  link.CellID
        2   ushort  link.LinkedObjID            // the other block
        2   ushort  link.LinkedObjRefEdgeIndex  // a global edge of the other block
    }
}

// BlockLookupTable
// A table that when given a start and goal block returns the index of the cell that should be used as subgoal in order to reach the actual goal.
for(int goalBlockID = 0; goalBlockID < blockCount; goalBlockID++)
{
    for(int startBlockID = 0; startBlockID < blockCount; startBlockID++)
    {
        2   short   refCellID   // the memory for this is not zeroed and may contain garbage where startBlockID == goalBlockID which are invalid paths anyway.
    }
}

4   uint    int0    // expecting 0
//SimpleDungeonData
//simpleDungeonDataOffset will get you here
2   ushort  regionID    // yes twice
4   uint    blockCount
for (uint i = 0; i < blockCount; i++)
{
    4   uint    edgeCount
    for (uint i = 0; i < edgeCount; i++)
    {
        12  Vector3 edgeCenter
    }
}
4   uint    int1    // expecting 0

Simplification

Some RefBlocks in AINavData may have be computed based on simplified mesh versions resulting in a mismatch of cell indices if you use the original mesh. This has been the major reason why this format took so long to figure out in the fist place. 😄 room102 comparison

The simplified mesh is a retriangulated version of the original with only the most important points and some additional Steiner points. The actual algorithm is unknown to me but you may reverse engineer it at vsro_client.sub_0044BF10. It's also possible to patch the client into dumping these as the simplification code is still included despite not being used there.

Examples

table

Unsmoothed paths generated with AINavData. full path image

Clone this wiki locally