From 8125d51a0f804b77197142c986aacbdb8dce7752 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 6 Aug 2022 16:55:09 +0200 Subject: [PATCH 1/7] Use std::unique_ptr to implement ScopedLoad This gives correct implementation of move constructor and assignment operators. --- .../loadinglistener/loadinglistener.hpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 14a1b96f9a..e61f3837f1 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -2,6 +2,7 @@ #define COMPONENTS_LOADINGLISTENER_H #include +#include namespace Loading { @@ -33,12 +34,26 @@ namespace Loading virtual ~Listener() = default; }; + struct LoadingOff + { + void operator()(Listener* listener) const + { + if (listener != nullptr) + listener->loadingOff(); + } + }; + /// @brief Used for stopping a loading sequence when the object goes out of scope struct ScopedLoad { - ScopedLoad(Listener* l) : mListener(l) { mListener->loadingOn(); } - ~ScopedLoad() { mListener->loadingOff(); } - Listener* mListener; + std::unique_ptr mListener; + + explicit ScopedLoad(Listener* listener) + : mListener(listener) + { + if (mListener != nullptr) + mListener->loadingOn(); + } }; } From e1bed86d7ec119bd8e86ef2cd2bfd16b82aa6976 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 18 Sep 2021 15:52:03 +0200 Subject: [PATCH 2/7] Do single navigator update per frame Primarily for crossing cell border case. Each Navigator::update call has a cost. Doing it multiple times per frame increased frame duration on cell loading. Call Navigator::wait only when cell has changed but do not use Scene::hasCellChanged because it doesn't always indicates it. --- .../mwmechanics/mechanicsmanagerimp.cpp | 8 --- apps/openmw/mwworld/scene.cpp | 25 ++----- apps/openmw/mwworld/scene.hpp | 5 ++ apps/openmw/mwworld/worldimp.cpp | 23 +++---- apps/openmw/mwworld/worldimp.hpp | 1 - .../detournavigator/navigator.cpp | 26 +++++-- .../detournavigator/asyncnavmeshupdater.cpp | 37 +++++----- .../detournavigator/asyncnavmeshupdater.hpp | 4 +- components/detournavigator/debug.cpp | 6 ++ components/detournavigator/debug.hpp | 4 ++ components/detournavigator/navigator.hpp | 38 +++------- components/detournavigator/navigatorimpl.cpp | 69 +++++++------------ components/detournavigator/navigatorimpl.hpp | 24 +++---- components/detournavigator/navigatorstub.hpp | 50 +++----------- components/detournavigator/navmeshmanager.cpp | 25 +++---- components/detournavigator/navmeshmanager.hpp | 10 +-- 16 files changed, 140 insertions(+), 215 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e0e70348b1..acb03b1504 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include #include "../mwworld/esmstore.hpp" @@ -813,12 +811,6 @@ namespace MWMechanics bool MechanicsManager::toggleAI() { mAI = !mAI; - - MWBase::World* world = MWBase::Environment::get().getWorld(); - world->getNavigator()->setUpdatesEnabled(mAI); - if (mAI) - world->getNavigator()->update(world->getPlayerPtr().getRefData().getPosition().asVec3()); - return mAI; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d49d6e8fda..82375c8067 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -365,8 +365,6 @@ namespace MWWorld if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) mNavigator.removePathgrid(*pathgrid); - mNavigator.update(mWorld.getPlayerPtr().getRefData().getPosition().asVec3()); - MWBase::Environment::get().getMechanicsManager()->drop (cell); mRendering.removeCell(cell); @@ -514,12 +512,7 @@ namespace MWWorld void Scene::playerMoved(const osg::Vec3f &pos) { - if (mCurrentCell == nullptr) - return; - - mNavigator.updatePlayerPosition(pos); - - if (!mCurrentCell->isExterior()) + if (!mCurrentCell || !mCurrentCell->isExterior()) return; osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter); @@ -619,7 +612,7 @@ namespace MWWorld if (changeEvent) mCellChanged = true; - mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent); + mCellLoaded = true; } void Scene::addPostponedPhysicsObjects() @@ -868,13 +861,13 @@ namespace MWWorld if (changeEvent) mCellChanged = true; + mCellLoaded = true; + if (useFading) MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); - mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent); - MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx); } @@ -921,11 +914,6 @@ namespace MWWorld addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering); addObject(ptr, mWorld, *mPhysics, mNavigator); mWorld.scaleObject(ptr, ptr.getCellRef().getScale()); - if (mCurrentCell != nullptr) - { - const auto player = mWorld.getPlayerPtr(); - mNavigator.update(player.getRefData().getPosition().asVec3()); - } } catch (std::exception& e) { @@ -945,11 +933,6 @@ namespace MWWorld if (const auto object = mPhysics->getObject(ptr)) { mNavigator.removeObject(DetourNavigator::ObjectId(object)); - if (mCurrentCell != nullptr) - { - const auto player = mWorld.getPlayerPtr(); - mNavigator.update(player.getRefData().getPosition().asVec3()); - } } else if (mPhysics->getActor(ptr)) { diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 075213a66a..7e69e8e97d 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -85,6 +85,7 @@ namespace MWWorld CellStore* mCurrentCell; // the cell the player is in CellStoreCollection mActiveCells; bool mCellChanged; + bool mCellLoaded = false; MWWorld::World& mWorld; MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; @@ -152,6 +153,10 @@ namespace MWWorld bool hasCellChanged() const; ///< Has the set of active cells changed, since the last frame? + bool hasCellLoaded() const { return mCellLoaded; } + + void resetCellLoaded() { mCellLoaded = false; } + void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true); ///< Move to interior cell. /// @param changeEvent Set cellChanged flag? diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index af5abdd8f3..e212b9ec7e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -154,7 +154,6 @@ namespace MWWorld mUserDataPath(userDataPath), mDefaultHalfExtents(Settings::Manager::getVector3("default actor pathfind half extents", "Game")), mDefaultActorCollisionShapeType(DetourNavigator::toCollisionShapeType(Settings::Manager::getInt("actor collision shape type", "Game"))), - mShouldUpdateNavigator(false), mActivationDistanceOverride (activationDistanceOverride), mStartCell(startCell), mDistanceToFacedObject(-1.f), mTeleportEnabled(true), mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0), @@ -1536,12 +1535,7 @@ namespace MWWorld if (const auto object = mPhysics->getObject(door.first)) updateNavigatorObject(*object); - auto player = getPlayerPtr(); - if (mShouldUpdateNavigator && player.getCell() != nullptr) - { - mNavigator->update(player.getRefData().getPosition().asVec3()); - mShouldUpdateNavigator = false; - } + mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); } void World::updateNavigatorObject(const MWPhysics::Object& object) @@ -1549,8 +1543,7 @@ namespace MWWorld const MWWorld::Ptr ptr = object.getPtr(); const DetourNavigator::ObjectShapes shapes(object.getShapeInstance(), DetourNavigator::ObjectTransform {ptr.getRefData().getPosition(), ptr.getCellRef().getScale()}); - mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()) - || mShouldUpdateNavigator; + mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()); } const MWPhysics::RayCastingInterface* World::getRayCasting() const @@ -1821,10 +1814,7 @@ namespace MWWorld updateWeather(duration, paused); - if (!paused) - { - updateNavigator(); - } + updateNavigator(); mPlayer->update(); @@ -1842,6 +1832,13 @@ namespace MWWorld mSpellPreloadTimer = 0.1f; preloadSpells(); } + + if (mWorldScene->hasCellLoaded()) + { + mNavigator->wait(*MWBase::Environment::get().getWindowManager()->getLoadingScreen(), + DetourNavigator::WaitConditionType::requiredTilesPresent); + mWorldScene->resetCellLoaded(); + } } void World::updatePhysics (float duration, bool paused, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c48504cb05..74e34d5132 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -113,7 +113,6 @@ namespace MWWorld osg::Vec3f mDefaultHalfExtents; DetourNavigator::CollisionShapeType mDefaultActorCollisionShapeType; - bool mShouldUpdateNavigator; int mActivationDistanceOverride; diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index f49f3cdc74..57dd50739e 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -439,8 +439,17 @@ namespace const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1); mNavigator->addAgent(mAgentBounds); - EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1)); - EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2)); + mNavigator->addHeightfield(mCellPosition, cellSize1, surface1); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(); + + mNavigator->addHeightfield(mCellPosition, cellSize2, surface2); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); } TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape) @@ -1142,7 +1151,16 @@ namespace const float level2 = 2; mNavigator->addAgent(mAgentBounds); - EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1)); - EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2)); + mNavigator->addWater(mCellPosition, cellSize1, level1); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(); + + mNavigator->addWater(mCellPosition, cellSize2, level2); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); } } diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 3cc19d12ba..f1af3fc614 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -216,27 +216,13 @@ namespace DetourNavigator void AsyncNavMeshUpdater::wait(Loading::Listener& listener, WaitConditionType waitConditionType) { - if (mSettings.get().mWaitUntilMinDistanceToPlayer == 0) - return; - listener.setLabel("#{Navigation:BuildingNavigationMesh}"); - const std::size_t initialJobsLeft = getTotalJobs(); - std::size_t maxProgress = initialJobsLeft + mThreads.size(); - listener.setProgressRange(maxProgress); switch (waitConditionType) { case WaitConditionType::requiredTilesPresent: - { - const int minDistanceToPlayer = waitUntilJobsDoneForNotPresentTiles(initialJobsLeft, maxProgress, listener); - if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer) - { - mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); - listener.setProgress(maxProgress); - } + waitUntilJobsDoneForNotPresentTiles(listener); break; - } case WaitConditionType::allJobsDone: waitUntilAllJobsDone(); - listener.setProgress(maxProgress); break; } } @@ -255,8 +241,10 @@ namespace DetourNavigator thread.join(); } - int AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener) + void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener) { + const std::size_t initialJobsLeft = getTotalJobs(); + std::size_t maxProgress = initialJobsLeft + mThreads.size(); std::size_t prevJobsLeft = initialJobsLeft; std::size_t jobsDone = 0; std::size_t jobsLeft = 0; @@ -275,7 +263,13 @@ namespace DetourNavigator return minDistanceToPlayer >= maxDistanceToPlayer; }; std::unique_lock lock(mMutex); - while (!mDone.wait_for(lock, std::chrono::milliseconds(250), isDone)) + if (getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles) >= maxDistanceToPlayer + || (mJobs.empty() && mProcessingTiles.lockConst()->empty())) + return; + Loading::ScopedLoad load(&listener); + listener.setLabel("#{Navigation:BuildingNavigationMesh}"); + listener.setProgressRange(maxProgress); + while (!mDone.wait_for(lock, std::chrono::milliseconds(20), isDone)) { if (maxProgress < jobsLeft) { @@ -291,14 +285,19 @@ namespace DetourNavigator listener.increaseProgress(newJobsDone); } } - return minDistanceToPlayer; + lock.unlock(); + if (minDistanceToPlayer < maxDistanceToPlayer) + { + mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); + listener.setProgress(maxProgress); + } } void AsyncNavMeshUpdater::waitUntilAllJobsDone() { { std::unique_lock lock(mMutex); - mDone.wait(lock, [this] { return mJobs.size() == 0; }); + mDone.wait(lock, [this] { return mJobs.empty(); }); } mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 30bbc59ee8..f9fadde4f6 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -223,9 +223,9 @@ namespace DetourNavigator void cleanupLastUpdates(); - int waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener); + inline void waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener); - void waitUntilAllJobsDone(); + inline void waitUntilAllJobsDone(); }; void reportStats(const AsyncNavMeshUpdater::Stats& stats, unsigned int frameNumber, osg::Stats& out); diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp index d274023e78..536cad78b2 100644 --- a/components/detournavigator/debug.cpp +++ b/components/detournavigator/debug.cpp @@ -3,6 +3,7 @@ #include "recastmesh.hpp" #include "settings.hpp" #include "settingsutils.hpp" +#include "version.hpp" #include @@ -191,6 +192,11 @@ namespace DetourNavigator return stream << "ChangeType::" << static_cast(value); } + std::ostream& operator<<(std::ostream& stream, const Version& value) + { + return stream << "Version {" << value.mGeneration << ", " << value.mRevision << "}"; + } + void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const RecastSettings& settings) { diff --git a/components/detournavigator/debug.hpp b/components/detournavigator/debug.hpp index 818be0616c..5dcbe55ffb 100644 --- a/components/detournavigator/debug.hpp +++ b/components/detournavigator/debug.hpp @@ -18,6 +18,8 @@ class dtNavMesh; namespace DetourNavigator { + struct Version; + std::ostream& operator<<(std::ostream& stream, const TileBounds& value); std::ostream& operator<<(std::ostream& stream, Status value); @@ -54,6 +56,8 @@ namespace DetourNavigator std::ostream& operator<<(std::ostream& stream, ChangeType value); + std::ostream& operator<<(std::ostream& stream, const Version& value); + class RecastMesh; struct RecastSettings; diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 1379ebd835..59fa28b908 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -100,65 +100,56 @@ namespace DetourNavigator * @param id is used to distinguish different objects * @param shape members must live until object is updated by another shape removed from Navigator * @param transform allows to setup objects geometry according to its world state - * @return true if object is added, false if there is already object with given id */ - virtual bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; + virtual void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; /** * @brief addObject is used to add doors. * @param id is used to distinguish different objects. * @param shape members must live until object is updated by another shape or removed from Navigator. * @param transform allows to setup objects geometry according to its world state. - * @return true if object is added, false if there is already object with given id. */ - virtual bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; + virtual void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; /** * @brief updateObject replace object geometry by given data. * @param id is used to find object. * @param shape members must live until object is updated by another shape removed from Navigator. * @param transform allows to setup objects geometry according to its world state. - * @return true if object is updated, false if there is no object with given id. */ - virtual bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; + virtual void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; /** * @brief updateObject replace object geometry by given data. * @param id is used to find object. * @param shape members must live until object is updated by another shape removed from Navigator. * @param transform allows to setup objects geometry according to its world state. - * @return true if object is updated, false if there is no object with given id. */ - virtual bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; + virtual void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; /** * @brief removeObject to make it no more available at the scene. * @param id is used to find object. - * @return true if object is removed, false if there is no object with given id. */ - virtual bool removeObject(const ObjectId id) = 0; + virtual void removeObject(const ObjectId id) = 0; /** * @brief addWater is used to set water level at given world cell. * @param cellPosition allows to distinguish cells if there is many in current world. * @param cellSize set cell borders. std::numeric_limits::max() disables cell borders. * @param shift set global shift of cell center. - * @return true if there was no water at given cell if cellSize != std::numeric_limits::max() or there is - * at least single object is added to the scene, false if there is already water for given cell or there is no - * any other objects. */ - virtual bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level) = 0; + virtual void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) = 0; /** * @brief removeWater to make it no more available at the scene. * @param cellPosition allows to find cell. - * @return true if there was water at given cell. */ - virtual bool removeWater(const osg::Vec2i& cellPosition) = 0; + virtual void removeWater(const osg::Vec2i& cellPosition) = 0; - virtual bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0; + virtual void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0; - virtual bool removeHeightfield(const osg::Vec2i& cellPosition) = 0; + virtual void removeHeightfield(const osg::Vec2i& cellPosition) = 0; virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0; @@ -170,17 +161,6 @@ namespace DetourNavigator */ virtual void update(const osg::Vec3f& playerPosition) = 0; - /** - * @brief updatePlayerPosition starts background navmesh update using current scene state only when player position has been changed. - * @param playerPosition setup initial point to order build tiles of navmesh. - */ - virtual void updatePlayerPosition(const osg::Vec3f& playerPosition) = 0; - - /** - * @brief disable navigator updates - */ - virtual void setUpdatesEnabled(bool enabled) = 0; - /** * @brief wait locks thread until tiles are updated from last update call based on passed condition type. * @param waitConditionType defines when waiting will stop diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 2738c4a3f6..478451760f 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -11,7 +11,6 @@ namespace DetourNavigator NavigatorImpl::NavigatorImpl(const Settings& settings, std::unique_ptr&& db) : mSettings(settings) , mNavMeshManager(mSettings, std::move(db)) - , mUpdatesEnabled(true) { } @@ -42,7 +41,12 @@ namespace DetourNavigator mNavMeshManager.updateBounds(playerPosition); } - bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + void NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + { + addObjectImpl(id, shapes, transform); + } + + bool NavigatorImpl::addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform); bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground); @@ -59,72 +63,65 @@ namespace DetourNavigator return result; } - bool NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + void NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) { - if (addObject(id, static_cast(shapes), transform)) + if (addObjectImpl(id, static_cast(shapes), transform)) { const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart); const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd); mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door); mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door); - return true; } - return false; } - bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + void NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform); - bool result = mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground); + mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground); if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get()) { const ObjectId avoidId(avoidShape); const CollisionShape avoidCollisionShape(shapes.mShapeInstance, *avoidShape, shapes.mTransform); if (mNavMeshManager.updateObject(avoidId, avoidCollisionShape, transform, AreaType_null)) - { updateAvoidShapeId(id, avoidId); - result = true; - } } - return result; } - bool NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + void NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) { return updateObject(id, static_cast(shapes), transform); } - bool NavigatorImpl::removeObject(const ObjectId id) + void NavigatorImpl::removeObject(const ObjectId id) { - bool result = mNavMeshManager.removeObject(id); + mNavMeshManager.removeObject(id); const auto avoid = mAvoidIds.find(id); if (avoid != mAvoidIds.end()) - result = mNavMeshManager.removeObject(avoid->second) || result; + mNavMeshManager.removeObject(avoid->second); const auto water = mWaterIds.find(id); if (water != mWaterIds.end()) - result = mNavMeshManager.removeObject(water->second) || result; + mNavMeshManager.removeObject(water->second); mNavMeshManager.removeOffMeshConnections(id); - return result; } - bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) + void NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) { - return mNavMeshManager.addWater(cellPosition, cellSize, level); + mNavMeshManager.addWater(cellPosition, cellSize, level); } - bool NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) + void NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) { - return mNavMeshManager.removeWater(cellPosition); + mNavMeshManager.removeWater(cellPosition); } - bool NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) + void NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) { - return mNavMeshManager.addHeightfield(cellPosition, cellSize, shape); + mNavMeshManager.addHeightfield(cellPosition, cellSize, shape); } - bool NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition) + void NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition) { - return mNavMeshManager.removeHeightfield(cellPosition); + mNavMeshManager.removeHeightfield(cellPosition); } void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) @@ -150,31 +147,15 @@ namespace DetourNavigator void NavigatorImpl::update(const osg::Vec3f& playerPosition) { - if (!mUpdatesEnabled) - return; removeUnusedNavMeshes(); for (const auto& v : mAgents) mNavMeshManager.update(playerPosition, v.first); } - void NavigatorImpl::updatePlayerPosition(const osg::Vec3f& playerPosition) - { - const TilePosition tilePosition = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition)); - if (mLastPlayerPosition.has_value() && *mLastPlayerPosition == tilePosition) - return; - mNavMeshManager.updateBounds(playerPosition); - update(playerPosition); - mLastPlayerPosition = tilePosition; - } - - void NavigatorImpl::setUpdatesEnabled(bool enabled) - { - mUpdatesEnabled = enabled; - } - void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType) { - mNavMeshManager.wait(listener, waitConditionType); + if (mSettings.mWaitUntilMinDistanceToPlayer > 0) + mNavMeshManager.wait(listener, waitConditionType); } SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index f7b2d6d8c8..ff324280a6 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -26,23 +26,23 @@ namespace DetourNavigator void updateBounds(const osg::Vec3f& playerPosition) override; - bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; - bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; - bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; - bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; - bool removeObject(const ObjectId id) override; + void removeObject(const ObjectId id) override; - bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level) override; + void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) override; - bool removeWater(const osg::Vec2i& cellPosition) override; + void removeWater(const osg::Vec2i& cellPosition) override; - bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override; + void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override; - bool removeHeightfield(const osg::Vec2i& cellPosition) override; + void removeHeightfield(const osg::Vec2i& cellPosition) override; void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) override; @@ -50,10 +50,6 @@ namespace DetourNavigator void update(const osg::Vec3f& playerPosition) override; - void updatePlayerPosition(const osg::Vec3f& playerPosition) override; - - void setUpdatesEnabled(bool enabled) override; - void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override; SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const override; @@ -71,12 +67,12 @@ namespace DetourNavigator private: Settings mSettings; NavMeshManager mNavMeshManager; - bool mUpdatesEnabled; std::optional mLastPlayerPosition; std::map mAgents; std::unordered_map mAvoidIds; std::unordered_map mWaterIds; + inline bool addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform); void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId); void updateWaterShapeId(const ObjectId id, const ObjectId waterId); void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map& ids); diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 1eb1860217..fec6e8f04c 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -22,50 +22,24 @@ namespace DetourNavigator void setWorldspace(std::string_view /*worldspace*/) override {} - bool addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override - { - return false; - } + void addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {} - bool addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override - { - return false; - } + void addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {} - bool updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override - { - return false; - } + void updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {} - bool updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override - { - return false; - } + void updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {} - bool removeObject(const ObjectId /*id*/) override - { - return false; - } + void removeObject(const ObjectId /*id*/) override {} - bool addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/) override - { - return false; - } + void addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/) override {} - bool removeWater(const osg::Vec2i& /*cellPosition*/) override - { - return false; - } + void removeWater(const osg::Vec2i& /*cellPosition*/) override {} - bool addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/) override - { - return false; - } + void addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/) + override {} - bool removeHeightfield(const osg::Vec2i& /*cellPosition*/) override - { - return false; - } + void removeHeightfield(const osg::Vec2i& /*cellPosition*/) override {} void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) override {} @@ -75,10 +49,6 @@ namespace DetourNavigator void updateBounds(const osg::Vec3f& /*playerPosition*/) override {} - void updatePlayerPosition(const osg::Vec3f& /*playerPosition*/) override {}; - - void setUpdatesEnabled(bool /*enabled*/) override {} - void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {} SharedNavMeshCacheItem getNavMesh(const AgentBounds& /*agentBounds*/) const override diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 50744731b1..0e1dc591a3 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -107,51 +107,46 @@ namespace DetourNavigator [&] (const TilePosition& tile, ChangeType changeType) { addChangedTile(tile, changeType); }); } - bool NavMeshManager::removeObject(const ObjectId id) + void NavMeshManager::removeObject(const ObjectId id) { const auto object = mRecastMeshManager.removeObject(id); if (!object) - return false; + return; addChangedTiles(object->mShape, object->mTransform, ChangeType::remove); - return true; } - bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) + void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) { if (!mRecastMeshManager.addWater(cellPosition, cellSize, level)) - return false; + return; const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level)); addChangedTiles(cellSize, shift, ChangeType::add); - return true; } - bool NavMeshManager::removeWater(const osg::Vec2i& cellPosition) + void NavMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto water = mRecastMeshManager.removeWater(cellPosition); if (!water) - return false; + return; const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, water->mCellSize, water->mLevel)); addChangedTiles(water->mCellSize, shift, ChangeType::remove); - return true; } - bool NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) + void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) { if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape)) - return false; + return; const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize); addChangedTiles(cellSize, shift, ChangeType::add); - return true; } - bool NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) { const auto heightfield = mRecastMeshManager.removeHeightfield(cellPosition); if (!heightfield) - return false; + return; const btVector3 shift = getHeightfieldShift(heightfield->mShape, cellPosition, heightfield->mCellSize); addChangedTiles(heightfield->mCellSize, shift, ChangeType::remove); - return true; } void NavMeshManager::addAgent(const AgentBounds& agentBounds) diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index ade378aeec..7a9a1e2ba4 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -32,17 +32,17 @@ namespace DetourNavigator bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); - bool removeObject(const ObjectId id); + void removeObject(const ObjectId id); void addAgent(const AgentBounds& agentBounds); - bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level); + void addWater(const osg::Vec2i& cellPosition, int cellSize, float level); - bool removeWater(const osg::Vec2i& cellPosition); + void removeWater(const osg::Vec2i& cellPosition); - bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); + void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); - bool removeHeightfield(const osg::Vec2i& cellPosition); + void removeHeightfield(const osg::Vec2i& cellPosition); bool reset(const AgentBounds& agentBounds); From 2885885331e403d35f04c7ddc553b6209336e46a Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 6 Aug 2022 18:22:32 +0200 Subject: [PATCH 3/7] Increase mutex scope in TileCachedRecastMeshManager functions Which are called from the main thread. --- .../tilecachedrecastmeshmanager.cpp | 90 ++++++++++--------- .../tilecachedrecastmeshmanager.hpp | 2 +- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index e01eb1521e..046eb7750d 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -149,15 +149,15 @@ namespace DetourNavigator else { const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level)); + const auto worldspaceTiles = mWorldspaceTiles.lock(); getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), [&] (const TilePosition& tilePosition) { - const auto locked = mWorldspaceTiles.lock(); - auto tile = locked->mTiles.find(tilePosition); - if (tile == locked->mTiles.end()) + auto tile = worldspaceTiles->mTiles.find(tilePosition); + if (tile == worldspaceTiles->mTiles.end()) { const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); - tile = locked->mTiles.emplace_hint(tile, tilePosition, + tile = worldspaceTiles->mTiles.emplace_hint(tile, tilePosition, std::make_shared(tileBounds, mTilesGeneration)); } if (tile->second->addWater(cellPosition, cellSize, level)) @@ -180,20 +180,22 @@ namespace DetourNavigator if (object == mWaterTilesPositions.end()) return std::nullopt; std::optional result; - for (const auto& tilePosition : object->second) { - const auto locked = mWorldspaceTiles.lock(); - const auto tile = locked->mTiles.find(tilePosition); - if (tile == locked->mTiles.end()) - continue; - const auto tileResult = tile->second->removeWater(cellPosition); - if (tile->second->isEmpty()) + const auto worldspaceTiles = mWorldspaceTiles.lock(); + for (const auto& tilePosition : object->second) { - locked->mTiles.erase(tile); - ++mTilesGeneration; + const auto tile = worldspaceTiles->mTiles.find(tilePosition); + if (tile == worldspaceTiles->mTiles.end()) + continue; + const auto tileResult = tile->second->removeWater(cellPosition); + if (tile->second->isEmpty()) + { + worldspaceTiles->mTiles.erase(tile); + ++mTilesGeneration; + } + if (tileResult && !result) + result = tileResult; } - if (tileResult && !result) - result = tileResult; } mWaterTilesPositions.erase(object); if (result) @@ -214,23 +216,25 @@ namespace DetourNavigator bool result = false; - getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), - [&] (const TilePosition& tilePosition) - { - const auto locked = mWorldspaceTiles.lock(); - auto tile = locked->mTiles.find(tilePosition); - if (tile == locked->mTiles.end()) - { - const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); - tile = locked->mTiles.emplace_hint(tile, tilePosition, - std::make_shared(tileBounds, mTilesGeneration)); - } - if (tile->second->addHeightfield(cellPosition, cellSize, shape)) + { + const auto worldspaceTiles = mWorldspaceTiles.lock(); + getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), + [&] (const TilePosition& tilePosition) { - tilesPositions.push_back(tilePosition); - result = true; - } - }); + auto tile = worldspaceTiles->mTiles.find(tilePosition); + if (tile == worldspaceTiles->mTiles.end()) + { + const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); + tile = worldspaceTiles->mTiles.emplace_hint(tile, tilePosition, + std::make_shared(tileBounds, mTilesGeneration)); + } + if (tile->second->addHeightfield(cellPosition, cellSize, shape)) + { + tilesPositions.push_back(tilePosition); + result = true; + } + }); + } if (result) ++mRevision; @@ -244,20 +248,22 @@ namespace DetourNavigator if (object == mHeightfieldTilesPositions.end()) return std::nullopt; std::optional result; - for (const auto& tilePosition : object->second) { - const auto locked = mWorldspaceTiles.lock(); - const auto tile = locked->mTiles.find(tilePosition); - if (tile == locked->mTiles.end()) - continue; - const auto tileResult = tile->second->removeHeightfield(cellPosition); - if (tile->second->isEmpty()) + const auto worldspaceTiles = mWorldspaceTiles.lock(); + for (const auto& tilePosition : object->second) { - locked->mTiles.erase(tile); - ++mTilesGeneration; + const auto tile = worldspaceTiles->mTiles.find(tilePosition); + if (tile == worldspaceTiles->mTiles.end()) + continue; + const auto tileResult = tile->second->removeHeightfield(cellPosition); + if (tile->second->isEmpty()) + { + worldspaceTiles->mTiles.erase(tile); + ++mTilesGeneration; + } + if (tileResult && !result) + result = tileResult; } - if (tileResult && !result) - result = tileResult; } mHeightfieldTilesPositions.erase(object); if (result) diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 270db9e8ae..f6ef24ceed 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -165,7 +165,7 @@ namespace DetourNavigator bool addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles); - bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, + static bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles); std::optional removeTile(const ObjectId id, const TilePosition& tilePosition, From 8147d491781a17ed060392e49744e836c4e92370 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 6 Aug 2022 18:51:39 +0200 Subject: [PATCH 4/7] Remove redundant lock mGeneration is const and mRevision is changed only from the same thread. --- components/detournavigator/recastmeshmanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index b40da43d2d..5d09aaea33 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -170,7 +170,6 @@ namespace DetourNavigator Version RecastMeshManager::getVersion() const { - const std::lock_guard lock(mMutex); return Version {mGeneration, mRevision}; } } From 0abe643a15eb18d1324aedf4141a8c8ffaa2504f Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 19 Aug 2022 23:04:34 +0200 Subject: [PATCH 5/7] Add sum column to stats table --- scripts/osg_stats.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index 3a5067851d..89aaca70ed 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -313,6 +313,7 @@ def make_stats(source, key, values, precision): number=len(values), min=fixed_float(min(values), precision), max=fixed_float(max(values), precision), + sum=fixed_float(sum(values), precision), mean=fixed_float(statistics.mean(values), precision), median=fixed_float(statistics.median(values), precision), stdev=fixed_float(statistics.stdev(values), precision), From cca8faf42283f48e145696d3f2ba4785b468df93 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 19 Aug 2022 23:09:38 +0200 Subject: [PATCH 6/7] Use dashed line stype to draw sum --- scripts/osg_stats.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index 89aaca70ed..b31f737ed7 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -157,7 +157,7 @@ def draw_timeseries(sources, keys, add_sum, begin_frame, end_frame): for key in keys: ax.plot(x, frames[key], label=f'{key}:{name}') if add_sum: - ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label=f'sum:{name}') + ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label=f'sum:{name}', linestyle='--') ax.grid(True) ax.legend() fig.canvas.manager.set_window_title('timeseries') @@ -170,7 +170,8 @@ def draw_commulative_timeseries(sources, keys, add_sum, begin_frame, end_frame): for key in keys: ax.plot(x, numpy.cumsum(frames[key]), label=f'{key}:{name}') if add_sum: - ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label=f'sum:{name}') + ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label=f'sum:{name}', + linestyle='--') ax.grid(True) ax.legend() fig.canvas.manager.set_window_title('commulative_timeseries') From aea461424071862e523882f647ec98fb9763a5f8 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 20 Aug 2022 19:17:45 +0200 Subject: [PATCH 7/7] Fix clang tidy warning --- components/detournavigator/navigatorimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 478451760f..838ed8c0b7 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -127,7 +127,7 @@ namespace DetourNavigator void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) { Misc::CoordinateConverter converter(&cell); - for (auto& edge : pathgrid.mEdges) + for (const auto& edge : pathgrid.mEdges) { const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0])); const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1]));