diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5c260b096d..d89e43fe29 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -305,7 +305,7 @@ namespace MWBase virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, bool keepActive=false) = 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 a23a2e56f4..291f13b214 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -176,8 +176,6 @@ void Actor::updateCollisionObjectPosition() trans.setOrigin(Misc::Convert::toBullet(newPosition)); trans.setRotation(Misc::Convert::toBullet(mRotation)); mCollisionObject->setWorldTransform(trans); - - mWorldPositionChanged = false; } osg::Vec3f Actor::getCollisionObjectPosition() const @@ -189,14 +187,13 @@ osg::Vec3f Actor::getCollisionObjectPosition() const 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) @@ -205,15 +202,16 @@ void Actor::adjustPosition(const osg::Vec3f& offset) 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 146a065063..024d8c862c 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -95,7 +95,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) @@ -189,7 +189,6 @@ namespace MWPhysics osg::Vec3f mScale; osg::Vec3f mPositionOffset; - bool mWorldPositionChanged; bool mSkipSimulation; mutable std::mutex mPositionMutex; diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index da07d5975b..abe23bd3b6 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -452,6 +452,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 dabd1fdcad..5f42166df2 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -167,15 +167,14 @@ 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 8e42419ff7..09409311ca 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -33,7 +33,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 @@ -328,7 +328,7 @@ namespace MWScript } dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObject(ptr, newPos, true, true)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true)); } }; @@ -757,7 +757,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)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; @@ -793,7 +793,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)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 001a295796..5b07ef3ff8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1276,14 +1276,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 3e5b3d7731..f85cfc5629 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -394,7 +394,7 @@ namespace MWWorld MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, 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;