1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-05 11:45:34 +00:00

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
This commit is contained in:
fredzio 2021-03-28 21:19:14 +02:00
parent 5fce5b12f4
commit 7a67492d81
2 changed files with 18 additions and 3 deletions

View file

@ -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;
}

View file

@ -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())