1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 19:19:55 +00:00
openmw-tes3mp/apps/openmw/mwphysics/projectile.hpp
fredzio b39437dfb6 Don't allow projectiles to stand still when they hit an ally.
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.
2020-12-14 22:23:01 +01:00

112 lines
2.4 KiB
C++

#ifndef OPENMW_MWPHYSICS_PROJECTILE_H
#define OPENMW_MWPHYSICS_PROJECTILE_H
#include <atomic>
#include <memory>
#include <mutex>
#include "components/misc/convert.hpp"
#include "ptrholder.hpp"
class btCollisionObject;
class btCollisionShape;
class btConvexShape;
class btVector3;
namespace osg
{
class Vec3f;
}
namespace Resource
{
class BulletShape;
}
namespace MWPhysics
{
class PhysicsTaskScheduler;
class PhysicsSystem;
class Projectile final : public PtrHolder
{
public:
Projectile(const int projectileId, const MWWorld::Ptr& caster, const osg::Vec3f& position, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem);
~Projectile() override;
btConvexShape* getConvexShape() const { return mConvexShape; }
void commitPositionChange();
void setPosition(const osg::Vec3f& position);
btCollisionObject* getCollisionObject() const
{
return mCollisionObject.get();
}
int getProjectileId() const
{
return mProjectileId;
}
bool isActive() const
{
return mActive.load(std::memory_order_acquire);
}
MWWorld::Ptr getTarget() const
{
assert(!mActive);
return mHitTarget;
}
MWWorld::Ptr getCaster() const;
void setCaster(MWWorld::Ptr caster);
osg::Vec3f getHitPos() const
{
assert(!mActive);
return Misc::Convert::toOsg(mHitPosition);
}
void hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal);
void activate();
void setValidTargets(const std::vector<MWWorld::Ptr>& targets);
bool isValidTarget(const MWWorld::Ptr& target) const;
private:
std::unique_ptr<btCollisionShape> mShape;
btConvexShape* mConvexShape;
std::unique_ptr<btCollisionObject> mCollisionObject;
btTransform mLocalTransform;
bool mTransformUpdatePending;
std::atomic<bool> mActive;
MWWorld::Ptr mCaster;
MWWorld::Ptr mHitTarget;
btVector3 mHitPosition;
btVector3 mHitNormal;
std::vector<MWWorld::Ptr> mValidTargets;
mutable std::mutex mMutex;
osg::Vec3f mPosition;
PhysicsSystem *mPhysics;
PhysicsTaskScheduler *mTaskScheduler;
Projectile(const Projectile&);
Projectile& operator=(const Projectile&);
int mProjectileId;
};
}
#endif