diff --git a/CHANGELOG.md b/CHANGELOG.md index d44007385..5b89eea03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,7 @@ Feature #3983: Wizard: Add link to buy Morrowind Feature #4894: Consider actors as obstacles for pathfinding Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing + Feature #4917: Do not trigger NavMesh update when RecastMesh update should not change NavMesh Feature #4977: Use the "default icon.tga" when an item's icon is not found Feature #5043: Head Bobbing Feature #5199: OpenMW-CS: Improve scene view colors diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index d377aed1e..3b7dc4915 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -835,4 +835,55 @@ namespace ASSERT_THAT(result, Optional(Vec3fEq(mEnd.x(), mEnd.y(), 1.87719))); } + + TEST_F(DetourNavigatorNavigatorTest, update_for_oscillating_object_that_does_not_change_navmesh_should_not_trigger_navmesh_update) + { + const std::array heightfieldData {{ + 0, 0, 0, 0, 0, + 0, -25, -25, -25, -25, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + }}; + btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData); + heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + + const btBoxShape oscillatingBoxShape(btVector3(20, 20, 20)); + const btVector3 oscillatingBoxShapePosition(32, 32, 400); + const btBoxShape boderBoxShape(btVector3(50, 50, 50)); + + mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, + btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); + // add this box to make navmesh bound box independent from oscillatingBoxShape rotations + mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape, + btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + + const auto navMeshes = mNavigator->getNavMeshes(); + ASSERT_EQ(navMeshes.size(), 1); + { + const auto navMesh = navMeshes.begin()->second->lockConst(); + ASSERT_EQ(navMesh->getGeneration(), 1); + ASSERT_EQ(navMesh->getNavMeshRevision(), 4); + } + + for (int n = 0; n < 10; ++n) + { + const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10), + oscillatingBoxShapePosition); + mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + } + + ASSERT_EQ(navMeshes.size(), 1); + { + const auto navMesh = navMeshes.begin()->second->lockConst(); + ASSERT_EQ(navMesh->getGeneration(), 1); + ASSERT_EQ(navMesh->getNavMeshRevision(), 4); + } + } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ad2783b57..2fe09070a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -182,6 +182,8 @@ add_component_dir(detournavigator navigator findrandompointaroundcircle raycast + navmeshtileview + oscillatingrecastmeshobject ) set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui diff --git a/components/bullethelpers/aabb.hpp b/components/bullethelpers/aabb.hpp new file mode 100644 index 000000000..6509b946c --- /dev/null +++ b/components/bullethelpers/aabb.hpp @@ -0,0 +1,29 @@ +#ifndef OPENMW_COMPONENTS_BULLETHELPERS_AABB_H +#define OPENMW_COMPONENTS_BULLETHELPERS_AABB_H + +#include +#include +#include +#include + +inline bool operator==(const btAABB& lhs, const btAABB& rhs) +{ + return lhs.m_min == rhs.m_min && lhs.m_max == rhs.m_max; +} + +inline bool operator!=(const btAABB& lhs, const btAABB& rhs) +{ + return !(lhs == rhs); +} + +namespace BulletHelpers +{ + inline btAABB getAabb(const btCollisionShape& shape, const btTransform& transform) + { + btAABB result; + shape.getAabb(transform, result.m_min, result.m_max); + return result; + } +} + +#endif diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index bb78df764..4855cf0ad 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -2,6 +2,7 @@ #include "debug.hpp" #include "makenavmesh.hpp" #include "settings.hpp" +#include "version.hpp" #include #include @@ -180,6 +181,19 @@ namespace DetourNavigator const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile, offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache); + if (recastMesh != nullptr) + { + Version navMeshVersion; + { + const auto locked = navMeshCacheItem->lockConst(); + navMeshVersion.mGeneration = locked->getGeneration(); + navMeshVersion.mRevision = locked->getNavMeshRevision(); + } + mRecastMeshManager.get().reportNavMeshChange(job.mChangedTile, + Version {recastMesh->getGeneration(), recastMesh->getRevision()}, + navMeshVersion); + } + const auto finish = std::chrono::steady_clock::now(); writeDebugFiles(job, recastMesh.get()); diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 90b426610..22b047fbd 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -61,4 +61,9 @@ namespace DetourNavigator { return mImpl.isEmpty(); } + + void CachedRecastMeshManager::reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion) + { + mImpl.reportNavMeshChange(recastMeshVersion, navMeshVersion); + } } diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 54574aa99..a19f017a4 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_DETOURNAVIGATOR_CACHEDRECASTMESHMANAGER_H #include "recastmeshmanager.hpp" +#include "version.hpp" namespace DetourNavigator { @@ -25,6 +26,8 @@ namespace DetourNavigator bool isEmpty() const; + void reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion); + private: RecastMeshManager mImpl; std::shared_ptr mCached; diff --git a/components/detournavigator/navmeshcacheitem.hpp b/components/detournavigator/navmeshcacheitem.hpp index 76f74f266..a9a4ebee6 100644 --- a/components/detournavigator/navmeshcacheitem.hpp +++ b/components/detournavigator/navmeshcacheitem.hpp @@ -5,6 +5,7 @@ #include "tileposition.hpp" #include "navmeshtilescache.hpp" #include "dtstatus.hpp" +#include "navmeshtileview.hpp" #include @@ -141,6 +142,12 @@ namespace DetourNavigator template UpdateNavMeshStatus updateTile(const TilePosition& position, T&& navMeshData) { + const dtMeshTile* currentTile = getTile(position); + if (currentTile != nullptr + && asNavMeshTileConstView(*currentTile) == asNavMeshTileConstView(getRawData(navMeshData))) + { + return UpdateNavMeshStatus::ignored; + } const auto removed = removeTileImpl(position); const auto addStatus = addTileImpl(getRawData(navMeshData), getSize(navMeshData)); if (dtStatusSucceed(addStatus)) @@ -206,6 +213,12 @@ namespace DetourNavigator int* const dataSize = nullptr; return dtStatusSucceed(mImpl->removeTile(tileRef, data, dataSize)); } + + const dtMeshTile* getTile(const TilePosition& position) const + { + const int layer = 0; + return mImpl->getTileAt(position.x(), position.y(), layer); + } }; using GuardedNavMeshCacheItem = Misc::ScopeGuarded; diff --git a/components/detournavigator/navmeshtileview.cpp b/components/detournavigator/navmeshtileview.cpp new file mode 100644 index 000000000..96f07c6b1 --- /dev/null +++ b/components/detournavigator/navmeshtileview.cpp @@ -0,0 +1,183 @@ +#include "navmeshtileview.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace +{ + template + struct Ref + { + T& mRef; + + explicit Ref(T& ref) : mRef(ref) {} + + friend bool operator==(const Ref& lhs, const Ref& rhs) + { + return lhs.mRef == rhs.mRef; + } + }; + + template + struct ArrayRef + { + T (&mRef)[size]; + + explicit ArrayRef(T (&ref)[size]) : mRef(ref) {} + + friend bool operator==(const ArrayRef& lhs, const ArrayRef& rhs) + { + return std::equal(std::begin(lhs.mRef), std::end(lhs.mRef), std::begin(rhs.mRef)); + } + }; + + template + struct Span + { + T* mBegin; + T* mEnd; + + explicit Span(T* data, int size) : mBegin(data), mEnd(data + static_cast(size)) {} + + friend bool operator==(const Span& lhs, const Span& rhs) + { + // size is already equal if headers are equal + assert((lhs.mEnd - lhs.mBegin) == (rhs.mEnd - rhs.mBegin)); + return std::equal(lhs.mBegin, lhs.mEnd, rhs.mBegin); + } + }; + + auto makeTuple(const dtMeshHeader& v) + { + return std::tuple( + v.x, + v.y, + v.layer, + v.userId, + v.polyCount, + v.vertCount, + v.maxLinkCount, + v.detailMeshCount, + v.detailVertCount, + v.detailTriCount, + v.bvNodeCount, + v.offMeshConCount, + v.offMeshBase, + v.walkableHeight, + v.walkableRadius, + v.walkableClimb, + v.detailVertCount, + ArrayRef(v.bmin), + ArrayRef(v.bmax), + v.bvQuantFactor + ); + } + + auto makeTuple(const dtPoly& v) + { + return std::tuple(ArrayRef(v.verts), ArrayRef(v.neis), v.flags, v.vertCount, v.areaAndtype); + } + + auto makeTuple(const dtPolyDetail& v) + { + return std::tuple(v.vertBase, v.triBase, v.vertCount, v.triCount); + } + + auto makeTuple(const dtBVNode& v) + { + return std::tuple(ArrayRef(v.bmin), ArrayRef(v.bmax), v.i); + } + + auto makeTuple(const dtOffMeshConnection& v) + { + return std::tuple(ArrayRef(v.pos), v.rad, v.poly, v.flags, v.side, v.userId); + } + + auto makeTuple(const DetourNavigator::NavMeshTileConstView& v) + { + return std::tuple( + Ref(*v.mHeader), + Span(v.mPolys, v.mHeader->polyCount), + Span(v.mVerts, v.mHeader->vertCount), + Span(v.mDetailMeshes, v.mHeader->detailMeshCount), + Span(v.mDetailVerts, v.mHeader->detailVertCount), + Span(v.mDetailTris, v.mHeader->detailTriCount), + Span(v.mBvTree, v.mHeader->bvNodeCount), + Span(v.mOffMeshCons, v.mHeader->offMeshConCount) + ); + } +} + +template +inline auto operator==(const T& lhs, const T& rhs) + -> std::enable_if_t, void>, bool> +{ + return makeTuple(lhs) == makeTuple(rhs); +} + +namespace DetourNavigator +{ + NavMeshTileConstView asNavMeshTileConstView(const unsigned char* data) + { + const dtMeshHeader* header = reinterpret_cast(data); + + if (header->magic != DT_NAVMESH_MAGIC) + throw std::logic_error("Invalid navmesh magic"); + + if (header->version != DT_NAVMESH_VERSION) + throw std::logic_error("Invalid navmesh version"); + + // Similar code to https://github.com/recastnavigation/recastnavigation/blob/c5cbd53024c8a9d8d097a4371215e3342d2fdc87/Detour/Source/DetourNavMesh.cpp#L978-L996 + const int headerSize = dtAlign4(sizeof(dtMeshHeader)); + const int vertsSize = dtAlign4(sizeof(float) * 3 * header->vertCount); + const int polysSize = dtAlign4(sizeof(dtPoly) * header->polyCount); + const int linksSize = dtAlign4(sizeof(dtLink) * (header->maxLinkCount)); + const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * header->detailMeshCount); + const int detailVertsSize = dtAlign4(sizeof(float) * 3 * header->detailVertCount); + const int detailTrisSize = dtAlign4(sizeof(unsigned char) * 4 * header->detailTriCount); + const int bvtreeSize = dtAlign4(sizeof(dtBVNode) * header->bvNodeCount); + const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->offMeshConCount); + + const unsigned char* ptr = data + headerSize; + + NavMeshTileConstView view; + + view.mHeader = header; + view.mVerts = dtGetThenAdvanceBufferPointer(ptr, vertsSize); + view.mPolys = dtGetThenAdvanceBufferPointer(ptr, polysSize); + ptr += linksSize; + view.mDetailMeshes = dtGetThenAdvanceBufferPointer(ptr, detailMeshesSize); + view.mDetailVerts = dtGetThenAdvanceBufferPointer(ptr, detailVertsSize); + view.mDetailTris = dtGetThenAdvanceBufferPointer(ptr, detailTrisSize); + view.mBvTree = dtGetThenAdvanceBufferPointer(ptr, bvtreeSize); + view.mOffMeshCons = dtGetThenAdvanceBufferPointer(ptr, offMeshLinksSize); + + return view; + } + + NavMeshTileConstView asNavMeshTileConstView(const dtMeshTile& tile) + { + NavMeshTileConstView view; + + view.mHeader = tile.header; + view.mPolys = tile.polys; + view.mVerts = tile.verts; + view.mDetailMeshes = tile.detailMeshes; + view.mDetailVerts = tile.detailVerts; + view.mDetailTris = tile.detailTris; + view.mBvTree = tile.bvTree; + view.mOffMeshCons = tile.offMeshCons; + + return view; + } + + bool operator==(const NavMeshTileConstView& lhs, const NavMeshTileConstView& rhs) + { + return makeTuple(lhs) == makeTuple(rhs); + } +} diff --git a/components/detournavigator/navmeshtileview.hpp b/components/detournavigator/navmeshtileview.hpp new file mode 100644 index 000000000..92017360c --- /dev/null +++ b/components/detournavigator/navmeshtileview.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILEVIEW_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILEVIEW_H + +struct dtMeshHeader; +struct dtPoly; +struct dtPolyDetail; +struct dtBVNode; +struct dtOffMeshConnection; +struct dtMeshTile; + +namespace DetourNavigator +{ + struct NavMeshTileConstView + { + const dtMeshHeader* mHeader; + const dtPoly* mPolys; + const float* mVerts; + const dtPolyDetail* mDetailMeshes; + const float* mDetailVerts; + const unsigned char* mDetailTris; + const dtBVNode* mBvTree; + const dtOffMeshConnection* mOffMeshCons; + + friend bool operator==(const NavMeshTileConstView& lhs, const NavMeshTileConstView& rhs); + }; + + NavMeshTileConstView asNavMeshTileConstView(const unsigned char* data); + NavMeshTileConstView asNavMeshTileConstView(const dtMeshTile& tile); +} + +#endif diff --git a/components/detournavigator/oscillatingrecastmeshobject.cpp b/components/detournavigator/oscillatingrecastmeshobject.cpp new file mode 100644 index 000000000..dd0b95600 --- /dev/null +++ b/components/detournavigator/oscillatingrecastmeshobject.cpp @@ -0,0 +1,35 @@ +#include "oscillatingrecastmeshobject.hpp" + +#include + +namespace DetourNavigator +{ + OscillatingRecastMeshObject::OscillatingRecastMeshObject(RecastMeshObject impl, std::size_t lastChangeRevision) + : mImpl(std::move(impl)) + , mLastChangeRevision(lastChangeRevision) + , mAabb(BulletHelpers::getAabb(mImpl.getShape(), mImpl.getTransform())) + { + } + + bool OscillatingRecastMeshObject::update(const btTransform& transform, const AreaType areaType, + std::size_t lastChangeRevision) + { + const btTransform oldTransform = mImpl.getTransform(); + if (!mImpl.update(transform, areaType)) + return false; + if (transform == oldTransform) + return true; + if (mLastChangeRevision != lastChangeRevision) + { + mLastChangeRevision = lastChangeRevision; + // btAABB doesn't have copy-assignment operator + const btAABB aabb = BulletHelpers::getAabb(mImpl.getShape(), transform); + mAabb.m_min = aabb.m_min; + mAabb.m_max = aabb.m_max; + return true; + } + const btAABB currentAabb = mAabb; + mAabb.merge(BulletHelpers::getAabb(mImpl.getShape(), transform)); + return currentAabb != mAabb; + } +} diff --git a/components/detournavigator/oscillatingrecastmeshobject.hpp b/components/detournavigator/oscillatingrecastmeshobject.hpp new file mode 100644 index 000000000..476fd4e0d --- /dev/null +++ b/components/detournavigator/oscillatingrecastmeshobject.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H + +#include "areatype.hpp" +#include "recastmeshobject.hpp" + +#include +#include + +namespace DetourNavigator +{ + class OscillatingRecastMeshObject + { + public: + explicit OscillatingRecastMeshObject(RecastMeshObject impl, std::size_t lastChangeRevision); + + bool update(const btTransform& transform, const AreaType areaType, std::size_t lastChangeRevision); + + const RecastMeshObject& getImpl() const { return mImpl; } + + private: + RecastMeshObject mImpl; + std::size_t mLastChangeRevision; + btAABB mAabb; + }; +} + +#endif diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 3796c9816..146038ae6 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -13,7 +13,8 @@ namespace DetourNavigator bool RecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType) { - const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(), RecastMeshObject(shape, transform, areaType)); + const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(), + OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1)); if (!mObjects.emplace(id, iterator).second) { mObjectsOrder.erase(iterator); @@ -28,7 +29,9 @@ namespace DetourNavigator const auto object = mObjects.find(id); if (object == mObjects.end()) return false; - if (!object->second->update(transform, areaType)) + const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value() + ? mLastNavMeshReportedChange->mRevision : mRevision; + if (!object->second->update(transform, areaType, lastChangeRevision)) return false; ++mRevision; return true; @@ -39,7 +42,7 @@ namespace DetourNavigator const auto object = mObjects.find(id); if (object == mObjects.end()) return std::nullopt; - const RemovedRecastMeshObject result {object->second->getShape(), object->second->getTransform()}; + const RemovedRecastMeshObject result {object->second->getImpl().getShape(), object->second->getImpl().getTransform()}; mObjectsOrder.erase(object->second); mObjects.erase(object); ++mRevision; @@ -74,7 +77,7 @@ namespace DetourNavigator std::shared_ptr RecastMeshManager::getMesh() { rebuild(); - return mMeshBuilder.create(mGeneration, mLastBuildRevision); + return mMeshBuilder.create(mGeneration, mRevision); } bool RecastMeshManager::isEmpty() const @@ -82,15 +85,27 @@ namespace DetourNavigator return mObjects.empty(); } + void RecastMeshManager::reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion) + { + if (recastMeshVersion.mGeneration != mGeneration) + return; + if (mLastNavMeshReport.has_value() && navMeshVersion < mLastNavMeshReport->mNavMeshVersion) + return; + mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion}; + if (!mLastNavMeshReportedChange.has_value() + || mLastNavMeshReportedChange->mNavMeshVersion < mLastNavMeshReport->mNavMeshVersion) + mLastNavMeshReportedChange = mLastNavMeshReport; + } + void RecastMeshManager::rebuild() { - if (mLastBuildRevision == mRevision) - return; mMeshBuilder.reset(); for (const auto& v : mWaterOrder) mMeshBuilder.addWater(v.mCellSize, v.mTransform); - for (const auto& v : mObjectsOrder) + for (const auto& object : mObjectsOrder) + { + const RecastMeshObject& v = object.getImpl(); mMeshBuilder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); - mLastBuildRevision = mRevision; + } } } diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index 5b568e004..daa123fcb 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -2,8 +2,9 @@ #define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H #include "recastmeshbuilder.hpp" -#include "recastmeshobject.hpp" +#include "oscillatingrecastmeshobject.hpp" #include "objectid.hpp" +#include "version.hpp" #include @@ -50,15 +51,24 @@ namespace DetourNavigator bool isEmpty() const; + void reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion); + private: + struct Report + { + std::size_t mRevision; + Version mNavMeshVersion; + }; + std::size_t mRevision = 0; - std::size_t mLastBuildRevision = 0; std::size_t mGeneration; RecastMeshBuilder mMeshBuilder; - std::list mObjectsOrder; - std::unordered_map::iterator> mObjects; + std::list mObjectsOrder; + std::unordered_map::iterator> mObjects; std::list mWaterOrder; std::map::iterator> mWater; + std::optional mLastNavMeshReportedChange; + std::optional mLastNavMeshReport; void rebuild(); }; diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index aac0b4c3c..3f3546278 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -8,6 +8,22 @@ namespace DetourNavigator { + namespace + { + bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, + std::vector& children) + { + assert(static_cast(shape.getNumChildShapes()) == children.size()); + bool result = false; + for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) + { + assert(shape.getChildShape(i) == std::addressof(children[static_cast(i)].getShape())); + result = children[static_cast(i)].update(shape.getChildTransform(i), areaType) || result; + } + return result; + } + } + RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform, const AreaType areaType) : mShape(shape) @@ -42,19 +58,6 @@ namespace DetourNavigator return result; } - bool RecastMeshObject::updateCompoundObject(const btCompoundShape& shape, - const AreaType areaType, std::vector& children) - { - assert(static_cast(shape.getNumChildShapes()) == children.size()); - bool result = false; - for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) - { - assert(shape.getChildShape(i) == std::addressof(children[static_cast(i)].mShape.get())); - result = children[static_cast(i)].update(shape.getChildTransform(i), areaType) || result; - } - return result; - } - std::vector makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType) { if (shape.isCompound()) diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index f25647ae5..e659300e6 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -41,9 +41,6 @@ namespace DetourNavigator AreaType mAreaType; btVector3 mLocalScaling; std::vector mChildren; - - static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, - std::vector& children); }; std::vector makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index fddaa88f1..20ebc8fea 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -145,6 +145,15 @@ namespace DetourNavigator return mRevision; } + void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) + { + const auto tiles = mTiles.lock(); + const auto it = tiles->find(tilePosition); + if (it == tiles->end()) + return; + it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion); + } + bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, std::map& tiles) diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index fa192bd73..68683f410 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -5,6 +5,7 @@ #include "tileposition.hpp" #include "settingsutils.hpp" #include "gettilespositions.hpp" +#include "version.hpp" #include @@ -88,6 +89,8 @@ namespace DetourNavigator std::size_t getRevision() const; + void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion); + private: const Settings& mSettings; Misc::ScopeGuarded> mTiles; diff --git a/components/detournavigator/version.hpp b/components/detournavigator/version.hpp new file mode 100644 index 000000000..c9de98459 --- /dev/null +++ b/components/detournavigator/version.hpp @@ -0,0 +1,21 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_VERSION_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_VERSION_H + +#include +#include + +namespace DetourNavigator +{ + struct Version + { + std::size_t mGeneration; + std::size_t mRevision; + + friend inline bool operator<(const Version& lhs, const Version& rhs) + { + return std::tie(lhs.mGeneration, lhs.mRevision) < std::tie(rhs.mGeneration, rhs.mRevision); + } + }; +} + +#endif