mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
Merge branch 'fixfriendlyfire' into 'master'
Fix projectiles friendly fire (#5744) See merge request OpenMW/openmw!466
This commit is contained in:
commit
884b434ee0
6 changed files with 68 additions and 42 deletions
|
@ -30,12 +30,9 @@ namespace MWPhysics
|
|||
return btScalar(1);
|
||||
auto* targetHolder = static_cast<PtrHolder*>(mMe->getUserPointer());
|
||||
const MWWorld::Ptr target = targetHolder->getPtr();
|
||||
// do nothing if we hit the caster. Sometimes the launching origin is inside of caster collision shape
|
||||
if (projectileHolder->getCaster() != target)
|
||||
{
|
||||
if (projectileHolder->isValidTarget(target))
|
||||
projectileHolder->hit(target, convexResult.m_hitPointLocal, convexResult.m_hitNormalLocal);
|
||||
return btScalar(1);
|
||||
}
|
||||
return btScalar(1);
|
||||
}
|
||||
|
||||
btVector3 hitNormalWorld;
|
||||
|
|
|
@ -537,6 +537,13 @@ namespace MWPhysics
|
|||
if (actor->getStandingOnPtr() == old)
|
||||
actor->setStandingOnPtr(updated);
|
||||
}
|
||||
|
||||
for (auto& [_, projectile] : mProjectiles)
|
||||
{
|
||||
if (projectile->getCaster() == old)
|
||||
projectile->setCaster(updated);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr)
|
||||
|
|
|
@ -55,7 +55,7 @@ Projectile::~Projectile()
|
|||
|
||||
void Projectile::commitPositionChange()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||
std::scoped_lock lock(mMutex);
|
||||
if (mTransformUpdatePending)
|
||||
{
|
||||
mCollisionObject->setWorldTransform(mLocalTransform);
|
||||
|
@ -65,7 +65,7 @@ void Projectile::commitPositionChange()
|
|||
|
||||
void Projectile::setPosition(const osg::Vec3f &position)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||
std::scoped_lock lock(mMutex);
|
||||
mLocalTransform.setOrigin(Misc::Convert::toBullet(position));
|
||||
mTransformUpdatePending = true;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ void Projectile::hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal)
|
|||
{
|
||||
if (!mActive.load(std::memory_order_acquire))
|
||||
return;
|
||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||
std::scoped_lock lock(mMutex);
|
||||
mHitTarget = target;
|
||||
mHitPosition = pos;
|
||||
mHitNormal = normal;
|
||||
|
@ -86,4 +86,46 @@ void Projectile::activate()
|
|||
assert(!mActive);
|
||||
mActive.store(true, 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 (!mValidTargets.empty())
|
||||
{
|
||||
bool validTarget = false;
|
||||
for (const auto& targetActor : mValidTargets)
|
||||
{
|
||||
if (targetActor == target)
|
||||
{
|
||||
validTarget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return validTarget;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ namespace MWPhysics
|
|||
return mHitTarget;
|
||||
}
|
||||
|
||||
MWWorld::Ptr getCaster() const { return mCaster; }
|
||||
MWWorld::Ptr getCaster() const;
|
||||
void setCaster(MWWorld::Ptr caster);
|
||||
|
||||
osg::Vec3f getHitPos() const
|
||||
{
|
||||
|
@ -73,6 +74,9 @@ namespace MWPhysics
|
|||
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;
|
||||
|
@ -87,7 +91,9 @@ namespace MWPhysics
|
|||
btVector3 mHitPosition;
|
||||
btVector3 mHitNormal;
|
||||
|
||||
mutable std::mutex mPositionMutex;
|
||||
std::vector<MWWorld::Ptr> mValidTargets;
|
||||
|
||||
mutable std::mutex mMutex;
|
||||
|
||||
osg::Vec3f mPosition;
|
||||
|
||||
|
|
|
@ -387,7 +387,7 @@ namespace MWWorld
|
|||
if (magicBoltState.mToDelete)
|
||||
continue;
|
||||
|
||||
const auto* projectile = mPhysics->getProjectile(magicBoltState.mProjectileId);
|
||||
auto* projectile = mPhysics->getProjectile(magicBoltState.mProjectileId);
|
||||
if (!projectile->isActive())
|
||||
continue;
|
||||
// If the actor caster is gone, the magic bolt needs to be removed from the scene during the next frame.
|
||||
|
@ -423,6 +423,7 @@ namespace MWWorld
|
|||
std::vector<MWWorld::Ptr> targetActors;
|
||||
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
|
||||
caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors);
|
||||
projectile->setValidTargets(targetActors);
|
||||
|
||||
// Check for impact
|
||||
// TODO: use a proper btRigidBody / btGhostObject?
|
||||
|
@ -469,7 +470,7 @@ namespace MWWorld
|
|||
if (projectileState.mToDelete)
|
||||
continue;
|
||||
|
||||
const auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId);
|
||||
auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId);
|
||||
if (!projectile->isActive())
|
||||
continue;
|
||||
// gravity constant - must be way lower than the gravity affecting actors, since we're not
|
||||
|
@ -499,6 +500,7 @@ namespace MWWorld
|
|||
std::vector<MWWorld::Ptr> targetActors;
|
||||
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
|
||||
caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors);
|
||||
projectile->setValidTargets(targetActors);
|
||||
|
||||
// Check for impact
|
||||
// TODO: use a proper btRigidBody / btGhostObject?
|
||||
|
@ -547,7 +549,7 @@ namespace MWWorld
|
|||
const auto pos = projectile->getHitPos();
|
||||
MWWorld::Ptr caster = projectileState.getCaster();
|
||||
assert(target != caster);
|
||||
if (!isValidTarget(caster, target))
|
||||
if (!projectile->isValidTarget(target))
|
||||
{
|
||||
projectile->activate();
|
||||
continue;
|
||||
|
@ -583,7 +585,7 @@ namespace MWWorld
|
|||
const auto pos = projectile->getHitPos();
|
||||
MWWorld::Ptr caster = magicBoltState.getCaster();
|
||||
assert(target != caster);
|
||||
if (!isValidTarget(caster, target))
|
||||
if (!projectile->isValidTarget(target))
|
||||
{
|
||||
projectile->activate();
|
||||
continue;
|
||||
|
@ -607,32 +609,6 @@ namespace MWWorld
|
|||
mMagicBolts.end());
|
||||
}
|
||||
|
||||
bool ProjectileManager::isValidTarget(const MWWorld::Ptr& caster, const MWWorld::Ptr& target)
|
||||
{
|
||||
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
|
||||
std::vector<MWWorld::Ptr> targetActors;
|
||||
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
|
||||
{
|
||||
caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors);
|
||||
if (!targetActors.empty())
|
||||
{
|
||||
bool validTarget = false;
|
||||
for (MWWorld::Ptr& targetActor : targetActors)
|
||||
{
|
||||
if (targetActor == target)
|
||||
{
|
||||
validTarget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return validTarget;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProjectileManager::cleanupProjectile(ProjectileManager::ProjectileState& state)
|
||||
{
|
||||
mParent->removeChild(state.mNode);
|
||||
|
|
|
@ -132,8 +132,6 @@ namespace MWWorld
|
|||
void moveProjectiles(float dt);
|
||||
void moveMagicBolts(float dt);
|
||||
|
||||
bool isValidTarget(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
|
||||
|
||||
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient,
|
||||
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = "");
|
||||
void update (State& state, float duration);
|
||||
|
|
Loading…
Reference in a new issue