1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-24 18:39:59 +00:00

Better handling of the esm3 vs esm4 cell problem

Common attribute are in one structure that has two constructors, one for ESM3 vs ESM4 Cell
Mood part of MWWorld::Cell
This commit is contained in:
florent.teppe 2023-01-27 01:13:17 +01:00
parent 6d25d4bc13
commit 531e55e04c
31 changed files with 268 additions and 194 deletions

View File

@ -78,7 +78,7 @@ add_openmw_dir (mwworld
actionequip timestamp actionalchemy cellstore actionapply actioneat actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
cellpreloader datetimemanager groundcoverstore magiceffects cellpreloader datetimemanager groundcoverstore magiceffects cell
) )
add_openmw_dir (mwphysics add_openmw_dir (mwphysics

View File

@ -94,6 +94,7 @@ namespace MWWorld
class TimeStamp; class TimeStamp;
class ESMStore; class ESMStore;
class RefData; class RefData;
struct Cell;
typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList; typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList;
} }
@ -181,7 +182,7 @@ namespace MWBase
/// ///
/// \note If cell==0, the cell the player is currently in will be used instead to /// \note If cell==0, the cell the player is currently in will be used instead to
/// generate a name. /// generate a name.
virtual std::string_view getCellName(const ESM::CellVariant& cell) const = 0; virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0;
virtual void removeRefScript(MWWorld::RefData* ref) = 0; virtual void removeRefScript(MWWorld::RefData* ref) = 0;
//< Remove the script attached to ref from mLocalScripts //< Remove the script attached to ref from mLocalScripts

View File

@ -307,7 +307,7 @@ namespace MWClass
const osg::Vec2i index const osg::Vec2i index
= MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]); = MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]);
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(index.x(), index.y()); const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(index.x(), index.y());
dest = world->getCellName(ESM::CellVariant(cell)); dest = world->getCellName(MWWorld::Cell(cell));
} }
return "#{sCell=" + std::string{ dest } + "}"; return "#{sCell=" + std::string{ dest } + "}";

View File

@ -954,7 +954,7 @@ namespace MWGui
mMap->setCellName(name); mMap->setCellName(name);
mHud->setCellName(name); mHud->setCellName(name);
auto cellCommon = cell->getCellVariant().getCommon(); auto cellCommon = cell->getCell();
if (cellCommon->isExterior()) if (cellCommon->isExterior())
{ {

View File

@ -176,7 +176,7 @@ namespace MWLua
// TODO: change AiEscort implementation to accept ptr instead of a non-unique refId. // TODO: change AiEscort implementation to accept ptr instead of a non-unique refId.
const ESM::RefId& refId = target.ptr().getCellRef().getRefId(); const ESM::RefId& refId = target.ptr().getCellRef().getRefId();
int gameHoursDuration = static_cast<int>(std::ceil(duration / 3600.0)); int gameHoursDuration = static_cast<int>(std::ceil(duration / 3600.0));
const ESM::CellCommon* esmCell = cell.mStore->getCell(); auto* esmCell = cell.mStore->getCell();
if (esmCell->isExterior()) if (esmCell->isExterior())
ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
else else

View File

@ -357,13 +357,13 @@ namespace MWMechanics
case AiCombatStorage::FleeState_Idle: case AiCombatStorage::FleeState_Idle:
{ {
float triggerDist = getMaxAttackDistance(target); float triggerDist = getMaxAttackDistance(target);
auto cellVariant = storage.mCell->getCellVariant(); auto cellVariant = storage.mCell->getCell();
if (!cellVariant.isEsm4() && storage.mLOS if (!cellVariant->isEsm4() && storage.mLOS
&& (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
{ {
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search( = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(
cellVariant.getEsm3()); cellVariant->getEsm3());
bool runFallback = true; bool runFallback = true;
@ -371,7 +371,7 @@ namespace MWMechanics
&& !actor.getClass().isPureWaterCreature(actor)) && !actor.getClass().isPureWaterCreature(actor))
{ {
ESM::Pathgrid::PointList points; ESM::Pathgrid::PointList points;
Misc::CoordinateConverter coords(storage.mCell->getCell()); Misc::CoordinateConverter coords(*storage.mCell->getCell());
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3(); osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
coords.toLocal(localPos); coords.toLocal(localPos);

View File

@ -411,11 +411,14 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const
bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position)
{ {
const ESM::Cell* playerCell(&getPlayer().getCell()->getCellVariant().getEsm3()); if (getPlayer().getCell()->getCell()->isEsm4())
return false;
const ESM::Cell* playerCell(&getPlayer().getCell()->getCell()->getEsm3());
if (playerCell->isExterior()) if (playerCell->isExterior())
{ {
// get actor's distance from origin of center cell // get actor's distance from origin of center cell
Misc::CoordinateConverter(playerCell).toLocal(position); Misc::CoordinateConverter(ESM::CellVariant(playerCell)).toLocal(position);
// currently assumes 3 x 3 grid for exterior cells, with player at center cell. // currently assumes 3 x 3 grid for exterior cells, with player at center cell.
// AI shuts down actors before they reach edges of 3 x 3 grid. // AI shuts down actors before they reach edges of 3 x 3 grid.

View File

@ -271,9 +271,9 @@ namespace MWMechanics
} }
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed node points for this actor.
if (!actor.getCell()->getCellVariant().isEsm4() && storage.mPopulateAvailableNodes) if (!actor.getCell()->getCell()->isEsm4() && storage.mPopulateAvailableNodes)
{ {
getAllowedNodes(actor, &actor.getCell()->getCellVariant().getEsm3(), storage); getAllowedNodes(actor, &actor.getCell()->getCell()->getEsm3(), storage);
} }
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
@ -721,8 +721,8 @@ namespace MWMechanics
return; return;
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
if (!actor.getCell()->getCellVariant().isEsm4() && storage.mPopulateAvailableNodes) if (!actor.getCell()->getCell()->isEsm4() && storage.mPopulateAvailableNodes)
getAllowedNodes(actor, &actor.getCell()->getCellVariant().getEsm3(), storage); getAllowedNodes(actor, &actor.getCell()->getCell()->getEsm3(), storage);
if (storage.mAllowedNodes.empty()) if (storage.mAllowedNodes.empty())
return; return;
@ -730,7 +730,7 @@ namespace MWMechanics
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng); int index = Misc::Rng::rollDice(storage.mAllowedNodes.size(), prng);
ESM::Pathgrid::Point worldDest = storage.mAllowedNodes[index]; ESM::Pathgrid::Point worldDest = storage.mAllowedNodes[index];
auto converter = Misc::CoordinateConverter(actor.getCell()->getCell()); auto converter = Misc::CoordinateConverter(*actor.getCell()->getCell());
ESM::Pathgrid::Point dest = converter.toLocalPoint(worldDest); ESM::Pathgrid::Point dest = converter.toLocalPoint(worldDest);
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange( bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(
@ -800,9 +800,9 @@ namespace MWMechanics
void AiWander::getNeighbouringNodes( void AiWander::getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
{ {
if (currentCell->getCellVariant().isEsm4()) if (currentCell->getCell()->isEsm4())
return; return;
auto cell3 = currentCell->getCellVariant().getEsm3(); auto cell3 = currentCell->getCell()->getEsm3();
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(cell3); = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(cell3);
@ -839,7 +839,7 @@ namespace MWMechanics
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor)) if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
{ {
// get NPC's position in local (i.e. cell) coordinates // get NPC's position in local (i.e. cell) coordinates
auto converter = Misc::CoordinateConverter(cell); auto converter = Misc::CoordinateConverter(ESM::CellVariant(cell));
const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition);
// Find closest pathgrid point // Find closest pathgrid point

View File

@ -196,7 +196,7 @@ namespace MWMechanics
return; return;
// NOTE: getClosestPoint expects local coordinates // NOTE: getClosestPoint expects local coordinates
Misc::CoordinateConverter converter(mCell->getCell()); Misc::CoordinateConverter converter(*mCell->getCell());
// NOTE: It is possible that getClosestPoint returns a pathgrind point index // NOTE: It is possible that getClosestPoint returns a pathgrind point index
// that is unreachable in some situations. e.g. actor is standing // that is unreachable in some situations. e.g. actor is standing

View File

@ -98,13 +98,13 @@ namespace MWMechanics
*/ */
bool PathgridGraph::load(const MWWorld::CellStore* cell) bool PathgridGraph::load(const MWWorld::CellStore* cell)
{ {
if (!cell || !cell->getCellVariant().isValid()) if (!cell)
return false; return false;
if (mIsGraphConstructed) if (mIsGraphConstructed)
return true; return true;
mCell = cell->getCellVariant().isEsm4() ? nullptr : &cell->getCellVariant().getEsm3(); mCell = cell->getCell()->isEsm4() ? nullptr : &cell->getCell()->getEsm3();
if (!mCell) if (!mCell)
return false; return false;
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell); mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell);

View File

@ -9,6 +9,8 @@
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <apps/openmw/mwworld/cell.hpp>
namespace namespace
{ {
float DLLandFogStart; float DLLandFogStart;
@ -40,12 +42,11 @@ namespace MWRender
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog"); DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
} }
void FogManager::configure(float viewDistance, const ESM::CellVariant& cell) void FogManager::configure(float viewDistance, const MWWorld::Cell& cell)
{ {
osg::Vec4f color osg::Vec4f color = SceneUtil::colourFromRGB(cell.getMood().mFogColor);
= SceneUtil::colourFromRGB(cell.isEsm4() ? cell.getEsm4().mLighting.fogColor : cell.getEsm3().mAmbi.mFog);
const float fogDensity = !cell.isEsm4() ? cell.getEsm3().mAmbi.mFogDensity : cell.getEsm4().mLighting.fogPower; const float fogDensity = cell.getMood().mFogDensity;
if (mDistantFog) if (mDistantFog)
{ {
float density = std::max(0.2f, fogDensity); float density = std::max(0.2f, fogDensity);

View File

@ -3,9 +3,9 @@
#include <osg/Vec4f> #include <osg/Vec4f>
namespace ESM namespace MWWorld
{ {
struct CellVariant; struct Cell;
} }
namespace MWRender namespace MWRender
@ -15,7 +15,7 @@ namespace MWRender
public: public:
FogManager(); FogManager();
void configure(float viewDistance, const ESM::CellVariant& cell); void configure(float viewDistance, const MWWorld::Cell& cell);
void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset,
const osg::Vec4f& color); const osg::Vec4f& color);

View File

@ -102,15 +102,14 @@ namespace MWRender
void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store)
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
if (store->getCellVariant().isEsm4()) if (store->getCell()->isEsm4())
return; return;
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(store->getCell()->getEsm3());
= world->getStore().get<ESM::Pathgrid>().search(store->getCellVariant().getEsm3());
if (!pathgrid) if (!pathgrid)
return; return;
osg::Vec3f cellPathGridPos(0, 0, 0); osg::Vec3f cellPathGridPos(0, 0, 0);
Misc::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos); Misc::CoordinateConverter(*store->getCell()).toWorld(cellPathGridPos);
osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform; osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform;
cellPathGrid->setPosition(cellPathGridPos); cellPathGrid->setPosition(cellPathGridPos);

View File

@ -740,15 +740,14 @@ namespace MWRender
mSky->setMoonColour(red); mSky->setMoonColour(red);
} }
void RenderingManager::configureAmbient(const ESM::CellVariant& cell) void RenderingManager::configureAmbient(const MWWorld::Cell& cell)
{ {
bool isInterior = !cell.getCommon()->isExterior() && !cell.getCommon()->isQuasiExterior(); bool isInterior = !cell.isExterior() && !cell.isQuasiExterior();
bool needsAdjusting = false; bool needsAdjusting = false;
if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP) if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP)
needsAdjusting = isInterior; needsAdjusting = isInterior;
osg::Vec4f ambient = SceneUtil::colourFromRGB( osg::Vec4f ambient = SceneUtil::colourFromRGB(cell.getMood().mAmbiantColor);
cell.isEsm4() ? cell.getEsm4().mLighting.ambient : cell.getEsm3().mAmbi.mAmbient);
if (needsAdjusting) if (needsAdjusting)
{ {
@ -772,8 +771,7 @@ namespace MWRender
setAmbientColour(ambient); setAmbientColour(ambient);
osg::Vec4f diffuse = SceneUtil::colourFromRGB( osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell.getMood().mDirectionalColor);
!cell.isEsm4() ? cell.getEsm3().mAmbi.mSunlight : cell.getEsm4().mLighting.directional);
setSunColour(diffuse, diffuse, 1.f); setSunColour(diffuse, diffuse, 1.f);
@ -894,7 +892,7 @@ namespace MWRender
return false; return false;
} }
void RenderingManager::configureFog(const ESM::CellVariant& cell) void RenderingManager::configureFog(const MWWorld::Cell& cell)
{ {
mFog->configure(mViewDistance, cell); mFog->configure(mViewDistance, cell);
} }
@ -1428,7 +1426,7 @@ namespace MWRender
mMinimumAmbientLuminance mMinimumAmbientLuminance
= std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
if (MWMechanics::getPlayer().isInCell()) if (MWMechanics::getPlayer().isInCell())
configureAmbient(MWMechanics::getPlayer().getCell()->getCellVariant()); configureAmbient(*MWMechanics::getPlayer().getCell()->getCell());
} }
else if (it->first == "Shaders" else if (it->first == "Shaders"
&& (it->second == "light bounds multiplier" || it->second == "maximum light distance" && (it->second == "light bounds multiplier" || it->second == "maximum light distance"

View File

@ -74,6 +74,7 @@ namespace DetourNavigator
namespace MWWorld namespace MWWorld
{ {
class GroundcoverStore; class GroundcoverStore;
struct Cell;
} }
namespace Debug namespace Debug
@ -141,8 +142,8 @@ namespace MWRender
void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis); void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis);
void setNight(bool isNight) { mNight = isNight; } void setNight(bool isNight) { mNight = isNight; }
void configureAmbient(const ESM::CellVariant& cell); void configureAmbient(const MWWorld::Cell& cell);
void configureFog(const ESM::CellVariant& cell); void configureFog(const MWWorld::Cell& cell);
void configureFog( void configureFog(
float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour); float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour);

View File

@ -781,10 +781,10 @@ namespace MWSound
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::ConstPtr player = world->getPlayerPtr(); const MWWorld::ConstPtr player = world->getPlayerPtr();
if (player.getCell()->getCellVariant().isEsm4()) if (player.getCell()->getCell()->isEsm4())
return; return;
const ESM::Cell* curcell = &player.getCell()->getCellVariant().getEsm3(); const ESM::Cell* curcell = &player.getCell()->getCell()->getEsm3();
const auto update = mWaterSoundUpdater.update(player, *world); const auto update = mWaterSoundUpdater.update(player, *world);
WaterSoundAction action; WaterSoundAction action;

View File

@ -0,0 +1,66 @@
#include "cell.hpp"
#include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/misc/algorithm.hpp>
namespace MWWorld
{
Cell::Cell(const ESM4::Cell* cell)
: ESM::CellVariant(cell)
{
assert(cell != nullptr);
mNameID = cell->mEditorId;
mDisplayname = cell->mFullName;
mGridPos.x() = cell->mX;
mGridPos.y() = cell->mY;
mRegion = ESM::RefId::sEmpty; // Unimplemented for now
mFlags.hasWater = (cell->mCellFlags & ESM4::CELL_HasWater) != 0;
mFlags.isExterior = !(cell->mCellFlags & ESM4::CELL_Interior);
mFlags.isQuasiExterior = (cell->mCellFlags & ESM4::CELL_QuasiExt) != 0;
mFlags.noSleep = false; // No such notion in ESM4
mCellId.mWorldspace = Misc::StringUtils::lowerCase(cell->mEditorId);
mCellId.mWorld = ESM::RefId::sEmpty;
mCellId.mIndex.mX = cell->getGridX();
mCellId.mIndex.mX = cell->getGridY();
mCellId.mPaged = isExterior();
mMood.mAmbiantColor = cell->mLighting.ambient;
mMood.mFogColor = cell->mLighting.fogColor;
mMood.mDirectionalColor = cell->mLighting.directional;
mMood.mFogDensity = cell->mLighting.fogPower;
}
Cell::Cell(const ESM::Cell* cell)
: ESM::CellVariant(cell)
{
assert(cell != nullptr);
mNameID = cell->mName;
mDisplayname = cell->mName;
mGridPos.x() = cell->getGridX();
mGridPos.y() = cell->getGridY();
mRegion = ESM::RefId::sEmpty; // Unimplemented for now
mFlags.hasWater = (cell->mData.mFlags & ESM::Cell::HasWater) != 0;
mFlags.isExterior = !(cell->mData.mFlags & ESM::Cell::Interior);
mFlags.isQuasiExterior = (cell->mData.mFlags & ESM::Cell::QuasiEx) != 0;
mFlags.noSleep = (cell->mData.mFlags & ESM::Cell::NoSleep) != 0;
mCellId = cell->getCellId();
mMood.mAmbiantColor = cell->mAmbi.mAmbient;
mMood.mFogColor = cell->mAmbi.mFog;
mMood.mDirectionalColor = cell->mAmbi.mSunlight;
mMood.mFogDensity = cell->mAmbi.mFogDensity;
}
std::string Cell::getDescription() const
{
return isEsm4() ? mNameID : getEsm3().getDescription();
}
}

View File

@ -0,0 +1,67 @@
#ifndef OPENW_MWORLD_CELL
#define OPENW_MWORLD_CELL
#include <components/esm/esm3esm4bridge.hpp>
#include <components/esm/refid.hpp>
#include <components/esm3/cellid.hpp>
namespace ESM
{
struct Cell;
struct CellId;
}
namespace ESM4
{
struct Cell;
}
namespace MWWorld
{
struct Cell : public ESM::CellVariant
{
struct MoodData
{
uint32_t mAmbiantColor;
uint32_t mDirectionalColor;
uint32_t mFogColor;
float mFogDensity;
};
public:
explicit Cell(const ESM4::Cell* cell);
explicit Cell(const ESM::Cell* cell);
int getGridX() const { return mGridPos.x(); }
int getGridY() const { return mGridPos.y(); }
bool isExterior() const { return mFlags.isExterior; }
bool isQuasiExterior() const { return mFlags.isQuasiExterior; }
bool hasWater() const { return mFlags.hasWater; }
bool noSleep() const { return mFlags.noSleep; }
const ESM::CellId& getCellId() const { return mCellId; };
const ESM::RefId& getRegion() const { return mRegion; }
std::string_view getEditorName() const { return mNameID; }
std::string getDescription() const;
const MoodData& getMood() const { return mMood; }
private:
struct
{
uint8_t isExterior : 1;
uint8_t isQuasiExterior : 1;
uint8_t hasWater : 1;
uint8_t noSleep : 1;
uint8_t _free : 4;
} mFlags;
osg::Vec2i mGridPos;
std::string mDisplayname; // How the game displays it
std::string mNameID; // The name that will be used by the script and console commands
ESM::RefId mRegion;
ESM::CellId mCellId;
MoodData mMood;
};
}
#endif

View File

@ -536,10 +536,10 @@ namespace MWWorld
return false; return false;
} }
CellStore::CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) CellStore::CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
: mStore(esmStore) : mStore(esmStore)
, mReaders(readers) , mReaders(readers)
, mCellVariant(cell) , mCellVariant(std::move(cell))
, mState(State_Unloaded) , mState(State_Unloaded)
, mHasState(false) , mHasState(false)
, mLastRespawn(0, 0) , mLastRespawn(0, 0)
@ -547,36 +547,17 @@ namespace MWWorld
, mRechargingItemsUpToDate(false) , mRechargingItemsUpToDate(false)
{ {
mCell = mCellVariant.isEsm4() ? nullptr : &mCellVariant.getEsm3();
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
if (mCell) if (!mCellVariant.isEsm4())
mWaterLevel = mCell->mWater; mWaterLevel = mCellVariant.getEsm3().mWater;
} }
CellStore::~CellStore() = default; CellStore::~CellStore() = default;
CellStore::CellStore(CellStore&&) = default; CellStore::CellStore(CellStore&&) = default;
const ESM::CellCommon* CellStore::getCell() const const MWWorld::Cell* CellStore::getCell() const
{ {
return mCellVariant.getCommon(); return &mCellVariant;
}
ESM::CellVariant CellStore::getCellVariant() const
{
return mCellVariant;
}
std::string_view CellStore::getEditorName() const
{
if (mCellVariant.isEsm4())
{
return mCellVariant.getEsm4().mEditorId;
}
else
{
return mCellVariant.getEsm3().mName;
}
} }
CellStore::State CellStore::getState() const CellStore::State CellStore::getState() const
@ -732,20 +713,24 @@ namespace MWWorld
void CellStore::listRefs() void CellStore::listRefs()
{ {
assert(mCell);
if (mCell->mContextList.empty()) if (mCellVariant.isEsm4())
return;
auto cell3 = mCellVariant.getEsm3();
if (cell3.mContextList.empty())
return; // this is a dynamically generated cell -> skipping. return; // this is a dynamically generated cell -> skipping.
// Load references from all plugins that do something with this cell. // Load references from all plugins that do something with this cell.
for (size_t i = 0; i < mCell->mContextList.size(); i++) for (size_t i = 0; i < cell3.mContextList.size(); i++)
{ {
try try
{ {
// Reopen the ESM reader and seek to the right position. // Reopen the ESM reader and seek to the right position.
const std::size_t index = static_cast<std::size_t>(mCell->mContextList[i].index); const std::size_t index = static_cast<std::size_t>(cell3.mContextList[i].index);
const ESM::ReadersCache::BusyItem reader = mReaders.get(index); const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
mCell->restore(*reader, i); cell3.restore(*reader, i);
ESM::CellRef ref; ESM::CellRef ref;
@ -761,8 +746,8 @@ namespace MWWorld
// Don't list reference if it was moved to a different cell. // Don't list reference if it was moved to a different cell.
ESM::MovedCellRefTracker::const_iterator iter ESM::MovedCellRefTracker::const_iterator iter
= std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum); = std::find(cell3.mMovedRefs.begin(), cell3.mMovedRefs.end(), ref.mRefNum);
if (iter != mCell->mMovedRefs.end()) if (iter != cell3.mMovedRefs.end())
{ {
continue; continue;
} }
@ -778,7 +763,7 @@ namespace MWWorld
} }
// List moved references, from separately tracked list. // List moved references, from separately tracked list.
for (const auto& [ref, deleted] : mCell->mLeasedRefs) for (const auto& [ref, deleted] : cell3.mLeasedRefs)
{ {
if (!deleted) if (!deleted)
mIds.push_back(ref.mRefID); mIds.push_back(ref.mRefID);
@ -809,18 +794,19 @@ namespace MWWorld
} }
else else
{ {
if (mCell->mContextList.empty()) auto cell3 = mCellVariant.getEsm3();
if (cell3.mContextList.empty())
return; // this is a dynamically generated cell -> skipping. return; // this is a dynamically generated cell -> skipping.
// Load references from all plugins that do something with this cell. // Load references from all plugins that do something with this cell.
for (size_t i = 0; i < mCell->mContextList.size(); i++) for (size_t i = 0; i < cell3.mContextList.size(); i++)
{ {
try try
{ {
// Reopen the ESM reader and seek to the right position. // Reopen the ESM reader and seek to the right position.
const std::size_t index = static_cast<std::size_t>(mCell->mContextList[i].index); const std::size_t index = static_cast<std::size_t>(cell3.mContextList[i].index);
const ESM::ReadersCache::BusyItem reader = mReaders.get(index); const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
mCell->restore(*reader, i); cell3.restore(*reader, i);
ESM::CellRef ref; ESM::CellRef ref;
// Get each reference in turn // Get each reference in turn
@ -835,8 +821,8 @@ namespace MWWorld
// Don't load reference if it was moved to a different cell. // Don't load reference if it was moved to a different cell.
ESM::MovedCellRefTracker::const_iterator iter ESM::MovedCellRefTracker::const_iterator iter
= std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum); = std::find(cell3.mMovedRefs.begin(), cell3.mMovedRefs.end(), ref.mRefNum);
if (iter != mCell->mMovedRefs.end()) if (iter != cell3.mMovedRefs.end())
{ {
continue; continue;
} }
@ -851,7 +837,7 @@ namespace MWWorld
} }
} }
// Load moved references, from separately tracked list. // Load moved references, from separately tracked list.
for (const auto& leasedRef : mCell->mLeasedRefs) for (const auto& leasedRef : cell3.mLeasedRefs)
{ {
ESM::CellRef& ref = const_cast<ESM::CellRef&>(leasedRef.first); ESM::CellRef& ref = const_cast<ESM::CellRef&>(leasedRef.first);
bool deleted = leasedRef.second; bool deleted = leasedRef.second;
@ -865,12 +851,12 @@ namespace MWWorld
bool CellStore::isExterior() const bool CellStore::isExterior() const
{ {
return mCellVariant.getCommon()->isExterior(); return mCellVariant.isExterior();
} }
bool CellStore::isQuasiExterior() const bool CellStore::isQuasiExterior() const
{ {
return mCellVariant.getCommon()->isExterior(); return mCellVariant.isQuasiExterior();
} }
Ptr CellStore::searchInContainer(const ESM::RefId& id) Ptr CellStore::searchInContainer(const ESM::RefId& id)
@ -954,9 +940,12 @@ namespace MWWorld
void CellStore::loadState(const ESM::CellState& state) void CellStore::loadState(const ESM::CellState& state)
{ {
if (mCellVariant.isEsm4())
return;
mHasState = true; mHasState = true;
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) if (!mCellVariant.isExterior() && mCellVariant.hasWater())
mWaterLevel = state.mWaterLevel; mWaterLevel = state.mWaterLevel;
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn); mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
@ -964,9 +953,9 @@ namespace MWWorld
void CellStore::saveState(ESM::CellState& state) const void CellStore::saveState(ESM::CellState& state) const
{ {
state.mId = mCell->getCellId(); state.mId = mCellVariant.getCellId();
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) if (!mCellVariant.isExterior() && mCellVariant.hasWater())
state.mWaterLevel = mWaterLevel; state.mWaterLevel = mWaterLevel;
state.mHasFogOfWar = (mFogState.get() ? 1 : 0); state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
@ -977,7 +966,7 @@ namespace MWWorld
{ {
if (mFogState.get()) if (mFogState.get())
{ {
mFogState->save(writer, mCell->mData.mFlags & ESM::Cell::Interior); mFogState->save(writer, !mCellVariant.isExterior());
} }
} }

View File

@ -12,10 +12,10 @@
#include <variant> #include <variant>
#include <vector> #include <vector>
#include "cell.hpp"
#include "cellreflist.hpp" #include "cellreflist.hpp"
#include "livecellref.hpp" #include "livecellref.hpp"
#include <components/esm/esm3esm4bridge.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include <components/esm3/fogstate.hpp> #include <components/esm3/fogstate.hpp>
#include <components/misc/tuplemeta.hpp> #include <components/misc/tuplemeta.hpp>
@ -98,8 +98,7 @@ namespace MWWorld
// Note this is nullptr until the cell is explored to save some memory // Note this is nullptr until the cell is explored to save some memory
std::unique_ptr<ESM::FogState> mFogState; std::unique_ptr<ESM::FogState> mFogState;
const ESM::Cell* mCell; MWWorld::Cell mCellVariant;
ESM::CellVariant mCellVariant;
State mState; State mState;
bool mHasState; bool mHasState;
std::vector<ESM::RefId> mIds; std::vector<ESM::RefId> mIds;
@ -194,14 +193,11 @@ namespace MWWorld
} }
/// @param readerList The readers to use for loading of the cell on-demand. /// @param readerList The readers to use for loading of the cell on-demand.
CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
CellStore(CellStore&&); CellStore(CellStore&&);
~CellStore(); ~CellStore();
const ESM::CellCommon* getCell() const; const MWWorld::Cell* getCell() const;
ESM::CellVariant getCellVariant() const;
std::string_view getEditorName() const;
State getState() const; State getState() const;

View File

@ -355,9 +355,9 @@ namespace MWWorld
if (cell->getCell()->hasWater()) if (cell->getCell()->hasWater())
mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard);
if (!cell->getCellVariant().isEsm4()) if (!cell->getCell()->isEsm4())
{ {
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell->getCellVariant().getEsm3())) if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell->getCell()->getEsm3()))
mNavigator.removePathgrid(*pathgrid); mNavigator.removePathgrid(*pathgrid);
} }
@ -383,11 +383,11 @@ namespace MWWorld
assert(mActiveCells.find(cell) == mActiveCells.end()); assert(mActiveCells.find(cell) == mActiveCells.end());
mActiveCells.insert(cell); mActiveCells.insert(cell);
Log(Debug::Info) << "Loading cell " << cell->getEditorName(); Log(Debug::Info) << "Loading cell " << cell->getCell()->getEditorName();
const int cellX = cell->getCellVariant().getCommon()->getGridX(); const int cellX = cell->getCell()->getGridX();
const int cellY = cell->getCellVariant().getCommon()->getGridY(); const int cellY = cell->getCell()->getGridY();
auto cellVariant = cell->getCellVariant(); auto cellVariant = *cell->getCell();
if (!cellVariant.isEsm4()) if (!cellVariant.isEsm4())
{ {
auto cell3 = cellVariant.getEsm3(); auto cell3 = cellVariant.getEsm3();
@ -450,7 +450,7 @@ namespace MWWorld
mRendering.addCell(cell); mRendering.addCell(cell);
MWBase::Environment::get().getWindowManager()->addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell);
bool waterEnabled = (!cellVariant.isEsm4()) && (cellVariant.getEsm3().hasWater() || cell->isExterior()); bool waterEnabled = (!cellVariant.isEsm4()) && (cellVariant.hasWater() || cell->isExterior());
float waterLevel = cell->getWaterLevel(); float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled); mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled) if (waterEnabled)
@ -473,7 +473,7 @@ namespace MWWorld
else else
mPhysics->disableWater(); mPhysics->disableWater();
if (!cell->isExterior() && !cellVariant.getCommon()->isQuasiExterior()) if (!cell->isExterior() && !cellVariant.isQuasiExterior())
mRendering.configureAmbient(cellVariant); mRendering.configureAmbient(cellVariant);
mPreloader->notifyLoaded(cell); mPreloader->notifyLoaded(cell);
@ -887,7 +887,8 @@ namespace MWWorld
loadingListener->setProgressRange(cell->count()); loadingListener->setProgressRange(cell->count());
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getEditorName()), navigatorUpdateGuard.get()); mNavigator.setWorldspace(
Misc::StringUtils::lowerCase(cell->getCell()->getEditorName()), navigatorUpdateGuard.get());
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
// Load cell. // Load cell.
@ -899,7 +900,7 @@ namespace MWWorld
changePlayerCell(cell, position, adjustPlayerPos); changePlayerCell(cell, position, adjustPlayerPos);
// adjust fog // adjust fog
mRendering.configureFog(mCurrentCell->getCellVariant()); mRendering.configureFog(*mCurrentCell->getCell());
// Sky system // Sky system
mWorld.adjustSky(); mWorld.adjustSky();
@ -914,8 +915,7 @@ namespace MWWorld
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag( MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->isQuasiExterior());
cell->getCellVariant().getCommon()->isQuasiExterior());
} }
void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)

View File

@ -634,22 +634,18 @@ namespace MWWorld
{ {
if (!cell) if (!cell)
cell = mWorldScene->getCurrentCell(); cell = mWorldScene->getCurrentCell();
return getCellName(cell->getCellVariant()); return getCellName(*cell->getCell());
} }
std::string_view World::getCellName(const ESM::CellVariant& cell) const std::string_view World::getCellName(const MWWorld::Cell& cell) const
{ {
auto cellCommon = cell.getCommon(); if (!cell.isExterior() || !cell.getEditorName().empty())
if (cellCommon) return cell.getEditorName();
{
if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty())
return cellCommon->getEditorName();
if (!cell.isEsm4()) if (!cell.isEsm4())
{ {
const ESM::Region* region = mStore.get<ESM::Region>().search(cell.getEsm3().mRegion); const ESM::Region* region = mStore.get<ESM::Region>().search(cell.getEsm3().mRegion);
return region->mName; return region->mName;
}
} }
return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString(); return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
@ -2313,7 +2309,7 @@ namespace MWWorld
if (!cell) if (!cell)
return false; return false;
if (!(cell->getCellVariant().getCommon()->hasWater())) if (!(cell->getCell()->hasWater()))
{ {
return false; return false;
} }
@ -2840,7 +2836,7 @@ namespace MWWorld
{ {
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
const ESM::CellCommon* ext = nullptr; const MWWorld::Cell* ext = nullptr;
try try
{ {
ext = mWorldModel.getCell(nameId)->getCell(); ext = mWorldModel.getCell(nameId)->getCell();
@ -3247,9 +3243,8 @@ namespace MWWorld
} }
else else
{ {
auto cellVariant = cell->getCellVariant(); auto cellVariant = *cell->getCell();
uint32_t ambient = !cellVariant.isEsm4() ? cellVariant.getEsm3().mAmbi.mAmbient uint32_t ambient = cellVariant.getMood().mAmbiantColor;
: cellVariant.getEsm4().mLighting.ambient;
int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff); int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff);
return !cell->getCell()->noSleep() && ambientTotal <= 201; return !cell->getCell()->noSleep() && ambientTotal <= 201;
} }
@ -3275,7 +3270,7 @@ namespace MWWorld
std::set<std::string_view> checkedCells; std::set<std::string_view> checkedCells;
std::set<std::string_view> currentCells; std::set<std::string_view> currentCells;
std::set<std::string_view> nextCells; std::set<std::string_view> nextCells;
nextCells.insert(cell->getEditorName()); nextCells.insert(cell->getCell()->getEditorName());
while (!nextCells.empty()) while (!nextCells.empty())
{ {

View File

@ -269,7 +269,7 @@ namespace MWWorld
/// ///
/// \note If cell==0, the cell the player is currently in will be used instead to /// \note If cell==0, the cell the player is currently in will be used instead to
/// generate a name. /// generate a name.
std::string_view getCellName(const ESM::CellVariant& cell) const override; std::string_view getCellName(const MWWorld::Cell& cell) const override;
void removeRefScript(MWWorld::RefData* ref) override; void removeRefScript(MWWorld::RefData* ref) override;
//< Remove the script attached to ref from mLocalScripts //< Remove the script attached to ref from mLocalScripts

View File

@ -67,7 +67,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
auto result = mInteriors.find(cell->mName); auto result = mInteriors.find(cell->mName);
if (result == mInteriors.end()) if (result == mInteriors.end())
result = mInteriors.emplace(cell->mName, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; result = mInteriors.emplace(cell->mName, CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
return &result->second; return &result->second;
} }
@ -79,7 +79,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
if (result == mExteriors.end()) if (result == mExteriors.end())
result = mExteriors result = mExteriors
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), .emplace(std::make_pair(cell->getGridX(), cell->getGridY()),
CellStore(ESM::CellVariant(cell), mStore, mReaders)) CellStore(MWWorld::Cell(cell), mStore, mReaders))
.first; .first;
return &result->second; return &result->second;
@ -186,7 +186,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
cell = MWBase::Environment::get().getWorld()->createRecord(record); cell = MWBase::Environment::get().getWorld()->createRecord(record);
} }
result = mExteriors.emplace(std::make_pair(x, y), CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; result = mExteriors.emplace(std::make_pair(x, y), CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
} }
if (result->second.getState() != CellStore::State_Loaded) if (result->second.getState() != CellStore::State_Loaded)
@ -208,11 +208,11 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
if (!cell4) if (!cell4)
{ {
const ESM::Cell* cell = mStore.get<ESM::Cell>().find(name); const ESM::Cell* cell = mStore.get<ESM::Cell>().find(name);
result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
} }
else else
{ {
result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell4), mStore, mReaders)).first; result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell4), mStore, mReaders)).first;
} }
} }

View File

@ -134,7 +134,7 @@ namespace DetourNavigator
void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid)
{ {
Misc::CoordinateConverter converter(&cell); Misc::CoordinateConverter converter = Misc::CoordinateConverter(ESM::CellVariant(&cell));
for (const auto& edge : pathgrid.mEdges) for (const auto& edge : pathgrid.mEdges)
{ {
const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0])); const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0]));

View File

@ -4,14 +4,6 @@
namespace ESM namespace ESM
{ {
const ESM::CellCommon* CellVariant::getCommon() const
{
if (isEsm4())
return &getEsm4();
else
return &getEsm3();
}
const ESM4::Cell& CellVariant::getEsm4() const const ESM4::Cell& CellVariant::getEsm4() const
{ {
auto cell4 = std::get<0>(mVariant); auto cell4 = std::get<0>(mVariant);

View File

@ -16,20 +16,6 @@ namespace ESM
struct Cell; struct Cell;
struct CellId; struct CellId;
struct RefId; struct RefId;
// Common interface for esm3 and esm4 cells
struct CellCommon
{
virtual int getGridX() const = 0;
virtual int getGridY() const = 0;
virtual bool isExterior() const = 0;
virtual bool isQuasiExterior() const = 0;
virtual bool hasWater() const = 0;
virtual bool noSleep() const { return false; }
virtual const ESM::CellId& getCellId() const = 0;
virtual const ESM::RefId& getRegion() const = 0;
virtual std::string_view getEditorName() const = 0;
virtual std::string getDescription() const = 0;
};
struct CellVariant struct CellVariant
{ {
@ -61,8 +47,6 @@ namespace ESM
const ESM4::Cell& getEsm4() const; const ESM4::Cell& getEsm4() const;
const ESM::Cell& getEsm3() const; const ESM::Cell& getEsm3() const;
const ESM::CellCommon* getCommon() const;
}; };
} }

View File

@ -8,7 +8,6 @@
#include "cellid.hpp" #include "cellid.hpp"
#include "cellref.hpp" #include "cellref.hpp"
#include "components/esm/defs.hpp" #include "components/esm/defs.hpp"
#include "components/esm/esm3esm4bridge.hpp"
#include "components/esm/esmcommon.hpp" #include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp" #include "components/esm/refid.hpp"
@ -66,7 +65,7 @@ namespace ESM
(using ESMReader::getContext()) and jumping back into place (using ESMReader::getContext()) and jumping back into place
whenever we need to load a given cell. whenever we need to load a given cell.
*/ */
struct Cell : public CellCommon struct Cell
{ {
constexpr static RecNameInts sRecordId = REC_CELL; constexpr static RecNameInts sRecordId = REC_CELL;
@ -151,14 +150,11 @@ namespace ESM
void save(ESMWriter& esm, bool isDeleted = false) const; void save(ESMWriter& esm, bool isDeleted = false) const;
void saveTempMarker(ESMWriter& esm, int tempCount) const; void saveTempMarker(ESMWriter& esm, int tempCount) const;
bool isExterior() const override { return !(mData.mFlags & Interior); } bool isExterior() const { return !(mData.mFlags & Interior); }
bool isQuasiExterior() const override { return mData.mFlags & QuasiEx; }
int getGridX() const override { return mData.mX; } int getGridX() const { return mData.mX; }
int getGridY() const override { return mData.mY; } int getGridY() const { return mData.mY; }
bool hasWater() const override { return ((mData.mFlags & HasWater) != 0) || isExterior(); }
bool hasAmbient() const { return mHasAmbi; } bool hasAmbient() const { return mHasAmbi; }
@ -171,7 +167,7 @@ namespace ESM
// exactly. // exactly.
void restore(ESMReader& esm, int iCtx) const; void restore(ESMReader& esm, int iCtx) const;
std::string getDescription() const override; std::string getDescription() const;
///< Return a short string describing the cell (mostly used for debugging/logging purpose) ///< Return a short string describing the cell (mostly used for debugging/logging purpose)
/* Get the next reference in this cell, if any. Returns false when /* Get the next reference in this cell, if any. Returns false when
@ -193,10 +189,7 @@ namespace ESM
void blank(); void blank();
///< Set record to default state (does not touch the ID/index). ///< Set record to default state (does not touch the ID/index).
const CellId& getCellId() const override; const CellId& getCellId() const;
const ESM::RefId& getRegion() const override { return mRegion; }
bool noSleep() const override { return mData.mFlags & ESM::Cell::NoSleep; }
std::string_view getEditorName() const override { return mName; }
}; };
} }
#endif #endif

View File

@ -241,12 +241,6 @@ void ESM4::Cell::load(ESM4::Reader& reader)
throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId));
} }
} }
mCellId.mWorldspace = Misc::StringUtils::lowerCase(mEditorId);
mCellId.mWorld = ESM::RefId::sEmpty;
mCellId.mIndex.mX = getGridX();
mCellId.mIndex.mX = getGridY();
mCellId.mPaged = isExterior();
} }
// void ESM4::Cell::save(ESM4::Writer& writer) const // void ESM4::Cell::save(ESM4::Writer& writer) const

View File

@ -35,7 +35,6 @@
#include "lighting.hpp" #include "lighting.hpp"
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/esm3esm4bridge.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include <components/esm3/cellid.hpp> #include <components/esm3/cellid.hpp>
@ -62,7 +61,7 @@ namespace ESM4
// Unlike TES3, multiple cells can have the same exterior co-ordinates. // Unlike TES3, multiple cells can have the same exterior co-ordinates.
// The cells need to be organised under world spaces. // The cells need to be organised under world spaces.
struct Cell final : public ESM::CellCommon struct Cell
{ {
FormId mParent; // world formId (for grouping cells), from the loading sequence FormId mParent; // world formId (for grouping cells), from the loading sequence
@ -96,8 +95,6 @@ namespace ESM4
CellGroup* mCellGroup; CellGroup* mCellGroup;
ESM::CellId mCellId;
void load(ESM4::Reader& reader); void load(ESM4::Reader& reader);
// void save(ESM4::Writer& writer) const; // void save(ESM4::Writer& writer) const;
@ -105,15 +102,9 @@ namespace ESM4
static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4; static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4;
int getGridX() const override { return mX; } int getGridX() const { return mX; }
int getGridY() const override { return mY; } int getGridY() const { return mY; }
bool isExterior() const override { return !(mCellFlags & CELL_Interior); } bool isExterior() const { return !(mCellFlags & CELL_Interior); }
virtual bool isQuasiExterior() const override { return mCellFlags & CELL_QuasiExt; }
virtual bool hasWater() const override { return false; /*unimplemented for now*/ }
const ESM::CellId& getCellId() const override { return mCellId; }
const ESM::RefId& getRegion() const override { return ESM::RefId::sEmpty; }
std::string_view getEditorName() const override { return mEditorId; }
std::string getDescription() const override { return mEditorId; }
}; };
} }

View File

@ -1,9 +1,11 @@
#ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H #ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
#define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H #define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
#include <components/esm/esm3esm4bridge.hpp>
#include <components/esm3/loadcell.hpp> #include <components/esm3/loadcell.hpp>
#include <components/esm3/loadland.hpp> #include <components/esm3/loadland.hpp>
#include <components/esm3/loadpgrd.hpp> #include <components/esm3/loadpgrd.hpp>
#include <components/esm4/loadcell.hpp>
namespace Misc namespace Misc
{ {
@ -17,8 +19,10 @@ namespace Misc
{ {
} }
explicit CoordinateConverter(const ESM::CellCommon* cell) explicit CoordinateConverter(const ESM::CellVariant& cell)
: CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY()) : CoordinateConverter(cell.isEsm4() ? cell.getEsm4().isExterior() : cell.getEsm3().isExterior(),
cell.isEsm4() ? cell.getEsm4().getGridX() : cell.getEsm3().getGridX(),
cell.isEsm4() ? cell.getEsm4().getGridY() : cell.getEsm3().getGridY())
{ {
} }