You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwphysics/projectile.cpp

124 lines
3.2 KiB
C++

#include <memory>
#include <BulletCollision/CollisionShapes/btSphereShape.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <components/misc/convert.hpp>
#include "../mwworld/class.hpp"
#include "collisiontype.hpp"
#include "mtphysics.hpp"
#include "projectile.hpp"
namespace MWPhysics
{
Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem)
: mHitWater(false)
, mActive(true)
, mCaster(caster)
, mPhysics(physicssystem)
, mTaskScheduler(scheduler)
{
mShape = std::make_unique<btSphereShape>(radius);
mConvexShape = static_cast<btConvexShape*>(mShape.get());
mCollisionObject = std::make_unique<btCollisionObject>();
mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
mCollisionObject->setActivationState(DISABLE_DEACTIVATION);
mCollisionObject->setCollisionShape(mShape.get());
mCollisionObject->setUserPointer(this);
setPosition(position);
const int collisionMask = CollisionType_World | CollisionType_HeightMap |
CollisionType_Actor | CollisionType_Door | CollisionType_Water | CollisionType_Projectile;
mTaskScheduler->addCollisionObject(mCollisionObject.get(), CollisionType_Projectile, collisionMask);
commitPositionChange();
}
Projectile::~Projectile()
{
if (!mActive)
mPhysics->reportCollision(mHitPosition, mHitNormal);
mTaskScheduler->removeCollisionObject(mCollisionObject.get());
}
void Projectile::commitPositionChange()
{
std::scoped_lock lock(mMutex);
if (mTransformUpdatePending)
{
auto& trans = mCollisionObject->getWorldTransform();
trans.setOrigin(Misc::Convert::toBullet(mPosition));
mCollisionObject->setWorldTransform(trans);
mTransformUpdatePending = false;
}
}
void Projectile::setPosition(const osg::Vec3f &position)
{
std::scoped_lock lock(mMutex);
mPosition = position;
mTransformUpdatePending = true;
}
osg::Vec3f Projectile::getPosition() const
{
std::scoped_lock lock(mMutex);
return mPosition;
}
void Projectile::hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal)
{
if (!mActive.load(std::memory_order_acquire))
return;
std::scoped_lock lock(mMutex);
mHitTarget = target;
mHitPosition = pos;
mHitNormal = normal;
mActive.store(false, std::memory_order_release);
}
MWWorld::Ptr Projectile::getCaster() const
{
std::scoped_lock lock(mMutex);
return mCaster;
}
void Projectile::setCaster(MWWorld::Ptr caster)
{
std::scoped_lock lock(mMutex);
mCaster = caster;
}
void Projectile::setValidTargets(const std::vector<MWWorld::Ptr>& targets)
{
std::scoped_lock lock(mMutex);
mValidTargets = targets;
}
bool Projectile::isValidTarget(const MWWorld::Ptr& target) const
{
std::scoped_lock lock(mMutex);
if (mCaster == target)
return false;
if (target.isEmpty() || mValidTargets.empty())
return true;
bool validTarget = false;
for (const auto& targetActor : mValidTargets)
{
if (targetActor == target)
{
validTarget = true;
break;
}
}
return validTarget;
}
}