From 7a67492d81858e53224703d4267dd612e43ae2c8 Mon Sep 17 00:00:00 2001 From: fredzio Date: Sun, 28 Mar 2021 21:19:14 +0200 Subject: [PATCH] Unbreak SetPos and the mods using it. To make SetPos works with async physics, it was modified to register a position offset that would be applied to the real position during the simulation. A common pattern to teleport NPC in scripts is a sequence of SetPos/Disable/Enable in the same frame. Since Disable/Enable creates a new physics actor using last known RefData::Position, the registered offset never get a chance to be applied. Modify disable() to call moveObject with the offset applied, so that the newly created physics actor will have up-to-date position --- apps/openmw/mwphysics/actor.cpp | 8 +++++--- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 905034cde5..bf7503e72f 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -123,6 +123,7 @@ void Actor::updatePosition() mSimulationPosition = mWorldPosition; mStandingOnPtr = nullptr; mSkipSimulation = true; + mPositionOffset = osg::Vec3f(); } void Actor::updateWorldPosition() @@ -179,9 +180,9 @@ bool Actor::setPosition(const osg::Vec3f& position) if (mSkipSimulation) return false; bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged; - mPreviousPosition = mPosition + mPositionOffset; - mPosition = position + mPositionOffset; - mPositionOffset = osg::Vec3f(); + applyOffsetChange(); + mPreviousPosition = mPosition; + mPosition = position; return hasChanged; } @@ -198,6 +199,7 @@ void Actor::applyOffsetChange() mWorldPosition += mPositionOffset; mPosition += mPositionOffset; mPreviousPosition += mPositionOffset; + mSimulationPosition += mPositionOffset; mPositionOffset = osg::Vec3f(); mWorldPositionChanged = true; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d6a4de71bd..5e0cdbb2b6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -862,6 +862,19 @@ namespace MWWorld if (reference == getPlayerPtr()) throw std::runtime_error("can not disable player object"); + // A common pattern to teleport NPC in scripts is a sequence of SetPos/Disable/Enable + // Disable/Enable create a new physics actor, and so the SetPos call is lost + // Call moveObject so that the newly created physics actor will have up-to-date position + if (reference.getClass().isActor()) + { + auto* physactor = mPhysics->getActor(reference); + if (physactor) + { + physactor->applyOffsetChange(); + const auto position = physactor->getSimulationPosition(); + moveObject(reference, position.x(), position.y(), position.z(), true); + } + } reference.getRefData().disable(); if (reference.getCellRef().getRefNum().hasContentFile())