1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-28 22:13:21 +00:00

Base GetColliding script functions on collisions detected by the movement solver

This commit is contained in:
Evil Eye 2024-01-20 16:50:51 +01:00
parent 6b35ee68e1
commit 467220e6d7
7 changed files with 64 additions and 19 deletions

View File

@ -61,6 +61,7 @@
Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such
Bug #7042: Weapon follow animations that immediately follow the hit animations cause multiple hits Bug #7042: Weapon follow animations that immediately follow the hit animations cause multiple hits
Bug #7044: Changing a class' services does not affect autocalculated NPCs Bug #7044: Changing a class' services does not affect autocalculated NPCs
Bug #7053: Running into objects doesn't trigger GetCollidingPC
Bug #7054: Quests aren't sorted by name Bug #7054: Quests aren't sorted by name
Bug #7064: NPCs don't report crime if the player is casting offensive spells on them while sneaking Bug #7064: NPCs don't report crime if the player is casting offensive spells on them while sneaking
Bug #7077: OpenMW fails to load certain particle effects in .osgt format Bug #7077: OpenMW fails to load certain particle effects in .osgt format

View File

@ -15,6 +15,7 @@
#include "collisiontype.hpp" #include "collisiontype.hpp"
#include "constants.hpp" #include "constants.hpp"
#include "contacttestwrapper.h" #include "contacttestwrapper.h"
#include "object.hpp"
#include "physicssystem.hpp" #include "physicssystem.hpp"
#include "projectile.hpp" #include "projectile.hpp"
#include "projectileconvexcallback.hpp" #include "projectileconvexcallback.hpp"
@ -243,11 +244,20 @@ namespace MWPhysics
float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + actor.mHalfExtentsZ; float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + actor.mHalfExtentsZ;
osg::Vec3f oldPosition = newPosition; osg::Vec3f oldPosition = newPosition;
bool usedStepLogic = false; bool usedStepLogic = false;
if (hitHeight < Constants::sStepSizeUp && !isActor(tracer.mHitObject)) if (!isActor(tracer.mHitObject))
{ {
// Try to step up onto it. if (hitHeight < Constants::sStepSizeUp)
// NOTE: this modifies newPosition and velocity on its own if successful {
usedStepLogic = stepper.step(newPosition, velocity, remainingTime, seenGround, iterations == 0); // Try to step up onto it.
// NOTE: this modifies newPosition and velocity on its own if successful
usedStepLogic = stepper.step(newPosition, velocity, remainingTime, seenGround, iterations == 0);
}
auto* ptrHolder = static_cast<PtrHolder*>(tracer.mHitObject->getUserPointer());
if (Object* hitObject = dynamic_cast<Object*>(ptrHolder))
{
hitObject->addCollision(
actor.mIsPlayer ? ScriptedCollisionType_Player : ScriptedCollisionType_Actor);
}
} }
if (usedStepLogic) if (usedStepLogic)
{ {

View File

@ -23,6 +23,7 @@ namespace MWPhysics
, mPosition(ptr.getRefData().getPosition().asVec3()) , mPosition(ptr.getRefData().getPosition().asVec3())
, mRotation(rotation) , mRotation(rotation)
, mTaskScheduler(scheduler) , mTaskScheduler(scheduler)
, mCollidedWith(ScriptedCollisionType_None)
{ {
mCollisionObject = BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(), mCollisionObject = BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(),
Misc::Convert::toBullet(mPosition), Misc::Convert::toBullet(rotation)); Misc::Convert::toBullet(mPosition), Misc::Convert::toBullet(rotation));
@ -166,4 +167,20 @@ namespace MWPhysics
} }
return result; return result;
} }
bool Object::collidedWith(ScriptedCollisionType type) const
{
return mCollidedWith & type;
}
void Object::addCollision(ScriptedCollisionType type)
{
std::unique_lock<std::mutex> lock(mPositionMutex);
mCollidedWith |= type;
}
void Object::resetCollisions()
{
mCollidedWith = ScriptedCollisionType_None;
}
} }

View File

@ -18,6 +18,14 @@ namespace MWPhysics
{ {
class PhysicsTaskScheduler; class PhysicsTaskScheduler;
enum ScriptedCollisionType : char
{
ScriptedCollisionType_None = 0,
ScriptedCollisionType_Actor = 1,
// Note that this isn't 3, colliding with a player doesn't count as colliding with an actor
ScriptedCollisionType_Player = 2
};
class Object final : public PtrHolder class Object final : public PtrHolder
{ {
public: public:
@ -38,6 +46,9 @@ namespace MWPhysics
/// @brief update object shape /// @brief update object shape
/// @return true if shape changed /// @return true if shape changed
bool animateCollisionShapes(); bool animateCollisionShapes();
bool collidedWith(ScriptedCollisionType type) const;
void addCollision(ScriptedCollisionType type);
void resetCollisions();
private: private:
osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance; osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance;
@ -50,6 +61,7 @@ namespace MWPhysics
bool mTransformUpdatePending = false; bool mTransformUpdatePending = false;
mutable std::mutex mPositionMutex; mutable std::mutex mPositionMutex;
PhysicsTaskScheduler* mTaskScheduler; PhysicsTaskScheduler* mTaskScheduler;
char mCollidedWith;
}; };
} }

View File

@ -673,12 +673,13 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200) // Slow fall reduces fall speed by a factor of (effect magnitude / 200)
const float slowFall const float slowFall
= 1.f - std::clamp(effects.getOrDefault(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f, 0.f, 1.f); = 1.f - std::clamp(effects.getOrDefault(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f, 0.f, 1.f);
const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState(); const bool isPlayer = ptr == world->getPlayerConstPtr();
const bool godmode = isPlayer && world->getGodModeState();
const bool inert = stats.isDead() const bool inert = stats.isDead()
|| (!godmode && stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Paralyze).getModifier() > 0); || (!godmode && stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Paralyze).getModifier() > 0);
simulations.emplace_back(ActorSimulation{ simulations.emplace_back(ActorSimulation{
physicActor, ActorFrameData{ *physicActor, inert, waterCollision, slowFall, waterlevel } }); physicActor, ActorFrameData{ *physicActor, inert, waterCollision, slowFall, waterlevel, isPlayer } });
// if the simulation will run, a jump request will be fulfilled. Update mechanics accordingly. // if the simulation will run, a jump request will be fulfilled. Update mechanics accordingly.
if (willSimulate) if (willSimulate)
@ -708,6 +709,8 @@ namespace MWPhysics
changed = false; changed = false;
} }
} }
for (auto& [_, object] : mObjects)
object->resetCollisions();
#ifndef BT_NO_PROFILE #ifndef BT_NO_PROFILE
CProfileManager::Reset(); CProfileManager::Reset();
@ -782,10 +785,12 @@ namespace MWPhysics
} }
} }
bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const bool PhysicsSystem::isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const
{ {
std::vector<MWWorld::Ptr> collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); auto found = mObjects.find(object.mRef);
return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); if (found != mObjects.end())
return found->second->collidedWith(type);
return false;
} }
void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const
@ -890,7 +895,8 @@ namespace MWPhysics
mDebugDrawer->addCollision(position, normal); mDebugDrawer->addCollision(position, normal);
} }
ActorFrameData::ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel) ActorFrameData::ActorFrameData(
Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel, bool isPlayer)
: mPosition() : mPosition()
, mStandingOn(nullptr) , mStandingOn(nullptr)
, mIsOnGround(actor.getOnGround()) , mIsOnGround(actor.getOnGround())
@ -917,6 +923,7 @@ namespace MWPhysics
, mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr())) , mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr()))
, mWaterCollision(waterCollision) , mWaterCollision(waterCollision)
, mSkipCollisionDetection(!actor.getCollisionMode()) , mSkipCollisionDetection(!actor.getCollisionMode())
, mIsPlayer(isPlayer)
{ {
} }

View File

@ -56,6 +56,7 @@ namespace MWPhysics
class Actor; class Actor;
class PhysicsTaskScheduler; class PhysicsTaskScheduler;
class Projectile; class Projectile;
enum ScriptedCollisionType : char;
using ActorMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Actor>>; using ActorMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Actor>>;
@ -79,7 +80,7 @@ namespace MWPhysics
struct ActorFrameData struct ActorFrameData
{ {
ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel); ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel, bool isPlayer);
osg::Vec3f mPosition; osg::Vec3f mPosition;
osg::Vec3f mInertia; osg::Vec3f mInertia;
const btCollisionObject* mStandingOn; const btCollisionObject* mStandingOn;
@ -102,6 +103,7 @@ namespace MWPhysics
const bool mIsAquatic; const bool mIsAquatic;
const bool mWaterCollision; const bool mWaterCollision;
const bool mSkipCollisionDetection; const bool mSkipCollisionDetection;
const bool mIsPlayer;
}; };
struct ProjectileFrameData struct ProjectileFrameData
@ -258,9 +260,8 @@ namespace MWPhysics
/// Get the handle of all actors standing on \a object in this frame. /// Get the handle of all actors standing on \a object in this frame.
void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const;
/// Return true if \a actor has collided with \a object in this frame. /// Return true if an object of the given type has collided with this object
/// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. bool isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const;
bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const;
/// Get the handle of all actors colliding with \a object in this frame. /// Get the handle of all actors colliding with \a object in this frame.
void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const;

View File

@ -2425,15 +2425,12 @@ namespace MWWorld
bool World::getPlayerCollidingWith(const MWWorld::ConstPtr& object) bool World::getPlayerCollidingWith(const MWWorld::ConstPtr& object)
{ {
MWWorld::Ptr player = getPlayerPtr(); return mPhysics->isObjectCollidingWith(object, MWPhysics::ScriptedCollisionType_Player);
return mPhysics->isActorCollidingWith(player, object);
} }
bool World::getActorCollidingWith(const MWWorld::ConstPtr& object) bool World::getActorCollidingWith(const MWWorld::ConstPtr& object)
{ {
std::vector<MWWorld::Ptr> actors; return mPhysics->isObjectCollidingWith(object, MWPhysics::ScriptedCollisionType_Actor);
mPhysics->getActorsCollidingWith(object, actors);
return !actors.empty();
} }
void World::hurtStandingActors(const ConstPtr& object, float healthPerSecond) void World::hurtStandingActors(const ConstPtr& object, float healthPerSecond)