mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-05 18:45:34 +00:00
Account for waterwalking when updating position. Otherwise we might
trace down the actor at waterlevel at the wrong coordinate. Triggered by multimark mod with waterwalking effect.
This commit is contained in:
parent
fe2a97ee39
commit
6e1c67a9ae
3 changed files with 27 additions and 26 deletions
|
@ -317,7 +317,7 @@ namespace MWPhysics
|
|||
|
||||
// init
|
||||
for (auto& data : actorsData)
|
||||
data.updatePosition();
|
||||
data.updatePosition(mCollisionWorld);
|
||||
mPrevStepCount = numSteps;
|
||||
mRemainingSteps = numSteps;
|
||||
mTimeAccum = timeAccum;
|
||||
|
|
|
@ -60,6 +60,22 @@
|
|||
#include "movementsolver.hpp"
|
||||
#include "mtphysics.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool canMoveToWaterSurface(const MWPhysics::Actor* physicActor, const float waterlevel, btCollisionWorld* world)
|
||||
{
|
||||
if (!physicActor)
|
||||
return false;
|
||||
const float halfZ = physicActor->getHalfExtents().z();
|
||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
||||
MWPhysics::ActorTracer tracer;
|
||||
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, world);
|
||||
return (tracer.mFraction >= 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
|
||||
|
@ -347,16 +363,7 @@ namespace MWPhysics
|
|||
|
||||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||
{
|
||||
const Actor* physicActor = getActor(actor);
|
||||
if (!physicActor)
|
||||
return false;
|
||||
const float halfZ = physicActor->getHalfExtents().z();
|
||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
||||
ActorTracer tracer;
|
||||
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld.get());
|
||||
return (tracer.mFraction >= 1.0f);
|
||||
return ::canMoveToWaterSurface(getActor(actor), waterlevel, mCollisionWorld.get());
|
||||
}
|
||||
|
||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
||||
|
@ -772,16 +779,10 @@ namespace MWPhysics
|
|||
const MWMechanics::MagicEffects& effects = character.getClass().getCreatureStats(character).getMagicEffects();
|
||||
|
||||
bool waterCollision = false;
|
||||
bool moveToWaterSurface = false;
|
||||
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
|
||||
{
|
||||
if (!world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3())))
|
||||
if (physicActor->getCollisionMode() || !world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3())))
|
||||
waterCollision = true;
|
||||
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(character, waterlevel))
|
||||
{
|
||||
moveToWaterSurface = true;
|
||||
waterCollision = true;
|
||||
}
|
||||
}
|
||||
|
||||
physicActor->setCanWaterWalk(waterCollision);
|
||||
|
@ -794,7 +795,7 @@ namespace MWPhysics
|
|||
if (!willSimulate)
|
||||
standingOn = physicActor->getStandingOnPtr();
|
||||
|
||||
actorsFrameData.emplace_back(std::move(physicActor), standingOn, moveToWaterSurface, movement, slowFall, waterlevel);
|
||||
actorsFrameData.emplace_back(std::move(physicActor), standingOn, waterCollision, movement, slowFall, waterlevel);
|
||||
}
|
||||
mMovementQueue.clear();
|
||||
return actorsFrameData;
|
||||
|
@ -937,9 +938,9 @@ namespace MWPhysics
|
|||
}
|
||||
|
||||
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn,
|
||||
bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel)
|
||||
bool waterCollision, osg::Vec3f movement, float slowFall, float waterlevel)
|
||||
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
|
||||
mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface),
|
||||
mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision),
|
||||
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos()
|
||||
{
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
@ -953,7 +954,7 @@ namespace MWPhysics
|
|||
mWasOnGround = actor->getOnGround();
|
||||
}
|
||||
|
||||
void ActorFrameData::updatePosition()
|
||||
void ActorFrameData::updatePosition(btCollisionWorld* world)
|
||||
{
|
||||
mActorRaw->updateWorldPosition();
|
||||
// If physics runs "fast enough", position are interpolated without simulation
|
||||
|
@ -961,10 +962,10 @@ namespace MWPhysics
|
|||
// regardless of simulation speed.
|
||||
mActorRaw->applyOffsetChange();
|
||||
mPosition = mActorRaw->getPosition();
|
||||
if (mMoveToWaterSurface)
|
||||
if (mWaterCollision && mPosition.z() < mWaterlevel && canMoveToWaterSurface(mActorRaw, mWaterlevel, world))
|
||||
{
|
||||
mPosition.z() = mWaterlevel;
|
||||
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition.x(), mPosition.y(), mPosition.z());
|
||||
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition.x(), mPosition.y(), mPosition.z(), false);
|
||||
}
|
||||
mOldHeight = mPosition.z();
|
||||
mRefpos = mActorRaw->getPtr().getRefData().getPosition();
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace MWPhysics
|
|||
struct ActorFrameData
|
||||
{
|
||||
ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel);
|
||||
void updatePosition();
|
||||
void updatePosition(btCollisionWorld* world);
|
||||
std::weak_ptr<Actor> mActor;
|
||||
Actor* mActorRaw;
|
||||
MWWorld::Ptr mStandingOn;
|
||||
|
@ -90,7 +90,7 @@ namespace MWPhysics
|
|||
bool mDidJump;
|
||||
bool mFloatToSurface;
|
||||
bool mNeedLand;
|
||||
bool mMoveToWaterSurface;
|
||||
bool mWaterCollision;
|
||||
float mWaterlevel;
|
||||
float mSlowFall;
|
||||
float mOldHeight;
|
||||
|
|
Loading…
Reference in a new issue