Explicitly bind TileCachedRecastMeshManager with mutex

This commit is contained in:
elsid 2022-02-03 22:24:26 +01:00
parent 3caeda7299
commit 0b644a897e
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
2 changed files with 54 additions and 49 deletions

View file

@ -43,7 +43,7 @@ namespace DetourNavigator
if (mBounds != infiniteTileBounds) if (mBounds != infiniteTileBounds)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
for (auto& object : mObjects) for (auto& object : mObjects)
{ {
const ObjectId id = object.first; const ObjectId id = object.first;
@ -58,7 +58,7 @@ namespace DetourNavigator
if (it == data.mTiles.end()) if (it == data.mTiles.end())
return; return;
data.mTiles.erase(it); data.mTiles.erase(it);
if (removeTile(id, position, mTiles)) if (removeTile(id, position, locked->mTiles))
changedTiles.emplace_back(position, ChangeType::remove); changedTiles.emplace_back(position, ChangeType::remove);
}; };
getTilesPositions(getIntersection(mRange, objectRange), onOldTilePosition); getTilesPositions(getIntersection(mRange, objectRange), onOldTilePosition);
@ -67,7 +67,7 @@ namespace DetourNavigator
{ {
if (data.mTiles.find(position) != data.mTiles.end()) if (data.mTiles.find(position) != data.mTiles.end())
return; return;
if (addTile(id, data.mShape, data.mTransform, data.mAreaType, position, mTiles)) if (addTile(id, data.mShape, data.mTransform, data.mAreaType, position, locked->mTiles))
{ {
data.mTiles.insert(position); data.mTiles.insert(position);
changedTiles.emplace_back(position, ChangeType::add); changedTiles.emplace_back(position, ChangeType::add);
@ -91,17 +91,16 @@ namespace DetourNavigator
std::string TileCachedRecastMeshManager::getWorldspace() const std::string TileCachedRecastMeshManager::getWorldspace() const
{ {
const std::lock_guard lock(mMutex); return mWorldspaceTiles.lockConst()->mWorldspace;
return mWorldspace;
} }
void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace) void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
if (mWorldspace == worldspace) if (locked->mWorldspace == worldspace)
return; return;
mTiles.clear(); locked->mTiles.clear();
mWorldspace = worldspace; locked->mWorldspace = worldspace;
} }
std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeObject(const ObjectId id) std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeObject(const ObjectId id)
@ -111,10 +110,10 @@ namespace DetourNavigator
return std::nullopt; return std::nullopt;
std::optional<RemovedRecastMeshObject> result; std::optional<RemovedRecastMeshObject> result;
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
for (const auto& tilePosition : object->second.mTiles) for (const auto& tilePosition : object->second.mTiles)
{ {
const auto removed = removeTile(id, tilePosition, mTiles); const auto removed = removeTile(id, tilePosition, locked->mTiles);
if (removed && !result) if (removed && !result)
result = removed; result = removed;
} }
@ -138,8 +137,8 @@ namespace DetourNavigator
if (cellSize == std::numeric_limits<int>::max()) if (cellSize == std::numeric_limits<int>::max())
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
for (auto& tile : mTiles) for (auto& tile : locked->mTiles)
{ {
if (tile.second->addWater(cellPosition, cellSize, level)) if (tile.second->addWater(cellPosition, cellSize, level))
{ {
@ -154,12 +153,12 @@ namespace DetourNavigator
getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings),
[&] (const TilePosition& tilePosition) [&] (const TilePosition& tilePosition)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
auto tile = mTiles.find(tilePosition); auto tile = locked->mTiles.find(tilePosition);
if (tile == mTiles.end()) if (tile == locked->mTiles.end())
{ {
const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition);
tile = mTiles.emplace_hint(tile, tilePosition, tile = locked->mTiles.emplace_hint(tile, tilePosition,
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)); std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration));
} }
if (tile->second->addWater(cellPosition, cellSize, level)) if (tile->second->addWater(cellPosition, cellSize, level))
@ -184,14 +183,14 @@ namespace DetourNavigator
std::optional<Water> result; std::optional<Water> result;
for (const auto& tilePosition : object->second) for (const auto& tilePosition : object->second)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
const auto tile = mTiles.find(tilePosition); const auto tile = locked->mTiles.find(tilePosition);
if (tile == mTiles.end()) if (tile == locked->mTiles.end())
continue; continue;
const auto tileResult = tile->second->removeWater(cellPosition); const auto tileResult = tile->second->removeWater(cellPosition);
if (tile->second->isEmpty()) if (tile->second->isEmpty())
{ {
mTiles.erase(tile); locked->mTiles.erase(tile);
++mTilesGeneration; ++mTilesGeneration;
} }
if (tileResult && !result) if (tileResult && !result)
@ -219,12 +218,12 @@ namespace DetourNavigator
getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings),
[&] (const TilePosition& tilePosition) [&] (const TilePosition& tilePosition)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
auto tile = mTiles.find(tilePosition); auto tile = locked->mTiles.find(tilePosition);
if (tile == mTiles.end()) if (tile == locked->mTiles.end())
{ {
const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition);
tile = mTiles.emplace_hint(tile, tilePosition, tile = locked->mTiles.emplace_hint(tile, tilePosition,
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)); std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration));
} }
if (tile->second->addHeightfield(cellPosition, cellSize, shape)) if (tile->second->addHeightfield(cellPosition, cellSize, shape))
@ -248,14 +247,14 @@ namespace DetourNavigator
std::optional<SizedHeightfieldShape> result; std::optional<SizedHeightfieldShape> result;
for (const auto& tilePosition : object->second) for (const auto& tilePosition : object->second)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
const auto tile = mTiles.find(tilePosition); const auto tile = locked->mTiles.find(tilePosition);
if (tile == mTiles.end()) if (tile == locked->mTiles.end())
continue; continue;
const auto tileResult = tile->second->removeHeightfield(cellPosition); const auto tileResult = tile->second->removeHeightfield(cellPosition);
if (tile->second->isEmpty()) if (tile->second->isEmpty())
{ {
mTiles.erase(tile); locked->mTiles.erase(tile);
++mTilesGeneration; ++mTilesGeneration;
} }
if (tileResult && !result) if (tileResult && !result)
@ -295,9 +294,9 @@ namespace DetourNavigator
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lockConst();
const auto it = mTiles.find(tilePosition); const auto it = locked->mTiles.find(tilePosition);
if (it == mTiles.end()) if (it == locked->mTiles.end())
return; return;
it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion); it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion);
} }
@ -341,11 +340,11 @@ namespace DetourNavigator
std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(std::string_view worldspace, std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(std::string_view worldspace,
const TilePosition& tilePosition) const const TilePosition& tilePosition) const
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lockConst();
if (mWorldspace != worldspace) if (locked->mWorldspace != worldspace)
return nullptr; return nullptr;
const auto it = mTiles.find(tilePosition); const auto it = locked->mTiles.find(tilePosition);
if (it == mTiles.end()) if (it == locked->mTiles.end())
return nullptr; return nullptr;
return it->second; return it->second;
} }

View file

@ -9,6 +9,8 @@
#include "heightfieldshape.hpp" #include "heightfieldshape.hpp"
#include "changetype.hpp" #include "changetype.hpp"
#include <components/misc/guarded.hpp>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -42,11 +44,11 @@ namespace DetourNavigator
std::set<TilePosition> tilesPositions; std::set<TilePosition> tilesPositions;
if (range.mBegin != range.mEnd) if (range.mBegin != range.mEnd)
{ {
const std::lock_guard lock(mMutex); const auto locked = mWorldspaceTiles.lock();
getTilesPositions(range, getTilesPositions(range,
[&] (const TilePosition& tilePosition) [&] (const TilePosition& tilePosition)
{ {
if (addTile(id, shape, transform, areaType, tilePosition, mTiles)) if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
tilesPositions.insert(tilePosition); tilesPositions.insert(tilePosition);
}); });
} }
@ -67,31 +69,31 @@ namespace DetourNavigator
bool changed = false; bool changed = false;
std::set<TilePosition> newTiles; std::set<TilePosition> newTiles;
{ {
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
const TilesPositionsRange range = getIntersection(mRange, objectRange);
const auto locked = mWorldspaceTiles.lock();
const auto onTilePosition = [&] (const TilePosition& tilePosition) const auto onTilePosition = [&] (const TilePosition& tilePosition)
{ {
if (data.mTiles.find(tilePosition) != data.mTiles.end()) if (data.mTiles.find(tilePosition) != data.mTiles.end())
{ {
newTiles.insert(tilePosition); newTiles.insert(tilePosition);
if (updateTile(id, transform, areaType, tilePosition, mTiles)) if (updateTile(id, transform, areaType, tilePosition, locked->mTiles))
{ {
onChangedTile(tilePosition, ChangeType::update); onChangedTile(tilePosition, ChangeType::update);
changed = true; changed = true;
} }
} }
else if (addTile(id, shape, transform, areaType, tilePosition, mTiles)) else if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
{ {
newTiles.insert(tilePosition); newTiles.insert(tilePosition);
onChangedTile(tilePosition, ChangeType::add); onChangedTile(tilePosition, ChangeType::add);
changed = true; changed = true;
} }
}; };
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
const TilesPositionsRange range = getIntersection(mRange, objectRange);
const std::lock_guard lock(mMutex);
getTilesPositions(range, onTilePosition); getTilesPositions(range, onTilePosition);
for (const auto& tile : data.mTiles) for (const auto& tile : data.mTiles)
{ {
if (newTiles.find(tile) == newTiles.end() && removeTile(id, tile, mTiles)) if (newTiles.find(tile) == newTiles.end() && removeTile(id, tile, locked->mTiles))
{ {
onChangedTile(tile, ChangeType::remove); onChangedTile(tile, ChangeType::remove);
changed = true; changed = true;
@ -125,8 +127,8 @@ namespace DetourNavigator
template <class Function> template <class Function>
void forEachTile(Function&& function) const void forEachTile(Function&& function) const
{ {
const std::lock_guard lock(mMutex); const auto& locked = mWorldspaceTiles.lockConst();
for (auto& [tilePosition, recastMeshManager] : mTiles) for (const auto& [tilePosition, recastMeshManager] : locked->mTiles)
function(tilePosition, *recastMeshManager); function(tilePosition, *recastMeshManager);
} }
@ -145,12 +147,16 @@ namespace DetourNavigator
std::set<TilePosition> mTiles; std::set<TilePosition> mTiles;
}; };
struct WorldspaceTiles
{
std::string mWorldspace;
TilesMap mTiles;
};
const RecastSettings& mSettings; const RecastSettings& mSettings;
mutable std::mutex mMutex;
TileBounds mBounds; TileBounds mBounds;
TilesPositionsRange mRange; TilesPositionsRange mRange;
std::string mWorldspace; Misc::ScopeGuarded<WorldspaceTiles> mWorldspaceTiles;
TilesMap mTiles;
std::unordered_map<ObjectId, ObjectData> mObjects; std::unordered_map<ObjectId, ObjectData> mObjects;
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions; std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
std::map<osg::Vec2i, std::vector<TilePosition>> mHeightfieldTilesPositions; std::map<osg::Vec2i, std::vector<TilePosition>> mHeightfieldTilesPositions;