diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 3c78104dc..e55ec9166 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -78,12 +78,14 @@ namespace MWPhysics WorldFrameData& worldData) { auto* physicActor = actor.mActorRaw; - auto ptr = actor.mPtr; const ESM::Position& refpos = actor.mRefpos; // Early-out for totally static creatures // (Not sure if gravity should still apply?) - if (!ptr.getClass().isMobile(ptr)) - return; + { + const auto ptr = physicActor->getPtr(); + if (!ptr.getClass().isMobile(ptr)) + return; + } // Reset per-frame data physicActor->setWalkingOnWater(false); @@ -211,6 +213,7 @@ namespace MWPhysics if (result) { // don't let pure water creatures move out of water after stepMove + const auto ptr = physicActor->getPtr(); if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z() + halfExtents.z() > actor.mWaterlevel) newPosition = oldPosition; } diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 60a7259f8..bedcaba6a 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -87,12 +87,13 @@ namespace void updateMechanics(MWPhysics::ActorFrameData& actorData) { + auto ptr = actorData.mActorRaw->getPtr(); if (actorData.mDidJump) - handleJump(actorData.mPtr); + handleJump(ptr); - MWMechanics::CreatureStats& stats = actorData.mPtr.getClass().getCreatureStats(actorData.mPtr); + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); if (actorData.mNeedLand) - stats.land(actorData.mPtr == MWMechanics::getPlayer() && (actorData.mFlying || actorData.mSwimming)); + stats.land(ptr == MWMechanics::getPlayer() && (actorData.mFlying || actorData.mSwimming)); else if (actorData.mFallHeight < 0) stats.addToFallHeight(-actorData.mFallHeight); } @@ -218,8 +219,13 @@ namespace MWPhysics { for (auto& data : mActorsFrameData) { + const auto actorActive = [&data](const auto& newFrameData) -> bool + { + const auto actor = data.mActor.lock(); + return actor && actor->getPtr() == newFrameData.mActorRaw->getPtr(); + }; // Only return actors that are still part of the scene - if (std::any_of(actorsData.begin(), actorsData.end(), [&data](const auto& newFrameData) { return data.mActorRaw->getPtr() == newFrameData.mActorRaw->getPtr(); })) + if (std::any_of(actorsData.begin(), actorsData.end(), actorActive)) { updateMechanics(data); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 8b9cb0a79..9c239200b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -783,7 +783,7 @@ namespace MWPhysics if (numSteps == 0) standingOn = physicActor->getStandingOnPtr(); - actorsFrameData.emplace_back(std::move(physicActor), character, standingOn, moveToWaterSurface, movement, slowFall, waterlevel); + actorsFrameData.emplace_back(std::move(physicActor), standingOn, moveToWaterSurface, movement, slowFall, waterlevel); } mMovementQueue.clear(); return actorsFrameData; @@ -925,18 +925,18 @@ namespace MWPhysics mDebugDrawer->addCollision(position, normal); } - ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, + ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel) : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface), mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos() { const MWBase::World *world = MWBase::Environment::get().getWorld(); - mPtr = actor->getPtr(); - mFlying = world->isFlying(character); - mSwimming = world->isSwimming(character); - mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0; - mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead(); + const auto ptr = actor->getPtr(); + mFlying = world->isFlying(ptr); + mSwimming = world->isSwimming(ptr); + mWantJump = ptr.getClass().getMovementSettings(ptr).mPosition[2] != 0; + mIsDead = ptr.getClass().getCreatureStats(ptr).isDead(); mWasOnGround = actor->getOnGround(); } @@ -950,7 +950,7 @@ namespace MWPhysics mActorRaw->setPosition(mPosition); } mOldHeight = mPosition.z(); - mRefpos = mPtr.getRefData().getPosition(); + mRefpos = mActorRaw->getPtr().getRefData().getPosition(); } WorldFrameData::WorldFrameData() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 8c7674991..39bf9dd8b 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -78,11 +78,10 @@ namespace MWPhysics struct ActorFrameData { - ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel); + ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel); void updatePosition(); std::weak_ptr mActor; Actor* mActorRaw; - MWWorld::Ptr mPtr; MWWorld::Ptr mStandingOn; bool mFlying; bool mSwimming; diff --git a/apps/openmw/mwphysics/ptrholder.hpp b/apps/openmw/mwphysics/ptrholder.hpp index f8188b43e..152a5d64f 100644 --- a/apps/openmw/mwphysics/ptrholder.hpp +++ b/apps/openmw/mwphysics/ptrholder.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWPHYSICS_PTRHOLDER_H #define OPENMW_MWPHYSICS_PTRHOLDER_H +#include + #include "../mwworld/ptr.hpp" namespace MWPhysics @@ -12,21 +14,27 @@ namespace MWPhysics void updatePtr(const MWWorld::Ptr& updated) { + std::scoped_lock lock(mMutex); mPtr = updated; } MWWorld::Ptr getPtr() { + std::scoped_lock lock(mMutex); return mPtr; } MWWorld::ConstPtr getPtr() const { + std::scoped_lock lock(mMutex); return mPtr; } protected: MWWorld::Ptr mPtr; + + private: + mutable std::mutex mMutex; }; }