mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 23:19:56 +00:00
b39437dfb6
When an NPC fire a projectile, it should affect only its targeted actor. To this end, after a hit is detected the target is checked against the list of AI targets and reactivated if necessary. Problem occurs when the hit occurs as a result of a friendly actor going into the projectile (detected in ClosestNotMeConvexResultCallback): while the projectile is inside the friend's collision box, it is deactivated, just to be immediately reactivated. Effectively, the projectile does nothing until the actor moves out. Add a check inside the ClosestNotMeConvexResultCallback before declaring a hit. Since the necessary data is not safely accessible from the async thread, maintain a copy inside the Projectile class.
54 lines
2.2 KiB
C++
54 lines
2.2 KiB
C++
#include "closestnotmeconvexresultcallback.hpp"
|
|
|
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
|
|
|
#include <components/misc/convert.hpp>
|
|
|
|
#include "../mwbase/world.hpp"
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
#include "collisiontype.hpp"
|
|
#include "projectile.hpp"
|
|
|
|
namespace MWPhysics
|
|
{
|
|
ClosestNotMeConvexResultCallback::ClosestNotMeConvexResultCallback(const btCollisionObject *me, const btVector3 &motion, btScalar minCollisionDot)
|
|
: btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)),
|
|
mMe(me), mMotion(motion), mMinCollisionDot(minCollisionDot)
|
|
{
|
|
}
|
|
|
|
btScalar ClosestNotMeConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
|
|
{
|
|
if (convexResult.m_hitCollisionObject == mMe)
|
|
return btScalar(1);
|
|
|
|
if (convexResult.m_hitCollisionObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Projectile)
|
|
{
|
|
auto* projectileHolder = static_cast<Projectile*>(convexResult.m_hitCollisionObject->getUserPointer());
|
|
if (!projectileHolder->isActive())
|
|
return btScalar(1);
|
|
auto* targetHolder = static_cast<PtrHolder*>(mMe->getUserPointer());
|
|
const MWWorld::Ptr target = targetHolder->getPtr();
|
|
if (projectileHolder->isValidTarget(target))
|
|
projectileHolder->hit(target, convexResult.m_hitPointLocal, convexResult.m_hitNormalLocal);
|
|
return btScalar(1);
|
|
}
|
|
|
|
btVector3 hitNormalWorld;
|
|
if (normalInWorldSpace)
|
|
hitNormalWorld = convexResult.m_hitNormalLocal;
|
|
else
|
|
{
|
|
///need to transform normal into worldspace
|
|
hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
|
}
|
|
|
|
// dot product of the motion vector against the collision contact normal
|
|
btScalar dotCollision = mMotion.dot(hitNormalWorld);
|
|
if (dotCollision <= mMinCollisionDot)
|
|
return btScalar(1);
|
|
|
|
return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
|
|
}
|
|
}
|