1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-31 06:32:39 +00:00

In 0.46, SetPos was setting position of actors before physics simulation, and from this position movement was simulated. This changed with async physics merging, and at the same time problems started, mostly with abot's scenic travel.

Skipping the simulation, switching off collisions, and other approaches were not correct as they either broke some mods, or some core mechanics of the engine such as teleportation or waterwalking. As it turns out, the way to go is to simply do _nothing_ (modulo some gymnastics to account for the 1 frame difference in case of async).

Scripted movement and the unstucking logic tends to collide. Early out of unstuck in case the actor doesn't attempt to move. This means there is no AI package for NPC, which are the case for some boats and striders, or the player is content with their position.
This commit is contained in:
fredzio 2023-03-16 21:33:36 +01:00
parent 35b2292e61
commit 63d4564455
8 changed files with 31 additions and 32 deletions

View File

@ -297,7 +297,7 @@ namespace MWBase
= 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;

View File

@ -185,8 +185,6 @@ namespace MWPhysics
trans.setOrigin(Misc::Convert::toBullet(newPosition));
trans.setRotation(Misc::Convert::toBullet(mRotation));
mCollisionObject->setWorldTransform(trans);
mWorldPositionChanged = false;
}
osg::Vec3f Actor::getCollisionObjectPosition() const
@ -198,14 +196,13 @@ namespace MWPhysics
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)
@ -214,15 +211,16 @@ namespace MWPhysics
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)

View File

@ -96,7 +96,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)
@ -176,7 +176,6 @@ namespace MWPhysics
osg::Vec3f mScale;
osg::Vec3f mPositionOffset;
bool mWorldPositionChanged = false;
bool mSkipSimulation = true;
mutable std::mutex mPositionMutex;

View File

@ -475,6 +475,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)

View File

@ -176,16 +176,15 @@ 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());

View File

@ -35,7 +35,7 @@ namespace MWScript
std::vector<MWWorld::Ptr> 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 <class R>
@ -331,7 +331,7 @@ namespace MWScript
}
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObject(ptr, newPos, true, true));
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true));
}
};
@ -753,7 +753,7 @@ namespace MWScript
// This approach can be used to create elevators.
moveStandingActors(ptr, diff);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff));
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
}
};
@ -788,7 +788,7 @@ namespace MWScript
// This approach can be used to create elevators.
moveStandingActors(ptr, diff);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff));
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
}
};

View File

@ -1249,14 +1249,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);
}

View File

@ -378,7 +378,7 @@ namespace MWWorld
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;