mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-02 06:06:41 +00:00
Fix infinite fall into void (#1415)
This commit is contained in:
parent
2bed7450b6
commit
b43c7238e9
3 changed files with 45 additions and 8 deletions
|
@ -172,6 +172,7 @@
|
||||||
Bug #7901: Editor: Teleport-related fields shouldn't be editable if a ref does not teleport
|
Bug #7901: Editor: Teleport-related fields shouldn't be editable if a ref does not teleport
|
||||||
Bug #7908: Key bindings names in the settings menu are layout-specific
|
Bug #7908: Key bindings names in the settings menu are layout-specific
|
||||||
Bug #7943: Using "addSoulGem" and "dropSoulGem" commands to creatures works only with "Weapon & Shield" flagged ones
|
Bug #7943: Using "addSoulGem" and "dropSoulGem" commands to creatures works only with "Weapon & Shield" flagged ones
|
||||||
|
Feature #1415: Infinite fall failsafe
|
||||||
Feature #2566: Handle NAM9 records for manual cell references
|
Feature #2566: Handle NAM9 records for manual cell references
|
||||||
Feature #3537: Shader-based water ripples
|
Feature #3537: Shader-based water ripples
|
||||||
Feature #5173: Support for NiFogProperty
|
Feature #5173: Support for NiFogProperty
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "../mwphysics/object.hpp"
|
#include "../mwphysics/object.hpp"
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/actionteleport.hpp"
|
||||||
|
|
||||||
#include "cellpreloader.hpp"
|
#include "cellpreloader.hpp"
|
||||||
#include "cellstore.hpp"
|
#include "cellstore.hpp"
|
||||||
#include "cellvisitors.hpp"
|
#include "cellvisitors.hpp"
|
||||||
|
@ -138,10 +140,22 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const MWPhysics::PhysicsSystem& physics,
|
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const MWPhysics::PhysicsSystem& physics,
|
||||||
DetourNavigator::Navigator& navigator, const DetourNavigator::UpdateGuard* navigatorUpdateGuard = nullptr)
|
float& lowestPoint, bool isInterior, DetourNavigator::Navigator& navigator,
|
||||||
|
const DetourNavigator::UpdateGuard* navigatorUpdateGuard = nullptr)
|
||||||
{
|
{
|
||||||
if (const auto object = physics.getObject(ptr))
|
if (const auto object = physics.getObject(ptr))
|
||||||
{
|
{
|
||||||
|
// Find the lowest point of this collision object in world space from its AABB if interior
|
||||||
|
// this point is used to determine the infinite fall cutoff from lowest point in the cell
|
||||||
|
if (isInterior)
|
||||||
|
{
|
||||||
|
btVector3 aabbMin;
|
||||||
|
btVector3 aabbMax;
|
||||||
|
const auto transform = object->getTransform();
|
||||||
|
object->getShapeInstance()->mCollisionShape->getAabb(transform, aabbMin, aabbMax);
|
||||||
|
lowestPoint = std::min(lowestPoint, static_cast<float>(aabbMin.z()));
|
||||||
|
}
|
||||||
|
|
||||||
const DetourNavigator::ObjectTransform objectTransform{ ptr.getRefData().getPosition(),
|
const DetourNavigator::ObjectTransform objectTransform{ ptr.getRefData().getPosition(),
|
||||||
ptr.getCellRef().getScale() };
|
ptr.getCellRef().getScale() };
|
||||||
|
|
||||||
|
@ -526,6 +540,7 @@ namespace MWWorld
|
||||||
navigatorUpdateGuard.reset();
|
navigatorUpdateGuard.reset();
|
||||||
assert(mActiveCells.empty());
|
assert(mActiveCells.empty());
|
||||||
mCurrentCell = nullptr;
|
mCurrentCell = nullptr;
|
||||||
|
mLowestPoint = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
mPreloader->clear();
|
mPreloader->clear();
|
||||||
}
|
}
|
||||||
|
@ -556,12 +571,28 @@ namespace MWWorld
|
||||||
|
|
||||||
void Scene::playerMoved(const osg::Vec3f& pos)
|
void Scene::playerMoved(const osg::Vec3f& pos)
|
||||||
{
|
{
|
||||||
if (!mCurrentCell || !mCurrentCell->isExterior())
|
if (!mCurrentCell)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter);
|
// The player is reset when z is 90 units below the lowest reference bound z.
|
||||||
if (newCell != mCurrentGridCenter)
|
constexpr float lowestPointAdjustment = -90.0f;
|
||||||
requestChangeCellGrid(pos, newCell);
|
if (mCurrentCell->isExterior())
|
||||||
|
{
|
||||||
|
osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter);
|
||||||
|
if (newCell != mCurrentGridCenter)
|
||||||
|
requestChangeCellGrid(pos, newCell);
|
||||||
|
}
|
||||||
|
else if (pos.z() < mLowestPoint + lowestPointAdjustment)
|
||||||
|
{
|
||||||
|
// Player has fallen into the void, reset to interior marker/coc (#1415)
|
||||||
|
const std::string_view cellNameId = mCurrentCell->getCell()->getNameId();
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
MWWorld::Ptr playerPtr = world->getPlayerPtr();
|
||||||
|
|
||||||
|
ESM::Position newPos;
|
||||||
|
const ESM::RefId refId = MWBase::Environment::get().getWorld()->findInteriorPosition(cellNameId, newPos);
|
||||||
|
MWWorld::ActionTeleport(refId, newPos, false).execute(playerPtr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent)
|
void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent)
|
||||||
|
@ -840,6 +871,7 @@ namespace MWWorld
|
||||||
, mPreloadDoors(Settings::cells().mPreloadDoors)
|
, mPreloadDoors(Settings::cells().mPreloadDoors)
|
||||||
, mPreloadFastTravel(Settings::cells().mPreloadFastTravel)
|
, mPreloadFastTravel(Settings::cells().mPreloadFastTravel)
|
||||||
, mPredictionTime(Settings::cells().mPredictionTime)
|
, mPredictionTime(Settings::cells().mPredictionTime)
|
||||||
|
, mLowestPoint(std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
mPreloader = std::make_unique<CellPreloader>(rendering.getResourceSystem(), physics->getShapeManager(),
|
mPreloader = std::make_unique<CellPreloader>(rendering.getResourceSystem(), physics->getShapeManager(),
|
||||||
rendering.getTerrain(), rendering.getLandManager());
|
rendering.getTerrain(), rendering.getLandManager());
|
||||||
|
@ -970,20 +1002,23 @@ namespace MWWorld
|
||||||
void Scene::insertCell(
|
void Scene::insertCell(
|
||||||
CellStore& cell, Loading::Listener* loadingListener, const DetourNavigator::UpdateGuard* navigatorUpdateGuard)
|
CellStore& cell, Loading::Listener* loadingListener, const DetourNavigator::UpdateGuard* navigatorUpdateGuard)
|
||||||
{
|
{
|
||||||
|
const bool isInterior = !cell.isExterior();
|
||||||
InsertVisitor insertVisitor(cell, loadingListener);
|
InsertVisitor insertVisitor(cell, loadingListener);
|
||||||
cell.forEach(insertVisitor);
|
cell.forEach(insertVisitor);
|
||||||
insertVisitor.insert(
|
insertVisitor.insert(
|
||||||
[&](const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering); });
|
[&](const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering); });
|
||||||
insertVisitor.insert(
|
insertVisitor.insert([&](const MWWorld::Ptr& ptr) {
|
||||||
[&](const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, *mPhysics, mNavigator, navigatorUpdateGuard); });
|
addObject(ptr, mWorld, *mPhysics, mLowestPoint, isInterior, mNavigator, navigatorUpdateGuard);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::addObjectToScene(const Ptr& ptr)
|
void Scene::addObjectToScene(const Ptr& ptr)
|
||||||
{
|
{
|
||||||
|
const bool isInterior = mCurrentCell && !mCurrentCell->isExterior();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering);
|
addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering);
|
||||||
addObject(ptr, mWorld, *mPhysics, mNavigator);
|
addObject(ptr, mWorld, *mPhysics, mLowestPoint, isInterior, mNavigator);
|
||||||
mWorld.scaleObject(ptr, ptr.getCellRef().getScale());
|
mWorld.scaleObject(ptr, ptr.getCellRef().getScale());
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
|
|
@ -101,6 +101,7 @@ namespace MWWorld
|
||||||
bool mPreloadDoors;
|
bool mPreloadDoors;
|
||||||
bool mPreloadFastTravel;
|
bool mPreloadFastTravel;
|
||||||
float mPredictionTime;
|
float mPredictionTime;
|
||||||
|
float mLowestPoint;
|
||||||
|
|
||||||
int mHalfGridSize = Constants::CellGridRadius;
|
int mHalfGridSize = Constants::CellGridRadius;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue