1
0
Fork 0
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:
florent.teppe 2023-04-24 21:20:07 +02:00
parent eb48f8724f
commit d8a782425b
12 changed files with 40 additions and 25 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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());

View file

@ -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;

View file

@ -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)

View file

@ -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&)
{ {

View file

@ -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)) };
} }
} }

View file

@ -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());

View file

@ -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;

View file

@ -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;

View file

@ -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;