mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-05 17: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:
parent
5fce5b12f4
commit
7a67492d81
2 changed files with 18 additions and 3 deletions
|
@ -123,6 +123,7 @@ void Actor::updatePosition()
|
||||||
mSimulationPosition = mWorldPosition;
|
mSimulationPosition = mWorldPosition;
|
||||||
mStandingOnPtr = nullptr;
|
mStandingOnPtr = nullptr;
|
||||||
mSkipSimulation = true;
|
mSkipSimulation = true;
|
||||||
|
mPositionOffset = osg::Vec3f();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actor::updateWorldPosition()
|
void Actor::updateWorldPosition()
|
||||||
|
@ -179,9 +180,9 @@ bool Actor::setPosition(const osg::Vec3f& position)
|
||||||
if (mSkipSimulation)
|
if (mSkipSimulation)
|
||||||
return false;
|
return false;
|
||||||
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
|
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
|
||||||
mPreviousPosition = mPosition + mPositionOffset;
|
applyOffsetChange();
|
||||||
mPosition = position + mPositionOffset;
|
mPreviousPosition = mPosition;
|
||||||
mPositionOffset = osg::Vec3f();
|
mPosition = position;
|
||||||
return hasChanged;
|
return hasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +199,7 @@ void Actor::applyOffsetChange()
|
||||||
mWorldPosition += mPositionOffset;
|
mWorldPosition += mPositionOffset;
|
||||||
mPosition += mPositionOffset;
|
mPosition += mPositionOffset;
|
||||||
mPreviousPosition += mPositionOffset;
|
mPreviousPosition += mPositionOffset;
|
||||||
|
mSimulationPosition += mPositionOffset;
|
||||||
mPositionOffset = osg::Vec3f();
|
mPositionOffset = osg::Vec3f();
|
||||||
mWorldPositionChanged = true;
|
mWorldPositionChanged = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -862,6 +862,19 @@ namespace MWWorld
|
||||||
if (reference == getPlayerPtr())
|
if (reference == getPlayerPtr())
|
||||||
throw std::runtime_error("can not disable player object");
|
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();
|
reference.getRefData().disable();
|
||||||
|
|
||||||
if (reference.getCellRef().getRefNum().hasContentFile())
|
if (reference.getCellRef().getRefNum().hasContentFile())
|
||||||
|
|
Loading…
Reference in a new issue