diff --git a/src/game/server/ai_utility.cpp b/src/game/server/ai_utility.cpp index 74a17043..5bfd1c1b 100644 --- a/src/game/server/ai_utility.cpp +++ b/src/game/server/ai_utility.cpp @@ -44,9 +44,7 @@ void Detour_FreeNavMeshByType(const NavMeshType_e navMeshType) { // Frees tiles, polys, tris, anything dynamically // allocated for this navmesh, and the navmesh itself. - v_Detour_FreeNavMesh(nav); - free(nav); - + delete nav; g_pNavMesh[navMeshType] = nullptr; } } diff --git a/src/game/server/detour_impl.h b/src/game/server/detour_impl.h index 0913d002..2f4dd323 100644 --- a/src/game/server/detour_impl.h +++ b/src/game/server/detour_impl.h @@ -8,7 +8,6 @@ // RUNTIME: DETOUR //------------------------------------------------------------------------- inline void(*v_Detour_LevelInit)(void); -inline void(*v_Detour_FreeNavMesh)(dtNavMesh* mesh); inline bool(*v_Detour_IsGoalPolyReachable)(dtNavMesh* const nav, const dtPolyRef fromPoly, const dtPolyRef goalPoly, const TraverseAnimType_e animType); inline dtStatus(*dtNavMesh__Init)(dtNavMesh* thisptr, unsigned char* data, int flags); inline dtStatus(*dtNavMesh__addTile)(dtNavMesh* thisptr, void* unused, unsigned char* data, int dataSize, int flags, dtTileRef lastRef); @@ -35,7 +34,6 @@ class VRecast : public IDetour virtual void GetAdr(void) const { LogFunAdr("Detour_LevelInit", v_Detour_LevelInit); - LogFunAdr("Detour_FreeNavMesh", v_Detour_FreeNavMesh); LogFunAdr("Detour_IsGoalPolyReachable", v_Detour_IsGoalPolyReachable); LogFunAdr("dtNavMesh::Init", dtNavMesh__Init); LogFunAdr("dtNavMesh::addTile", dtNavMesh__addTile); @@ -46,7 +44,6 @@ class VRecast : public IDetour virtual void GetFun(void) const { g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 54 41 55 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 45 33 E4").GetPtr(v_Detour_LevelInit); - g_GameDll.FindPatternSIMD("40 53 48 83 EC 30 48 89 6C 24 ?? 48 8B D9").GetPtr(v_Detour_FreeNavMesh); g_GameDll.FindPatternSIMD("48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 49 63 F1").GetPtr(v_Detour_IsGoalPolyReachable); g_GameDll.FindPatternSIMD("4C 89 44 24 ?? 53 41 56 48 81 EC ?? ?? ?? ?? 0F 10 11").GetPtr(dtNavMesh__Init); g_GameDll.FindPatternSIMD("44 89 4C 24 ?? 41 55").GetPtr(dtNavMesh__addTile); diff --git a/src/naveditor/Editor_TileMesh.cpp b/src/naveditor/Editor_TileMesh.cpp index bf8fcbec..f96837fa 100644 --- a/src/naveditor/Editor_TileMesh.cpp +++ b/src/naveditor/Editor_TileMesh.cpp @@ -655,7 +655,7 @@ bool Editor_TileMesh::handleBuild() params.traverseTableSize = 0; params.traverseTableCount = 0; #if DT_NAVMESH_SET_VERSION >= 8 - params.magicDataCount = 0; + params.hintCount = 0; #endif dtStatus status; diff --git a/src/thirdparty/recast/Detour/Include/DetourNavMesh.h b/src/thirdparty/recast/Detour/Include/DetourNavMesh.h index 5a804561..33e74325 100644 --- a/src/thirdparty/recast/Detour/Include/DetourNavMesh.h +++ b/src/thirdparty/recast/Detour/Include/DetourNavMesh.h @@ -347,6 +347,18 @@ struct dtPolyDetail unsigned char triCount; ///< The number of triangles in the sub-mesh. }; +/// Defines the vertical triangle of a wall hint. +struct dtTriangleSurface +{ + float pos[3]; ///< The surface position of the triangle. [(x, y, z)] + float minDist; ///< The minimum distance between the agent's and triangle position before they are considered close enough. + unsigned short vertAIndex; ///< The index of the first vert connecting A->B. + unsigned short vertBIndex; ///< The index of the second vert connecting B->C. + unsigned short vertCIndex; ///< The index of the third vert connecting C->A. + float surfArea; ///< The surface area of the triangle. (Note: this field was unused by the engine and therefore re-purposed). + unsigned char edgeFlags; ///< The edge flags, use #dtGetDetailTriEdgeFlags to retrieve them. +}; + /// Get flags for edge in detail triangle. /// @param triFlags[in] The flags for the triangle (last component of detail vertices above). /// @param edgeIndex[in] The index of the first vertex of the edge. For instance, if 0. @@ -397,6 +409,18 @@ struct dtCell #endif }; +/// Defines a hint in the navmesh. +/// @note This is used to define wall surface triangles to help with special movements such as wall running. +/// @see dtOffMeshConnection +struct dtHint +{ + float* verts; ///< The triangle vertices. [Size: (x, y, z) * dtHint::vertCount] + dtTriangleSurface* triangle; ///< The triangles. [Size: dtHint::vertCount] + char unk[24]; // Editor only. + int vertCount; ///< The number of vertices in the hint. + int triCount; ///< The number of triangles in the hint. +}; + /// Bounding volume node. /// @note This structure is rarely if ever used by the end user. /// @see dtMeshTile @@ -547,6 +571,14 @@ struct dtMeshHeader float bvQuantFactor; }; +/// Navigation mesh tile memory tracker base class. +/// @ingroup detour +class dtMeshTileMemoryTracker +{ +public: + virtual void destroy(const int flags) = 0; +}; + /// Defines a navigation mesh tile. /// @ingroup detour struct dtMeshTile @@ -588,7 +620,7 @@ public: int dataSize; ///< Size of the tile data. int flags; ///< Tile flags. (See: #dtTileFlags) dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid. - void* deleteCallback; ///< Custom destruction callback, called after free. (See [r5apex_ds + F437D9] for usage.) + dtMeshTileMemoryTracker* tracker; ///< The tiles memory tracker, called after destruction. (See [r5apex_ds + F437D9] for usage.) private: dtMeshTile(const dtMeshTile&); dtMeshTile& operator=(const dtMeshTile&); @@ -655,18 +687,14 @@ struct dtNavMeshParams { float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)] float tileWidth; ///< The width of each tile. (Along the x-axis.) - float tileHeight; ///< The height of each tile. (Along the z-axis.) + float tileHeight; ///< The height of each tile. (Along the y-axis.) int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely. int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely. int polyGroupCount; ///< The total number of disjoint polygon groups. int traverseTableSize; ///< The total size of the static traverse table. This is computed using calcTraverseTableSize(polyGroupcount). int traverseTableCount; ///< The total number of traverse tables in this navmesh. Each TraverseAnimType uses its own table as their available jump links should match their behavior and abilities. - #if DT_NAVMESH_SET_VERSION >= 7 - // NOTE: this seems to be used for some wallrunning code. This allocates a buffer of size 0x30 * magicDataCount, - // then copies in the data 0x30 * magicDataCount at the end of the navmesh file (past the traverse tables). - // See [r5apex_ds + F43600] for buffer allocation and data copy, see note at dtNavMesh::m_someMagicData for usage. - int magicDataCount; + int hintCount; ///< The total number of hints in the navmesh. #endif }; @@ -770,8 +798,8 @@ public: /// @return The maximum number of tiles supported by the navigation mesh. int getMaxTiles() const; - /// The number of tiles added to this mesh by dtNavMesh::addTile - /// @return The number of tiles added to this mesh by dtNavMesh::addTile + /// The number of tiles added to this mesh by #addTile. + /// @return The number of tiles added to this mesh by #addTile. int getTileCount() const { return m_tileCount; }; /// Gets the tile at the specified index. @@ -843,6 +871,8 @@ public: /// @param[in] size The size of the traverse table. void setTraverseTableSize(const int size) { m_params.traverseTableSize = size; } + void freeHints(); + /// @} /// @{ @@ -1049,10 +1079,7 @@ private: dtMeshTile* m_nextFree; ///< Freelist of tiles. dtMeshTile* m_tiles; ///< List of tiles. int** m_traverseTables; ///< Array of traverse tables. - - ///< FIXME: unknown structure pointer, used for some wallrunning code, see [r5apex_ds + F12687] for usage. - ///< See note at dtNavMeshParams::magicDataCount for buffer allocation. - void* m_someMagicData; + dtHint* m_hints; ///< List of hints. int m_unused0; int m_unused1; diff --git a/src/thirdparty/recast/Detour/Source/DetourNavMesh.cpp b/src/thirdparty/recast/Detour/Source/DetourNavMesh.cpp index fb471ca6..bdf02196 100644 --- a/src/thirdparty/recast/Detour/Source/DetourNavMesh.cpp +++ b/src/thirdparty/recast/Detour/Source/DetourNavMesh.cpp @@ -255,7 +255,7 @@ dtNavMesh::dtNavMesh() : m_nextFree(0), m_tiles(0), m_traverseTables(0), - m_someMagicData(0), + m_hints(0), m_unused0(0), m_unused1(0) { @@ -268,15 +268,24 @@ dtNavMesh::dtNavMesh() : rdVset(m_orig, 0.0f,0.0f,0.0f); } -dtNavMesh::~dtNavMesh() // TODO: see [r5apex_ds + F43720] to re-implement this correctly +dtNavMesh::~dtNavMesh() { for (int i = 0; i < m_maxTiles; ++i) { - if (m_tiles[i].flags & DT_TILE_FREE_DATA) + dtMeshTile& tile = m_tiles[i]; + const int flags = tile.flags; + + if (flags & DT_TILE_FREE_DATA) { - rdFree(m_tiles[i].data); - m_tiles[i].data = 0; - m_tiles[i].dataSize = 0; + if (flags & DT_CELL_FREE_DATA) + rdFree(tile.cells); + + rdFree(tile.data); + tile.data = 0; + tile.dataSize = 0; + + if (tile.tracker) + tile.tracker->destroy(1); } } @@ -284,8 +293,9 @@ dtNavMesh::~dtNavMesh() // TODO: see [r5apex_ds + F43720] to re-implement this c rdFree(m_tiles); freeTraverseTables(); + freeHints(); } - + dtStatus dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); @@ -354,7 +364,7 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int tabl params.traverseTableSize = 0; params.traverseTableCount = tableCount; #if DT_NAVMESH_SET_VERSION >= 7 - params.magicDataCount = 0; + params.hintCount = 0; #endif dtStatus status = init(¶ms); @@ -1380,7 +1390,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, if (!tile) return DT_FAILURE | DT_OUT_OF_MEMORY; - tile->deleteCallback = nullptr; + tile->tracker = nullptr; // Insert tile into the position lut. if (header->userId != DT_FULL_UNLINKED_TILE_USER_ID) @@ -2083,6 +2093,19 @@ void dtNavMesh::setTraverseTable(const int index, int* const table) m_traverseTables[index] = table; } +void dtNavMesh::freeHints() +{ + for (int i = 0; i < m_params.hintCount; i++) + { + dtHint& hint = m_hints[i]; + + rdFree(hint.verts); + rdFree(hint.triangle); + } + + rdFree(m_hints); +} + dtStatus dtNavMesh::setPolyFlags(dtPolyRef ref, unsigned short flags) { if (!ref) return DT_FAILURE;