1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-19 06:41:36 +00:00

Rework again SetPos command to make more mods work.

Previous version skipped collision the frame immediately after a call to SetPos. It worked for one-off calls (teleports for instance) and continuous call along a pre-defined path (scenic travel). However, in the case of mod which uses SetPos to simulate a player-controlled movement, it is equivalent to using tcl.
Solution:
1/ skip update of mPosition and  mPreviousPosition to avoid janky interpolation
2/ use back plain moveObject() instead of moveObjectBy() since we don't want physics simulation
3/ rework a little bit waterwalking influence on coordinate because of 1/
This commit is contained in:
fredzio 2021-10-19 18:36:30 +02:00
parent e3cfe5d35a
commit 68f4c336ce
7 changed files with 21 additions and 27 deletions

View file

@ -289,7 +289,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; 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 ///< @return an updated Ptr
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, const osg::Vec3f& vec, bool moveToActive, bool ignoreCollisions) = 0; virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, const osg::Vec3f& vec) = 0;
///< @return an updated Ptr ///< @return an updated Ptr
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;

View file

@ -124,7 +124,6 @@ void Actor::updatePosition()
mSimulationPosition = worldPosition; mSimulationPosition = worldPosition;
mPositionOffset = osg::Vec3f(); mPositionOffset = osg::Vec3f();
mStandingOnPtr = nullptr; mStandingOnPtr = nullptr;
mSkipCollisions = true;
mSkipSimulation = true; mSkipSimulation = true;
} }
@ -163,17 +162,19 @@ bool Actor::setPosition(const osg::Vec3f& position)
{ {
std::scoped_lock lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
applyOffsetChange(); applyOffsetChange();
bool hasChanged = mPosition != position || mWorldPositionChanged; bool hasChanged = (mPosition != position && !mSkipSimulation) || mWorldPositionChanged;
if (!mSkipSimulation)
{
mPreviousPosition = mPosition; mPreviousPosition = mPosition;
mPosition = position; mPosition = position;
}
return hasChanged; return hasChanged;
} }
void Actor::adjustPosition(const osg::Vec3f& offset, bool ignoreCollisions) void Actor::adjustPosition(const osg::Vec3f& offset)
{ {
std::scoped_lock lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
mPositionOffset += offset; mPositionOffset += offset;
mSkipCollisions = mSkipCollisions || ignoreCollisions;
} }
void Actor::applyOffsetChange() void Actor::applyOffsetChange()
@ -274,11 +275,6 @@ void Actor::setStandingOnPtr(const MWWorld::Ptr& ptr)
mStandingOnPtr = ptr; mStandingOnPtr = ptr;
} }
bool Actor::skipCollisions()
{
return std::exchange(mSkipCollisions, false);
}
bool Actor::canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const bool Actor::canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const
{ {
const float halfZ = getHalfExtents().z(); const float halfZ = getHalfExtents().z();

View file

@ -89,7 +89,7 @@ namespace MWPhysics
void updatePosition(); void updatePosition();
// register a position offset that will be applied during simulation. // register a position offset that will be applied during simulation.
void adjustPosition(const osg::Vec3f& offset, bool ignoreCollisions); void adjustPosition(const osg::Vec3f& offset);
// apply position offset. Can't be called during simulation // apply position offset. Can't be called during simulation
void applyOffsetChange(); void applyOffsetChange();
@ -156,8 +156,6 @@ namespace MWPhysics
mLastStuckPosition = position; mLastStuckPosition = position;
} }
bool skipCollisions();
bool canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const; bool canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const;
private: private:
@ -187,7 +185,6 @@ namespace MWPhysics
osg::Vec3f mScale; osg::Vec3f mScale;
osg::Vec3f mPositionOffset; osg::Vec3f mPositionOffset;
bool mWorldPositionChanged; bool mWorldPositionChanged;
bool mSkipCollisions;
bool mSkipSimulation; bool mSkipSimulation;
mutable std::mutex mPositionMutex; mutable std::mutex mPositionMutex;

View file

@ -941,7 +941,7 @@ namespace MWPhysics
, mWasOnGround(actor.getOnGround()) , mWasOnGround(actor.getOnGround())
, mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr())) , mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr()))
, mWaterCollision(waterCollision) , mWaterCollision(waterCollision)
, mSkipCollisionDetection(actor.skipCollisions() || !actor.getCollisionMode()) , mSkipCollisionDetection(!actor.getCollisionMode())
{ {
} }
@ -951,8 +951,9 @@ namespace MWPhysics
mPosition = actor.getPosition(); mPosition = actor.getPosition();
if (mWaterCollision && mPosition.z() < mWaterlevel && actor.canMoveToWaterSurface(mWaterlevel, world)) if (mWaterCollision && mPosition.z() < mWaterlevel && actor.canMoveToWaterSurface(mWaterlevel, world))
{ {
mPosition.z() = mWaterlevel; MWBase::Environment::get().getWorld()->moveObjectBy(actor.getPtr(), osg::Vec3f(0, 0, mWaterlevel - mPosition.z()));
MWBase::Environment::get().getWorld()->moveObject(actor.getPtr(), mPosition, false); actor.applyOffsetChange();
mPosition = actor.getPosition();
} }
mOldHeight = mPosition.z(); mOldHeight = mPosition.z();
const auto rotation = actor.getPtr().getRefData().getPosition().asRotationVec3(); const auto rotation = actor.getPtr().getRefData().getPosition().asRotationVec3();

View file

@ -32,7 +32,7 @@ namespace MWScript
std::vector<MWWorld::Ptr> actors; std::vector<MWWorld::Ptr> actors;
MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors); MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors);
for (auto& actor : actors) for (auto& actor : actors)
MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false, false); MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff);
} }
template<class R> template<class R>
@ -312,7 +312,7 @@ namespace MWScript
} }
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr, dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true, true)); MWBase::Environment::get().getWorld()->moveObject(ptr, newPos, true, true));
} }
}; };
@ -731,7 +731,7 @@ namespace MWScript
// This approach can be used to create elevators. // This approach can be used to create elevators.
moveStandingActors(ptr, diff); moveStandingActors(ptr, diff);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr, dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false, true)); MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff));
} }
}; };
@ -767,7 +767,7 @@ namespace MWScript
// This approach can be used to create elevators. // This approach can be used to create elevators.
moveStandingActors(ptr, diff); moveStandingActors(ptr, diff);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr, dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false, true)); MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff));
} }
}; };

View file

@ -1258,14 +1258,14 @@ namespace MWWorld
return moveObject(ptr, cell, position, movePhysics); return moveObject(ptr, cell, position, movePhysics);
} }
MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec, bool moveToActive, bool ignoreCollisions) MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec)
{ {
auto* actor = mPhysics->getActor(ptr); auto* actor = mPhysics->getActor(ptr);
osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec; osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec;
if (actor) if (actor)
actor->adjustPosition(vec, ignoreCollisions); actor->adjustPosition(vec);
if (ptr.getClass().isActor()) if (ptr.getClass().isActor())
return moveObject(ptr, newpos, false, moveToActive && ptr != getPlayerPtr()); return moveObject(ptr, newpos, false, ptr != getPlayerPtr());
return moveObject(ptr, newpos); return moveObject(ptr, newpos);
} }

View file

@ -376,7 +376,7 @@ namespace MWWorld
MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, bool keepActive=false) override; MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, bool keepActive=false) override;
///< @return an updated Ptr ///< @return an updated Ptr
MWWorld::Ptr moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec, bool moveToActive, bool ignoreCollisions) override; MWWorld::Ptr moveObjectBy(const Ptr& ptr, const osg::Vec3f& vec) override;
///< @return an updated Ptr ///< @return an updated Ptr
void scaleObject (const Ptr& ptr, float scale) override; void scaleObject (const Ptr& ptr, float scale) override;