diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 760e21cce..0f3d69d21 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -19,7 +19,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler) - : mCanWaterWalk(false), mWalkingOnWater(false) + : mStandingOnPtr(nullptr), mCanWaterWalk(false), mWalkingOnWater(false) , mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBoxTranslate), mHalfExtents(shape->mCollisionBoxHalfExtents) , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mInternalCollisionMode(true) @@ -268,4 +268,16 @@ void Actor::setCanWaterWalk(bool waterWalk) } } +MWWorld::Ptr Actor::getStandingOnPtr() const +{ + std::scoped_lock lock(mPositionMutex); + return mStandingOnPtr; +} + +void Actor::setStandingOnPtr(const MWWorld::Ptr& ptr) +{ + std::scoped_lock lock(mPositionMutex); + mStandingOnPtr = ptr; +} + } diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 00ba162af..6b23b31d3 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -144,7 +144,11 @@ namespace MWPhysics void setWalkingOnWater(bool walkingOnWater); bool isWalkingOnWater() const; + MWWorld::Ptr getStandingOnPtr() const; + void setStandingOnPtr(const MWWorld::Ptr& ptr); + private: + MWWorld::Ptr mStandingOnPtr; /// Removes then re-adds the collision object to the dynamics world void updateCollisionMask(); void addCollisionMask(int collisionMask); diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 1b99b4c3f..ff676413b 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -82,14 +82,6 @@ namespace ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; } - void updateStandingCollision(MWPhysics::ActorFrameData& actorData, MWPhysics::CollisionMap& standingCollisions) - { - if (!actorData.mStandingOn.isEmpty()) - standingCollisions[actorData.mPtr] = actorData.mStandingOn; - else - standingCollisions.erase(actorData.mPtr); - } - void updateMechanics(MWPhysics::ActorFrameData& actorData) { if (actorData.mDidJump) @@ -215,7 +207,7 @@ namespace MWPhysics thread.join(); } - const PtrPositionList& PhysicsTaskScheduler::moveActors(int numSteps, float timeAccum, std::vector&& actorsData, CollisionMap& standingCollisions, bool skipSimulation) + const PtrPositionList& PhysicsTaskScheduler::moveActors(int numSteps, float timeAccum, std::vector&& actorsData, bool skipSimulation) { // This function run in the main thread. // While the mSimulationMutex is held, background physics threads can't run. @@ -225,9 +217,6 @@ namespace MWPhysics // start by finishing previous background computation if (mNumThreads != 0) { - if (mAdvanceSimulation) - standingCollisions.clear(); - for (auto& data : mActorsFrameData) { // Ignore actors that were deleted while the background thread was running @@ -236,7 +225,7 @@ namespace MWPhysics updateMechanics(data); if (mAdvanceSimulation) - updateStandingCollision(data, standingCollisions); + data.mActorRaw->setStandingOnPtr(data.mStandingOn); if (mMovementResults.find(data.mPtr) != mMovementResults.end()) data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]); @@ -260,10 +249,10 @@ namespace MWPhysics // just return the actors' reference position without applying the movements if (skipSimulation) { - standingCollisions.clear(); mMovementResults.clear(); for (const auto& m : mActorsFrameData) { + m.mActorRaw->setStandingOnPtr(nullptr); m.mActorRaw->setPosition(m.mActorRaw->getWorldPosition(), true); mMovementResults[m.mPtr] = m.mActorRaw->getWorldPosition(); } @@ -275,14 +264,10 @@ namespace MWPhysics mMovementResults.clear(); syncComputation(); - if (mAdvanceSimulation) - { - standingCollisions.clear(); - for (auto& data : mActorsFrameData) - updateStandingCollision(data, standingCollisions); - } for (auto& data : mActorsFrameData) { + if (mAdvanceSimulation) + data.mActorRaw->setStandingOnPtr(data.mStandingOn); if (mMovementResults.find(data.mPtr) != mMovementResults.end()) data.mActorRaw->setNextPosition(mMovementResults[data.mPtr]); } diff --git a/apps/openmw/mwphysics/mtphysics.hpp b/apps/openmw/mwphysics/mtphysics.hpp index 84ea93c08..ef1c90b87 100644 --- a/apps/openmw/mwphysics/mtphysics.hpp +++ b/apps/openmw/mwphysics/mtphysics.hpp @@ -30,7 +30,7 @@ namespace MWPhysics /// @param timeAccum accumulated time from previous run to interpolate movements /// @param actorsData per actor data needed to compute new positions /// @return new position of each actor - const PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector&& actorsData, CollisionMap& standingCollisions, bool skip); + const PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector&& actorsData, bool skip); // Thread safe wrappers void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 6b94ef43b..5de26fdfc 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -148,11 +148,11 @@ namespace MWPhysics if (!physactor || !physactor->getOnGround()) return false; - CollisionMap::const_iterator found = mStandingCollisions.find(actor); - if (found == mStandingCollisions.end()) + const auto obj = physactor->getStandingOnPtr(); + if (obj.isEmpty()) return true; // assume standing on terrain (which is a non-object, so not collision tracked) - ObjectMap::const_iterator foundObj = mObjects.find(found->second); + ObjectMap::const_iterator foundObj = mObjects.find(obj); if (foundObj == mObjects.end()) return false; @@ -501,22 +501,6 @@ namespace MWPhysics } } - void PhysicsSystem::updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated) - { - CollisionMap::iterator found = map.find(old); - if (found != map.end()) - { - map[updated] = found->second; - map.erase(found); - } - - for (auto& collision : map) - { - if (collision.second == old) - collision.second = updated; - } - } - void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { ObjectMap::iterator found = mObjects.find(old); @@ -537,7 +521,11 @@ namespace MWPhysics mActors.emplace(updated, std::move(actor)); } - updateCollisionMapPtr(mStandingCollisions, old, updated); + for (auto& [_, actor] : mActors) + { + if (actor->getStandingOnPtr() == old) + actor->setStandingOnPtr(updated); + } } Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) @@ -675,7 +663,6 @@ namespace MWPhysics void PhysicsSystem::clearQueuedMovement() { mMovementQueue.clear(); - mStandingCollisions.clear(); } const PtrPositionList& PhysicsSystem::applyQueuedMovement(float dt, bool skipSimulation) @@ -688,7 +675,7 @@ namespace MWPhysics mTimeAccum -= numSteps * mPhysicsDt; - return mTaskScheduler->moveActors(numSteps, mTimeAccum, prepareFrameData(numSteps), mStandingCollisions, skipSimulation); + return mTaskScheduler->moveActors(numSteps, mTimeAccum, prepareFrameData(numSteps), skipSimulation); } std::vector PhysicsSystem::prepareFrameData(int numSteps) @@ -700,10 +687,8 @@ namespace MWPhysics { const auto foundActor = mActors.find(character); if (foundActor == mActors.end()) // actor was already removed from the scene - { - mStandingCollisions.erase(character); continue; - } + auto physicActor = foundActor->second; float waterlevel = -std::numeric_limits::max(); @@ -734,7 +719,7 @@ namespace MWPhysics // Ue current value only if we don't advance the simulation. Otherwise we might get a stale value. MWWorld::Ptr standingOn; if (numSteps == 0) - standingOn = mStandingCollisions[character]; + standingOn = physicActor->getStandingOnPtr(); actorsFrameData.emplace_back(std::move(physicActor), character, standingOn, moveToWaterSurface, movement, slowFall, waterlevel); } @@ -774,20 +759,18 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { - for (const auto& standingActor : mStandingCollisions) - { - if (standingActor.first == actor && standingActor.second == object) - return true; - } + const auto physActor = mActors.find(actor); + if (physActor != mActors.end()) + return physActor->second->getStandingOnPtr() == object; return false; } void PhysicsSystem::getActorsStandingOn(const MWWorld::ConstPtr &object, std::vector &out) const { - for (const auto& standingActor : mStandingCollisions) + for (const auto& [_, actor] : mActors) { - if (standingActor.second == object) - out.push_back(standingActor.first); + if (actor->getStandingOnPtr() == object) + out.emplace_back(actor->getPtr()); } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 4844b5e8e..ccfca5422 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -50,7 +50,6 @@ class btVector3; namespace MWPhysics { using PtrPositionList = std::map; - using CollisionMap = std::map; class HeightField; class Object; @@ -272,13 +271,6 @@ namespace MWPhysics bool mDebugDrawEnabled; - // Tracks standing collisions happening during a single frame. - // This will detect standing on an object, but won't detect running e.g. against a wall. - CollisionMap mStandingCollisions; - - // replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value - void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated); - using PtrVelocityList = std::vector>; PtrVelocityList mMovementQueue;