mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-05 21:45:33 +00:00
Merge branch 'teleport_here_not_there' into 'master'
Fix #5919 (and another bug) Closes #5919 See merge request OpenMW/openmw!722
This commit is contained in:
commit
603e4206fd
8 changed files with 54 additions and 75 deletions
|
@ -281,13 +281,13 @@ namespace MWBase
|
|||
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool moveToActive=false) = 0;
|
||||
virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false) = 0;
|
||||
///< @return an updated Ptr in case the Ptr's cell changes
|
||||
|
||||
virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0;
|
||||
///< @return an updated Ptr
|
||||
|
||||
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec) = 0;
|
||||
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec, bool moveToActive) = 0;
|
||||
///< @return an updated Ptr
|
||||
|
||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||
|
||||
#include <apps/openmw/mwmechanics/actorutil.hpp>
|
||||
#include <apps/openmw/mwworld/cellstore.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/resource/bulletshape.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
@ -181,6 +179,7 @@ bool Actor::setPosition(const osg::Vec3f& position)
|
|||
if (mSkipSimulation)
|
||||
return false;
|
||||
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
|
||||
updateWorldPosition();
|
||||
applyOffsetChange();
|
||||
mPreviousPosition = mPosition;
|
||||
mPosition = position;
|
||||
|
@ -197,15 +196,6 @@ void Actor::applyOffsetChange()
|
|||
{
|
||||
if (mPositionOffset.length() == 0)
|
||||
return;
|
||||
if (mPositionOffset.z() != 0)
|
||||
{
|
||||
// Often, offset are set in sequence x, y, z
|
||||
// We don't want actors to be moved under the ground
|
||||
// Check terrain height at new coordinate and update z offset if necessary
|
||||
const auto pos = mWorldPosition + mPositionOffset;
|
||||
const auto terrainHeight = mPtr.getCell()->isExterior() ? MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos) : -std::numeric_limits<float>::max();
|
||||
mPositionOffset.z() = std::max(pos.z(), terrainHeight) - mWorldPosition.z();
|
||||
}
|
||||
mWorldPosition += mPositionOffset;
|
||||
mPosition += mPositionOffset;
|
||||
mPreviousPosition += mPositionOffset;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false);
|
||||
}
|
||||
|
||||
template<class R>
|
||||
|
@ -284,6 +284,17 @@ namespace MWScript
|
|||
}
|
||||
else if(axis == "z")
|
||||
{
|
||||
// We should not place actors under ground
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
float terrainHeight = -std::numeric_limits<float>::max();
|
||||
if (ptr.getCell()->isExterior())
|
||||
terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt(curPos);
|
||||
|
||||
if (pos < terrainHeight)
|
||||
pos = terrainHeight;
|
||||
}
|
||||
|
||||
newPos[2] = pos;
|
||||
}
|
||||
else
|
||||
|
@ -292,7 +303,7 @@ namespace MWScript
|
|||
}
|
||||
|
||||
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr,
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos));
|
||||
MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -428,7 +439,7 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z, true);
|
||||
ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z, true, true);
|
||||
}
|
||||
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base,ptr);
|
||||
|
||||
|
@ -715,7 +726,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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -751,7 +762,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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -862,19 +862,6 @@ namespace MWWorld
|
|||
if (reference == getPlayerPtr())
|
||||
throw std::runtime_error("can not disable player object");
|
||||
|
||||
// A common pattern to teleport NPC in scripts is a sequence of SetPos/Disable/Enable
|
||||
// Disable/Enable create a new physics actor, and so the SetPos call is lost
|
||||
// Call moveObject so that the newly created physics actor will have up-to-date position
|
||||
if (reference.getClass().isActor())
|
||||
{
|
||||
auto* physactor = mPhysics->getActor(reference);
|
||||
if (physactor)
|
||||
{
|
||||
physactor->applyOffsetChange();
|
||||
const auto position = physactor->getSimulationPosition();
|
||||
moveObject(reference, position.x(), position.y(), position.z(), true);
|
||||
}
|
||||
}
|
||||
reference.getRefData().disable();
|
||||
|
||||
if (reference.getCellRef().getRefNum().hasContentFile())
|
||||
|
@ -1251,7 +1238,7 @@ namespace MWWorld
|
|||
return newPtr;
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z, bool movePhysics, bool moveToActive)
|
||||
MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z, bool movePhysics, bool moveToActive)
|
||||
{
|
||||
int cellX, cellY;
|
||||
positionToIndex(x, y, cellX, cellY);
|
||||
|
@ -1266,21 +1253,14 @@ namespace MWWorld
|
|||
return moveObject(ptr, cell, x, y, z, movePhysics);
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z, bool moveToActive)
|
||||
{
|
||||
return moveObjectImp(ptr, x, y, z, true, moveToActive);
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec)
|
||||
MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec, bool moveToActive)
|
||||
{
|
||||
auto* actor = mPhysics->getActor(ptr);
|
||||
if (actor)
|
||||
{
|
||||
actor->adjustPosition(vec);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec;
|
||||
return moveObject(ptr, newpos.x(), newpos.y(), newpos.z());
|
||||
return moveObject(ptr, newpos.x(), newpos.y(), newpos.z(), false, moveToActive && ptr != getPlayerPtr());
|
||||
}
|
||||
|
||||
void World::scaleObject (const Ptr& ptr, float scale)
|
||||
|
@ -1546,7 +1526,7 @@ namespace MWWorld
|
|||
auto* physactor = mPhysics->getActor(actor);
|
||||
assert(physactor);
|
||||
const auto position = physactor->getSimulationPosition();
|
||||
moveObjectImp(actor, position.x(), position.y(), position.z(), false);
|
||||
moveObject(actor, position.x(), position.y(), position.z(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1556,7 +1536,7 @@ namespace MWWorld
|
|||
auto* physactor = mPhysics->getActor(*player);
|
||||
assert(physactor);
|
||||
const auto position = physactor->getSimulationPosition();
|
||||
moveObjectImp(*player, position.x(), position.y(), position.z(), false);
|
||||
moveObject(*player, position.x(), position.y(), position.z(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,9 +138,6 @@ namespace MWWorld
|
|||
|
||||
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags);
|
||||
|
||||
Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false);
|
||||
///< @return an updated Ptr in case the Ptr's cell changes
|
||||
|
||||
Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos);
|
||||
|
||||
void updateSoundListener();
|
||||
|
@ -376,13 +373,13 @@ namespace MWWorld
|
|||
|
||||
void undeleteObject (const Ptr& ptr) override;
|
||||
|
||||
MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z, bool moveToActive=false) override;
|
||||
MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false) override;
|
||||
///< @return an updated Ptr in case the Ptr's cell changes
|
||||
|
||||
MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override;
|
||||
///< @return an updated Ptr
|
||||
|
||||
MWWorld::Ptr moveObjectBy(const Ptr& ptr, osg::Vec3f vec) override;
|
||||
MWWorld::Ptr moveObjectBy(const Ptr& ptr, osg::Vec3f vec, bool moveToActive) override;
|
||||
///< @return an updated Ptr
|
||||
|
||||
void scaleObject (const Ptr& ptr, float scale) override;
|
||||
|
|
Loading…
Reference in a new issue