1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-05 21:45:33 +00:00

Change (again) the way SetPos behave.

Instead of registering the desired change of position and rely on
physics simulation to apply it to the world, immediately change the
position in the world without reset the simulation.
This commit is contained in:
fredzio 2021-04-09 23:06:36 +02:00
parent 6e1c67a9ae
commit 8874a5be22
5 changed files with 27 additions and 49 deletions

View file

@ -281,13 +281,13 @@ namespace MWBase
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
virtual void undeleteObject (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 ///< @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; 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 ///< @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 ///< @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

@ -3,8 +3,6 @@
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.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/sceneutil/positionattitudetransform.hpp>
#include <components/resource/bulletshape.hpp> #include <components/resource/bulletshape.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
@ -181,6 +179,7 @@ bool Actor::setPosition(const osg::Vec3f& position)
if (mSkipSimulation) if (mSkipSimulation)
return false; return false;
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged; bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
updateWorldPosition();
applyOffsetChange(); applyOffsetChange();
mPreviousPosition = mPosition; mPreviousPosition = mPosition;
mPosition = position; mPosition = position;
@ -197,15 +196,6 @@ void Actor::applyOffsetChange()
{ {
if (mPositionOffset.length() == 0) if (mPositionOffset.length() == 0)
return; 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; mWorldPosition += mPositionOffset;
mPosition += mPositionOffset; mPosition += mPositionOffset;
mPreviousPosition += mPositionOffset; mPreviousPosition += mPositionOffset;

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); MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false);
} }
template<class R> template<class R>
@ -284,6 +284,17 @@ namespace MWScript
} }
else if(axis == "z") 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; newPos[2] = pos;
} }
else else
@ -292,7 +303,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)); MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true));
} }
}; };
@ -428,7 +439,7 @@ namespace MWScript
} }
else 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); dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base,ptr);
@ -715,7 +726,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)); MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
} }
}; };
@ -751,7 +762,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)); MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
} }
}; };

View file

@ -862,19 +862,6 @@ namespace MWWorld
if (reference == getPlayerPtr()) if (reference == getPlayerPtr())
throw std::runtime_error("can not disable player object"); 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(); reference.getRefData().disable();
if (reference.getCellRef().getRefNum().hasContentFile()) if (reference.getCellRef().getRefNum().hasContentFile())
@ -1251,7 +1238,7 @@ namespace MWWorld
return newPtr; 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; int cellX, cellY;
positionToIndex(x, y, cellX, cellY); positionToIndex(x, y, cellX, cellY);
@ -1266,21 +1253,14 @@ namespace MWWorld
return moveObject(ptr, cell, x, y, z, movePhysics); return moveObject(ptr, cell, x, y, z, movePhysics);
} }
MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z, bool moveToActive) MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec, bool moveToActive)
{
return moveObjectImp(ptr, x, y, z, true, moveToActive);
}
MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec)
{ {
auto* actor = mPhysics->getActor(ptr); auto* actor = mPhysics->getActor(ptr);
if (actor) if (actor)
{
actor->adjustPosition(vec); actor->adjustPosition(vec);
return ptr;
}
osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec; 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) void World::scaleObject (const Ptr& ptr, float scale)
@ -1546,7 +1526,7 @@ namespace MWWorld
auto* physactor = mPhysics->getActor(actor); auto* physactor = mPhysics->getActor(actor);
assert(physactor); assert(physactor);
const auto position = physactor->getSimulationPosition(); 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); auto* physactor = mPhysics->getActor(*player);
assert(physactor); assert(physactor);
const auto position = physactor->getSimulationPosition(); const auto position = physactor->getSimulationPosition();
moveObjectImp(*player, position.x(), position.y(), position.z(), false); moveObject(*player, position.x(), position.y(), position.z(), false, false);
} }
} }

View file

@ -138,9 +138,6 @@ namespace MWWorld
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags); 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); Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos);
void updateSoundListener(); void updateSoundListener();
@ -376,13 +373,13 @@ namespace MWWorld
void undeleteObject (const Ptr& ptr) override; 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 ///< @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; MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override;
///< @return an updated Ptr ///< @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 ///< @return an updated Ptr
void scaleObject (const Ptr& ptr, float scale) override; void scaleObject (const Ptr& ptr, float scale) override;