From c771986c56710b63c5851bdcc717501d0badf025 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 14 Jul 2018 15:05:28 +0300 Subject: [PATCH] Prioritise NavMesh jobs first to remove and last to add When player move fast enough, tiles update for specific area square couldn't catch player move. Tiles to be removed are left in the queue with lower priority then tiles to be added which are nearest to player. This can lead to overflow for amount of tiles. So we try to do remove first. But we detect change type approximately using mixed change type, because even if we do it precise, change type could change while job is in queue. --- .../detournavigator/asyncnavmeshupdater.cpp | 20 +++++--- .../detournavigator/asyncnavmeshupdater.hpp | 11 ++++- components/detournavigator/navmeshmanager.cpp | 48 ++++++++++++++----- components/detournavigator/navmeshmanager.hpp | 4 +- 4 files changed, 61 insertions(+), 22 deletions(-) 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; };