diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 91af31e22e..bea6ffa57c 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -9,16 +9,22 @@ namespace { + using DetourNavigator::ChangeType; using DetourNavigator::TilePosition; - int getDistance(const TilePosition& lhs, const TilePosition& rhs) + int getManhattanDistance(const TilePosition& lhs, const TilePosition& rhs) { return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()); } - std::pair makePriority(const TilePosition& changedTile, const TilePosition& playerTile) + std::tuple makePriority(const TilePosition& position, const ChangeType changeType, + const TilePosition& playerTile) { - return std::make_pair(getDistance(changedTile, playerTile), getDistance(changedTile, TilePosition {0, 0})); + return std::make_tuple( + changeType, + getManhattanDistance(position, playerTile), + getManhattanDistance(position, TilePosition {0, 0}) + ); } } @@ -60,7 +66,7 @@ namespace DetourNavigator void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr& navMeshCacheItem, const TilePosition& playerTile, - const std::set& changedTiles) + const std::map& changedTiles) { log("post jobs playerTile=", playerTile); @@ -73,9 +79,9 @@ namespace DetourNavigator for (const auto& changedTile : changedTiles) { - if (mPushed[agentHalfExtents].insert(changedTile).second) - mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile, - makePriority(changedTile, playerTile)}); + if (mPushed[agentHalfExtents].insert(changedTile.first).second) + mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile.first, + makePriority(changedTile.first, changedTile.second, playerTile)}); } log("posted ", mJobs.size(), " jobs"); diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 6b4facf6de..bba788c3c4 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -22,6 +22,13 @@ class dtNavMesh; namespace DetourNavigator { + enum class ChangeType + { + remove = 0, + mixed = 1, + add = 2, + }; + class AsyncNavMeshUpdater { public: @@ -29,7 +36,7 @@ namespace DetourNavigator ~AsyncNavMeshUpdater(); void post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr& mNavMeshCacheItem, - const TilePosition& playerTile, const std::set& changedTiles); + const TilePosition& playerTile, const std::map& changedTiles); void wait(); @@ -39,7 +46,7 @@ namespace DetourNavigator osg::Vec3f mAgentHalfExtents; std::shared_ptr mNavMeshCacheItem; TilePosition mChangedTile; - std::pair mPriority; + std::tuple mPriority; friend inline bool operator <(const Job& lhs, const Job& rhs) { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index c12351ee0a..b13c5d83c9 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -13,6 +13,16 @@ #include +namespace +{ + using DetourNavigator::ChangeType; + + ChangeType addChangeType(const ChangeType current, const ChangeType add) + { + return current == add ? current : ChangeType::mixed; + } +} + namespace DetourNavigator { NavMeshManager::NavMeshManager(const Settings& settings) @@ -26,7 +36,7 @@ namespace DetourNavigator { if (!mRecastMeshManager.addObject(id, shape, transform)) return false; - addChangedTiles(shape, transform); + addChangedTiles(shape, transform, ChangeType::add); return true; } @@ -34,7 +44,7 @@ namespace DetourNavigator { if (!mRecastMeshManager.updateObject(id, transform)) return false; - addChangedTiles(shape, transform); + addChangedTiles(shape, transform, ChangeType::mixed); return true; } @@ -43,7 +53,7 @@ namespace DetourNavigator const auto object = mRecastMeshManager.removeObject(id); if (!object) return false; - addChangedTiles(object->mShape, object->mTransform); + addChangedTiles(object->mShape, object->mTransform, ChangeType::remove); return true; } @@ -72,7 +82,7 @@ namespace DetourNavigator return; mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision(); mPlayerTile = playerTile; - std::set tilesToPost; + std::map tilesToPost; const auto& cached = getCached(agentHalfExtents); const auto changedTiles = mChangedTiles.find(agentHalfExtents); { @@ -80,10 +90,16 @@ namespace DetourNavigator if (changedTiles != mChangedTiles.end()) { for (const auto& tile : changedTiles->second) - if (locked->getTileAt(tile.x(), tile.y(), 0)) - tilesToPost.insert(tile); + if (locked->getTileAt(tile.first.x(), tile.first.y(), 0)) + { + auto tileToPost = tilesToPost.find(tile.first); + if (tileToPost == tilesToPost.end()) + tilesToPost.insert(tile); + else + tileToPost->second = addChangeType(tileToPost->second, tile.second); + } for (const auto& tile : tilesToPost) - changedTiles->second.erase(tile); + changedTiles->second.erase(tile.first); if (changedTiles->second.empty()) mChangedTiles.erase(changedTiles); } @@ -94,8 +110,10 @@ namespace DetourNavigator return; const auto shouldAdd = shouldAddTile(tile, playerTile, maxTiles); const auto presentInNavMesh = bool(locked->getTileAt(tile.x(), tile.y(), 0)); - if ((shouldAdd && !presentInNavMesh) || (!shouldAdd && presentInNavMesh)) - tilesToPost.insert(tile); + if (shouldAdd && !presentInNavMesh) + tilesToPost.insert(std::make_pair(tile, ChangeType::add)); + else if (!shouldAdd && presentInNavMesh) + tilesToPost.insert(std::make_pair(tile, ChangeType::mixed)); }); } mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, tilesToPost); @@ -120,12 +138,20 @@ namespace DetourNavigator return mCache; } - void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform) + void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform, + const ChangeType changeType) { getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& v) { for (const auto& cached : mCache) if (cached.second) - mChangedTiles[cached.first].insert(v); + { + auto& tiles = mChangedTiles[cached.first]; + auto tile = tiles.find(v); + if (tile == tiles.end()) + tiles.insert(std::make_pair(v, changeType)); + else + tile->second = addChangeType(tile->second, changeType); + } }); } diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index 109aa2237f..01840a3b60 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -45,13 +45,13 @@ namespace DetourNavigator const Settings& mSettings; TileCachedRecastMeshManager mRecastMeshManager; std::map> mCache; - std::map> mChangedTiles; + std::map> mChangedTiles; AsyncNavMeshUpdater mAsyncNavMeshUpdater; std::size_t mGenerationCounter = 0; boost::optional mPlayerTile; std::size_t mLastRecastMeshManagerRevision = 0; - void addChangedTiles(const btCollisionShape& shape, const btTransform& transform); + void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType); const std::shared_ptr& getCached(const osg::Vec3f& agentHalfExtents) const; };