1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-06 00:55:50 +00:00
OpenMW/apps/openmw/mwphysics/projectileconvexcallback.cpp
fredzio 07fa1803f7 Use btCollisionObject* instead of MWWorld::Ptr inside of Projectile
collision handling and castRay() to avoid calling getPtr(). It is a step forward
removing the mutex inside of PtrHolder.

Do the same for DeepestNotMeContactTestResultCallback. It is used
only for not-ranged combat for now, but do it anyway for parity with all
other callback. This way, once the PtrHolder mutex is gone one will not
have to worry about wether it is safe to use the callback in a specific
context.

To avoid use-after-free with projectile / projectile collision, defer deletion of projectile.
Since instead of storing a copy of target Ptr we have a pointer to its collision object,
we can't delete projectiles until after we finished iterating over the loops.
2021-08-08 15:05:07 +02:00

65 lines
2.1 KiB
C++

#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "../mwworld/class.hpp"
#include "actor.hpp"
#include "collisiontype.hpp"
#include "projectile.hpp"
#include "projectileconvexcallback.hpp"
#include "ptrholder.hpp"
namespace MWPhysics
{
ProjectileConvexCallback::ProjectileConvexCallback(const btCollisionObject* caster, const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj)
: btCollisionWorld::ClosestConvexResultCallback(from, to)
, mCaster(caster)
, mMe(me)
, mProjectile(proj)
{
assert(mProjectile);
}
btScalar ProjectileConvexCallback::addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace)
{
const auto* hitObject = result.m_hitCollisionObject;
// don't hit the caster
if (hitObject == mCaster)
return 1.f;
// don't hit the projectile
if (hitObject == mMe)
return 1.f;
btCollisionWorld::ClosestConvexResultCallback::addSingleResult(result, normalInWorldSpace);
switch (hitObject->getBroadphaseHandle()->m_collisionFilterGroup)
{
case CollisionType_Actor:
{
if (!mProjectile->isValidTarget(hitObject))
return 1.f;
break;
}
case CollisionType_Projectile:
{
auto* target = static_cast<Projectile*>(hitObject->getUserPointer());
if (!mProjectile->isValidTarget(target->getCasterCollisionObject()))
return 1.f;
target->hit(mMe, m_hitPointWorld, m_hitNormalWorld);
break;
}
case CollisionType_Water:
{
mProjectile->setWaterHitPosition(m_hitPointWorld);
if (mProjectile->canTraverseWater())
return 1.f;
break;
}
}
mProjectile->hit(hitObject, m_hitPointWorld, m_hitNormalWorld);
return result.m_hitFraction;
}
}