mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-01 10:09:48 +00:00
can actually load and teleport to esm4 exterior spaces
This commit is contained in:
parent
eb48f8724f
commit
d8a782425b
12 changed files with 40 additions and 25 deletions
|
@ -316,7 +316,8 @@ namespace MWBase
|
||||||
/// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is
|
/// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is
|
||||||
/// obstructed).
|
/// obstructed).
|
||||||
|
|
||||||
virtual void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const = 0;
|
virtual void indexToPosition(
|
||||||
|
int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const = 0;
|
||||||
///< Convert cell numbers to position.
|
///< Convert cell numbers to position.
|
||||||
|
|
||||||
virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0;
|
virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0;
|
||||||
|
|
|
@ -483,8 +483,10 @@ namespace MWPhysics
|
||||||
mHeightFields.erase(heightfield);
|
mHeightFields.erase(heightfield);
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeightField* PhysicsSystem::getHeightField(int x, int y) const
|
const HeightField* PhysicsSystem::getHeightField(int x, int y, ESM::RefId worldspace) const
|
||||||
{
|
{
|
||||||
|
if (worldspace != ESM::Cell::sDefaultWorldspaceId)
|
||||||
|
return nullptr;
|
||||||
const auto heightField = mHeightFields.find(std::make_pair(x, y));
|
const auto heightField = mHeightFields.find(std::make_pair(x, y));
|
||||||
if (heightField == mHeightFields.end())
|
if (heightField == mHeightFields.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -189,7 +189,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
void removeHeightField(int x, int y);
|
void removeHeightField(int x, int y);
|
||||||
|
|
||||||
const HeightField* getHeightField(int x, int y) const;
|
const HeightField* getHeightField(int x, int y, ESM::RefId worldspace) const;
|
||||||
|
|
||||||
bool toggleCollisionMode();
|
bool toggleCollisionMode();
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,11 @@ namespace MWRender
|
||||||
mCache = new CacheType;
|
mCache = new CacheType;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<ESMTerrain::LandObject> LandManager::getLand(int x, int y)
|
osg::ref_ptr<ESMTerrain::LandObject> LandManager::getLand(int x, int y, ESM::RefId worldspace)
|
||||||
{
|
{
|
||||||
|
if (worldspace != ESM::Cell::sDefaultWorldspaceId)
|
||||||
|
return osg::ref_ptr<ESMTerrain::LandObject>(nullptr);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(std::make_pair(x, y));
|
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(std::make_pair(x, y));
|
||||||
if (obj)
|
if (obj)
|
||||||
return static_cast<ESMTerrain::LandObject*>(obj.get());
|
return static_cast<ESMTerrain::LandObject*>(obj.get());
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace MWRender
|
||||||
LandManager(int loadFlags);
|
LandManager(int loadFlags);
|
||||||
|
|
||||||
/// @note Will return nullptr if not found.
|
/// @note Will return nullptr if not found.
|
||||||
osg::ref_ptr<ESMTerrain::LandObject> getLand(int x, int y);
|
osg::ref_ptr<ESMTerrain::LandObject> getLand(int x, int y, ESM::RefId worldspace);
|
||||||
|
|
||||||
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace MWRender
|
||||||
|
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
|
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
|
||||||
{
|
{
|
||||||
return mLandManager->getLand(cellX, cellY);
|
return mLandManager->getLand(cellX, cellY, ESM::Cell::sDefaultWorldspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace MWWorld
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mTerrain->cacheCell(mTerrainView.get(), mX, mY);
|
mTerrain->cacheCell(mTerrainView.get(), mX, mY);
|
||||||
mPreloadedObjects.insert(mLandManager->getLand(mX, mY));
|
mPreloadedObjects.insert(mLandManager->getLand(mX, mY, ESM::Cell::sDefaultWorldspaceId));
|
||||||
}
|
}
|
||||||
catch (std::exception&)
|
catch (std::exception&)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
inline osg::Vec2i positionToCellIndex(float x, float y)
|
inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false)
|
||||||
{
|
{
|
||||||
return { static_cast<int>(std::floor(x / Constants::CellSizeInUnits)),
|
const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits;
|
||||||
static_cast<int>(std::floor(y / Constants::CellSizeInUnits)) };
|
return { static_cast<int>(std::floor(x / cellSize)), static_cast<int>(std::floor(y / cellSize)) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <components/detournavigator/navigator.hpp>
|
#include <components/detournavigator/navigator.hpp>
|
||||||
#include <components/detournavigator/updateguard.hpp>
|
#include <components/detournavigator/updateguard.hpp>
|
||||||
#include <components/esm/records.hpp>
|
#include <components/esm/records.hpp>
|
||||||
|
#include <components/esm3/loadcell.hpp>
|
||||||
#include <components/loadinglistener/loadinglistener.hpp>
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
#include <components/misc/convert.hpp>
|
#include <components/misc/convert.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
@ -247,12 +248,13 @@ namespace
|
||||||
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection)
|
bool isCellInCollection(int x, int y, ESM::RefId worldspace, MWWorld::Scene::CellStoreCollection& collection)
|
||||||
{
|
{
|
||||||
for (auto* cell : collection)
|
for (auto* cell : collection)
|
||||||
{
|
{
|
||||||
assert(cell->getCell()->isExterior());
|
assert(cell->getCell()->isExterior());
|
||||||
if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY())
|
if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY()
|
||||||
|
&& cell->getCell()->getWorldSpace() == worldspace)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -346,7 +348,7 @@ namespace MWWorld
|
||||||
|
|
||||||
if (cell->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
if (mPhysics->getHeightField(cellX, cellY) != nullptr)
|
if (mPhysics->getHeightField(cellX, cellY, cell->getCell()->getWorldSpace()) != nullptr)
|
||||||
mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard);
|
mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard);
|
||||||
|
|
||||||
mPhysics->removeHeightField(cellX, cellY);
|
mPhysics->removeHeightField(cellX, cellY);
|
||||||
|
@ -391,10 +393,12 @@ namespace MWWorld
|
||||||
const int cellX = cell.getCell()->getGridX();
|
const int cellX = cell.getCell()->getGridX();
|
||||||
const int cellY = cell.getCell()->getGridY();
|
const int cellY = cell.getCell()->getGridY();
|
||||||
const MWWorld::Cell& cellVariant = *cell.getCell();
|
const MWWorld::Cell& cellVariant = *cell.getCell();
|
||||||
|
ESM::RefId worldspace = cellVariant.getWorldSpace();
|
||||||
|
|
||||||
if (cellVariant.isExterior())
|
if (cellVariant.isExterior())
|
||||||
{
|
{
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
osg::ref_ptr<const ESMTerrain::LandObject> land
|
||||||
|
= mRendering.getLandManager()->getLand(cellX, cellY, worldspace);
|
||||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||||
const int verts = ESM::Land::LAND_SIZE;
|
const int verts = ESM::Land::LAND_SIZE;
|
||||||
const int worldsize = ESM::Land::REAL_SIZE;
|
const int worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
@ -410,7 +414,7 @@ namespace MWWorld
|
||||||
mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts,
|
mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts,
|
||||||
ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||||
}
|
}
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace))
|
||||||
{
|
{
|
||||||
const osg::Vec2i cellPosition(cellX, cellY);
|
const osg::Vec2i cellPosition(cellX, cellY);
|
||||||
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
||||||
|
@ -465,7 +469,7 @@ namespace MWWorld
|
||||||
|
|
||||||
if (cellVariant.isExterior())
|
if (cellVariant.isExterior())
|
||||||
{
|
{
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace))
|
||||||
mNavigator.addWater(
|
mNavigator.addWater(
|
||||||
osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard);
|
osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard);
|
||||||
}
|
}
|
||||||
|
@ -507,17 +511,18 @@ namespace MWWorld
|
||||||
|
|
||||||
osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const
|
osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const
|
||||||
{
|
{
|
||||||
|
bool isEsm4Ext = mCurrentCell && mCurrentCell->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId;
|
||||||
if (currentGridCenter)
|
if (currentGridCenter)
|
||||||
{
|
{
|
||||||
float centerX, centerY;
|
float centerX, centerY;
|
||||||
mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true);
|
mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext);
|
||||||
float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y()));
|
float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y()));
|
||||||
const float maxDistance
|
const float maxDistance
|
||||||
= Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold
|
= Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold
|
||||||
if (distance <= maxDistance)
|
if (distance <= maxDistance)
|
||||||
return *currentGridCenter;
|
return *currentGridCenter;
|
||||||
}
|
}
|
||||||
return positionToCellIndex(pos.x(), pos.y());
|
return positionToCellIndex(pos.x(), pos.y(), isEsm4Ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::playerMoved(const osg::Vec3f& pos)
|
void Scene::playerMoved(const osg::Vec3f& pos)
|
||||||
|
@ -532,7 +537,8 @@ namespace MWWorld
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
mChangeCellGridRequest = ChangeCellGridRequest{ position, cell, ESM::Cell::sDefaultWorldspaceId, changeEvent };
|
mChangeCellGridRequest
|
||||||
|
= ChangeCellGridRequest{ position, cell, mCurrentCell->getCell()->getWorldSpace(), changeEvent };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::changeCellGrid(
|
void Scene::changeCellGrid(
|
||||||
|
@ -580,7 +586,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
for (int y = playerCellY - range; y <= playerCellY + range; ++y)
|
for (int y = playerCellY - range; y <= playerCellY + range; ++y)
|
||||||
{
|
{
|
||||||
if (!isCellInCollection(x, y, collection))
|
if (!isCellInCollection(x, y, exteriorWorldspace, collection))
|
||||||
{
|
{
|
||||||
refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count();
|
refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count();
|
||||||
cellsPositionsToLoad.emplace_back(x, y);
|
cellsPositionsToLoad.emplace_back(x, y);
|
||||||
|
@ -614,7 +620,7 @@ namespace MWWorld
|
||||||
|
|
||||||
for (const auto& [x, y] : cellsPositionsToLoad)
|
for (const auto& [x, y] : cellsPositionsToLoad)
|
||||||
{
|
{
|
||||||
if (!isCellInCollection(x, y, mActiveCells))
|
if (!isCellInCollection(x, y, exteriorWorldspace, mActiveCells))
|
||||||
{
|
{
|
||||||
CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace);
|
CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace);
|
||||||
loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get());
|
loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get());
|
||||||
|
|
|
@ -1512,9 +1512,9 @@ namespace MWWorld
|
||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre) const
|
void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const
|
||||||
{
|
{
|
||||||
const int cellSize = Constants::CellSizeInUnits;
|
const int cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits;
|
||||||
|
|
||||||
x = static_cast<float>(cellSize * cellX);
|
x = static_cast<float>(cellSize * cellX);
|
||||||
y = static_cast<float>(cellSize * cellY);
|
y = static_cast<float>(cellSize * cellY);
|
||||||
|
@ -2766,7 +2766,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
int x = ext->getGridX();
|
int x = ext->getGridX();
|
||||||
int y = ext->getGridY();
|
int y = ext->getGridY();
|
||||||
indexToPosition(x, y, pos.pos[0], pos.pos[1], true);
|
bool esm4Ext = ext->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId;
|
||||||
|
indexToPosition(x, y, pos.pos[0], pos.pos[1], true, esm4Ext);
|
||||||
|
|
||||||
// Note: Z pos will be adjusted by adjustPosition later
|
// Note: Z pos will be adjusted by adjustPosition later
|
||||||
pos.pos[2] = 0;
|
pos.pos[2] = 0;
|
||||||
|
|
|
@ -403,7 +403,8 @@ namespace MWWorld
|
||||||
|
|
||||||
float getMaxActivationDistance() const override;
|
float getMaxActivationDistance() const override;
|
||||||
|
|
||||||
void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const override;
|
void indexToPosition(
|
||||||
|
int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const override;
|
||||||
///< Convert cell numbers to position.
|
///< Convert cell numbers to position.
|
||||||
|
|
||||||
void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override;
|
void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override;
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Constants
|
||||||
|
|
||||||
// Size of one exterior cell in game units
|
// Size of one exterior cell in game units
|
||||||
constexpr int CellSizeInUnits = 8192;
|
constexpr int CellSizeInUnits = 8192;
|
||||||
|
constexpr int ESM4CellSizeInUnits = 4096;
|
||||||
|
|
||||||
// Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side)
|
// Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side)
|
||||||
constexpr int CellGridRadius = 1;
|
constexpr int CellGridRadius = 1;
|
||||||
|
|
Loading…
Reference in a new issue