mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-21 09:39:56 +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:
parent
e3cfe5d35a
commit
68f4c336ce
@ -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;
|
||||
///< @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
|
||||
|
||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||
|
@ -124,7 +124,6 @@ void Actor::updatePosition()
|
||||
mSimulationPosition = worldPosition;
|
||||
mPositionOffset = osg::Vec3f();
|
||||
mStandingOnPtr = nullptr;
|
||||
mSkipCollisions = true;
|
||||
mSkipSimulation = true;
|
||||
}
|
||||
|
||||
@ -163,17 +162,19 @@ bool Actor::setPosition(const osg::Vec3f& position)
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
applyOffsetChange();
|
||||
bool hasChanged = mPosition != position || mWorldPositionChanged;
|
||||
mPreviousPosition = mPosition;
|
||||
mPosition = position;
|
||||
bool hasChanged = (mPosition != position && !mSkipSimulation) || mWorldPositionChanged;
|
||||
if (!mSkipSimulation)
|
||||
{
|
||||
mPreviousPosition = mPosition;
|
||||
mPosition = position;
|
||||
}
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
void Actor::adjustPosition(const osg::Vec3f& offset, bool ignoreCollisions)
|
||||
void Actor::adjustPosition(const osg::Vec3f& offset)
|
||||
{
|
||||
std::scoped_lock lock(mPositionMutex);
|
||||
mPositionOffset += offset;
|
||||
mSkipCollisions = mSkipCollisions || ignoreCollisions;
|
||||
}
|
||||
|
||||
void Actor::applyOffsetChange()
|
||||
@ -274,11 +275,6 @@ void Actor::setStandingOnPtr(const MWWorld::Ptr& ptr)
|
||||
mStandingOnPtr = ptr;
|
||||
}
|
||||
|
||||
bool Actor::skipCollisions()
|
||||
{
|
||||
return std::exchange(mSkipCollisions, false);
|
||||
}
|
||||
|
||||
bool Actor::canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const
|
||||
{
|
||||
const float halfZ = getHalfExtents().z();
|
||||
|
@ -89,7 +89,7 @@ namespace MWPhysics
|
||||
void updatePosition();
|
||||
|
||||
// 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
|
||||
void applyOffsetChange();
|
||||
@ -156,8 +156,6 @@ namespace MWPhysics
|
||||
mLastStuckPosition = position;
|
||||
}
|
||||
|
||||
bool skipCollisions();
|
||||
|
||||
bool canMoveToWaterSurface(float waterlevel, const btCollisionWorld* world) const;
|
||||
|
||||
private:
|
||||
@ -187,7 +185,6 @@ namespace MWPhysics
|
||||
osg::Vec3f mScale;
|
||||
osg::Vec3f mPositionOffset;
|
||||
bool mWorldPositionChanged;
|
||||
bool mSkipCollisions;
|
||||
bool mSkipSimulation;
|
||||
mutable std::mutex mPositionMutex;
|
||||
|
||||
|
@ -941,7 +941,7 @@ namespace MWPhysics
|
||||
, mWasOnGround(actor.getOnGround())
|
||||
, mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr()))
|
||||
, mWaterCollision(waterCollision)
|
||||
, mSkipCollisionDetection(actor.skipCollisions() || !actor.getCollisionMode())
|
||||
, mSkipCollisionDetection(!actor.getCollisionMode())
|
||||
{
|
||||
}
|
||||
|
||||
@ -951,8 +951,9 @@ namespace MWPhysics
|
||||
mPosition = actor.getPosition();
|
||||
if (mWaterCollision && mPosition.z() < mWaterlevel && actor.canMoveToWaterSurface(mWaterlevel, world))
|
||||
{
|
||||
mPosition.z() = mWaterlevel;
|
||||
MWBase::Environment::get().getWorld()->moveObject(actor.getPtr(), mPosition, false);
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(actor.getPtr(), osg::Vec3f(0, 0, mWaterlevel - mPosition.z()));
|
||||
actor.applyOffsetChange();
|
||||
mPosition = actor.getPosition();
|
||||
}
|
||||
mOldHeight = mPosition.z();
|
||||
const auto rotation = actor.getPtr().getRefData().getPosition().asRotationVec3();
|
||||
|
@ -32,7 +32,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, false, false);
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff);
|
||||
}
|
||||
|
||||
template<class R>
|
||||
@ -312,7 +312,7 @@ namespace MWScript
|
||||
}
|
||||
|
||||
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.
|
||||
moveStandingActors(ptr, diff);
|
||||
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.
|
||||
moveStandingActors(ptr, diff);
|
||||
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false, true));
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1258,14 +1258,14 @@ namespace MWWorld
|
||||
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);
|
||||
osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec;
|
||||
if (actor)
|
||||
actor->adjustPosition(vec, ignoreCollisions);
|
||||
actor->adjustPosition(vec);
|
||||
if (ptr.getClass().isActor())
|
||||
return moveObject(ptr, newpos, false, moveToActive && ptr != getPlayerPtr());
|
||||
return moveObject(ptr, newpos, false, ptr != getPlayerPtr());
|
||||
return moveObject(ptr, newpos);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
///< @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
|
||||
|
||||
void scaleObject (const Ptr& ptr, float scale) override;
|
||||
|
Loading…
x
Reference in New Issue
Block a user