From e82d65a2c79aa61cdf242856a69f03d1f6b866ee Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:02:59 +0300 Subject: [PATCH 1/8] Use if-continue to skip build path --- apps/openmw/mwmechanics/aiwander.cpp | 31 +++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 405f36767..6b7d6bf16 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -309,22 +309,25 @@ namespace MWMechanics mDestination = osg::Vec3f(destinationX, destinationY, destinationZ); // Check if land creature will walk onto water or if water creature will swim onto land - if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || - (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) - { - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + if (!isWaterCreature && destinationIsAtWater(actor, mDestination)) + continue; - if (mPathFinder.isPathConstructed()) - { - storage.setState(AiWanderStorage::Wander_Walking, true); - mHasDestination = true; - mUsePathgrid = false; - } - return; + if (isWaterCreature && destinationThroughGround(currentPosition, mDestination)) + continue; + + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + mPathFinder.addPointToPath(mDestination); + + if (mPathFinder.isPathConstructed()) + { + storage.setState(AiWanderStorage::Wander_Walking, true); + mHasDestination = true; + mUsePathgrid = false; } + + break; } while (--attempts); } From e033b0c565849b80c0f92def1e11fc6fdea292ec Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:04:07 +0300 Subject: [PATCH 2/8] Avoid build path through the ground for flying wandering creatures --- apps/openmw/mwmechanics/aiwander.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6b7d6bf16..8c01c7b96 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -298,7 +298,8 @@ namespace MWMechanics const auto currentPosition = actor.getRefData().getPosition().asVec3(); std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here - bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); + const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); + const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor); do { // Determine a random location within radius of original position const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; @@ -312,7 +313,7 @@ namespace MWMechanics if (!isWaterCreature && destinationIsAtWater(actor, mDestination)) continue; - if (isWaterCreature && destinationThroughGround(currentPosition, mDestination)) + if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination)) continue; const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); From ebdff5d96e32fa6d8672d544e0741050892c45b0 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:05:13 +0300 Subject: [PATCH 3/8] Check for height map when cast ray for AiWander path --- apps/openmw/mwmechanics/aiwander.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8c01c7b96..8ed9cf8d2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -13,6 +13,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwphysics/collisiontype.hpp" + #include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" @@ -346,8 +348,10 @@ namespace MWMechanics * Returns true if the start to end point travels through a collision point (land). */ bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) { + const int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door; return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(), - destination.x(), destination.y(), destination.z()); + destination.x(), destination.y(), destination.z(), + mask); } void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { From ff67a9e2333fbbee8144dcba1c70d2f3d3743098 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:08:06 +0300 Subject: [PATCH 4/8] Build straight path for wandering flying and water creatures --- apps/openmw/mwmechanics/aiwander.cpp | 15 +++++++++++---- apps/openmw/mwmechanics/pathfinding.cpp | 7 +++++++ apps/openmw/mwmechanics/pathfinding.hpp | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8ed9cf8d2..e334f72da 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -318,10 +318,17 @@ namespace MWMechanics if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination)) continue; - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + if (isWaterCreature || isFlyingCreature) + { + mPathFinder.buildStraightPath(mDestination); + } + else + { + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); + mPathFinder.addPointToPath(mDestination); + } if (mPathFinder.isPathConstructed()) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e0285be92..13c218008 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -269,6 +269,13 @@ namespace MWMechanics mPath.pop_front(); } + void PathFinder::buildStraightPath(const osg::Vec3f& endPoint) + { + mPath.clear(); + mPath.push_back(endPoint); + mConstructed = true; + } + void PathFinder::buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 8a5b8338a..b59af44fd 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -72,6 +72,8 @@ namespace MWMechanics mCell = nullptr; } + void buildStraightPath(const osg::Vec3f& endPoint); + void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); From a65f60e1f1bc1f8bf35cddbdd2f809fb37a8cab9 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:10:46 +0300 Subject: [PATCH 5/8] Build path only by navmesh for wandering near spawn --- apps/openmw/mwmechanics/aiwander.cpp | 5 ++--- apps/openmw/mwmechanics/pathfinding.cpp | 10 ++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e334f72da..353786677 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -325,9 +325,8 @@ namespace MWMechanics else { const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); - mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); - mPathFinder.addPointToPath(mDestination); + mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents, + getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 13c218008..db6b8d686 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -287,6 +287,16 @@ namespace MWMechanics mConstructed = true; } + void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, + const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags) + { + mPath.clear(); + + buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); + + mConstructed = true; + } + void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index b59af44fd..1dc85c5e5 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -77,6 +77,9 @@ namespace MWMechanics void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); + void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, + const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags); + void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags); From 287433efa8ab146db98f31dc6dcbc58edd681813 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:58:22 +0300 Subject: [PATCH 6/8] Stop walking for water and flying creatures after single stuck --- apps/openmw/mwmechanics/aiwander.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 353786677..db2057df3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -47,6 +47,16 @@ namespace MWMechanics std::string("idle9"), }; + namespace + { + inline int getCountBeforeReset(const MWWorld::ConstPtr& actor) + { + if (actor.getClass().isPureWaterCreature(actor) || actor.getClass().isPureFlyingCreature(actor)) + return 1; + return COUNT_BEFORE_RESET; + } + } + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), @@ -493,7 +503,7 @@ namespace MWMechanics } // if stuck for sufficiently long, act like current location was the destination - if (storage.mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset + if (storage.mStuckCount >= getCountBeforeReset(actor)) // something has gone wrong, reset { mObstacleCheck.clear(); stopWalking(actor, storage); From 1e8bf3846e7b61a1b5265894e1cb7e7250de0586 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 01:59:09 +0300 Subject: [PATCH 7/8] Remove unused argument --- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- apps/openmw/mwmechanics/obstacle.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d8fe7919..c8b548bad 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -121,13 +121,13 @@ namespace MWMechanics * u = how long to move sideways * */ - void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance) + void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration) { const MWWorld::Class& cls = actor.getClass(); ESM::Position pos = actor.getRefData().getPosition(); if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor) * scaleMinimumDistance; + mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); float distSameSpot = mDistSameSpot * duration; diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index d7e582f8c..46c1bc83d 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -30,7 +30,7 @@ namespace MWMechanics bool isEvading() const; // Updates internal state, call each frame for moving actor - void update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance = 1.0f); + void update(const MWWorld::Ptr& actor, float duration); // change direction to try to fix "stuck" actor void takeEvasiveAction(MWMechanics::Movement& actorMovement) const; From 5434e924375ae878124aaab1b3353a1781b4ed8a Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 20 Mar 2019 02:00:08 +0300 Subject: [PATCH 8/8] Take in account actor half extents for obstacle check --- apps/openmw/mwmechanics/obstacle.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index c8b548bad..63167e302 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -2,6 +2,8 @@ #include +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -123,15 +125,17 @@ namespace MWMechanics */ void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration) { - const MWWorld::Class& cls = actor.getClass(); - ESM::Position pos = actor.getRefData().getPosition(); + const ESM::Position pos = actor.getRefData().getPosition(); - if(mDistSameSpot == -1) - mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor); - - float distSameSpot = mDistSameSpot * duration; + if (mDistSameSpot == -1) + { + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor); + mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y()); + } - bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; + const float distSameSpot = mDistSameSpot * duration; + const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2(); + const bool samePosition = squaredMovedDistance < distSameSpot * distSameSpot; // update position mPrevX = pos.pos[0];