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.
backport_gl_clamp_removal
fredzio 1 year ago
parent f81e78e4c1
commit 76c6848121

@ -305,7 +305,7 @@ namespace MWBase
virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, bool keepActive=false) = 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;

@ -176,8 +176,6 @@ void Actor::updateCollisionObjectPosition()
trans.setOrigin(Misc::Convert::toBullet(newPosition));
trans.setRotation(Misc::Convert::toBullet(mRotation));
mCollisionObject->setWorldTransform(trans);
mWorldPositionChanged = false;
}
osg::Vec3f Actor::getCollisionObjectPosition() const
@ -189,14 +187,13 @@ osg::Vec3f Actor::getCollisionObjectPosition() const
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)
@ -205,15 +202,16 @@ void Actor::adjustPosition(const osg::Vec3f& offset)
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)

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

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

@ -167,15 +167,14 @@ 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());

@ -33,7 +33,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>
@ -328,7 +328,7 @@ namespace MWScript
}
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
MWBase::Environment::get().getWorld()->moveObject(ptr, newPos, true, true));
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true));
}
};
@ -757,7 +757,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));
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
}
};
@ -793,7 +793,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));
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
}
};

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

@ -394,7 +394,7 @@ namespace MWWorld
MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, 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;

Loading…
Cancel
Save