diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d408166841..5ebf8527c0 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -297,7 +297,7 @@ namespace MWBase = 0; ///< @return an updated Ptr - virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr& ptr, const osg::Vec3f& vec) = 0; + virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr& ptr, const osg::Vec3f& vec, bool moveToActive) = 0; ///< @return an updated Ptr virtual void scaleObject(const MWWorld::Ptr& ptr, float scale, bool force = false) = 0; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 5349392cb7..dec055d68f 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -185,8 +185,6 @@ namespace MWPhysics trans.setOrigin(Misc::Convert::toBullet(newPosition)); trans.setRotation(Misc::Convert::toBullet(mRotation)); mCollisionObject->setWorldTransform(trans); - - mWorldPositionChanged = false; } osg::Vec3f Actor::getCollisionObjectPosition() const @@ -198,14 +196,13 @@ namespace MWPhysics bool Actor::setPosition(const osg::Vec3f& position) { std::scoped_lock lock(mPositionMutex); + const bool worldPositionChanged = mPositionOffset.length2() != 0; applyOffsetChange(); - bool hasChanged = (mPosition.operator!=(position) && !mSkipSimulation) || mWorldPositionChanged; - if (!mSkipSimulation) - { - mPreviousPosition = mPosition; - mPosition = position; - } - return hasChanged; + if (worldPositionChanged || mSkipSimulation) + return true; + mPreviousPosition = mPosition; + mPosition = position; + return mPreviousPosition != mPosition; } void Actor::adjustPosition(const osg::Vec3f& offset) @@ -214,15 +211,16 @@ namespace MWPhysics mPositionOffset += offset; } - void Actor::applyOffsetChange() + osg::Vec3f Actor::applyOffsetChange() { - if (mPositionOffset.length() == 0) - return; - mPosition += mPositionOffset; - mPreviousPosition += mPositionOffset; - mSimulationPosition += mPositionOffset; - mPositionOffset = osg::Vec3f(); - mWorldPositionChanged = true; + if (mPositionOffset.length2() != 0) + { + mPosition += mPositionOffset; + mPreviousPosition += mPositionOffset; + mSimulationPosition += mPositionOffset; + mPositionOffset = osg::Vec3f(); + } + return mPosition; } void Actor::setRotation(osg::Quat quat) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 543259c9e5..e53477506c 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -96,7 +96,7 @@ namespace MWPhysics void adjustPosition(const osg::Vec3f& offset); // apply position offset. Can't be called during simulation - void applyOffsetChange(); + osg::Vec3f applyOffsetChange(); /** * Returns the half extents of the collision body (scaled according to rendering scale) @@ -176,7 +176,6 @@ namespace MWPhysics osg::Vec3f mScale; osg::Vec3f mPositionOffset; - bool mWorldPositionChanged = false; bool mSkipSimulation = true; mutable std::mutex mPositionMutex; diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index a127124265..846be640e2 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -475,6 +475,9 @@ namespace MWPhysics if (actor.mSkipCollisionDetection) // noclipping/tcl return; + if (actor.mMovement.length2() == 0) // no AI nor player attempted to move, current position is assumed correct + return; + auto tempPosition = actor.mPosition; if (actor.mStuckFrames >= 10) diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index 0e61e60ed5..653380decf 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -176,16 +176,15 @@ namespace return; auto& [actor, frameDataRef] = *locked; auto& frameData = frameDataRef.get(); - actor->applyOffsetChange(); - frameData.mPosition = actor->getPosition(); + frameData.mPosition = actor->applyOffsetChange(); if (frameData.mWaterCollision && frameData.mPosition.z() < frameData.mWaterlevel && actor->canMoveToWaterSurface(frameData.mWaterlevel, mCollisionWorld)) { const auto offset = osg::Vec3f(0, 0, frameData.mWaterlevel - frameData.mPosition.z()); - MWBase::Environment::get().getWorld()->moveObjectBy(actor->getPtr(), offset); - actor->applyOffsetChange(); - frameData.mPosition = actor->getPosition(); + MWBase::Environment::get().getWorld()->moveObjectBy(actor->getPtr(), offset, false); + frameData.mPosition = actor->applyOffsetChange(); } + actor->updateCollisionObjectPosition(); frameData.mOldHeight = frameData.mPosition.z(); const auto rotation = actor->getPtr().getRefData().getPosition().asRotationVec3(); frameData.mRotation = osg::Vec2f(rotation.x(), rotation.z()); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index c624d24753..34423cdf00 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -35,7 +35,7 @@ namespace MWScript std::vector actors; MWBase::Environment::get().getWorld()->getActorsStandingOn(ptr, actors); for (auto& actor : actors) - MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff); + MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false); } template @@ -331,7 +331,7 @@ namespace MWScript } dynamic_cast(runtime.getContext()) - .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObject(ptr, newPos, true, true)); + .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true)); } }; @@ -753,7 +753,7 @@ namespace MWScript // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()) - .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); + .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; @@ -788,7 +788,7 @@ namespace MWScript // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()) - .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); + .updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 555df2bbf1..26194deb2c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1249,14 +1249,14 @@ namespace MWWorld return moveObject(ptr, cell, position, movePhysics); } - MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec) + MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec, bool moveToActive) { auto* actor = mPhysics->getActor(ptr); osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec; if (actor) actor->adjustPosition(vec); if (ptr.getClass().isActor()) - return moveObject(ptr, newpos, false, ptr != getPlayerPtr()); + return moveObject(ptr, newpos, false, moveToActive && ptr != getPlayerPtr()); return moveObject(ptr, newpos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 476a92eea7..f246728fe1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -378,7 +378,7 @@ namespace MWWorld bool keepActive = false) override; ///< @return an updated Ptr - MWWorld::Ptr moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec) override; + MWWorld::Ptr moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec, bool moveToActive) override; ///< @return an updated Ptr void scaleObject(const Ptr& ptr, float scale, bool force = false) override;