Limit RecastMeshManager range by active cell grid

esm4-texture
elsid 7 months ago
parent 49db37ee29
commit 45d62ee59f
No known key found for this signature in database
GPG Key ID: 4DE04C198CBA7625

@ -572,11 +572,11 @@ namespace MWWorld
void Scene::changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellLocation playerCellIndex, bool changeEvent) void Scene::changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellLocation playerCellIndex, bool changeEvent)
{ {
mHalfGridSize const int halfGridSize
= isEsm4Ext(playerCellIndex.mWorldspace) ? Constants::ESM4CellGridRadius : Constants::CellGridRadius; = isEsm4Ext(playerCellIndex.mWorldspace) ? Constants::ESM4CellGridRadius : Constants::CellGridRadius;
auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); auto navigatorUpdateGuard = mNavigator.makeUpdateGuard();
int playerCellX = playerCellIndex.mX; const int playerCellX = playerCellIndex.mX;
int playerCellY = playerCellIndex.mY; const int playerCellY = playerCellIndex.mY;
for (auto iter = mActiveCells.begin(); iter != mActiveCells.end();) for (auto iter = mActiveCells.begin(); iter != mActiveCells.end();)
{ {
@ -585,15 +585,21 @@ namespace MWWorld
{ {
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX()); const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY()); const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
if (dx > mHalfGridSize || dy > mHalfGridSize) if (dx > halfGridSize || dy > halfGridSize)
unloadCell(cell, navigatorUpdateGuard.get()); unloadCell(cell, navigatorUpdateGuard.get());
} }
else else
unloadCell(cell, navigatorUpdateGuard.get()); unloadCell(cell, navigatorUpdateGuard.get());
} }
mNavigator.updateBounds(playerCellIndex.mWorldspace, pos, navigatorUpdateGuard.get()); const DetourNavigator::CellGridBounds cellGridBounds{
.mCenter = osg::Vec2i(playerCellX, playerCellY),
.mHalfSize = halfGridSize,
};
mNavigator.updateBounds(playerCellIndex.mWorldspace, cellGridBounds, pos, navigatorUpdateGuard.get());
mHalfGridSize = halfGridSize;
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter);
mRendering.setActiveGrid(newGrid); mRendering.setActiveGrid(newGrid);
@ -696,7 +702,16 @@ namespace MWWorld
ESM::ExteriorCellLocation(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId)); ESM::ExteriorCellLocation(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId));
const osg::Vec3f position const osg::Vec3f position
= osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits;
mNavigator.updateBounds(ESM::Cell::sDefaultWorldspaceId, position, navigatorUpdateGuard.get()); const osg::Vec2i cellPosition(it->mData.mX, it->mData.mY);
const DetourNavigator::CellGridBounds cellGridBounds{
.mCenter = osg::Vec2i(it->mData.mX, it->mData.mY),
.mHalfSize = Constants::CellGridRadius,
};
mNavigator.updateBounds(
ESM::Cell::sDefaultWorldspaceId, cellGridBounds, position, navigatorUpdateGuard.get());
loadCell(cell, nullptr, false, position, navigatorUpdateGuard.get()); loadCell(cell, nullptr, false, position, navigatorUpdateGuard.get());
mNavigator.update(position, navigatorUpdateGuard.get()); mNavigator.update(position, navigatorUpdateGuard.get());
@ -752,7 +767,8 @@ namespace MWWorld
CellStore& cell = mWorld.getWorldModel().getInterior(it->mName); CellStore& cell = mWorld.getWorldModel().getInterior(it->mName);
ESM::Position position; ESM::Position position;
mWorld.findInteriorPosition(it->mName, position); mWorld.findInteriorPosition(it->mName, position);
mNavigator.updateBounds(cell.getCell()->getWorldSpace(), position.asVec3(), navigatorUpdateGuard.get()); mNavigator.updateBounds(
cell.getCell()->getWorldSpace(), std::nullopt, position.asVec3(), navigatorUpdateGuard.get());
loadCell(cell, nullptr, false, position.asVec3(), navigatorUpdateGuard.get()); loadCell(cell, nullptr, false, position.asVec3(), navigatorUpdateGuard.get());
mNavigator.update(position.asVec3(), navigatorUpdateGuard.get()); mNavigator.update(position.asVec3(), navigatorUpdateGuard.get());
@ -902,7 +918,8 @@ namespace MWWorld
loadingListener->setProgressRange(cell.count()); loadingListener->setProgressRange(cell.count());
mNavigator.updateBounds(cell.getCell()->getWorldSpace(), position.asVec3(), navigatorUpdateGuard.get()); mNavigator.updateBounds(
cell.getCell()->getWorldSpace(), std::nullopt, position.asVec3(), navigatorUpdateGuard.get());
// Load cell. // Load cell.
mPagedRefs.clear(); mPagedRefs.clear();

@ -859,6 +859,17 @@ namespace
EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version);
} }
std::pair<TilePosition, TilePosition> getMinMax(const RecastMeshTiles& tiles)
{
const auto lessByX = [](const auto& l, const auto& r) { return l.first.x() < r.first.x(); };
const auto lessByY = [](const auto& l, const auto& r) { return l.first.y() < r.first.y(); };
const auto [minX, maxX] = std::ranges::minmax_element(tiles, lessByX);
const auto [minY, maxY] = std::ranges::minmax_element(tiles, lessByY);
return { TilePosition(minX->first.x(), minY->first.y()), TilePosition(maxX->first.x(), maxY->first.y()) };
}
TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited) TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited)
{ {
const float size = static_cast<float>((1 << 22) - 1); const float size = static_cast<float>((1 << 22) - 1);
@ -867,8 +878,10 @@ namespace
.mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } }, .mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } },
.mScale = 1.0f, .mScale = 1.0f,
}; };
const std::optional<CellGridBounds> cellGridBounds = std::nullopt;
const osg::Vec3f playerPosition(32, 1024, 0);
mNavigator->updateBounds(mWorldspace, mPlayerPosition, nullptr); mNavigator->updateBounds(mWorldspace, cellGridBounds, playerPosition, nullptr);
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform), mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform),
btTransform::getIdentity(), nullptr); btTransform::getIdentity(), nullptr);
@ -878,7 +891,61 @@ namespace
std::mutex mutex; std::mutex mutex;
std::thread thread([&] { std::thread thread([&] {
mNavigator->update(mPlayerPosition, nullptr); auto guard = mNavigator->makeUpdateGuard();
mNavigator->update(playerPosition, guard.get());
std::lock_guard lock(mutex);
updated = true;
updateFinished.notify_all();
});
{
std::unique_lock lock(mutex);
updateFinished.wait_for(lock, std::chrono::seconds(10), [&] { return updated; });
ASSERT_TRUE(updated);
}
thread.join();
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
const auto recastMeshTiles = mNavigator->getRecastMeshTiles();
ASSERT_EQ(recastMeshTiles.size(), 1033);
EXPECT_EQ(getMinMax(recastMeshTiles), std::pair(TilePosition(-18, -17), TilePosition(18, 19)));
const auto navMesh = mNavigator->getNavMesh(mAgentBounds);
ASSERT_NE(navMesh, nullptr);
std::size_t usedNavMeshTiles = 0;
navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; });
EXPECT_EQ(usedNavMeshTiles, 1024);
}
TEST_F(DetourNavigatorNavigatorTest, update_should_be_limited_by_cell_grid_bounds)
{
const float size = static_cast<float>((1 << 22) - 1);
CollisionShapeInstance bigBox(std::make_unique<btBoxShape>(btVector3(size, size, 1)));
const ObjectTransform objectTransform{
.mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } },
.mScale = 1.0f,
};
const CellGridBounds cellGridBounds{
.mCenter = osg::Vec2i(0, 0),
.mHalfSize = 1,
};
const osg::Vec3f playerPosition(32, 1024, 0);
mNavigator->updateBounds(mWorldspace, cellGridBounds, playerPosition, nullptr);
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform),
btTransform::getIdentity(), nullptr);
bool updated = false;
std::condition_variable updateFinished;
std::mutex mutex;
std::thread thread([&] {
auto guard = mNavigator->makeUpdateGuard();
mNavigator->update(playerPosition, guard.get());
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
updated = true; updated = true;
updateFinished.notify_all(); updateFinished.notify_all();
@ -886,7 +953,7 @@ namespace
{ {
std::unique_lock lock(mutex); std::unique_lock lock(mutex);
updateFinished.wait_for(lock, std::chrono::seconds(3), [&] { return updated; }); updateFinished.wait_for(lock, std::chrono::seconds(10), [&] { return updated; });
ASSERT_TRUE(updated); ASSERT_TRUE(updated);
} }
@ -894,14 +961,16 @@ namespace
mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_EQ(mNavigator->getRecastMeshTiles().size(), 509); const auto recastMeshTiles = mNavigator->getRecastMeshTiles();
ASSERT_EQ(recastMeshTiles.size(), 854);
EXPECT_EQ(getMinMax(recastMeshTiles), std::pair(TilePosition(-12, -12), TilePosition(18, 19)));
const auto navMesh = mNavigator->getNavMesh(mAgentBounds); const auto navMesh = mNavigator->getNavMesh(mAgentBounds);
ASSERT_NE(navMesh, nullptr); ASSERT_NE(navMesh, nullptr);
std::size_t usedNavMeshTiles = 0; std::size_t usedNavMeshTiles = 0;
navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; }); navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; });
EXPECT_EQ(usedNavMeshTiles, 509); EXPECT_EQ(usedNavMeshTiles, 854);
} }
struct DetourNavigatorNavigatorNotSupportedAgentBoundsTest : TestWithParam<AgentBounds> struct DetourNavigatorNavigatorNotSupportedAgentBoundsTest : TestWithParam<AgentBounds>

@ -39,7 +39,7 @@ namespace DetourNavigator
result.mDetour.mMaxPolygonPathSize = 1024; result.mDetour.mMaxPolygonPathSize = 1024;
result.mDetour.mMaxSmoothPathSize = 1024; result.mDetour.mMaxSmoothPathSize = 1024;
result.mDetour.mMaxPolys = 4096; result.mDetour.mMaxPolys = 4096;
result.mMaxTilesNumber = 512; result.mMaxTilesNumber = 1024;
result.mMinUpdateInterval = std::chrono::milliseconds(50); result.mMinUpdateInterval = std::chrono::milliseconds(50);
result.mWriteToNavMeshDb = true; result.mWriteToNavMeshDb = true;
return result; return result;

@ -173,7 +173,7 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const TilesPositionsRange range{ const TilesPositionsRange range{
.mBegin = TilePosition(-1, -1), .mBegin = TilePosition(-1, -1),
.mEnd = TilePosition(1, 1), .mEnd = TilePosition(2, 2),
}; };
manager.setRange(range, nullptr); manager.setRange(range, nullptr);
manager.setWorldspace(mWorldspace, nullptr); manager.setWorldspace(mWorldspace, nullptr);

@ -0,0 +1,15 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_CELLGRIDBOUNDS_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_CELLGRIDBOUNDS_H
#include <osg/Vec2i>
namespace DetourNavigator
{
struct CellGridBounds
{
osg::Vec2i mCenter;
int mHalfSize;
};
}
#endif

@ -3,7 +3,9 @@
#include <cassert> #include <cassert>
#include <filesystem> #include <filesystem>
#include <optional>
#include "cellgridbounds.hpp"
#include "heightfieldshape.hpp" #include "heightfieldshape.hpp"
#include "objectid.hpp" #include "objectid.hpp"
#include "objecttransform.hpp" #include "objecttransform.hpp"
@ -89,7 +91,8 @@ namespace DetourNavigator
virtual void removeAgent(const AgentBounds& agentBounds) = 0; virtual void removeAgent(const AgentBounds& agentBounds) = 0;
// Updates bounds for recast mesh and navmesh tiles, removes tiles outside the range. // Updates bounds for recast mesh and navmesh tiles, removes tiles outside the range.
virtual void updateBounds(ESM::RefId worldspace, const osg::Vec3f& playerPosition, const UpdateGuard* guard) virtual void updateBounds(ESM::RefId worldspace, const std::optional<CellGridBounds>& cellGridBounds,
const osg::Vec3f& playerPosition, const UpdateGuard* guard)
= 0; = 0;
/** /**

@ -33,9 +33,10 @@ namespace DetourNavigator
--it->second; --it->second;
} }
void NavigatorImpl::updateBounds(ESM::RefId worldspace, const osg::Vec3f& playerPosition, const UpdateGuard* guard) void NavigatorImpl::updateBounds(ESM::RefId worldspace, const std::optional<CellGridBounds>& cellGridBounds,
const osg::Vec3f& playerPosition, const UpdateGuard* guard)
{ {
mNavMeshManager.updateBounds(worldspace, playerPosition, guard); mNavMeshManager.updateBounds(worldspace, cellGridBounds, playerPosition, guard);
} }
void NavigatorImpl::addObject( void NavigatorImpl::addObject(

@ -27,7 +27,8 @@ namespace DetourNavigator
void removeAgent(const AgentBounds& agentBounds) override; void removeAgent(const AgentBounds& agentBounds) override;
void updateBounds(ESM::RefId worldspace, const osg::Vec3f& playerPosition, const UpdateGuard* guard) override; void updateBounds(ESM::RefId worldspace, const std::optional<CellGridBounds>& cellGridBounds,
const osg::Vec3f& playerPosition, const UpdateGuard* guard) override;
void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform,
const UpdateGuard* guard) override; const UpdateGuard* guard) override;

@ -24,8 +24,8 @@ namespace DetourNavigator
void removeAgent(const AgentBounds& /*agentBounds*/) override {} void removeAgent(const AgentBounds& /*agentBounds*/) override {}
void updateBounds( void updateBounds(ESM::RefId /*worldspace*/, const std::optional<CellGridBounds>& /*cellGridBounds*/,
ESM::RefId /*worldspace*/, const osg::Vec3f& /*playerPosition*/, const UpdateGuard* /*guard*/) override const osg::Vec3f& /*playerPosition*/, const UpdateGuard* /*guard*/) override
{ {
} }

@ -1,4 +1,5 @@
#include "navmeshmanager.hpp" #include "navmeshmanager.hpp"
#include "debug.hpp" #include "debug.hpp"
#include "gettilespositions.hpp" #include "gettilespositions.hpp"
#include "makenavmesh.hpp" #include "makenavmesh.hpp"
@ -8,6 +9,7 @@
#include "waitconditiontype.hpp" #include "waitconditiontype.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/esm/util.hpp>
#include <osg/io_utils> #include <osg/io_utils>
@ -35,15 +37,46 @@ namespace DetourNavigator
{ {
namespace namespace
{ {
TilesPositionsRange makeRange(const TilePosition& center, int maxTiles) int getMaxRadius(int maxTiles)
{
return static_cast<int>(std::ceil(std::sqrt(static_cast<float>(maxTiles) / osg::PIf) + 1));
}
TilesPositionsRange makeRange(const TilePosition& center, int radius)
{ {
const int radius = static_cast<int>(std::ceil(std::sqrt(static_cast<float>(maxTiles) / osg::PIf) + 1));
return TilesPositionsRange{ return TilesPositionsRange{
.mBegin = center - TilePosition(radius, radius), .mBegin = center - TilePosition(radius, radius),
.mEnd = center + TilePosition(radius + 1, radius + 1), .mEnd = center + TilePosition(radius + 1, radius + 1),
}; };
} }
osg::Vec2f getMinCellGridPosition(const osg::Vec2i& center, int offset, float cellSize)
{
const osg::Vec2i cell = center + osg::Vec2i(offset, offset);
return osg::Vec2f(static_cast<float>(cell.x()) * cellSize, static_cast<float>(cell.y()) * cellSize);
}
TilesPositionsRange makeCellGridRange(
const RecastSettings& settings, ESM::RefId worldspace, const CellGridBounds& bounds)
{
const float floatCellSize = static_cast<float>(ESM::getCellSize(worldspace));
const osg::Vec2f min = getMinCellGridPosition(bounds.mCenter, -bounds.mHalfSize, floatCellSize);
const osg::Vec2f max = getMinCellGridPosition(bounds.mCenter, bounds.mHalfSize + 1, floatCellSize);
return TilesPositionsRange{
.mBegin = getTilePosition(settings, toNavMeshCoordinates(settings, min)),
.mEnd = getTilePosition(settings, toNavMeshCoordinates(settings, max)),
};
}
TilesPositionsRange makeRange(const Settings& settings, ESM::RefId worldspace,
const std::optional<CellGridBounds>& bounds, int radius, const TilePosition& center)
{
TilesPositionsRange result = makeRange(center, radius);
if (bounds.has_value())
result = getIntersection(result, makeCellGridRange(settings.mRecast, worldspace, *bounds));
return result;
}
TilePosition toNavMeshTilePosition(const RecastSettings& settings, const osg::Vec3f& position) TilePosition toNavMeshTilePosition(const RecastSettings& settings, const osg::Vec3f& position)
{ {
return getTilePosition(settings, toNavMeshCoordinates(settings, position)); return getTilePosition(settings, toNavMeshCoordinates(settings, position));
@ -52,13 +85,15 @@ namespace DetourNavigator
NavMeshManager::NavMeshManager(const Settings& settings, std::unique_ptr<NavMeshDb>&& db) NavMeshManager::NavMeshManager(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
: mSettings(settings) : mSettings(settings)
, mMaxRadius(getMaxRadius(settings.mMaxTilesNumber))
, mRecastMeshManager(settings.mRecast) , mRecastMeshManager(settings.mRecast)
, mOffMeshConnectionsManager(settings.mRecast) , mOffMeshConnectionsManager(settings.mRecast)
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db)) , mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db))
{ {
} }
void NavMeshManager::updateBounds(ESM::RefId worldspace, const osg::Vec3f& playerPosition, const UpdateGuard* guard) void NavMeshManager::updateBounds(ESM::RefId worldspace, const std::optional<CellGridBounds>& cellGridBounds,
const osg::Vec3f& playerPosition, const UpdateGuard* guard)
{ {
if (worldspace != mWorldspace) if (worldspace != mWorldspace)
{ {
@ -69,8 +104,9 @@ namespace DetourNavigator
} }
const TilePosition playerTile = toNavMeshTilePosition(mSettings.mRecast, playerPosition); const TilePosition playerTile = toNavMeshTilePosition(mSettings.mRecast, playerPosition);
const TilesPositionsRange range = makeRange(playerTile, mSettings.mMaxTilesNumber);
mRecastMeshManager.setRange(range, guard); mRecastMeshManager.setRange(makeRange(mSettings, worldspace, cellGridBounds, mMaxRadius, playerTile), guard);
mCellGridBounds = cellGridBounds;
} }
bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
@ -162,7 +198,7 @@ namespace DetourNavigator
return; return;
mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision(); mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision();
mPlayerTile = playerTile; mPlayerTile = playerTile;
mRecastMeshManager.setRange(makeRange(playerTile, mSettings.mMaxTilesNumber), guard); mRecastMeshManager.setRange(makeRange(mSettings, mWorldspace, mCellGridBounds, mMaxRadius, playerTile), guard);
const auto changedTiles = mRecastMeshManager.takeChangedTiles(guard); const auto changedTiles = mRecastMeshManager.takeChangedTiles(guard);
const TilesPositionsRange range = mRecastMeshManager.getLimitedObjectsRange(); const TilesPositionsRange range = mRecastMeshManager.getLimitedObjectsRange();
for (const auto& [agentBounds, cached] : mCache) for (const auto& [agentBounds, cached] : mCache)

@ -3,6 +3,7 @@
#include "agentbounds.hpp" #include "agentbounds.hpp"
#include "asyncnavmeshupdater.hpp" #include "asyncnavmeshupdater.hpp"
#include "cellgridbounds.hpp"
#include "heightfieldshape.hpp" #include "heightfieldshape.hpp"
#include "offmeshconnectionsmanager.hpp" #include "offmeshconnectionsmanager.hpp"
#include "recastmeshtiles.hpp" #include "recastmeshtiles.hpp"
@ -24,7 +25,8 @@ namespace DetourNavigator
ScopedUpdateGuard makeUpdateGuard() { return mRecastMeshManager.makeUpdateGuard(); } ScopedUpdateGuard makeUpdateGuard() { return mRecastMeshManager.makeUpdateGuard(); }
void updateBounds(ESM::RefId worldspace, const osg::Vec3f& playerPosition, const UpdateGuard* guard); void updateBounds(ESM::RefId worldspace, const std::optional<CellGridBounds>& cellGridBounds,
const osg::Vec3f& playerPosition, const UpdateGuard* guard);
bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
const AreaType areaType, const UpdateGuard* guard); const AreaType areaType, const UpdateGuard* guard);
@ -65,7 +67,9 @@ namespace DetourNavigator
private: private:
const Settings& mSettings; const Settings& mSettings;
const int mMaxRadius;
ESM::RefId mWorldspace; ESM::RefId mWorldspace;
std::optional<CellGridBounds> mCellGridBounds;
TileCachedRecastMeshManager mRecastMeshManager; TileCachedRecastMeshManager mRecastMeshManager;
OffMeshConnectionsManager mOffMeshConnectionsManager; OffMeshConnectionsManager mOffMeshConnectionsManager;
AsyncNavMeshUpdater mAsyncNavMeshUpdater; AsyncNavMeshUpdater mAsyncNavMeshUpdater;

@ -107,11 +107,10 @@ namespace DetourNavigator
}); });
} }
if (changed)
{
const MaybeLockGuard lock(mMutex, guard); const MaybeLockGuard lock(mMutex, guard);
if (changed)
++mRevision; ++mRevision;
}
mRange = range; mRange = range;
} }
@ -357,6 +356,8 @@ namespace DetourNavigator
const std::lock_guard lock(mMutex); const std::lock_guard lock(mMutex);
if (mWorldspace != worldspace) if (mWorldspace != worldspace)
return nullptr; return nullptr;
if (!isInTilesPositionsRange(mRange, tilePosition))
return nullptr;
const auto it = mCache.find(tilePosition); const auto it = mCache.find(tilePosition);
if (it != mCache.end() && it->second.mRecastMesh->getVersion() == it->second.mVersion) if (it != mCache.end() && it->second.mRecastMesh->getVersion() == it->second.mVersion)
return it->second.mRecastMesh; return it->second.mRecastMesh;
@ -380,6 +381,8 @@ namespace DetourNavigator
const std::lock_guard lock(mMutex); const std::lock_guard lock(mMutex);
if (mWorldspace != worldspace) if (mWorldspace != worldspace)
return nullptr; return nullptr;
if (!isInTilesPositionsRange(mRange, tilePosition))
return nullptr;
const auto it = mCache.find(tilePosition); const auto it = mCache.find(tilePosition);
if (it == mCache.end()) if (it == mCache.end())
return nullptr; return nullptr;

Loading…
Cancel
Save