From 8a94e053a871b6812965cd61f88ae58d897a167e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 18 Dec 2023 21:45:27 +0100 Subject: [PATCH] Fix crash when resizing navmesh capacity with crowd created for that navmesh --- Source/Engine/Navigation/NavMeshRuntime.cpp | 19 ++++------- .../recastnavigation/DetourNavMesh.cpp | 32 ++++++++++++------- .../recastnavigation/DetourNavMesh.h | 3 ++ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/Source/Engine/Navigation/NavMeshRuntime.cpp b/Source/Engine/Navigation/NavMeshRuntime.cpp index 989b1697f..4fcf0e038 100644 --- a/Source/Engine/Navigation/NavMeshRuntime.cpp +++ b/Source/Engine/Navigation/NavMeshRuntime.cpp @@ -36,7 +36,7 @@ NavMeshRuntime::NavMeshRuntime(const NavMeshProperties& properties) NavMeshRuntime::~NavMeshRuntime() { - dtFreeNavMesh(_navMesh); + Dispose(); dtFreeNavMeshQuery(_navMeshQuery); } @@ -336,9 +336,7 @@ void NavMeshRuntime::SetTileSize(float tileSize) // Dispose the existing mesh (its invalid) if (_navMesh) { - dtFreeNavMesh(_navMesh); - _navMesh = nullptr; - _tiles.Clear(); + Dispose(); } _tileSize = tileSize; @@ -363,14 +361,9 @@ void NavMeshRuntime::EnsureCapacity(int32 tilesToAddCount) // Ensure to have size assigned ASSERT(_tileSize != 0); - // Fre previous data (if any) - if (_navMesh) - { - dtFreeNavMesh(_navMesh); - } - - // Allocate new navmesh - _navMesh = dtAllocNavMesh(); + // Allocate navmesh and initialize the default query + if (!_navMesh) + _navMesh = dtAllocNavMesh(); if (dtStatusFailed(_navMeshQuery->init(_navMesh, MAX_NODES))) { LOG(Error, "Failed to initialize navmesh {0}.", Properties.Name); @@ -517,7 +510,7 @@ void NavMeshRuntime::RemoveTile(int32 x, int32 y, int32 layer) } } -void NavMeshRuntime::RemoveTiles(bool (* prediction)(const NavMeshRuntime* navMesh, const NavMeshTile& tile, void* customData), void* userData) +void NavMeshRuntime::RemoveTiles(bool (*prediction)(const NavMeshRuntime* navMesh, const NavMeshTile& tile, void* customData), void* userData) { ScopeLock lock(Locker); ASSERT(prediction); diff --git a/Source/ThirdParty/recastnavigation/DetourNavMesh.cpp b/Source/ThirdParty/recastnavigation/DetourNavMesh.cpp index 2240526eb..eba1b4dc3 100644 --- a/Source/ThirdParty/recastnavigation/DetourNavMesh.cpp +++ b/Source/ThirdParty/recastnavigation/DetourNavMesh.cpp @@ -208,21 +208,13 @@ dtNavMesh::dtNavMesh() : dtNavMesh::~dtNavMesh() { - for (int i = 0; i < m_maxTiles; ++i) - { - if (m_tiles[i].flags & DT_TILE_FREE_DATA) - { - dtFree(m_tiles[i].data); - m_tiles[i].data = 0; - m_tiles[i].dataSize = 0; - } - } - dtFree(m_posLookup); - dtFree(m_tiles); + purge(); } dtStatus dtNavMesh::init(const dtNavMeshParams* params) { + if (m_tiles) + purge(); memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); m_tileWidth = params->tileWidth; @@ -1178,6 +1170,24 @@ int dtNavMesh::getMaxTiles() const return m_maxTiles; } +void dtNavMesh::purge() +{ + for (int i = 0; i < m_maxTiles; ++i) + { + if (m_tiles[i].flags & DT_TILE_FREE_DATA) + { + dtFree(m_tiles[i].data); + m_tiles[i].data = 0; + m_tiles[i].dataSize = 0; + } + } + m_maxTiles = 0; + dtFree(m_posLookup); + m_posLookup = 0; + dtFree(m_tiles); + m_tiles = 0; +} + dtMeshTile* dtNavMesh::getTile(int i) { return &m_tiles[i]; diff --git a/Source/ThirdParty/recastnavigation/DetourNavMesh.h b/Source/ThirdParty/recastnavigation/DetourNavMesh.h index 4c1277d78..8837d576d 100644 --- a/Source/ThirdParty/recastnavigation/DetourNavMesh.h +++ b/Source/ThirdParty/recastnavigation/DetourNavMesh.h @@ -613,6 +613,9 @@ private: dtNavMesh(const dtNavMesh&); dtNavMesh& operator=(const dtNavMesh&); + /// Clears all tiles from memory. Can be called before init to rebuild navigation mesh with different parameters. + void purge(); + /// Returns pointer to tile in the tile array. dtMeshTile* getTile(int i);