1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-11-08 21:16:40 +00:00

Merge branch 'killmutex' into 'master'

Remove mutex from PtrHolder

See merge request OpenMW/openmw!1110
This commit is contained in:
psi29a 2021-08-08 19:45:16 +00:00
commit cb7a4d20dd
14 changed files with 98 additions and 120 deletions

View file

@ -21,7 +21,7 @@ namespace MWPhysics
Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk) Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk)
: mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false) : mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false)
, mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBox.center), mOriginalHalfExtents(shape->mCollisionBox.extents) , mMeshTranslation(shape->mCollisionBox.center), mOriginalHalfExtents(shape->mCollisionBox.extents)
, mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0} , mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0}
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
, mInternalCollisionMode(true) , mInternalCollisionMode(true)

View file

@ -132,11 +132,6 @@ namespace MWPhysics
return mInternalCollisionMode && mOnSlope; return mInternalCollisionMode && mOnSlope;
} }
btCollisionObject* getCollisionObject() const
{
return mCollisionObject.get();
}
/// Sets whether this actor should be able to collide with the water surface /// Sets whether this actor should be able to collide with the water surface
void setCanWaterWalk(bool waterWalk); void setCanWaterWalk(bool waterWalk);
@ -188,8 +183,6 @@ namespace MWPhysics
std::unique_ptr<btCollisionShape> mShape; std::unique_ptr<btCollisionShape> mShape;
btConvexShape* mConvexShape; btConvexShape* mConvexShape;
std::unique_ptr<btCollisionObject> mCollisionObject;
osg::Vec3f mMeshTranslation; osg::Vec3f mMeshTranslation;
osg::Vec3f mOriginalHalfExtents; osg::Vec3f mOriginalHalfExtents;
osg::Vec3f mHalfExtents; osg::Vec3f mHalfExtents;

View file

@ -77,10 +77,8 @@ namespace MWPhysics
auto* projectileHolder = static_cast<Projectile*>(convexResult.m_hitCollisionObject->getUserPointer()); auto* projectileHolder = static_cast<Projectile*>(convexResult.m_hitCollisionObject->getUserPointer());
if (!projectileHolder->isActive()) if (!projectileHolder->isActive())
return btScalar(1); return btScalar(1);
auto* targetHolder = static_cast<PtrHolder*>(mMe->getUserPointer()); if (projectileHolder->isValidTarget(mMe))
const MWWorld::Ptr target = targetHolder->getPtr(); projectileHolder->hit(mMe, convexResult.m_hitPointLocal, convexResult.m_hitNormalLocal);
if (projectileHolder->isValidTarget(target))
projectileHolder->hit(target, convexResult.m_hitPointLocal, convexResult.m_hitNormalLocal);
return btScalar(1); return btScalar(1);
} }

View file

@ -7,6 +7,7 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "collisiontype.hpp"
#include "ptrholder.hpp" #include "ptrholder.hpp"
namespace MWPhysics namespace MWPhysics
@ -19,17 +20,14 @@ namespace MWPhysics
btScalar ClosestNotMeRayResultCallback::addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) btScalar ClosestNotMeRayResultCallback::addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
{ {
if (rayResult.m_collisionObject == mMe) const auto* hitObject = rayResult.m_collisionObject;
if (hitObject == mMe)
return 1.f; return 1.f;
if (!mTargets.empty()) if (hitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor && !mTargets.empty())
{ {
if ((std::find(mTargets.begin(), mTargets.end(), rayResult.m_collisionObject) == mTargets.end())) if ((std::find(mTargets.begin(), mTargets.end(), hitObject) == mTargets.end()))
{ return 1.f;
auto* holder = static_cast<PtrHolder*>(rayResult.m_collisionObject->getUserPointer());
if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor())
return 1.f;
}
} }
return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);

View file

@ -6,6 +6,7 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "collisiontype.hpp"
#include "ptrholder.hpp" #include "ptrholder.hpp"
namespace MWPhysics namespace MWPhysics
@ -23,14 +24,10 @@ namespace MWPhysics
const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; const btCollisionObject* collisionObject = col1Wrap->m_collisionObject;
if (collisionObject != mMe) if (collisionObject != mMe)
{ {
if (!mTargets.empty()) if (collisionObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor && !mTargets.empty())
{ {
if ((std::find(mTargets.begin(), mTargets.end(), collisionObject) == mTargets.end())) if ((std::find(mTargets.begin(), mTargets.end(), collisionObject) == mTargets.end()))
{ return 0.f;
PtrHolder* holder = static_cast<PtrHolder*>(collisionObject->getUserPointer());
if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor())
return 0.f;
}
} }
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());

View file

@ -83,16 +83,6 @@ namespace MWPhysics
} }
} }
btCollisionObject* Object::getCollisionObject()
{
return mCollisionObject.get();
}
const btCollisionObject* Object::getCollisionObject() const
{
return mCollisionObject.get();
}
btTransform Object::getTransform() const btTransform Object::getTransform() const
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::unique_lock<std::mutex> lock(mPositionMutex);

View file

@ -33,8 +33,6 @@ namespace MWPhysics
void setRotation(osg::Quat quat); void setRotation(osg::Quat quat);
void updatePosition(); void updatePosition();
void commitPositionChange(); void commitPositionChange();
btCollisionObject* getCollisionObject();
const btCollisionObject* getCollisionObject() const;
btTransform getTransform() const; btTransform getTransform() const;
/// Return solid flag. Not used by the object itself, true by default. /// Return solid flag. Not used by the object itself, true by default.
bool isSolid() const; bool isSolid() const;
@ -45,7 +43,6 @@ namespace MWPhysics
bool animateCollisionShapes(); bool animateCollisionShapes();
private: private:
std::unique_ptr<btCollisionObject> mCollisionObject;
osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance; osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance;
std::map<int, osg::NodePath> mRecIndexToNodePath; std::map<int, osg::NodePath> mRecIndexToNodePath;
bool mSolid; bool mSolid;

View file

@ -635,19 +635,7 @@ namespace MWPhysics
if (btFrom == btTo) if (btFrom == btTo)
return; return;
const auto casterPtr = projectile->getCaster(); ProjectileConvexCallback resultCallback(projectile->getCasterCollisionObject(), projectile->getCollisionObject(), btFrom, btTo, projectile);
const auto* caster = [this,&casterPtr]() -> const btCollisionObject*
{
const Actor* actor = getActor(casterPtr);
if (actor)
return actor->getCollisionObject();
const Object* object = getObject(casterPtr);
if (object)
return object->getCollisionObject();
return nullptr;
}();
ProjectileConvexCallback resultCallback(caster, btFrom, btTo, projectile);
resultCallback.m_collisionFilterMask = 0xff; resultCallback.m_collisionFilterMask = 0xff;
resultCallback.m_collisionFilterGroup = CollisionType_Projectile; resultCallback.m_collisionFilterGroup = CollisionType_Projectile;

View file

@ -7,8 +7,10 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "actor.hpp"
#include "collisiontype.hpp" #include "collisiontype.hpp"
#include "mtphysics.hpp" #include "mtphysics.hpp"
#include "object.hpp"
#include "projectile.hpp" #include "projectile.hpp"
namespace MWPhysics namespace MWPhysics
@ -17,7 +19,7 @@ Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, f
: mCanCrossWaterSurface(canCrossWaterSurface) : mCanCrossWaterSurface(canCrossWaterSurface)
, mCrossedWaterSurface(false) , mCrossedWaterSurface(false)
, mActive(true) , mActive(true)
, mCaster(caster) , mHitTarget(nullptr)
, mWaterHitPosition(std::nullopt) , mWaterHitPosition(std::nullopt)
, mPhysics(physicssystem) , mPhysics(physicssystem)
, mTaskScheduler(scheduler) , mTaskScheduler(scheduler)
@ -32,6 +34,7 @@ Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, f
mCollisionObject->setUserPointer(this); mCollisionObject->setUserPointer(this);
setPosition(position); setPosition(position);
setCaster(caster);
const int collisionMask = CollisionType_World | CollisionType_HeightMap | const int collisionMask = CollisionType_World | CollisionType_HeightMap |
CollisionType_Actor | CollisionType_Door | CollisionType_Water | CollisionType_Projectile; CollisionType_Actor | CollisionType_Door | CollisionType_Water | CollisionType_Projectile;
@ -77,54 +80,67 @@ bool Projectile::canTraverseWater() const
return mCanCrossWaterSurface; return mCanCrossWaterSurface;
} }
void Projectile::hit(const MWWorld::Ptr& target, btVector3 pos, btVector3 normal) void Projectile::hit(const btCollisionObject* target, btVector3 pos, btVector3 normal)
{ {
if (!mActive.load(std::memory_order_acquire)) bool active = true;
if (!mActive.compare_exchange_strong(active, false, std::memory_order_relaxed) || !active)
return; return;
std::scoped_lock lock(mMutex);
mHitTarget = target; mHitTarget = target;
mHitPosition = pos; mHitPosition = pos;
mHitNormal = normal; mHitNormal = normal;
mActive.store(false, std::memory_order_release); }
MWWorld::Ptr Projectile::getTarget() const
{
assert(!mActive);
auto* target = static_cast<PtrHolder*>(mHitTarget->getUserPointer());
return target ? target->getPtr() : MWWorld::Ptr();
} }
MWWorld::Ptr Projectile::getCaster() const MWWorld::Ptr Projectile::getCaster() const
{ {
std::scoped_lock lock(mMutex);
return mCaster; return mCaster;
} }
void Projectile::setCaster(const MWWorld::Ptr& caster) void Projectile::setCaster(const MWWorld::Ptr& caster)
{ {
std::scoped_lock lock(mMutex);
mCaster = caster; mCaster = caster;
mCasterColObj = [this,&caster]() -> const btCollisionObject*
{
const Actor* actor = mPhysics->getActor(caster);
if (actor)
return actor->getCollisionObject();
const Object* object = mPhysics->getObject(caster);
if (object)
return object->getCollisionObject();
return nullptr;
}();
} }
void Projectile::setValidTargets(const std::vector<MWWorld::Ptr>& targets) void Projectile::setValidTargets(const std::vector<MWWorld::Ptr>& targets)
{ {
std::scoped_lock lock(mMutex); std::scoped_lock lock(mMutex);
mValidTargets = targets; mValidTargets.clear();
for (const auto& ptr : targets)
{
const auto* physicActor = mPhysics->getActor(ptr);
if (physicActor)
mValidTargets.push_back(physicActor->getCollisionObject());
}
} }
bool Projectile::isValidTarget(const MWWorld::Ptr& target) const bool Projectile::isValidTarget(const btCollisionObject* target) const
{ {
assert(target);
std::scoped_lock lock(mMutex); std::scoped_lock lock(mMutex);
if (mCaster == target) if (mCasterColObj == target)
return false; return false;
if (target.isEmpty() || mValidTargets.empty()) if (mValidTargets.empty())
return true; return true;
bool validTarget = false; return std::any_of(mValidTargets.begin(), mValidTargets.end(),
for (const auto& targetActor : mValidTargets) [target](const btCollisionObject* actor) { return target == actor; });
{
if (targetActor == target)
{
validTarget = true;
break;
}
}
return validTarget;
} }
std::optional<btVector3> Projectile::getWaterHitPosition() std::optional<btVector3> Projectile::getWaterHitPosition()

View file

@ -42,31 +42,26 @@ namespace MWPhysics
void setPosition(const osg::Vec3f& position); void setPosition(const osg::Vec3f& position);
osg::Vec3f getPosition() const; osg::Vec3f getPosition() const;
btCollisionObject* getCollisionObject() const
{
return mCollisionObject.get();
}
bool isActive() const bool isActive() const
{ {
return mActive.load(std::memory_order_acquire); return mActive.load(std::memory_order_acquire);
} }
MWWorld::Ptr getTarget() const MWWorld::Ptr getTarget() const;
{
assert(!mActive);
return mHitTarget;
}
MWWorld::Ptr getCaster() const; MWWorld::Ptr getCaster() const;
void setCaster(const MWWorld::Ptr& caster); void setCaster(const MWWorld::Ptr& caster);
const btCollisionObject* getCasterCollisionObject() const
{
return mCasterColObj;
}
bool canTraverseWater() const; bool canTraverseWater() const;
void hit(const MWWorld::Ptr& target, btVector3 pos, btVector3 normal); void hit(const btCollisionObject* target, btVector3 pos, btVector3 normal);
void setValidTargets(const std::vector<MWWorld::Ptr>& targets); void setValidTargets(const std::vector<MWWorld::Ptr>& targets);
bool isValidTarget(const MWWorld::Ptr& target) const; bool isValidTarget(const btCollisionObject* target) const;
std::optional<btVector3> getWaterHitPosition(); std::optional<btVector3> getWaterHitPosition();
void setWaterHitPosition(btVector3 pos); void setWaterHitPosition(btVector3 pos);
@ -76,19 +71,19 @@ namespace MWPhysics
std::unique_ptr<btCollisionShape> mShape; std::unique_ptr<btCollisionShape> mShape;
btConvexShape* mConvexShape; btConvexShape* mConvexShape;
std::unique_ptr<btCollisionObject> mCollisionObject;
bool mTransformUpdatePending; bool mTransformUpdatePending;
bool mCanCrossWaterSurface; bool mCanCrossWaterSurface;
bool mCrossedWaterSurface; bool mCrossedWaterSurface;
std::atomic<bool> mActive; std::atomic<bool> mActive;
MWWorld::Ptr mCaster; MWWorld::Ptr mCaster;
MWWorld::Ptr mHitTarget; const btCollisionObject* mCasterColObj;
const btCollisionObject* mHitTarget;
std::optional<btVector3> mWaterHitPosition; std::optional<btVector3> mWaterHitPosition;
osg::Vec3f mPosition; osg::Vec3f mPosition;
btVector3 mHitPosition; btVector3 mHitPosition;
btVector3 mHitNormal; btVector3 mHitNormal;
std::vector<MWWorld::Ptr> mValidTargets; std::vector<const btCollisionObject*> mValidTargets;
mutable std::mutex mMutex; mutable std::mutex mMutex;

View file

@ -1,3 +1,5 @@
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "actor.hpp" #include "actor.hpp"
@ -8,41 +10,41 @@
namespace MWPhysics namespace MWPhysics
{ {
ProjectileConvexCallback::ProjectileConvexCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj) ProjectileConvexCallback::ProjectileConvexCallback(const btCollisionObject* caster, const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj)
: btCollisionWorld::ClosestConvexResultCallback(from, to) : btCollisionWorld::ClosestConvexResultCallback(from, to)
, mMe(me), mProjectile(proj) , mCaster(caster)
, mMe(me)
, mProjectile(proj)
{ {
assert(mProjectile); assert(mProjectile);
} }
btScalar ProjectileConvexCallback::addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace) btScalar ProjectileConvexCallback::addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace)
{ {
const auto* hitObject = result.m_hitCollisionObject;
// don't hit the caster // don't hit the caster
if (result.m_hitCollisionObject == mMe) if (hitObject == mCaster)
return 1.f; return 1.f;
// don't hit the projectile // don't hit the projectile
if (result.m_hitCollisionObject == mProjectile->getCollisionObject()) if (hitObject == mMe)
return 1.f; return 1.f;
btCollisionWorld::ClosestConvexResultCallback::addSingleResult(result, normalInWorldSpace); btCollisionWorld::ClosestConvexResultCallback::addSingleResult(result, normalInWorldSpace);
switch (result.m_hitCollisionObject->getBroadphaseHandle()->m_collisionFilterGroup) switch (hitObject->getBroadphaseHandle()->m_collisionFilterGroup)
{ {
case CollisionType_Actor: case CollisionType_Actor:
{ {
auto* target = static_cast<Actor*>(result.m_hitCollisionObject->getUserPointer()); if (!mProjectile->isValidTarget(hitObject))
if (!mProjectile->isValidTarget(target->getPtr()))
return 1.f; return 1.f;
mProjectile->hit(target->getPtr(), result.m_hitPointLocal, result.m_hitNormalLocal);
break; break;
} }
case CollisionType_Projectile: case CollisionType_Projectile:
{ {
auto* target = static_cast<Projectile*>(result.m_hitCollisionObject->getUserPointer()); auto* target = static_cast<Projectile*>(hitObject->getUserPointer());
if (!mProjectile->isValidTarget(target->getCaster())) if (!mProjectile->isValidTarget(target->getCasterCollisionObject()))
return 1.f; return 1.f;
target->hit(mProjectile->getPtr(), m_hitPointWorld, m_hitNormalWorld); target->hit(mMe, m_hitPointWorld, m_hitNormalWorld);
mProjectile->hit(target->getPtr(), m_hitPointWorld, m_hitNormalWorld);
break; break;
} }
case CollisionType_Water: case CollisionType_Water:
@ -50,17 +52,10 @@ namespace MWPhysics
mProjectile->setWaterHitPosition(m_hitPointWorld); mProjectile->setWaterHitPosition(m_hitPointWorld);
if (mProjectile->canTraverseWater()) if (mProjectile->canTraverseWater())
return 1.f; return 1.f;
mProjectile->hit(MWWorld::Ptr(), m_hitPointWorld, m_hitNormalWorld);
break;
}
default:
{
auto* target = static_cast<PtrHolder*>(result.m_hitCollisionObject->getUserPointer());
auto ptr = target ? target->getPtr() : MWWorld::Ptr();
mProjectile->hit(ptr, m_hitPointWorld, m_hitNormalWorld);
break; break;
} }
} }
mProjectile->hit(hitObject, m_hitPointWorld, m_hitNormalWorld);
return result.m_hitFraction; return result.m_hitFraction;
} }

View file

@ -12,11 +12,12 @@ namespace MWPhysics
class ProjectileConvexCallback : public btCollisionWorld::ClosestConvexResultCallback class ProjectileConvexCallback : public btCollisionWorld::ClosestConvexResultCallback
{ {
public: public:
ProjectileConvexCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj); ProjectileConvexCallback(const btCollisionObject* caster, const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj);
btScalar addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace) override; btScalar addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace) override;
private: private:
const btCollisionObject* mCaster;
const btCollisionObject* mMe; const btCollisionObject* mMe;
Projectile* mProjectile; Projectile* mProjectile;
}; };

View file

@ -2,6 +2,9 @@
#define OPENMW_MWPHYSICS_PTRHOLDER_H #define OPENMW_MWPHYSICS_PTRHOLDER_H
#include <mutex> #include <mutex>
#include <memory>
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
@ -10,31 +13,26 @@ namespace MWPhysics
class PtrHolder class PtrHolder
{ {
public: public:
virtual ~PtrHolder() {} virtual ~PtrHolder() = default;
void updatePtr(const MWWorld::Ptr& updated) void updatePtr(const MWWorld::Ptr& updated)
{ {
std::scoped_lock lock(mMutex);
mPtr = updated; mPtr = updated;
} }
MWWorld::Ptr getPtr() MWWorld::Ptr getPtr()
{ {
std::scoped_lock lock(mMutex);
return mPtr; return mPtr;
} }
MWWorld::ConstPtr getPtr() const btCollisionObject* getCollisionObject() const
{ {
std::scoped_lock lock(mMutex); return mCollisionObject.get();
return mPtr;
} }
protected: protected:
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
std::unique_ptr<btCollisionObject> mCollisionObject;
private:
mutable std::mutex mMutex;
}; };
} }

View file

@ -521,7 +521,7 @@ namespace MWWorld
} }
MWMechanics::projectileHit(caster, target, bow, projectileRef.getPtr(), pos, projectileState.mAttackStrength); MWMechanics::projectileHit(caster, target, bow, projectileRef.getPtr(), pos, projectileState.mAttackStrength);
cleanupProjectile(projectileState); projectileState.mToDelete = true;
} }
for (auto& magicBoltState : mMagicBolts) for (auto& magicBoltState : mMagicBolts)
{ {
@ -550,7 +550,19 @@ namespace MWWorld
cast.inflict(target, caster, magicBoltState.mEffects, ESM::RT_Target, false, true); cast.inflict(target, caster, magicBoltState.mEffects, ESM::RT_Target, false, true);
MWBase::Environment::get().getWorld()->explodeSpell(pos, magicBoltState.mEffects, caster, target, ESM::RT_Target, magicBoltState.mSpellId, magicBoltState.mSourceName); MWBase::Environment::get().getWorld()->explodeSpell(pos, magicBoltState.mEffects, caster, target, ESM::RT_Target, magicBoltState.mSpellId, magicBoltState.mSourceName);
cleanupMagicBolt(magicBoltState); magicBoltState.mToDelete = true;
}
for (auto& projectileState : mProjectiles)
{
if (projectileState.mToDelete)
cleanupProjectile(projectileState);
}
for (auto& magicBoltState : mMagicBolts)
{
if (magicBoltState.mToDelete)
cleanupMagicBolt(magicBoltState);
} }
mProjectiles.erase(std::remove_if(mProjectiles.begin(), mProjectiles.end(), [](const State& state) { return state.mToDelete; }), mProjectiles.erase(std::remove_if(mProjectiles.begin(), mProjectiles.end(), [](const State& state) { return state.mToDelete; }),
mProjectiles.end()); mProjectiles.end());