mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Read navmesh tile data from database
When tile is not found in memory cache try to find it in the database.
This commit is contained in:
parent
953a4c5550
commit
c9b8ba7b46
32 changed files with 424 additions and 157 deletions
|
@ -264,6 +264,7 @@ namespace NavMeshTool
|
|||
{
|
||||
it = navMeshInputs.emplace(cell.mCellId.mWorldspace,
|
||||
std::make_unique<WorldspaceNavMeshInput>(cell.mCellId.mWorldspace, settings.mRecast)).first;
|
||||
it->second->mTileCachedRecastMeshManager.setWorldspace(cell.mCellId.mWorldspace);
|
||||
}
|
||||
return *it->second;
|
||||
} ();
|
||||
|
|
|
@ -788,7 +788,7 @@ namespace MWMechanics
|
|||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
world->getNavigator()->setUpdatesEnabled(mAI);
|
||||
if (mAI)
|
||||
world->getNavigator()->update(world->getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
world->getNavigator()->update(world->getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
|
||||
return mAI;
|
||||
}
|
||||
|
|
|
@ -350,8 +350,7 @@ namespace MWWorld
|
|||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
mNavigator.removePathgrid(*pathgrid);
|
||||
|
||||
const auto player = world->getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
mNavigator.update(world->getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (cell);
|
||||
|
||||
|
@ -378,6 +377,8 @@ namespace MWWorld
|
|||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
|
||||
mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||
|
@ -507,10 +508,13 @@ namespace MWWorld
|
|||
|
||||
void Scene::playerMoved(const osg::Vec3f &pos)
|
||||
{
|
||||
if (mCurrentCell == nullptr)
|
||||
return;
|
||||
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mNavigator.updatePlayerPosition(player.getRefData().getPosition().asVec3());
|
||||
|
||||
if (!mCurrentCell || !mCurrentCell->isExterior())
|
||||
if (!mCurrentCell->isExterior())
|
||||
return;
|
||||
|
||||
osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter);
|
||||
|
@ -886,8 +890,11 @@ namespace MWWorld
|
|||
addObject(ptr, *mPhysics, mRendering, mPagedRefs);
|
||||
addObject(ptr, *mPhysics, mNavigator);
|
||||
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
if (mCurrentCell != nullptr)
|
||||
{
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -903,8 +910,11 @@ namespace MWWorld
|
|||
if (const auto object = mPhysics->getObject(ptr))
|
||||
{
|
||||
mNavigator.removeObject(DetourNavigator::ObjectId(object));
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
if (mCurrentCell != nullptr)
|
||||
{
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
}
|
||||
}
|
||||
else if (mPhysics->getActor(ptr))
|
||||
{
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace MWWorld
|
|||
{
|
||||
auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
||||
navigatorSettings.mRecast.mSwimHeightScale = mSwimHeightScale;
|
||||
mNavigator = DetourNavigator::makeNavigator(navigatorSettings);
|
||||
mNavigator = DetourNavigator::makeNavigator(navigatorSettings, userDataPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1524,9 +1524,10 @@ namespace MWWorld
|
|||
if (const auto object = mPhysics->getObject(door.first))
|
||||
updateNavigatorObject(*object);
|
||||
|
||||
if (mShouldUpdateNavigator)
|
||||
auto player = getPlayerPtr();
|
||||
if (mShouldUpdateNavigator && player.getCell() != nullptr)
|
||||
{
|
||||
mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
mNavigator->update(player.getRefData().getPosition().asVec3());
|
||||
mShouldUpdateNavigator = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <components/detournavigator/navigatorimpl.hpp>
|
||||
#include <components/detournavigator/exceptions.hpp>
|
||||
#include <components/detournavigator/navigatorutils.hpp>
|
||||
#include <components/detournavigator/navmeshdb.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/loadinglistener/loadinglistener.hpp>
|
||||
#include <components/esm/loadland.hpp>
|
||||
|
@ -37,6 +38,7 @@ namespace
|
|||
Settings mSettings;
|
||||
std::unique_ptr<Navigator> mNavigator;
|
||||
const osg::Vec3f mPlayerPosition;
|
||||
const std::string mWorldspace;
|
||||
const osg::Vec3f mAgentHalfExtents;
|
||||
osg::Vec3f mStart;
|
||||
osg::Vec3f mEnd;
|
||||
|
@ -53,6 +55,7 @@ namespace
|
|||
|
||||
DetourNavigatorNavigatorTest()
|
||||
: mPlayerPosition(256, 256, 0)
|
||||
, mWorldspace("sys::default")
|
||||
, mAgentHalfExtents(29, 29, 66)
|
||||
, mStart(52, 460, 1)
|
||||
, mEnd(460, 52, 1)
|
||||
|
@ -87,7 +90,7 @@ namespace
|
|||
mSettings.mDetour.mMaxPolys = 4096;
|
||||
mSettings.mMaxTilesNumber = 512;
|
||||
mSettings.mMinUpdateInterval = std::chrono::milliseconds(50);
|
||||
mNavigator.reset(new NavigatorImpl(mSettings));
|
||||
mNavigator.reset(new NavigatorImpl(mSettings, std::make_unique<NavMeshDb>(":memory:")));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -854,7 +857,7 @@ namespace
|
|||
TEST_F(DetourNavigatorNavigatorTest, multiple_threads_should_lock_tiles)
|
||||
{
|
||||
mSettings.mAsyncNavMeshUpdaterThreads = 2;
|
||||
mNavigator.reset(new NavigatorImpl(mSettings));
|
||||
mNavigator.reset(new NavigatorImpl(mSettings, std::make_unique<NavMeshDb>(":memory:")));
|
||||
|
||||
const std::array<float, 5 * 5> heightfieldData {{
|
||||
0, 0, 0, 0, 0,
|
||||
|
|
|
@ -24,14 +24,6 @@ namespace
|
|||
using namespace DetourNavigator;
|
||||
using namespace DetourNavigator::Tests;
|
||||
|
||||
void* permRecastAlloc(int size)
|
||||
{
|
||||
void* result = rcAlloc(static_cast<std::size_t>(size), RC_ALLOC_PERM);
|
||||
if (result == nullptr)
|
||||
throw std::bad_alloc();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Random>
|
||||
void generateRecastArray(T*& values, int size, Random& random)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_empty_should_return_nullptr)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_for_empty_should_return_zero)
|
||||
|
@ -75,12 +75,13 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||
for (int x = -1; x < 1; ++x)
|
||||
for (int y = -1; y < 1; ++y)
|
||||
ASSERT_NE(manager.getMesh(TilePosition(x, y)), nullptr);
|
||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_changed_object_should_return_changed_tiles)
|
||||
|
@ -113,90 +114,98 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_nullptr_for_unused_tile)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_moved_object_should_return_recast_mesh_for_each_used_tile)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
|
||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
||||
|
||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_moved_object_should_return_nullptr_for_unused_tile)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
|
||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
|
||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(1, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_removed_object_should_return_nullptr_for_all_previously_used_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||
manager.removeObject(ObjectId(&boxShape));
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_not_changed_object_after_update_should_return_recast_mesh_for_same_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
|
||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
|
||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_add_object_new_should_return_incremented_value)
|
||||
|
@ -235,6 +244,7 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_update_not_changed_object_should_return_same_value)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||
|
@ -273,17 +283,19 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_not_max_int_should_add_new_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 8192;
|
||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
||||
for (int x = -1; x < 12; ++x)
|
||||
for (int y = -1; y < 12; ++y)
|
||||
ASSERT_NE(manager.getMesh(TilePosition(x, y)), nullptr);
|
||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_max_int_should_not_add_new_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||
|
@ -292,7 +304,7 @@ namespace
|
|||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
||||
for (int x = -6; x < 6; ++x)
|
||||
for (int y = -6; y < 6; ++y)
|
||||
ASSERT_EQ(manager.getMesh(TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_absent_cell_should_return_nullopt)
|
||||
|
@ -315,18 +327,20 @@ namespace
|
|||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_remove_empty_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 8192;
|
||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
||||
ASSERT_TRUE(manager.removeWater(cellPosition));
|
||||
for (int x = -6; x < 6; ++x)
|
||||
for (int y = -6; y < 6; ++y)
|
||||
ASSERT_EQ(manager.getMesh(TilePosition(x, y)), nullptr);
|
||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_leave_not_empty_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||
|
@ -336,12 +350,13 @@ namespace
|
|||
ASSERT_TRUE(manager.removeWater(cellPosition));
|
||||
for (int x = -6; x < 6; ++x)
|
||||
for (int y = -6; y < 6; ++y)
|
||||
ASSERT_EQ(manager.getMesh(TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_object_should_not_remove_tile_with_water)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const osg::Vec2i cellPosition(0, 0);
|
||||
const int cellSize = 8192;
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
|
@ -351,6 +366,19 @@ namespace
|
|||
ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape)));
|
||||
for (int x = -1; x < 12; ++x)
|
||||
for (int y = -1; y < 12; ++y)
|
||||
ASSERT_NE(manager.getMesh(TilePosition(x, y)), nullptr);
|
||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, set_new_worldspace_should_remove_tiles)
|
||||
{
|
||||
TileCachedRecastMeshManager manager(mSettings);
|
||||
manager.setWorldspace("worldspace");
|
||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||
const CollisionShape shape(nullptr, boxShape, mObjectTransform);
|
||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||
manager.setWorldspace("other");
|
||||
for (int x = -1; x < 1; ++x)
|
||||
for (int y = -1; y < 1; ++y)
|
||||
ASSERT_EQ(manager.getMesh("other", TilePosition(x, y)), nullptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,6 +207,7 @@ add_component_dir(detournavigator
|
|||
navmeshdb
|
||||
serialization
|
||||
navmeshdbutils
|
||||
recast
|
||||
)
|
||||
|
||||
add_component_dir(loadinglistener
|
||||
|
|
|
@ -76,10 +76,11 @@ namespace
|
|||
namespace DetourNavigator
|
||||
{
|
||||
Job::Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::chrono::steady_clock::time_point processTime)
|
||||
: mAgentHalfExtents(agentHalfExtents)
|
||||
, mNavMeshCacheItem(std::move(navMeshCacheItem))
|
||||
, mWorldspace(worldspace)
|
||||
, mChangedTile(changedTile)
|
||||
, mProcessTime(processTime)
|
||||
, mChangeType(changeType)
|
||||
|
@ -89,10 +90,11 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
|
||||
OffMeshConnectionsManager& offMeshConnectionsManager)
|
||||
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db)
|
||||
: mSettings(settings)
|
||||
, mRecastMeshManager(recastMeshManager)
|
||||
, mOffMeshConnectionsManager(offMeshConnectionsManager)
|
||||
, mDb(std::move(db))
|
||||
, mShouldStop()
|
||||
, mNavMeshTilesCache(settings.mMaxNavMeshTilesCacheSize)
|
||||
{
|
||||
|
@ -111,8 +113,8 @@ namespace DetourNavigator
|
|||
thread.join();
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents,
|
||||
const SharedNavMeshCacheItem& navMeshCacheItem, const TilePosition& playerTile,
|
||||
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& navMeshCacheItem,
|
||||
const TilePosition& playerTile, std::string_view worldspace,
|
||||
const std::map<TilePosition, ChangeType>& changedTiles)
|
||||
{
|
||||
bool playerTileChanged = false;
|
||||
|
@ -147,8 +149,8 @@ namespace DetourNavigator
|
|||
? mLastUpdates[std::tie(agentHalfExtents, changedTile)] + mSettings.get().mMinUpdateInterval
|
||||
: std::chrono::steady_clock::time_point();
|
||||
|
||||
const JobIt it = mJobs.emplace(mJobs.end(), agentHalfExtents, navMeshCacheItem, changedTile,
|
||||
changeType, getManhattanDistance(changedTile, playerTile), processTime);
|
||||
const JobIt it = mJobs.emplace(mJobs.end(), agentHalfExtents, navMeshCacheItem, worldspace,
|
||||
changedTile, changeType, getManhattanDistance(changedTile, playerTile), processTime);
|
||||
|
||||
if (playerTileChanged)
|
||||
mWaiting.push_back(it);
|
||||
|
@ -302,12 +304,13 @@ namespace DetourNavigator
|
|||
if (!navMeshCacheItem)
|
||||
return true;
|
||||
|
||||
const auto recastMesh = mRecastMeshManager.get().getMesh(job.mChangedTile);
|
||||
const auto recastMesh = mRecastMeshManager.get().getMesh(job.mWorldspace, job.mChangedTile);
|
||||
const auto playerTile = *mPlayerTile.lockConst();
|
||||
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
||||
|
||||
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile,
|
||||
offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache, getUpdateType(job.mChangeType));
|
||||
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mWorldspace, job.mChangedTile,
|
||||
playerTile, offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache,
|
||||
getUpdateType(job.mChangeType), mDb, mNextShapeId);
|
||||
|
||||
if (recastMesh != nullptr)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "tileposition.hpp"
|
||||
#include "navmeshtilescache.hpp"
|
||||
#include "waitconditiontype.hpp"
|
||||
#include "navmeshdb.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
|
@ -57,6 +58,7 @@ namespace DetourNavigator
|
|||
{
|
||||
const osg::Vec3f mAgentHalfExtents;
|
||||
const std::weak_ptr<GuardedNavMeshCacheItem> mNavMeshCacheItem;
|
||||
const std::string mWorldspace;
|
||||
const TilePosition mChangedTile;
|
||||
const std::chrono::steady_clock::time_point mProcessTime;
|
||||
unsigned mTryNumber = 0;
|
||||
|
@ -65,7 +67,7 @@ namespace DetourNavigator
|
|||
const int mDistanceToOrigin;
|
||||
|
||||
Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::chrono::steady_clock::time_point processTime);
|
||||
};
|
||||
|
||||
|
@ -75,11 +77,12 @@ namespace DetourNavigator
|
|||
{
|
||||
public:
|
||||
AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
|
||||
OffMeshConnectionsManager& offMeshConnectionsManager);
|
||||
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db);
|
||||
~AsyncNavMeshUpdater();
|
||||
|
||||
void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem,
|
||||
const TilePosition& playerTile, const std::map<TilePosition, ChangeType>& changedTiles);
|
||||
const TilePosition& playerTile, std::string_view worldspace,
|
||||
const std::map<TilePosition, ChangeType>& changedTiles);
|
||||
|
||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType);
|
||||
|
||||
|
@ -89,6 +92,8 @@ namespace DetourNavigator
|
|||
std::reference_wrapper<const Settings> mSettings;
|
||||
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
|
||||
std::reference_wrapper<OffMeshConnectionsManager> mOffMeshConnectionsManager;
|
||||
Misc::ScopeGuarded<std::unique_ptr<NavMeshDb>> mDb;
|
||||
ShapeId mNextShapeId {1};
|
||||
std::atomic_bool mShouldStop;
|
||||
mutable std::mutex mMutex;
|
||||
std::condition_variable mHasJob;
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace DetourNavigator
|
|||
{
|
||||
Ignore ignore {consumer};
|
||||
|
||||
const std::shared_ptr<RecastMesh> recastMesh = mRecastMeshProvider.getMesh(mTilePosition);
|
||||
const std::shared_ptr<RecastMesh> recastMesh = mRecastMeshProvider.getMesh(mWorldspace, mTilePosition);
|
||||
|
||||
if (recastMesh == nullptr || isEmpty(*recastMesh))
|
||||
return;
|
||||
|
|
|
@ -10,9 +10,15 @@
|
|||
#include "preparednavmeshdata.hpp"
|
||||
#include "navmeshdata.hpp"
|
||||
#include "recastmeshbuilder.hpp"
|
||||
#include "navmeshdb.hpp"
|
||||
#include "serialization.hpp"
|
||||
#include "dbrefgeometryobject.hpp"
|
||||
#include "navmeshdbutils.hpp"
|
||||
|
||||
#include <components/misc/convert.hpp>
|
||||
#include <components/bullethelpers/processtrianglecallback.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
#include <components/misc/guarded.hpp>
|
||||
|
||||
#include <DetourNavMesh.h>
|
||||
#include <DetourNavMeshBuilder.h>
|
||||
|
@ -540,9 +546,10 @@ namespace DetourNavigator
|
|||
}
|
||||
|
||||
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
|
||||
const TilePosition& changedTile, const TilePosition& playerTile,
|
||||
const std::string& worldspace, const TilePosition& changedTile, const TilePosition& playerTile,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const Settings& settings,
|
||||
const SharedNavMeshCacheItem& navMeshCacheItem, NavMeshTilesCache& navMeshTilesCache, UpdateType updateType)
|
||||
const SharedNavMeshCacheItem& navMeshCacheItem, NavMeshTilesCache& navMeshTilesCache, UpdateType updateType,
|
||||
Misc::ScopeGuarded<std::unique_ptr<NavMeshDb>>& db, ShapeId& nextShapeId)
|
||||
{
|
||||
Log(Debug::Debug) << std::fixed << std::setprecision(2) <<
|
||||
"Update NavMesh with multiple tiles:" <<
|
||||
|
@ -578,7 +585,24 @@ namespace DetourNavigator
|
|||
|
||||
if (!cachedNavMeshData)
|
||||
{
|
||||
auto prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings.mRecast);
|
||||
std::optional<TileData> stored;
|
||||
if (const auto dbLocked = db.lock(); *dbLocked != nullptr)
|
||||
{
|
||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(**dbLocked, v, nextShapeId); });
|
||||
stored = (*dbLocked)->getTileData(worldspace, changedTile, serialize(settings.mRecast, *recastMesh, objects));
|
||||
}
|
||||
|
||||
std::unique_ptr<PreparedNavMeshData> prepared;
|
||||
if (stored.has_value() && stored->mVersion == settings.mNavMeshVersion)
|
||||
{
|
||||
prepared = std::make_unique<PreparedNavMeshData>();
|
||||
if (!deserialize(stored->mData, *prepared))
|
||||
prepared = nullptr;
|
||||
}
|
||||
|
||||
if (prepared == nullptr)
|
||||
prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings.mRecast);
|
||||
|
||||
if (prepared == nullptr)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include "sharednavmesh.hpp"
|
||||
#include "navmeshtilescache.hpp"
|
||||
#include "offmeshconnection.hpp"
|
||||
#include "navmeshdb.hpp"
|
||||
|
||||
#include <components/misc/guarded.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
|
@ -63,9 +66,10 @@ namespace DetourNavigator
|
|||
};
|
||||
|
||||
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
|
||||
const TilePosition& changedTile, const TilePosition& playerTile,
|
||||
const std::string& worldspace, const TilePosition& changedTile, const TilePosition& playerTile,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const Settings& settings,
|
||||
const SharedNavMeshCacheItem& navMeshCacheItem, NavMeshTilesCache& navMeshTilesCache, UpdateType updateType);
|
||||
const SharedNavMeshCacheItem& navMeshCacheItem, NavMeshTilesCache& navMeshTilesCache, UpdateType updateType,
|
||||
Misc::ScopeGuarded<std::unique_ptr<NavMeshDb>>& db, ShapeId& nextShapeId);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
std::unique_ptr<Navigator> makeNavigator(const Settings& settings)
|
||||
std::unique_ptr<Navigator> makeNavigator(const Settings& settings, const std::string& userDataPath)
|
||||
{
|
||||
DetourNavigator::RecastGlobalAllocator::init();
|
||||
return std::make_unique<NavigatorImpl>(settings);
|
||||
|
||||
std::unique_ptr<NavMeshDb> db;
|
||||
if (settings.mEnableNavMeshDiskCache)
|
||||
db = std::make_unique<NavMeshDb>(userDataPath + "/navmesh.db");
|
||||
|
||||
return std::make_unique<NavigatorImpl>(settings, std::move(db));
|
||||
}
|
||||
|
||||
std::unique_ptr<Navigator> makeNavigatorStub()
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <components/resource/bulletshape.hpp>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
|
@ -75,6 +77,12 @@ namespace DetourNavigator
|
|||
*/
|
||||
virtual void removeAgent(const osg::Vec3f& agentHalfExtents) = 0;
|
||||
|
||||
/**
|
||||
* @brief setWorldspace should be called before adding object from new worldspace
|
||||
* @param worldspace
|
||||
*/
|
||||
virtual void setWorldspace(std::string_view worldspace) = 0;
|
||||
|
||||
/**
|
||||
* @brief addObject is used to add complex object with allowed to walk and avoided to walk shapes
|
||||
* @param id is used to distinguish different objects
|
||||
|
@ -188,7 +196,7 @@ namespace DetourNavigator
|
|||
virtual float getMaxNavmeshAreaRealRadius() const = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<Navigator> makeNavigator(const Settings& settings);
|
||||
std::unique_ptr<Navigator> makeNavigator(const Settings& settings, const std::string& userDataPath);
|
||||
|
||||
std::unique_ptr<Navigator> makeNavigatorStub();
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
NavigatorImpl::NavigatorImpl(const Settings& settings)
|
||||
NavigatorImpl::NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
|
||||
: mSettings(settings)
|
||||
, mNavMeshManager(mSettings)
|
||||
, mNavMeshManager(mSettings, std::move(db))
|
||||
, mUpdatesEnabled(true)
|
||||
{
|
||||
}
|
||||
|
@ -32,6 +32,11 @@ namespace DetourNavigator
|
|||
--it->second;
|
||||
}
|
||||
|
||||
void NavigatorImpl::setWorldspace(std::string_view worldspace)
|
||||
{
|
||||
mNavMeshManager.setWorldspace(worldspace);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "navmeshmanager.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
|
@ -15,12 +16,14 @@ namespace DetourNavigator
|
|||
* @brief Navigator constructor initializes all internal data. Constructed object is ready to build a scene.
|
||||
* @param settings allows to customize navigator work. Constructor is only place to set navigator settings.
|
||||
*/
|
||||
explicit NavigatorImpl(const Settings& settings);
|
||||
explicit NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db);
|
||||
|
||||
void addAgent(const osg::Vec3f& agentHalfExtents) override;
|
||||
|
||||
void removeAgent(const osg::Vec3f& agentHalfExtents) override;
|
||||
|
||||
void setWorldspace(std::string_view worldspace) override;
|
||||
|
||||
bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override;
|
||||
|
||||
bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override;
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace DetourNavigator
|
|||
|
||||
void removeAgent(const osg::Vec3f& /*agentHalfExtents*/) override {}
|
||||
|
||||
void setWorldspace(std::string_view /*worldspace*/) override {}
|
||||
|
||||
bool addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -41,13 +41,23 @@ namespace
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
NavMeshManager::NavMeshManager(const Settings& settings)
|
||||
NavMeshManager::NavMeshManager(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
|
||||
: mSettings(settings)
|
||||
, mRecastMeshManager(mSettings.mRecast)
|
||||
, mOffMeshConnectionsManager(mSettings.mRecast)
|
||||
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager)
|
||||
, mRecastMeshManager(settings.mRecast)
|
||||
, mOffMeshConnectionsManager(settings.mRecast)
|
||||
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db))
|
||||
{}
|
||||
|
||||
void NavMeshManager::setWorldspace(std::string_view worldspace)
|
||||
{
|
||||
if (worldspace == mWorldspace)
|
||||
return;
|
||||
mRecastMeshManager.setWorldspace(worldspace);
|
||||
for (auto& [agent, cache] : mCache)
|
||||
cache = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter);
|
||||
mWorldspace = worldspace;
|
||||
}
|
||||
|
||||
bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType)
|
||||
{
|
||||
|
@ -208,7 +218,7 @@ namespace DetourNavigator
|
|||
recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0});
|
||||
});
|
||||
}
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, tilesToPost);
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost);
|
||||
if (changedTiles != mChangedTiles.end())
|
||||
changedTiles->second.clear();
|
||||
Log(Debug::Debug) << "Cache update posted for agent=" << agentHalfExtents <<
|
||||
|
@ -241,9 +251,10 @@ namespace DetourNavigator
|
|||
std::vector<TilePosition> tiles;
|
||||
mRecastMeshManager.forEachTile(
|
||||
[&tiles] (const TilePosition& tile, const CachedRecastMeshManager&) { tiles.push_back(tile); });
|
||||
const std::string worldspace = mRecastMeshManager.getWorldspace();
|
||||
RecastMeshTiles result;
|
||||
for (const TilePosition& tile : tiles)
|
||||
if (auto mesh = mRecastMeshManager.getCachedMesh(tile))
|
||||
if (auto mesh = mRecastMeshManager.getCachedMesh(worldspace, tile))
|
||||
result.emplace(tile, std::move(mesh));
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ namespace DetourNavigator
|
|||
class NavMeshManager
|
||||
{
|
||||
public:
|
||||
NavMeshManager(const Settings& settings);
|
||||
explicit NavMeshManager(const Settings& settings, std::unique_ptr<NavMeshDb>&& db);
|
||||
|
||||
void setWorldspace(std::string_view worldspace);
|
||||
|
||||
bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType);
|
||||
|
@ -62,6 +64,7 @@ namespace DetourNavigator
|
|||
|
||||
private:
|
||||
const Settings& mSettings;
|
||||
std::string mWorldspace;
|
||||
TileCachedRecastMeshManager mRecastMeshManager;
|
||||
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
||||
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "preparednavmeshdata.hpp"
|
||||
#include "preparednavmeshdatatuple.hpp"
|
||||
#include "recast.hpp"
|
||||
|
||||
#include <Recast.h>
|
||||
#include <RecastAlloc.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -15,13 +15,6 @@ namespace
|
|||
value.nverts = 0;
|
||||
value.ntris = 0;
|
||||
}
|
||||
|
||||
void freePolyMeshDetail(rcPolyMeshDetail& value) noexcept
|
||||
{
|
||||
rcFree(value.meshes);
|
||||
rcFree(value.verts);
|
||||
rcFree(value.tris);
|
||||
}
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
|
|
49
components/detournavigator/recast.cpp
Normal file
49
components/detournavigator/recast.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "recast.hpp"
|
||||
|
||||
#include <Recast.h>
|
||||
#include <RecastAlloc.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
void* permRecastAlloc(std::size_t size)
|
||||
{
|
||||
void* const result = rcAlloc(size, RC_ALLOC_PERM);
|
||||
if (result == nullptr)
|
||||
throw std::bad_alloc();
|
||||
return result;
|
||||
}
|
||||
|
||||
void permRecastAlloc(rcPolyMesh& value)
|
||||
{
|
||||
permRecastAlloc(value.verts, getVertsLength(value));
|
||||
permRecastAlloc(value.polys, getPolysLength(value));
|
||||
permRecastAlloc(value.regs, getRegsLength(value));
|
||||
permRecastAlloc(value.flags, getFlagsLength(value));
|
||||
permRecastAlloc(value.areas, getAreasLength(value));
|
||||
}
|
||||
|
||||
void permRecastAlloc(rcPolyMeshDetail& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
permRecastAlloc(value.meshes, getMeshesLength(value));
|
||||
permRecastAlloc(value.verts, getVertsLength(value));
|
||||
permRecastAlloc(value.tris, getTrisLength(value));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
freePolyMeshDetail(value);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void freePolyMeshDetail(rcPolyMeshDetail& value) noexcept
|
||||
{
|
||||
rcFree(value.meshes);
|
||||
rcFree(value.verts);
|
||||
rcFree(value.tris);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include <Recast.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
|
@ -46,6 +47,21 @@ namespace DetourNavigator
|
|||
{
|
||||
return 4 * static_cast<std::size_t>(value.ntris);
|
||||
}
|
||||
|
||||
void* permRecastAlloc(std::size_t size);
|
||||
|
||||
template <class T>
|
||||
inline void permRecastAlloc(T*& values, std::size_t size)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>);
|
||||
values = new (permRecastAlloc(size * sizeof(T))) T[size];
|
||||
}
|
||||
|
||||
void permRecastAlloc(rcPolyMesh& value);
|
||||
|
||||
void permRecastAlloc(rcPolyMeshDetail& value);
|
||||
|
||||
void freePolyMeshDetail(rcPolyMeshDetail& value) noexcept;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,9 +20,9 @@ namespace DetourNavigator
|
|||
: mImpl(impl)
|
||||
{}
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition) const
|
||||
std::shared_ptr<RecastMesh> getMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
||||
{
|
||||
return mImpl.get().getNewMesh(tilePosition);
|
||||
return mImpl.get().getNewMesh(worldspace, tilePosition);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -2,14 +2,18 @@
|
|||
|
||||
#include "dbrefgeometryobject.hpp"
|
||||
#include "preparednavmeshdata.hpp"
|
||||
#include "recast.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include <components/serialization/binaryreader.hpp>
|
||||
#include <components/serialization/binarywriter.hpp>
|
||||
#include <components/serialization/format.hpp>
|
||||
#include <components/serialization/sizeaccumulator.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace DetourNavigator
|
||||
|
@ -142,8 +146,9 @@ namespace
|
|||
visitor(*this, dbRefGeometryObjects);
|
||||
}
|
||||
|
||||
template <class Visitor>
|
||||
auto operator()(Visitor&& visitor, const rcPolyMesh& value) const
|
||||
template <class Visitor, class T>
|
||||
auto operator()(Visitor&& visitor, T& value) const
|
||||
-> std::enable_if_t<std::is_same_v<std::decay_t<T>, rcPolyMesh>>
|
||||
{
|
||||
visitor(*this, value.nverts);
|
||||
visitor(*this, value.npolys);
|
||||
|
@ -155,6 +160,19 @@ namespace
|
|||
visitor(*this, value.ch);
|
||||
visitor(*this, value.borderSize);
|
||||
visitor(*this, value.maxEdgeError);
|
||||
if constexpr (mode == Serialization::Mode::Read)
|
||||
{
|
||||
if (value.verts == nullptr)
|
||||
permRecastAlloc(value.verts, getVertsLength(value));
|
||||
if (value.polys == nullptr)
|
||||
permRecastAlloc(value.polys, getPolysLength(value));
|
||||
if (value.regs == nullptr)
|
||||
permRecastAlloc(value.regs, getRegsLength(value));
|
||||
if (value.flags == nullptr)
|
||||
permRecastAlloc(value.flags, getFlagsLength(value));
|
||||
if (value.areas == nullptr)
|
||||
permRecastAlloc(value.areas, getAreasLength(value));
|
||||
}
|
||||
visitor(*this, value.verts, getVertsLength(value));
|
||||
visitor(*this, value.polys, getPolysLength(value));
|
||||
visitor(*this, value.regs, getRegsLength(value));
|
||||
|
@ -162,22 +180,48 @@ namespace
|
|||
visitor(*this, value.areas, getAreasLength(value));
|
||||
}
|
||||
|
||||
template <class Visitor>
|
||||
auto operator()(Visitor&& visitor, const rcPolyMeshDetail& value) const
|
||||
template <class Visitor, class T>
|
||||
auto operator()(Visitor&& visitor, T& value) const
|
||||
-> std::enable_if_t<std::is_same_v<std::decay_t<T>, rcPolyMeshDetail>>
|
||||
{
|
||||
visitor(*this, value.nmeshes);
|
||||
if constexpr (mode == Serialization::Mode::Read)
|
||||
if (value.meshes == nullptr)
|
||||
permRecastAlloc(value.meshes, getMeshesLength(value));
|
||||
visitor(*this, value.meshes, getMeshesLength(value));
|
||||
visitor(*this, value.nverts);
|
||||
if constexpr (mode == Serialization::Mode::Read)
|
||||
if (value.verts == nullptr)
|
||||
permRecastAlloc(value.verts, getVertsLength(value));
|
||||
visitor(*this, value.verts, getVertsLength(value));
|
||||
visitor(*this, value.ntris);
|
||||
if constexpr (mode == Serialization::Mode::Read)
|
||||
if (value.tris == nullptr)
|
||||
permRecastAlloc(value.tris, getTrisLength(value));
|
||||
visitor(*this, value.tris, getTrisLength(value));
|
||||
}
|
||||
|
||||
template <class Visitor>
|
||||
auto operator()(Visitor&& visitor, const PreparedNavMeshData& value) const
|
||||
template <class Visitor, class T>
|
||||
auto operator()(Visitor&& visitor, T& value) const
|
||||
-> std::enable_if_t<std::is_same_v<std::decay_t<T>, PreparedNavMeshData>>
|
||||
{
|
||||
visitor(*this, DetourNavigator::preparedNavMeshDataMagic);
|
||||
visitor(*this, DetourNavigator::preparedNavMeshDataVersion);
|
||||
if constexpr (mode == Serialization::Mode::Write)
|
||||
{
|
||||
visitor(*this, DetourNavigator::preparedNavMeshDataMagic);
|
||||
visitor(*this, DetourNavigator::preparedNavMeshDataVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(mode == Serialization::Mode::Read);
|
||||
char magic[std::size(DetourNavigator::preparedNavMeshDataMagic)];
|
||||
visitor(*this, magic);
|
||||
if (std::memcmp(magic, DetourNavigator::preparedNavMeshDataMagic, sizeof(magic)) != 0)
|
||||
throw std::runtime_error("Bad PreparedNavMeshData magic");
|
||||
std::uint32_t version = 0;
|
||||
visitor(*this, version);
|
||||
if (version != DetourNavigator::preparedNavMeshDataVersion)
|
||||
throw std::runtime_error("Bad PreparedNavMeshData version");
|
||||
}
|
||||
visitor(*this, value.mUserId);
|
||||
visitor(*this, value.mCellSize);
|
||||
visitor(*this, value.mCellHeight);
|
||||
|
@ -211,4 +255,18 @@ namespace DetourNavigator
|
|||
format(Serialization::BinaryWriter(result.data(), result.data() + result.size()), value);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool deserialize(const std::vector<std::byte>& data, PreparedNavMeshData& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
constexpr Format<Serialization::Mode::Read> format;
|
||||
format(Serialization::BinaryReader(data.data(), data.data() + data.size()), value);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace DetourNavigator
|
|||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects);
|
||||
|
||||
std::vector<std::byte> serialize(const PreparedNavMeshData& value);
|
||||
|
||||
bool deserialize(const std::vector<std::byte>& data, PreparedNavMeshData& value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace DetourNavigator
|
|||
result.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
|
||||
result.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator"));
|
||||
result.mNavMeshVersion = ::Settings::Manager::getInt("nav mesh version", "Navigator");
|
||||
result.mEnableNavMeshDiskCache = ::Settings::Manager::getBool("enable nav mesh disk cache", "Navigator");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace DetourNavigator
|
|||
bool mEnableWriteNavMeshToFile = false;
|
||||
bool mEnableRecastMeshFileNameRevision = false;
|
||||
bool mEnableNavMeshFileNameRevision = false;
|
||||
bool mEnableNavMeshDiskCache = false;
|
||||
RecastSettings mRecast;
|
||||
DetourSettings mDetour;
|
||||
int mWaitUntilMinDistanceToPlayer = 0;
|
||||
|
|
|
@ -14,15 +14,30 @@ namespace DetourNavigator
|
|||
: mSettings(settings)
|
||||
{}
|
||||
|
||||
std::string TileCachedRecastMeshManager::getWorldspace() const
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
return mWorldspace;
|
||||
}
|
||||
|
||||
void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace)
|
||||
{
|
||||
const std::lock_guard lock(mMutex);
|
||||
if (mWorldspace == worldspace)
|
||||
return;
|
||||
mTiles.clear();
|
||||
mWorldspace = worldspace;
|
||||
}
|
||||
|
||||
bool TileCachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape,
|
||||
const btTransform& transform, const AreaType areaType)
|
||||
{
|
||||
std::vector<TilePosition> tilesPositions;
|
||||
{
|
||||
auto tiles = mTiles.lock();
|
||||
const std::lock_guard lock(mMutex);
|
||||
getTilesPositions(shape.getShape(), transform, mSettings, [&] (const TilePosition& tilePosition)
|
||||
{
|
||||
if (addTile(id, shape, transform, areaType, tilePosition, tiles.get()))
|
||||
if (addTile(id, shape, transform, areaType, tilePosition, mTiles))
|
||||
tilesPositions.push_back(tilePosition);
|
||||
});
|
||||
}
|
||||
|
@ -41,10 +56,10 @@ namespace DetourNavigator
|
|||
return std::nullopt;
|
||||
std::optional<RemovedRecastMeshObject> result;
|
||||
{
|
||||
auto tiles = mTiles.lock();
|
||||
const std::lock_guard lock(mMutex);
|
||||
for (const auto& tilePosition : object->second)
|
||||
{
|
||||
const auto removed = removeTile(id, tilePosition, tiles.get());
|
||||
const auto removed = removeTile(id, tilePosition, mTiles);
|
||||
if (removed && !result)
|
||||
result = removed;
|
||||
}
|
||||
|
@ -62,8 +77,8 @@ namespace DetourNavigator
|
|||
|
||||
if (cellSize == std::numeric_limits<int>::max())
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
for (auto& tile : *tiles)
|
||||
const std::lock_guard lock(mMutex);
|
||||
for (auto& tile : mTiles)
|
||||
{
|
||||
if (tile.second->addWater(cellPosition, cellSize, level))
|
||||
{
|
||||
|
@ -77,13 +92,13 @@ namespace DetourNavigator
|
|||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level));
|
||||
getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& tilePosition)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
auto tile = tiles->find(tilePosition);
|
||||
if (tile == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
auto tile = mTiles.find(tilePosition);
|
||||
if (tile == mTiles.end())
|
||||
{
|
||||
const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition);
|
||||
tile = tiles->emplace(tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)).first;
|
||||
tile = mTiles.emplace_hint(tile, tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration));
|
||||
}
|
||||
if (tile->second->addWater(cellPosition, cellSize, level))
|
||||
{
|
||||
|
@ -107,14 +122,14 @@ namespace DetourNavigator
|
|||
std::optional<Water> result;
|
||||
for (const auto& tilePosition : object->second)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
const auto tile = tiles->find(tilePosition);
|
||||
if (tile == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
const auto tile = mTiles.find(tilePosition);
|
||||
if (tile == mTiles.end())
|
||||
continue;
|
||||
const auto tileResult = tile->second->removeWater(cellPosition);
|
||||
if (tile->second->isEmpty())
|
||||
{
|
||||
tiles->erase(tile);
|
||||
mTiles.erase(tile);
|
||||
++mTilesGeneration;
|
||||
}
|
||||
if (tileResult && !result)
|
||||
|
@ -135,13 +150,13 @@ namespace DetourNavigator
|
|||
|
||||
getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& tilePosition)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
auto tile = tiles->find(tilePosition);
|
||||
if (tile == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
auto tile = mTiles.find(tilePosition);
|
||||
if (tile == mTiles.end())
|
||||
{
|
||||
const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition);
|
||||
tile = tiles->emplace(tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)).first;
|
||||
tile = mTiles.emplace_hint(tile, tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration));
|
||||
}
|
||||
if (tile->second->addHeightfield(cellPosition, cellSize, shape))
|
||||
{
|
||||
|
@ -164,14 +179,14 @@ namespace DetourNavigator
|
|||
std::optional<SizedHeightfieldShape> result;
|
||||
for (const auto& tilePosition : object->second)
|
||||
{
|
||||
const auto tiles = mTiles.lock();
|
||||
const auto tile = tiles->find(tilePosition);
|
||||
if (tile == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
const auto tile = mTiles.find(tilePosition);
|
||||
if (tile == mTiles.end())
|
||||
continue;
|
||||
const auto tileResult = tile->second->removeHeightfield(cellPosition);
|
||||
if (tile->second->isEmpty())
|
||||
{
|
||||
tiles->erase(tile);
|
||||
mTiles.erase(tile);
|
||||
++mTilesGeneration;
|
||||
}
|
||||
if (tileResult && !result)
|
||||
|
@ -182,23 +197,23 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition) const
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
||||
{
|
||||
if (const auto manager = getManager(tilePosition))
|
||||
if (const auto manager = getManager(worldspace, tilePosition))
|
||||
return manager->getMesh();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getCachedMesh(const TilePosition& tilePosition) const
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getCachedMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
||||
{
|
||||
if (const auto manager = getManager(tilePosition))
|
||||
if (const auto manager = getManager(worldspace, tilePosition))
|
||||
return manager->getCachedMesh();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getNewMesh(const TilePosition& tilePosition) const
|
||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getNewMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
||||
{
|
||||
if (const auto manager = getManager(tilePosition))
|
||||
if (const auto manager = getManager(worldspace, tilePosition))
|
||||
return manager->getNewMesh();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -210,9 +225,9 @@ namespace DetourNavigator
|
|||
|
||||
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const
|
||||
{
|
||||
const auto tiles = mTiles.lockConst();
|
||||
const auto it = tiles->find(tilePosition);
|
||||
if (it == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
const auto it = mTiles.find(tilePosition);
|
||||
if (it == mTiles.end())
|
||||
return;
|
||||
it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion);
|
||||
}
|
||||
|
@ -225,8 +240,8 @@ namespace DetourNavigator
|
|||
if (tile == tiles.end())
|
||||
{
|
||||
const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition);
|
||||
tile = tiles.emplace(tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration)).first;
|
||||
tile = tiles.emplace_hint(tile, tilePosition,
|
||||
std::make_shared<CachedRecastMeshManager>(tileBounds, mTilesGeneration));
|
||||
}
|
||||
return tile->second->addObject(id, shape, transform, areaType);
|
||||
}
|
||||
|
@ -253,11 +268,14 @@ namespace DetourNavigator
|
|||
return tileResult;
|
||||
}
|
||||
|
||||
std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(const TilePosition& tilePosition) const
|
||||
std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(std::string_view worldspace,
|
||||
const TilePosition& tilePosition) const
|
||||
{
|
||||
const auto tiles = mTiles.lockConst();
|
||||
const auto it = tiles->find(tilePosition);
|
||||
if (it == tiles->end())
|
||||
const std::lock_guard lock(mMutex);
|
||||
if (mWorldspace != worldspace)
|
||||
return nullptr;
|
||||
const auto it = mTiles.find(tilePosition);
|
||||
if (it == mTiles.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "version.hpp"
|
||||
#include "heightfieldshape.hpp"
|
||||
|
||||
#include <components/misc/guarded.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
@ -22,6 +20,10 @@ namespace DetourNavigator
|
|||
public:
|
||||
explicit TileCachedRecastMeshManager(const RecastSettings& settings);
|
||||
|
||||
std::string getWorldspace() const;
|
||||
|
||||
void setWorldspace(std::string_view worldspace);
|
||||
|
||||
bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType);
|
||||
|
||||
|
@ -36,19 +38,19 @@ namespace DetourNavigator
|
|||
bool changed = false;
|
||||
std::vector<TilePosition> newTiles;
|
||||
{
|
||||
auto tiles = mTiles.lock();
|
||||
const std::lock_guard lock(mMutex);
|
||||
const auto onTilePosition = [&] (const TilePosition& tilePosition)
|
||||
{
|
||||
if (std::binary_search(currentTiles.begin(), currentTiles.end(), tilePosition))
|
||||
{
|
||||
newTiles.push_back(tilePosition);
|
||||
if (updateTile(id, transform, areaType, tilePosition, tiles.get()))
|
||||
if (updateTile(id, transform, areaType, tilePosition, mTiles))
|
||||
{
|
||||
onChangedTile(tilePosition);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (addTile(id, shape, transform, areaType, tilePosition, tiles.get()))
|
||||
else if (addTile(id, shape, transform, areaType, tilePosition, mTiles))
|
||||
{
|
||||
newTiles.push_back(tilePosition);
|
||||
onChangedTile(tilePosition);
|
||||
|
@ -59,7 +61,7 @@ namespace DetourNavigator
|
|||
std::sort(newTiles.begin(), newTiles.end());
|
||||
for (const auto& tile : currentTiles)
|
||||
{
|
||||
if (!std::binary_search(newTiles.begin(), newTiles.end(), tile) && removeTile(id, tile, tiles.get()))
|
||||
if (!std::binary_search(newTiles.begin(), newTiles.end(), tile) && removeTile(id, tile, mTiles))
|
||||
{
|
||||
onChangedTile(tile);
|
||||
changed = true;
|
||||
|
@ -84,16 +86,17 @@ namespace DetourNavigator
|
|||
|
||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition) const;
|
||||
std::shared_ptr<RecastMesh> getMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
|
||||
|
||||
std::shared_ptr<RecastMesh> getCachedMesh(const TilePosition& tilePosition) const;
|
||||
std::shared_ptr<RecastMesh> getCachedMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
|
||||
|
||||
std::shared_ptr<RecastMesh> getNewMesh(const TilePosition& tilePosition) const;
|
||||
std::shared_ptr<RecastMesh> getNewMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
|
||||
|
||||
template <class Function>
|
||||
void forEachTile(Function&& function) const
|
||||
{
|
||||
for (auto& [tilePosition, recastMeshManager] : *mTiles.lockConst())
|
||||
const std::lock_guard lock(mMutex);
|
||||
for (auto& [tilePosition, recastMeshManager] : mTiles)
|
||||
function(tilePosition, *recastMeshManager);
|
||||
}
|
||||
|
||||
|
@ -105,7 +108,9 @@ namespace DetourNavigator
|
|||
using TilesMap = std::map<TilePosition, std::shared_ptr<CachedRecastMeshManager>>;
|
||||
|
||||
const RecastSettings& mSettings;
|
||||
Misc::ScopeGuarded<TilesMap> mTiles;
|
||||
mutable std::mutex mMutex;
|
||||
std::string mWorldspace;
|
||||
TilesMap mTiles;
|
||||
std::unordered_map<ObjectId, std::vector<TilePosition>> mObjectsTilesPositions;
|
||||
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
||||
std::map<osg::Vec2i, std::vector<TilePosition>> mHeightfieldTilesPositions;
|
||||
|
@ -121,7 +126,8 @@ namespace DetourNavigator
|
|||
std::optional<RemovedRecastMeshObject> removeTile(const ObjectId id, const TilePosition& tilePosition,
|
||||
TilesMap& tiles);
|
||||
|
||||
inline std::shared_ptr<CachedRecastMeshManager> getManager(const TilePosition& tilePosition) const;
|
||||
inline std::shared_ptr<CachedRecastMeshManager> getManager(std::string_view worldspace,
|
||||
const TilePosition& tilePosition) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,17 @@ Allows to complete cell loading only when minimal navigation mesh area is genera
|
|||
nearby the player. Increasing this value will keep loading screen longer but will slightly increase nav mesh generation
|
||||
speed on systems bound by CPU. Zero means no waiting.
|
||||
|
||||
enable nav mesh disk cache
|
||||
--------------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
If true navmesh cache stored on disk will be used in addition to memory cache.
|
||||
If navmesh tile is not present in memory cache, it will be looked up in the disk cache.
|
||||
If it's not found there it will be generated.
|
||||
|
||||
Advanced settings
|
||||
*****************
|
||||
|
||||
|
|
|
@ -934,6 +934,9 @@ wait until min distance to player = 5
|
|||
# Should be increased each time there is a difference between output of makeNavMeshTileData function for the same input.
|
||||
nav mesh version = 1
|
||||
|
||||
# Use navigation mesh cache stored on disk (true, false)
|
||||
enable nav mesh disk cache = true
|
||||
|
||||
[Shadows]
|
||||
|
||||
# Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true.
|
||||
|
|
Loading…
Reference in a new issue