diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 20e2979eb..b8c1ed72f 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -13,7 +13,7 @@ namespace DetourNavigator { if (!mImpl.addObject(id, shape, transform, areaType)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -21,7 +21,7 @@ namespace DetourNavigator { if (!mImpl.updateObject(id, transform, areaType)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -29,7 +29,7 @@ namespace DetourNavigator { const auto object = mImpl.removeObject(id); if (object) - mCached.reset(); + mCached.lock()->reset(); return object; } @@ -38,7 +38,7 @@ namespace DetourNavigator { if (!mImpl.addWater(cellPosition, cellSize, transform)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -46,15 +46,18 @@ namespace DetourNavigator { const auto water = mImpl.removeWater(cellPosition); if (water) - mCached.reset(); + mCached.lock()->reset(); return water; } std::shared_ptr CachedRecastMeshManager::getMesh() { - if (!mCached) - mCached = mImpl.getMesh(); - return mCached; + std::shared_ptr cached = *mCached.lock(); + if (cached != nullptr) + return cached; + cached = mImpl.getMesh(); + *mCached.lock() = cached; + return cached; } bool CachedRecastMeshManager::isEmpty() const diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index c00096764..f2cf54c92 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -4,6 +4,8 @@ #include "recastmeshmanager.hpp" #include "version.hpp" +#include + namespace DetourNavigator { class CachedRecastMeshManager @@ -32,7 +34,7 @@ namespace DetourNavigator private: RecastMeshManager mImpl; - std::shared_ptr mCached; + Misc::ScopeGuarded> mCached; }; } diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index d475bff1e..aa47e45d9 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -13,6 +13,7 @@ namespace DetourNavigator bool RecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { + const std::lock_guard lock(mMutex); const auto object = mObjects.lower_bound(id); if (object != mObjects.end() && object->first == id) return false; @@ -25,6 +26,7 @@ namespace DetourNavigator bool RecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) { + const std::lock_guard lock(mMutex); const auto object = mObjects.find(id); if (object == mObjects.end()) return false; @@ -38,6 +40,7 @@ namespace DetourNavigator std::optional RecastMeshManager::removeObject(const ObjectId id) { + const std::lock_guard lock(mMutex); const auto object = mObjects.find(id); if (object == mObjects.end()) return std::nullopt; @@ -51,6 +54,7 @@ namespace DetourNavigator bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform) { + const std::lock_guard lock(mMutex); const auto iterator = mWaterOrder.emplace(mWaterOrder.end(), Water {cellSize, transform}); if (!mWater.emplace(cellPosition, iterator).second) { @@ -63,6 +67,7 @@ namespace DetourNavigator std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { + const std::lock_guard lock(mMutex); const auto water = mWater.find(cellPosition); if (water == mWater.end()) return std::nullopt; @@ -76,18 +81,34 @@ namespace DetourNavigator std::shared_ptr RecastMeshManager::getMesh() { RecastMeshBuilder builder(mSettings, mTileBounds); - for (const auto& v : mWaterOrder) - builder.addWater(v.mCellSize, v.mTransform); - for (const auto& object : mObjectsOrder) + using Object = std::tuple< + osg::ref_ptr, + std::reference_wrapper, + btTransform, + AreaType + >; + std::vector objects; + std::size_t revision; { - const RecastMeshObject& v = object.getImpl(); - builder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); + const std::lock_guard lock(mMutex); + for (const auto& v : mWaterOrder) + builder.addWater(v.mCellSize, v.mTransform); + objects.reserve(mObjectsOrder.size()); + for (const auto& object : mObjectsOrder) + { + const RecastMeshObject& impl = object.getImpl(); + objects.emplace_back(impl.getHolder(), impl.getShape(), impl.getTransform(), impl.getAreaType()); + } + revision = mRevision; } - return std::move(builder).create(mGeneration, mRevision); + for (const auto& [holder, shape, transform, areaType] : objects) + builder.addObject(shape, transform, areaType); + return std::move(builder).create(mGeneration, revision); } bool RecastMeshManager::isEmpty() const { + const std::lock_guard lock(mMutex); return mObjects.empty(); } @@ -95,6 +116,7 @@ namespace DetourNavigator { if (recastMeshVersion.mGeneration != mGeneration) return; + const std::lock_guard lock(mMutex); if (mLastNavMeshReport.has_value() && navMeshVersion < mLastNavMeshReport->mNavMeshVersion) return; mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion}; @@ -105,6 +127,7 @@ namespace DetourNavigator Version RecastMeshManager::getVersion() const { + const std::lock_guard lock(mMutex); return Version {mGeneration, mRevision}; } } diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index df629ba79..bf60ad8f1 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -13,6 +13,7 @@ #include #include #include +#include class btCollisionShape; @@ -65,9 +66,10 @@ namespace DetourNavigator }; const Settings& mSettings; + const std::size_t mGeneration; + const TileBounds mTileBounds; + mutable std::mutex mMutex; std::size_t mRevision = 0; - std::size_t mGeneration; - TileBounds mTileBounds; std::list mObjectsOrder; std::map::iterator> mObjects; std::list mWaterOrder; diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index 94509a5f9..eefbc5384 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -39,6 +39,11 @@ namespace DetourNavigator bool update(const btTransform& transform, const AreaType areaType); + const osg::ref_ptr& getHolder() const + { + return mHolder; + } + const btCollisionShape& getShape() const { return mShape; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 14e94eac3..8e94f0994 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -67,7 +67,7 @@ namespace DetourNavigator const auto tiles = mTiles.lock(); for (auto& tile : *tiles) { - if (tile.second.addWater(cellPosition, cellSize, transform)) + if (tile.second->addWater(cellPosition, cellSize, transform)) { tilesPositions.push_back(tile.first); result = true; @@ -86,9 +86,9 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles->insert(std::make_pair(tilePosition, - CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + std::make_shared(mSettings, tileBounds, mTilesGeneration))).first; } - if (tile->second.addWater(cellPosition, cellSize, transform)) + if (tile->second->addWater(cellPosition, cellSize, transform)) { tilesPositions.push_back(tilePosition); result = true; @@ -114,8 +114,8 @@ namespace DetourNavigator const auto tile = tiles->find(tilePosition); if (tile == tiles->end()) continue; - const auto tileResult = tile->second.removeWater(cellPosition); - if (tile->second.isEmpty()) + const auto tileResult = tile->second->removeWater(cellPosition); + if (tile->second->isEmpty()) { tiles->erase(tile); ++mTilesGeneration; @@ -130,11 +130,17 @@ namespace DetourNavigator std::shared_ptr TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition) { - const auto tiles = mTiles.lock(); - const auto it = tiles->find(tilePosition); - if (it == tiles->end()) + const auto manager = [&] () -> std::shared_ptr + { + const auto tiles = mTiles.lock(); + const auto it = tiles->find(tilePosition); + if (it == tiles->end()) + return nullptr; + return it->second; + } (); + if (manager == nullptr) return nullptr; - return it->second.getMesh(); + return manager->getMesh(); } bool TileCachedRecastMeshManager::hasTile(const TilePosition& tilePosition) @@ -153,12 +159,12 @@ namespace DetourNavigator const auto it = tiles->find(tilePosition); if (it == tiles->end()) return; - it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion); + it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion); } bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, - std::map& tiles) + TilesMap& tiles) { auto tile = tiles.find(tilePosition); if (tile == tiles.end()) @@ -167,26 +173,26 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles.insert(std::make_pair( - tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + tilePosition, std::make_shared(mSettings, tileBounds, mTilesGeneration))).first; } - return tile->second.addObject(id, shape, transform, areaType); + return tile->second->addObject(id, shape, transform, areaType); } bool TileCachedRecastMeshManager::updateTile(const ObjectId id, const btTransform& transform, - const AreaType areaType, const TilePosition& tilePosition, std::map& tiles) + const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles) { const auto tile = tiles.find(tilePosition); - return tile != tiles.end() && tile->second.updateObject(id, transform, areaType); + return tile != tiles.end() && tile->second->updateObject(id, transform, areaType); } std::optional TileCachedRecastMeshManager::removeTile(const ObjectId id, - const TilePosition& tilePosition, std::map& tiles) + const TilePosition& tilePosition, TilesMap& tiles) { const auto tile = tiles.find(tilePosition); if (tile == tiles.end()) return std::optional(); - const auto tileResult = tile->second.removeObject(id); - if (tile->second.isEmpty()) + const auto tileResult = tile->second->removeObject(id); + if (tile->second->isEmpty()) { tiles.erase(tile); ++mTilesGeneration; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 956c2bcf2..23b2b63b7 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -88,7 +88,7 @@ namespace DetourNavigator void forEachTile(Function&& function) { for (auto& [tilePosition, recastMeshManager] : *mTiles.lock()) - function(tilePosition, recastMeshManager); + function(tilePosition, *recastMeshManager); } std::size_t getRevision() const; @@ -96,22 +96,23 @@ namespace DetourNavigator void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion); private: + using TilesMap = std::map>; + const Settings& mSettings; - Misc::ScopeGuarded> mTiles; + Misc::ScopeGuarded mTiles; std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; std::size_t mRevision = 0; std::size_t mTilesGeneration = 0; bool addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType, const TilePosition& tilePosition, float border, - std::map& tiles); + const AreaType areaType, const TilePosition& tilePosition, float border, TilesMap& tiles); bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, - const TilePosition& tilePosition, std::map& tiles); + const TilePosition& tilePosition, TilesMap& tiles); std::optional removeTile(const ObjectId id, const TilePosition& tilePosition, - std::map& tiles); + TilesMap& tiles); }; }