1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 20:29:57 +00:00

Ignore player when checking whether AiTravel destination is occupied by other actor

This commit is contained in:
elsid 2022-04-11 19:30:54 +02:00
parent fd6899e91d
commit 39da3bfef8
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
10 changed files with 79 additions and 21 deletions

View file

@ -10,6 +10,7 @@
#include <components/esm3/cellid.hpp> #include <components/esm3/cellid.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/misc/span.hpp>
#include <osg/Timer> #include <osg/Timer>
@ -658,7 +659,7 @@ namespace MWBase
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors = nullptr) const = 0; const Misc::Span<const MWWorld::ConstPtr>& ignore, std::vector<MWWorld::Ptr>* occupyingActors = nullptr) const = 0;
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;

View file

@ -83,7 +83,7 @@ namespace MWMechanics
if (mDestinationCheck.update(duration) == Misc::TimerStatus::Elapsed) if (mDestinationCheck.update(duration) == Misc::TimerStatus::Elapsed)
{ {
std::vector<MWWorld::Ptr> occupyingActors; std::vector<MWWorld::Ptr> occupyingActors;
if (isAreaOccupiedByOtherActor(actor, targetPos, &occupyingActors)) if (isAreaOccupiedByOtherActor(actor, targetPos, true, &occupyingActors))
{ {
const float actorRadius = getActorRadius(actor); const float actorRadius = getActorRadius(actor);
const float distanceToTarget = distance(actorPos, targetPos); const float distanceToTarget = distance(actorPos, targetPos);

View file

@ -1,5 +1,7 @@
#include "obstacle.hpp" #include "obstacle.hpp"
#include <array>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -74,13 +76,19 @@ namespace MWMechanics
return MWWorld::Ptr(); // none found return MWWorld::Ptr(); // none found
} }
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer,
std::vector<MWWorld::Ptr>* occupyingActors) std::vector<MWWorld::Ptr>* occupyingActors)
{ {
const auto world = MWBase::Environment::get().getWorld(); const auto world = MWBase::Environment::get().getWorld();
const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor); const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor);
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z())); const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor, occupyingActors); if (ignorePlayer)
{
const std::array ignore {actor, world->getPlayerConstPtr()};
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, ignore, occupyingActors);
}
const std::array ignore {actor};
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, ignore, occupyingActors);
} }
ObstacleCheck::ObstacleCheck() ObstacleCheck::ObstacleCheck()

View file

@ -24,7 +24,7 @@ namespace MWMechanics
/** \return Pointer to the door, or empty pointer if none exists **/ /** \return Pointer to the door, or empty pointer if none exists **/
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination, bool ignorePlayer = false,
std::vector<MWWorld::Ptr>* occupyingActors = nullptr); std::vector<MWWorld::Ptr>* occupyingActors = nullptr);
class ObstacleCheck class ObstacleCheck

View file

@ -22,15 +22,15 @@ namespace MWPhysics
return nearest.distance(position) < radius; return nearest.distance(position) < radius;
} }
template <class OnCollision> template <class Ignore, class OnCollision>
class HasSphereCollisionCallback final : public btBroadphaseAabbCallback class HasSphereCollisionCallback final : public btBroadphaseAabbCallback
{ {
public: public:
HasSphereCollisionCallback(const btVector3& position, const btScalar radius, btCollisionObject* object, HasSphereCollisionCallback(const btVector3& position, const btScalar radius, const int mask, const int group,
const int mask, const int group, OnCollision* onCollision) const Ignore& ignore, OnCollision* onCollision)
: mPosition(position), : mPosition(position),
mRadius(radius), mRadius(radius),
mCollisionObject(object), mIgnore(ignore),
mCollisionFilterMask(mask), mCollisionFilterMask(mask),
mCollisionFilterGroup(group), mCollisionFilterGroup(group),
mOnCollision(onCollision) mOnCollision(onCollision)
@ -42,7 +42,7 @@ namespace MWPhysics
if (mResult && mOnCollision == nullptr) if (mResult && mOnCollision == nullptr)
return false; return false;
const auto collisionObject = static_cast<btCollisionObject*>(proxy->m_clientObject); const auto collisionObject = static_cast<btCollisionObject*>(proxy->m_clientObject);
if (collisionObject == mCollisionObject if (mIgnore(collisionObject)
|| !needsCollision(*proxy) || !needsCollision(*proxy)
|| !testAabbAgainstSphere(proxy->m_aabbMin, proxy->m_aabbMax, mPosition, mRadius)) || !testAabbAgainstSphere(proxy->m_aabbMin, proxy->m_aabbMax, mPosition, mRadius))
return true; return true;
@ -63,7 +63,7 @@ namespace MWPhysics
private: private:
btVector3 mPosition; btVector3 mPosition;
btScalar mRadius; btScalar mRadius;
btCollisionObject* mCollisionObject; Ignore mIgnore;
int mCollisionFilterMask; int mCollisionFilterMask;
int mCollisionFilterGroup; int mCollisionFilterGroup;
OnCollision* mOnCollision; OnCollision* mOnCollision;

View file

@ -2,7 +2,11 @@
#include <LinearMath/btIDebugDraw.h> #include <LinearMath/btIDebugDraw.h>
#include <LinearMath/btVector3.h> #include <LinearMath/btVector3.h>
#include <memory> #include <memory>
#include <algorithm>
#include <vector>
#include <osg/Group> #include <osg/Group>
#include <osg/Stats> #include <osg/Stats>
#include <osg/Timer> #include <osg/Timer>
@ -884,12 +888,19 @@ namespace MWPhysics
} }
bool PhysicsSystem::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, bool PhysicsSystem::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const const Misc::Span<const MWWorld::ConstPtr>& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const
{ {
btCollisionObject* object = nullptr; std::vector<const btCollisionObject*> ignoredObjects;
const auto it = mActors.find(ignore.mRef); ignoredObjects.reserve(ignore.size());
if (it != mActors.end()) for (const auto& v : ignore)
object = it->second->getCollisionObject(); if (const auto it = mActors.find(v.mRef); it != mActors.end())
ignoredObjects.push_back(it->second->getCollisionObject());
std::sort(ignoredObjects.begin(), ignoredObjects.end());
ignoredObjects.erase(std::unique(ignoredObjects.begin(), ignoredObjects.end()), ignoredObjects.end());
const auto ignoreFilter = [&] (const btCollisionObject* v)
{
return std::binary_search(ignoredObjects.begin(), ignoredObjects.end(), v);
};
const auto bulletPosition = Misc::Convert::toBullet(position); const auto bulletPosition = Misc::Convert::toBullet(position);
const auto aabbMin = bulletPosition - btVector3(radius, radius, radius); const auto aabbMin = bulletPosition - btVector3(radius, radius, radius);
const auto aabbMax = bulletPosition + btVector3(radius, radius, radius); const auto aabbMax = bulletPosition + btVector3(radius, radius, radius);
@ -897,7 +908,7 @@ namespace MWPhysics
const int group = 0xff; const int group = 0xff;
if (occupyingActors == nullptr) if (occupyingActors == nullptr)
{ {
HasSphereCollisionCallback callback(bulletPosition, radius, object, mask, group, HasSphereCollisionCallback callback(bulletPosition, radius, mask, group, ignoreFilter,
static_cast<void (*)(const btCollisionObject*)>(nullptr)); static_cast<void (*)(const btCollisionObject*)>(nullptr));
mTaskScheduler->aabbTest(aabbMin, aabbMax, callback); mTaskScheduler->aabbTest(aabbMin, aabbMax, callback);
return callback.getResult(); return callback.getResult();
@ -907,7 +918,7 @@ namespace MWPhysics
if (PtrHolder* holder = static_cast<PtrHolder*>(object->getUserPointer())) if (PtrHolder* holder = static_cast<PtrHolder*>(object->getUserPointer()))
occupyingActors->push_back(holder->getPtr()); occupyingActors->push_back(holder->getPtr());
}; };
HasSphereCollisionCallback callback(bulletPosition, radius, object, mask, group, &onCollision); HasSphereCollisionCallback callback(bulletPosition, radius, mask, group, ignoreFilter, &onCollision);
mTaskScheduler->aabbTest(aabbMin, aabbMax, callback); mTaskScheduler->aabbTest(aabbMin, aabbMax, callback);
return callback.getResult(); return callback.getResult();
} }

View file

@ -16,6 +16,8 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Timer> #include <osg/Timer>
#include <components/misc/span.hpp>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "collisiontype.hpp" #include "collisiontype.hpp"
@ -277,7 +279,7 @@ namespace MWPhysics
} }
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const; const Misc::Span<const MWWorld::ConstPtr>& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const;
void reportStats(unsigned int frameNumber, osg::Stats& stats) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
void reportCollision(const btVector3& position, const btVector3& normal); void reportCollision(const btVector3& position, const btVector3& normal);

View file

@ -3997,7 +3997,7 @@ namespace MWWorld
} }
bool World::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, bool World::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const const Misc::Span<const MWWorld::ConstPtr>& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const
{ {
return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore, occupyingActors); return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore, occupyingActors);
} }

View file

@ -736,7 +736,7 @@ namespace MWWorld
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const override; const Misc::Span<const MWWorld::ConstPtr>& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const override;
void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;

36
components/misc/span.hpp Normal file
View file

@ -0,0 +1,36 @@
#ifndef OPENMW_COMPONENTS_MISC_SPAN_H
#define OPENMW_COMPONENTS_MISC_SPAN_H
#include <cstddef>
namespace Misc
{
template <class T>
class Span
{
public:
constexpr Span() = default;
constexpr Span(T* pointer, std::size_t size)
: mPointer(pointer)
, mSize(size)
{}
template <class Range>
constexpr Span(Range& range)
: Span(range.data(), range.size())
{}
constexpr T* begin() const { return mPointer; }
constexpr T* end() const { return mPointer + mSize; }
constexpr std::size_t size() const { return mSize; }
private:
T* mPointer = nullptr;
std::size_t mSize = 0;
};
}
#endif