Base GetColliding script functions on collisions detected by the movement solver

ini_importer_tests
Evil Eye 4 months ago
parent 6b35ee68e1
commit 467220e6d7

@ -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 #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 #7053: Running into objects doesn't trigger GetCollidingPC
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 #7077: OpenMW fails to load certain particle effects in .osgt format

@ -15,6 +15,7 @@
#include "collisiontype.hpp"
#include "constants.hpp"
#include "contacttestwrapper.h"
#include "object.hpp"
#include "physicssystem.hpp"
#include "projectile.hpp"
#include "projectileconvexcallback.hpp"
@ -243,11 +244,20 @@ namespace MWPhysics
float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + actor.mHalfExtentsZ;
osg::Vec3f oldPosition = newPosition;
bool usedStepLogic = false;
if (hitHeight < Constants::sStepSizeUp && !isActor(tracer.mHitObject))
if (!isActor(tracer.mHitObject))
{
// 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);
if (hitHeight < Constants::sStepSizeUp)
{
// 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)
{

@ -23,6 +23,7 @@ namespace MWPhysics
, mPosition(ptr.getRefData().getPosition().asVec3())
, mRotation(rotation)
, mTaskScheduler(scheduler)
, mCollidedWith(ScriptedCollisionType_None)
{
mCollisionObject = BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(),
Misc::Convert::toBullet(mPosition), Misc::Convert::toBullet(rotation));
@ -166,4 +167,20 @@ namespace MWPhysics
}
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;
}
}

@ -18,6 +18,14 @@ namespace MWPhysics
{
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
{
public:
@ -38,6 +46,9 @@ namespace MWPhysics
/// @brief update object shape
/// @return true if shape changed
bool animateCollisionShapes();
bool collidedWith(ScriptedCollisionType type) const;
void addCollision(ScriptedCollisionType type);
void resetCollisions();
private:
osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance;
@ -50,6 +61,7 @@ namespace MWPhysics
bool mTransformUpdatePending = false;
mutable std::mutex mPositionMutex;
PhysicsTaskScheduler* mTaskScheduler;
char mCollidedWith;
};
}

@ -673,12 +673,13 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
const float slowFall
= 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()
|| (!godmode && stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Paralyze).getModifier() > 0);
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 (willSimulate)
@ -708,6 +709,8 @@ namespace MWPhysics
changed = false;
}
}
for (auto& [_, object] : mObjects)
object->resetCollisions();
#ifndef BT_NO_PROFILE
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);
return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end());
auto found = mObjects.find(object.mRef);
if (found != mObjects.end())
return found->second->collidedWith(type);
return false;
}
void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const
@ -890,7 +895,8 @@ namespace MWPhysics
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()
, mStandingOn(nullptr)
, mIsOnGround(actor.getOnGround())
@ -917,6 +923,7 @@ namespace MWPhysics
, mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr()))
, mWaterCollision(waterCollision)
, mSkipCollisionDetection(!actor.getCollisionMode())
, mIsPlayer(isPlayer)
{
}

@ -56,6 +56,7 @@ namespace MWPhysics
class Actor;
class PhysicsTaskScheduler;
class Projectile;
enum ScriptedCollisionType : char;
using ActorMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Actor>>;
@ -79,7 +80,7 @@ namespace MWPhysics
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 mInertia;
const btCollisionObject* mStandingOn;
@ -102,6 +103,7 @@ namespace MWPhysics
const bool mIsAquatic;
const bool mWaterCollision;
const bool mSkipCollisionDetection;
const bool mIsPlayer;
};
struct ProjectileFrameData
@ -258,9 +260,8 @@ namespace MWPhysics
/// 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;
/// Return true if \a actor has collided with \a object in this frame.
/// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc.
bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const;
/// Return true if an object of the given type has collided with this object
bool isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const;
/// 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;

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

Loading…
Cancel
Save