mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-19 21:53:53 +00:00
Restore pre-async handling of absolute actors positionning
One of the issue since the introduction of async physics is the quirky handling of scripted moves. Previous attempt to account for them was based on detecting changes in actor position while the physics thread is running. To this end, semantics of Actor::updatePosition() (which is responsible for set the absolute position of an actor in the world) was toned down to merely store the desired position, with the physics system actually responsible for moving the actor. For the cases were complete override of the physics simulation was needed, I introduced Actor::resetPosition(), which actually have same semantics as original updatePosition(). This in turn introduced a loads of new bugs when the weakened semantics broke key assumptions inside the engine (spawning, summoning, teleport, etc). Instead of tracking them down, count on the newly introduced support for object relative movements in the engine (World::moveObjectBy) to register relative movements and restore original handling of absolute positionning. Changes are relatively small: - move resetPosition() content into updatePosition() - call updatePosition() everywhere it was called before - remove all added calls to the now non-existing resetPosition() tldr; ditch last month worth of bug introduction and eradication and redo it properly
This commit is contained in:
parent
6b5e614b1a
commit
5bd921fa3a
6 changed files with 24 additions and 59 deletions
|
@ -74,7 +74,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
|
|||
|
||||
updateRotation();
|
||||
updateScale();
|
||||
resetPosition();
|
||||
updatePosition();
|
||||
addCollisionMask(getCollisionMask());
|
||||
updateCollisionObjectPosition();
|
||||
}
|
||||
|
@ -119,30 +119,34 @@ int Actor::getCollisionMask() const
|
|||
return collisionMask;
|
||||
}
|
||||
|
||||
void Actor::updatePositionUnsafe()
|
||||
void Actor::updatePosition()
|
||||
{
|
||||
if (!mWorldPositionChanged && mWorldPosition != mPtr.getRefData().getPosition().asVec3())
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
updateWorldPosition();
|
||||
mPreviousPosition = mWorldPosition;
|
||||
mPosition = mWorldPosition;
|
||||
mSimulationPosition = mWorldPosition;
|
||||
mStandingOnPtr = nullptr;
|
||||
mSkipSimulation = true;
|
||||
}
|
||||
|
||||
void Actor::updateWorldPosition()
|
||||
{
|
||||
if (mWorldPosition != mPtr.getRefData().getPosition().asVec3())
|
||||
mWorldPositionChanged = true;
|
||||
mWorldPosition = mPtr.getRefData().getPosition().asVec3();
|
||||
}
|
||||
|
||||
void Actor::updatePosition()
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
updatePositionUnsafe();
|
||||
}
|
||||
|
||||
osg::Vec3f Actor::getWorldPosition() const
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
return mWorldPosition;
|
||||
}
|
||||
|
||||
void Actor::setSimulationPosition(const osg::Vec3f& position)
|
||||
{
|
||||
if (!mResetSimulation)
|
||||
if (!mSkipSimulation)
|
||||
mSimulationPosition = position;
|
||||
mResetSimulation = false;
|
||||
mSkipSimulation = false;
|
||||
}
|
||||
|
||||
osg::Vec3f Actor::getSimulationPosition() const
|
||||
|
@ -150,8 +154,9 @@ osg::Vec3f Actor::getSimulationPosition() const
|
|||
return mSimulationPosition;
|
||||
}
|
||||
|
||||
void Actor::updateCollisionObjectPositionUnsafe()
|
||||
void Actor::updateCollisionObjectPosition()
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
|
||||
osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale);
|
||||
osg::Vec3f newPosition = scaledTranslation + mPosition;
|
||||
|
@ -161,12 +166,6 @@ void Actor::updateCollisionObjectPositionUnsafe()
|
|||
mWorldPositionChanged = false;
|
||||
}
|
||||
|
||||
void Actor::updateCollisionObjectPosition()
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
updateCollisionObjectPositionUnsafe();
|
||||
}
|
||||
|
||||
osg::Vec3f Actor::getCollisionObjectPosition() const
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
|
@ -189,18 +188,6 @@ void Actor::adjustPosition(const osg::Vec3f& offset)
|
|||
mPositionOffset += offset;
|
||||
}
|
||||
|
||||
void Actor::resetPosition()
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
updatePositionUnsafe();
|
||||
mPreviousPosition = mWorldPosition;
|
||||
mPosition = mWorldPosition;
|
||||
mSimulationPosition = mWorldPosition;
|
||||
mStandingOnPtr = nullptr;
|
||||
mWorldPositionChanged = false;
|
||||
mResetSimulation = true;
|
||||
}
|
||||
|
||||
osg::Vec3f Actor::getPosition() const
|
||||
{
|
||||
return mPosition;
|
||||
|
@ -214,8 +201,6 @@ osg::Vec3f Actor::getPreviousPosition() const
|
|||
void Actor::updateRotation ()
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
if (mRotation == mPtr.getRefData().getBaseNode()->getAttitude())
|
||||
return;
|
||||
mRotation = mPtr.getRefData().getBaseNode()->getAttitude();
|
||||
}
|
||||
|
||||
|
@ -246,7 +231,6 @@ osg::Vec3f Actor::getHalfExtents() const
|
|||
|
||||
osg::Vec3f Actor::getOriginalHalfExtents() const
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
return mHalfExtents;
|
||||
}
|
||||
|
||||
|
@ -283,7 +267,6 @@ void Actor::setWalkingOnWater(bool walkingOnWater)
|
|||
|
||||
void Actor::setCanWaterWalk(bool waterWalk)
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
if (waterWalk != mCanWaterWalk)
|
||||
{
|
||||
mCanWaterWalk = waterWalk;
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace MWPhysics
|
|||
* Set mWorldPosition to the position in the Ptr's RefData. This is used by the physics simulation to account for
|
||||
* when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation.
|
||||
*/
|
||||
void updatePosition();
|
||||
void updateWorldPosition();
|
||||
osg::Vec3f getWorldPosition() const;
|
||||
|
||||
/**
|
||||
|
@ -93,7 +93,7 @@ namespace MWPhysics
|
|||
* Returns true if the new position is different.
|
||||
*/
|
||||
bool setPosition(const osg::Vec3f& position);
|
||||
void resetPosition();
|
||||
void updatePosition();
|
||||
void adjustPosition(const osg::Vec3f& offset);
|
||||
|
||||
osg::Vec3f getPosition() const;
|
||||
|
@ -155,8 +155,6 @@ namespace MWPhysics
|
|||
void updateCollisionMask();
|
||||
void addCollisionMask(int collisionMask);
|
||||
int getCollisionMask() const;
|
||||
void updateCollisionObjectPositionUnsafe();
|
||||
void updatePositionUnsafe();
|
||||
|
||||
bool mCanWaterWalk;
|
||||
std::atomic<bool> mWalkingOnWater;
|
||||
|
@ -180,7 +178,7 @@ namespace MWPhysics
|
|||
osg::Vec3f mPreviousPosition;
|
||||
osg::Vec3f mPositionOffset;
|
||||
bool mWorldPositionChanged;
|
||||
bool mResetSimulation;
|
||||
bool mSkipSimulation;
|
||||
btTransform mLocalTransform;
|
||||
mutable std::mutex mPositionMutex;
|
||||
|
||||
|
|
|
@ -281,8 +281,8 @@ namespace MWPhysics
|
|||
mActorsFrameData.clear();
|
||||
for (const auto& [_, actor] : actors)
|
||||
{
|
||||
actor->resetPosition();
|
||||
actor->setSimulationPosition(actor->getWorldPosition()); // resetPosition skip next simulation, now we need to "consume" it
|
||||
actor->updatePosition();
|
||||
actor->setSimulationPosition(actor->getWorldPosition()); // updatePosition skip next simulation, now we need to "consume" it
|
||||
actor->updateCollisionObjectPosition();
|
||||
mMovedActors.emplace_back(actor->getPtr());
|
||||
}
|
||||
|
|
|
@ -437,7 +437,6 @@ namespace MWPhysics
|
|||
ActorMap::iterator found = mActors.find(ptr);
|
||||
if (found == mActors.end())
|
||||
return ptr.getRefData().getPosition().asVec3();
|
||||
resetPosition(ptr);
|
||||
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
|
||||
}
|
||||
|
||||
|
@ -642,17 +641,6 @@ namespace MWPhysics
|
|||
if (foundActor != mActors.end())
|
||||
{
|
||||
foundActor->second->updatePosition();
|
||||
mTaskScheduler->updateSingleAabb(foundActor->second);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsSystem::resetPosition(const MWWorld::ConstPtr &ptr)
|
||||
{
|
||||
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||
if (foundActor != mActors.end())
|
||||
{
|
||||
foundActor->second->resetPosition();
|
||||
mTaskScheduler->updateSingleAabb(foundActor->second, true);
|
||||
return;
|
||||
}
|
||||
|
@ -694,8 +682,6 @@ namespace MWPhysics
|
|||
if (found != mActors.end())
|
||||
{
|
||||
bool cmode = found->second->getCollisionMode();
|
||||
if (cmode)
|
||||
resetPosition(found->first);
|
||||
cmode = !cmode;
|
||||
found->second->enableCollisionMode(cmode);
|
||||
// NB: Collision body isn't disabled for vanilla TCL compatibility
|
||||
|
@ -942,7 +928,7 @@ namespace MWPhysics
|
|||
|
||||
void ActorFrameData::updatePosition()
|
||||
{
|
||||
mActorRaw->updatePosition();
|
||||
mActorRaw->updateWorldPosition();
|
||||
mPosition = mActorRaw->getPosition();
|
||||
if (mMoveToWaterSurface)
|
||||
{
|
||||
|
|
|
@ -143,7 +143,6 @@ namespace MWPhysics
|
|||
void updateScale (const MWWorld::Ptr& ptr);
|
||||
void updateRotation (const MWWorld::Ptr& ptr);
|
||||
void updatePosition (const MWWorld::Ptr& ptr);
|
||||
void resetPosition(const MWWorld::ConstPtr &ptr);
|
||||
|
||||
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject);
|
||||
|
||||
|
|
|
@ -1356,7 +1356,6 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
moveObject(ptr, ptr.getCell(), pos.x(), pos.y(), pos.z());
|
||||
mPhysics->resetPosition(ptr);
|
||||
}
|
||||
|
||||
void World::fixPosition()
|
||||
|
|
Loading…
Reference in a new issue