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:
parent
35b2292e61
commit
63d4564455
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user