1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-19 08:36:47 +00:00

encapsulations of esm3 cell and esm4 cells.

This commit is contained in:
florent.teppe 2023-01-22 23:40:55 +01:00
parent 08b68fcd48
commit 562e129bd0
40 changed files with 292 additions and 162 deletions

View file

@ -57,6 +57,8 @@ namespace ESM
struct ItemLevList; struct ItemLevList;
struct TimeStamp; struct TimeStamp;
struct RefId; struct RefId;
struct CellVariant;
} }
namespace MWPhysics namespace MWPhysics
@ -179,7 +181,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::Cell* cell) const = 0; virtual std::string_view getCellName(const ESM::CellVariant& 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(cell); dest = world->getCellName(ESM::CellVariant(cell));
} }
return "#{sCell=" + std::string{ dest } + "}"; return "#{sCell=" + std::string{ dest } + "}";

View file

@ -705,7 +705,7 @@ namespace MWGui
ESM::Position markedPosition; ESM::Position markedPosition;
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
if (markedCell && markedCell->isExterior() == !mInterior if (markedCell && markedCell->isExterior() == !mInterior
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getEditorName(), mPrefix)))
{ {
MarkerUserData markerPos(mLocalMapRender); MarkerUserData markerPos(mLocalMapRender);
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",

View file

@ -200,7 +200,7 @@ namespace MWGui
MWWorld::Ptr player = world->getPlayerPtr(); MWWorld::Ptr player = world->getPlayerPtr();
if (mSleeping && player.getCell()->isExterior()) if (mSleeping && player.getCell()->isExterior())
{ {
const ESM::RefId& regionstr = player.getCell()->getCell()->mRegion; const ESM::RefId& regionstr = player.getCell()->getCell()->getRegion();
if (!regionstr.empty()) if (!regionstr.empty())
{ {
const ESM::Region* region = world->getStore().get<ESM::Region>().find(regionstr); const ESM::Region* region = world->getStore().get<ESM::Region>().find(regionstr);

View file

@ -954,20 +954,21 @@ namespace MWGui
mMap->setCellName(name); mMap->setCellName(name);
mHud->setCellName(name); mHud->setCellName(name);
auto cellCommon = cell->getCellVariant().getCommon();
if (cell->getCell()->isExterior()) if (cellCommon->isExterior())
{ {
if (!cell->getCell()->mName.empty()) if (!cellCommon->getEditorName().empty())
mMap->addVisitedLocation(name, cell->getCell()->getGridX(), cell->getCell()->getGridY()); mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY());
mMap->cellExplored(cell->getCell()->getGridX(), cell->getCell()->getGridY()); mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY());
setActiveMap(cell->getCell()->getGridX(), cell->getCell()->getGridY(), false); setActiveMap(cellCommon->getGridX(), cellCommon->getGridY(), false);
} }
else else
{ {
mMap->setCellPrefix(cell->getCell()->mName); mMap->setCellPrefix(std::string(cellCommon->getEditorName()));
mHud->setCellPrefix(cell->getCell()->mName); mHud->setCellPrefix(std::string(cellCommon->getEditorName()));
osg::Vec3f worldPos; osg::Vec3f worldPos;
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))

View file

@ -1,5 +1,6 @@
#include "luabindings.hpp" #include "luabindings.hpp"
#include <components/esm/cellcommon.hpp>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
@ -29,35 +30,35 @@ namespace MWLua
cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; }; cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; };
cellT[sol::meta_function::to_string] = [](const CellT& c) { cellT[sol::meta_function::to_string] = [](const CellT& c) {
const ESM::Cell* cell = c.mStore->getCell(); auto cell = c.mStore->getCell();
std::stringstream res; std::stringstream res;
if (cell->isExterior()) if (cell->isExterior())
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")"; res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")";
else else
res << "interior(" << cell->mName << ")"; res << "interior(" << cell->getEditorName() << ")";
return res.str(); return res.str();
}; };
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName; }); cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getEditorName(); });
cellT["region"] cellT["region"]
= sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion.getRefIdString(); }); = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); });
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
cellT["hasSky"] = sol::readonly_property([](const CellT& c) { cellT["hasSky"] = sol::readonly_property([](const CellT& c) {
return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->isQuasiExterior()) != 0;
}); });
cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); }); cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); });
// deprecated, use cell:hasTag("QuasiExterior") instead // deprecated, use cell:hasTag("QuasiExterior") instead
cellT["isQuasiExterior"] = sol::readonly_property( cellT["isQuasiExterior"]
[](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; }); = sol::readonly_property([](const CellT& c) { return (c.mStore->getCell()->isQuasiExterior()) != 0; });
cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool { cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool {
if (tag == "NoSleep") if (tag == "NoSleep")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0; return (c.mStore->getCell()->noSleep()) != 0;
else if (tag == "QuasiExterior") else if (tag == "QuasiExterior")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; return (c.mStore->getCell()->isQuasiExterior()) != 0;
return false; return false;
}; };

View file

@ -176,12 +176,12 @@ 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::Cell* esmCell = cell.mStore->getCell(); const ESM::CellCommon* 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
ai.stack(MWMechanics::AiEscort( ai.stack(MWMechanics::AiEscort(
refId, esmCell->mName, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), refId, esmCell->getEditorName(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false),
ptr); ptr);
}; };
selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) { selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) {

View file

@ -274,8 +274,8 @@ namespace MWMechanics
.find("fInteriorHeadTrackMult") .find("fInteriorHeadTrackMult")
->mValue.getFloat(); ->mValue.getFloat();
float maxDistance = fMaxHeadTrackDistance; float maxDistance = fMaxHeadTrackDistance;
const ESM::Cell* currentCell = actor.getCell()->getCell(); auto currentCell = actor.getCell()->getCell();
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx)) if (!currentCell->isExterior() && !(currentCell->isQuasiExterior()))
maxDistance *= fInteriorHeadTrackMult; maxDistance *= fInteriorHeadTrackMult;
const osg::Vec3f actor1Pos(actorRefData.getPosition().asVec3()); const osg::Vec3f actor1Pos(actorRefData.getPosition().asVec3());

View file

@ -357,12 +357,12 @@ namespace MWMechanics
case AiCombatStorage::FleeState_Idle: case AiCombatStorage::FleeState_Idle:
{ {
float triggerDist = getMaxAttackDistance(target); float triggerDist = getMaxAttackDistance(target);
auto cell3 = storage.mCell->getCellVariant().getEsm3();
if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) if (cell3 && storage.mLOS
&& (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(*cell3);
*storage.mCell->getCell());
bool runFallback = true; bool runFallback = true;

View file

@ -174,7 +174,8 @@ namespace MWMechanics
return true; return true;
} }
} }
else if (Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->mName)) // Cell to travel to else if (Misc::StringUtils::ciEqual(
mCellId, actor.getCell()->getCell()->getEditorName())) // Cell to travel to
{ {
mRemainingDuration = mDuration; mRemainingDuration = mDuration;
return true; return true;

View file

@ -411,7 +411,7 @@ 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()->getCell()); const ESM::Cell* playerCell(getPlayer().getCell()->getCellVariant().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

View file

@ -271,9 +271,10 @@ namespace MWMechanics
} }
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed node points for this actor.
if (storage.mPopulateAvailableNodes) auto cell3 = actor.getCell()->getCellVariant().getEsm3();
if (cell3 && storage.mPopulateAvailableNodes)
{ {
getAllowedNodes(actor, actor.getCell()->getCell(), storage); getAllowedNodes(actor, cell3, storage);
} }
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
@ -721,8 +722,9 @@ namespace MWMechanics
return; return;
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
if (storage.mPopulateAvailableNodes) auto cell3 = actor.getCell()->getCellVariant().getEsm3();
getAllowedNodes(actor, actor.getCell()->getCell(), storage); if (cell3 && storage.mPopulateAvailableNodes)
getAllowedNodes(actor, cell3, storage);
if (storage.mAllowedNodes.empty()) if (storage.mAllowedNodes.empty())
return; return;
@ -800,8 +802,11 @@ 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)
{ {
auto cell3 = currentCell->getCellVariant().getEsm3();
if (!cell3)
return;
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*currentCell->getCell()); = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell3);
if (pathgrid == nullptr || pathgrid->mPoints.empty()) if (pathgrid == nullptr || pathgrid->mPoints.empty())
return; return;

View file

@ -12,6 +12,7 @@
namespace ESM namespace ESM
{ {
struct Cell; struct Cell;
struct CellCommon;
namespace AiSequence namespace AiSequence
{ {
struct AiWander; struct AiWander;
@ -158,6 +159,8 @@ namespace MWMechanics
GroupIndex_MaxIdle = 9 GroupIndex_MaxIdle = 9
}; };
/// convert point from local (i.e. cell) to world coordinates
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::CellCommon* cell);
void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage);
void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage, void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage,

View file

@ -104,8 +104,10 @@ namespace MWMechanics
if (mIsGraphConstructed) if (mIsGraphConstructed)
return true; return true;
mCell = cell->getCell(); mCell = cell->getCellVariant().getEsm3();
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell->getCell()); if (!mCell)
return false;
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell);
if (!mPathgrid) if (!mPathgrid)
return false; return false;

View file

@ -489,7 +489,7 @@ namespace MWMechanics
{ {
std::string_view dest; std::string_view dest;
if (!markedCell->isExterior()) if (!markedCell->isExterior())
dest = markedCell->getCell()->mName; dest = markedCell->getCell()->getEditorName();
MWWorld::ActionTeleport action(dest, markedPosition, false); MWWorld::ActionTeleport action(dest, markedPosition, false);
action.execute(target); action.execute(target);
if (!caster.isEmpty()) if (!caster.isEmpty())

View file

@ -2,7 +2,9 @@
#include <algorithm> #include <algorithm>
#include <components/esm/cellcommon.hpp>
#include <components/esm3/loadcell.hpp> #include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -38,13 +40,17 @@ 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::Cell* cell) void FogManager::configure(float viewDistance, const ESM::CellVariant& cell)
{ {
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); auto cell3 = cell.getEsm3();
auto cell4 = cell.getEsm4();
osg::Vec4f color = SceneUtil::colourFromRGB(cell3 ? cell3->mAmbi.mFog : cell4->mLighting.fogColor);
const float fogDensity = cell3 ? cell3->mAmbi.mFogDensity : cell4->mLighting.fogPower;
if (mDistantFog) if (mDistantFog)
{ {
float density = std::max(0.2f, cell->mAmbi.mFogDensity); float density = std::max(0.2f, fogDensity);
mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density; mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density;
mLandFogEnd = DLInteriorFogEnd; mLandFogEnd = DLInteriorFogEnd;
mUnderwaterFogStart = DLUnderwaterFogStart; mUnderwaterFogStart = DLUnderwaterFogStart;
@ -52,7 +58,7 @@ namespace MWRender
mFogColor = color; mFogColor = color;
} }
else else
configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); configure(viewDistance, fogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
} }
void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset,

View file

@ -5,7 +5,7 @@
namespace ESM namespace ESM
{ {
struct Cell; struct CellVariant;
} }
namespace MWRender namespace MWRender
@ -15,7 +15,7 @@ namespace MWRender
public: public:
FogManager(); FogManager();
void configure(float viewDistance, const ESM::Cell* cell); void configure(float viewDistance, const ESM::CellVariant& 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,7 +102,10 @@ 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();
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*store->getCell()); auto cell3 = store->getCellVariant().getEsm3();
if (!cell3)
return;
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell3);
if (!pathgrid) if (!pathgrid)
return; return;

View file

@ -49,6 +49,7 @@
#include <components/terrain/terraingrid.hpp> #include <components/terrain/terraingrid.hpp>
#include <components/esm3/loadcell.hpp> #include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/debug/debugdraw.hpp> #include <components/debug/debugdraw.hpp>
#include <components/detournavigator/navigator.hpp> #include <components/detournavigator/navigator.hpp>
@ -739,14 +740,24 @@ namespace MWRender
mSky->setMoonColour(red); mSky->setMoonColour(red);
} }
void RenderingManager::configureAmbient(const ESM::Cell* cell) void RenderingManager::configureAmbient(const ESM::CellVariant& cell)
{ {
bool isInterior = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx); bool isInterior = !cell.getCommon()->isExterior() && !cell.getCommon()->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;
auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient); osg::Vec4f ambient;
auto cell3 = cell.getEsm3();
auto cell4 = cell.getEsm4();
if (cell3)
{
ambient = SceneUtil::colourFromRGB(cell3->mAmbi.mAmbient);
}
else
{
ambient = SceneUtil::colourFromRGB(cell4->mLighting.ambient);
}
if (needsAdjusting) if (needsAdjusting)
{ {
@ -770,7 +781,9 @@ namespace MWRender
setAmbientColour(ambient); setAmbientColour(ambient);
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); osg::Vec4f diffuse = cell3 ? SceneUtil::colourFromRGB(cell3->mAmbi.mSunlight)
: SceneUtil::colourFromRGB(cell4->mLighting.directional);
setSunColour(diffuse, diffuse, 1.f); setSunColour(diffuse, diffuse, 1.f);
const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f); const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f);
@ -890,7 +903,7 @@ namespace MWRender
return false; return false;
} }
void RenderingManager::configureFog(const ESM::Cell* cell) void RenderingManager::configureFog(const ESM::CellVariant& cell)
{ {
mFog->configure(mViewDistance, cell); mFog->configure(mViewDistance, cell);
} }
@ -1424,7 +1437,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()->getCell()); configureAmbient(MWMechanics::getPlayer().getCell()->getCellVariant());
} }
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

@ -43,6 +43,7 @@ namespace ESM
{ {
struct Cell; struct Cell;
struct RefNum; struct RefNum;
struct CellVariant;
} }
namespace Terrain namespace Terrain
@ -140,8 +141,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::Cell* cell); void configureAmbient(const ESM::CellVariant& cell);
void configureFog(const ESM::Cell* cell); void configureFog(const ESM::CellVariant& 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

@ -772,7 +772,8 @@ namespace MWRender
bool wasInterior = mInterior; bool wasInterior = mInterior;
if (!isInterior) if (!isInterior)
{ {
mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); mWaterNode->setPosition(
getSceneNodeCoordinates(store->getCell()->getGridX(), store->getCell()->getGridY()));
mInterior = false; mInterior = false;
} }
else else

View file

@ -766,14 +766,14 @@ 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();
const ESM::Cell* cell = player.getCell()->getCell(); auto cell = player.getCell()->getCell();
if (!cell->isExterior()) if (!cell->isExterior())
return; return;
if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound)) if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound))
return; return;
if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->mRegion, *world)) if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion(), *world))
mCurrentRegionSound = playSound(*next, 1.0f, 1.0f); mCurrentRegionSound = playSound(*next, 1.0f, 1.0f);
} }
@ -781,7 +781,7 @@ 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();
const ESM::Cell* curcell = player.getCell()->getCell(); const ESM::Cell* curcell = player.getCell()->getCellVariant().getEsm3();
const auto update = mWaterSoundUpdater.update(player, *world); const auto update = mWaterSoundUpdater.update(player, *world);
WaterSoundAction action; WaterSoundAction action;

View file

@ -505,7 +505,7 @@ namespace MWWorld
return false; return false;
} }
CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) CellStore::CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
: mStore(esmStore) : mStore(esmStore)
, mReaders(readers) , mReaders(readers)
, mCellVariant(cell) , mCellVariant(cell)
@ -526,12 +526,12 @@ namespace MWWorld
CellStore::~CellStore() = default; CellStore::~CellStore() = default;
CellStore::CellStore(CellStore&&) = default; CellStore::CellStore(CellStore&&) = default;
const ESM::Cell* CellStore::getCell() const const ESM::CellCommon* CellStore::getCell() const
{ {
return mCell; return mCellVariant.getCommon();
} }
CellVariant CellStore::getCellVariant() const ESM::CellVariant CellStore::getCellVariant() const
{ {
return mCellVariant; return mCellVariant;
} }
@ -1087,8 +1087,11 @@ namespace MWWorld
auto cell4Left = mCellVariant.getEsm4(); auto cell4Left = mCellVariant.getEsm4();
auto cell4Right = right.mCellVariant.getEsm4(); auto cell4Right = right.mCellVariant.getEsm4();
auto cell3Left = mCellVariant.getEsm3();
auto cell3Right = right.mCellVariant.getEsm3();
if (!cell4Left && !cell4Right) if (!cell4Left && !cell4Right)
return getCell()->getCellId() == right.getCell()->getCellId(); return cell3Left->getCellId() == cell3Right->getCellId();
else if (cell4Left && cell4Right) else if (cell4Left && cell4Right)
return cell4Left->mId == cell4Right->mId; return cell4Left->mId == cell4Right->mId;
else else
@ -1299,4 +1302,5 @@ namespace MWWorld
} }
return {}; return {};
} }
} }

View file

@ -9,11 +9,13 @@
#include <string_view> #include <string_view>
#include <tuple> #include <tuple>
#include <typeinfo> #include <typeinfo>
#include <variant>
#include <vector> #include <vector>
#include "cellreflist.hpp" #include "cellreflist.hpp"
#include "livecellref.hpp" #include "livecellref.hpp"
#include <components/esm/cellcommon.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>
@ -49,6 +51,7 @@ namespace ESM
struct Static; struct Static;
struct Weapon; struct Weapon;
struct BodyPart; struct BodyPart;
struct CellCommon;
} }
namespace ESM4 namespace ESM4
@ -64,39 +67,6 @@ namespace MWWorld
class ESMStore; class ESMStore;
struct CellStoreImp; struct CellStoreImp;
struct CellVariant
{
std::variant<const ESM4::Cell*, const ESM::Cell*> mVariant;
CellVariant(const ESM4::Cell* cell)
: mVariant(cell)
{
}
CellVariant(const ESM::Cell* cell)
: mVariant(cell)
{
}
bool isEsm4() const { return getEsm4(); }
const ESM4::Cell* getEsm4() const
{
auto cell4 = std::get_if<const ESM4::Cell*>(&mVariant);
if (cell4)
return *cell4;
return nullptr;
}
const ESM::Cell* getEsm3() const
{
auto cell3 = std::get_if<const ESM::Cell*>(&mVariant);
if (cell3)
return *cell3;
return nullptr;
}
};
using CellStoreTuple = std::tuple<CellRefList<ESM::Activator>, CellRefList<ESM::Potion>, using CellStoreTuple = std::tuple<CellRefList<ESM::Activator>, CellRefList<ESM::Potion>,
CellRefList<ESM::Apparatus>, CellRefList<ESM::Armor>, CellRefList<ESM::Book>, CellRefList<ESM::Clothing>, CellRefList<ESM::Apparatus>, CellRefList<ESM::Armor>, CellRefList<ESM::Book>, CellRefList<ESM::Clothing>,
CellRefList<ESM::Container>, CellRefList<ESM::Creature>, CellRefList<ESM::Door>, CellRefList<ESM::Ingredient>, CellRefList<ESM::Container>, CellRefList<ESM::Creature>, CellRefList<ESM::Door>, CellRefList<ESM::Ingredient>,
@ -129,7 +99,7 @@ namespace MWWorld
std::unique_ptr<ESM::FogState> mFogState; std::unique_ptr<ESM::FogState> mFogState;
const ESM::Cell* mCell; const ESM::Cell* mCell;
CellVariant mCellVariant; ESM::CellVariant mCellVariant;
State mState; State mState;
bool mHasState; bool mHasState;
std::vector<ESM::RefId> mIds; std::vector<ESM::RefId> mIds;
@ -224,12 +194,12 @@ 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(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers);
CellStore(CellStore&&); CellStore(CellStore&&);
~CellStore(); ~CellStore();
const ESM::Cell* getCell() const; const ESM::CellCommon* getCell() const;
CellVariant getCellVariant() const; ESM::CellVariant getCellVariant() const;
std::string_view getEditorName() const; std::string_view getEditorName() const;

View file

@ -317,8 +317,8 @@ namespace MWWorld
{ {
if (mActiveCells.find(cell) == mActiveCells.end()) if (mActiveCells.find(cell) == mActiveCells.end())
return; return;
std::string description = cell->getCell()->getDescription();
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription(); Log(Debug::Info) << "Unloading cell " << description;
ListAndResetObjectsVisitor visitor; ListAndResetObjectsVisitor visitor;
@ -355,8 +355,12 @@ 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 (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell->getCell())) auto cell3 = cell->getCellVariant().getEsm3();
if (cell3)
{
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell3))
mNavigator.removePathgrid(*pathgrid); mNavigator.removePathgrid(*pathgrid);
}
MWBase::Environment::get().getMechanicsManager()->drop(cell); MWBase::Environment::get().getMechanicsManager()->drop(cell);
@ -383,14 +387,11 @@ namespace MWWorld
Log(Debug::Info) << "Loading cell " << cell->getEditorName(); Log(Debug::Info) << "Loading cell " << cell->getEditorName();
auto cell3 = cell->getCellVariant().getEsm3(); auto cell3 = cell->getCellVariant().getEsm3();
int cellX = 0; const int cellX = cell->getCellVariant().getCommon()->getGridX();
int cellY = 0; const int cellY = cell->getCellVariant().getCommon()->getGridY();
if (cell3 != nullptr) if (cell3 != nullptr)
{ {
int cellX = cell3->getGridX();
int cellY = cell3->getGridY();
if (cell3->isExterior()) if (cell3->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);
@ -472,8 +473,10 @@ namespace MWWorld
else else
mPhysics->disableWater(); mPhysics->disableWater();
if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx)) const auto cellVariant = cell->getCellVariant();
mRendering.configureAmbient(cell3);
if (!cell->isExterior() && !cellVariant.getCommon()->isQuasiExterior())
mRendering.configureAmbient(cellVariant);
mPreloader->notifyLoaded(cell); mPreloader->notifyLoaded(cell);
} }
@ -549,7 +552,7 @@ namespace MWWorld
mNavigator.setWorldspace( mNavigator.setWorldspace(
Misc::StringUtils::lowerCase( Misc::StringUtils::lowerCase(
mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace), mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace),
navigatorUpdateGuard.get()); navigatorUpdateGuard.get());
mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get());
@ -672,7 +675,7 @@ namespace MWWorld
CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY);
mNavigator.setWorldspace( mNavigator.setWorldspace(
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
const osg::Vec3f position const osg::Vec3f position
= osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits;
mNavigator.updateBounds(position, navigatorUpdateGuard.get()); mNavigator.updateBounds(position, navigatorUpdateGuard.get());
@ -730,7 +733,7 @@ namespace MWWorld
CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); CellStore* cell = mWorld.getWorldModel().getInterior(it->mName);
mNavigator.setWorldspace( mNavigator.setWorldspace(
Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
ESM::Position position; ESM::Position position;
mWorld.findInteriorPosition(it->mName, position); mWorld.findInteriorPosition(it->mName, position);
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
@ -746,7 +749,7 @@ namespace MWWorld
{ {
assert(!(*iter)->getCell()->isExterior()); assert(!(*iter)->getCell()->isExterior());
if (it->mName == (*iter)->getCell()->mName) if (it->mName == (*iter)->getCell()->getEditorName())
{ {
unloadCell(*iter, navigatorUpdateGuard.get()); unloadCell(*iter, navigatorUpdateGuard.get());
break; break;
@ -898,7 +901,7 @@ namespace MWWorld
changePlayerCell(cell, position, adjustPlayerPos); changePlayerCell(cell, position, adjustPlayerPos);
// adjust fog // adjust fog
mRendering.configureFog(mCurrentCell->getCell()); mRendering.configureFog(mCurrentCell->getCellVariant());
// Sky system // Sky system
mWorld.adjustSky(); mWorld.adjustSky();
@ -914,7 +917,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()->mData.mFlags & ESM::Cell::QuasiEx); 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

@ -704,7 +704,7 @@ namespace MWWorld
if (!paused || mFastForward) if (!paused || mFastForward)
{ {
// Add new transitions when either the player's current external region changes. // Add new transitions when either the player's current external region changes.
if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->mRegion)) if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->getRegion()))
{ {
auto it = mRegions.find(mCurrentRegion); auto it = mRegions.find(mCurrentRegion);
if (it != mRegions.end()) if (it != mRegions.end())

View file

@ -23,7 +23,7 @@
#include <components/esm3/loadmgef.hpp> #include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadregn.hpp> #include <components/esm3/loadregn.hpp>
#include <components/esm3/loadstat.hpp> #include <components/esm3/loadstat.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
@ -634,19 +634,23 @@ namespace MWWorld
{ {
if (!cell) if (!cell)
cell = mWorldScene->getCurrentCell(); cell = mWorldScene->getCurrentCell();
return getCellName(cell->getCell()); return getCellName(cell->getCellVariant());
} }
std::string_view World::getCellName(const ESM::Cell* cell) const std::string_view World::getCellName(const ESM::CellVariant& cell) const
{ {
if (cell) auto cellCommon = cell.getCommon();
if (cellCommon)
{ {
if (!cell->isExterior() || !cell->mName.empty()) if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty())
return cell->mName; return cellCommon->getEditorName();
if (const ESM::Region* region = mStore.get<ESM::Region>().search(cell->mRegion)) if (cell.getEsm3())
{
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();
} }
@ -1139,7 +1143,7 @@ namespace MWWorld
{ {
if (!newCell->isExterior()) if (!newCell->isExterior())
{ {
changeToInteriorCell(newCell->getCell()->mName, pos, false); changeToInteriorCell(newCell->getCell()->getEditorName(), pos, false);
removeContainerScripts(getPlayerPtr()); removeContainerScripts(getPlayerPtr());
} }
else else
@ -1400,7 +1404,7 @@ namespace MWWorld
esmPos.pos[2] = traced.z(); esmPos.pos[2] = traced.z();
std::string_view cell; std::string_view cell;
if (!actor.getCell()->isExterior()) if (!actor.getCell()->isExterior())
cell = actor.getCell()->getCell()->mName; cell = actor.getCell()->getCell()->getEditorName();
MWWorld::ActionTeleport(cell, esmPos, false).execute(actor); MWWorld::ActionTeleport(cell, esmPos, false).execute(actor);
} }
} }
@ -1988,10 +1992,7 @@ namespace MWWorld
const CellStore* currentCell = mWorldScene->getCurrentCell(); const CellStore* currentCell = mWorldScene->getCurrentCell();
if (currentCell) if (currentCell)
{ {
if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) return currentCell->getCell()->isQuasiExterior();
return false;
else
return true;
} }
return false; return false;
} }
@ -2312,7 +2313,7 @@ namespace MWWorld
if (!cell) if (!cell)
return false; return false;
if (!(cell->getCell()->hasWater())) if (!(cell->getCellVariant().getCommon()->hasWater()))
{ {
return false; return false;
} }
@ -2468,8 +2469,7 @@ namespace MWWorld
|| isFlying(player)) || isFlying(player))
return Rest_PlayerIsInAir; return Rest_PlayerIsInAir;
if ((currentCell->getCell()->mData.mFlags & ESM::Cell::NoSleep) if (currentCell->getCell()->noSleep() || player.getClass().getNpcStats(player).isWerewolf())
|| player.getClass().getNpcStats(player).isWerewolf())
return Rest_OnlyWaiting; return Rest_OnlyWaiting;
return Rest_Allowed; return Rest_Allowed;
@ -2840,7 +2840,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::Cell* ext = nullptr; const ESM::CellCommon* ext = nullptr;
try try
{ {
ext = mWorldModel.getCell(nameId)->getCell(); ext = mWorldModel.getCell(nameId)->getCell();
@ -3247,9 +3247,11 @@ namespace MWWorld
} }
else else
{ {
uint32_t ambient = cell->getCell()->mAmbi.mAmbient; auto cellVariant = cell->getCellVariant();
uint32_t ambient = cellVariant.getEsm3() ? cellVariant.getEsm3()->mAmbi.mAmbient
: 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()->mData.mFlags & ESM::Cell::NoSleep) && ambientTotal <= 201; return !cell->getCell()->noSleep() && ambientTotal <= 201;
} }
} }
@ -3328,7 +3330,7 @@ namespace MWWorld
std::set<std::string_view> nextCells; std::set<std::string_view> nextCells;
MWWorld::ConstPtr closestMarker; MWWorld::ConstPtr closestMarker;
nextCells.insert(ptr.getCell()->getCell()->mName); nextCells.insert(ptr.getCell()->getCell()->getEditorName());
while (!nextCells.empty()) while (!nextCells.empty())
{ {
currentCells = nextCells; currentCells = nextCells;
@ -3423,7 +3425,7 @@ namespace MWWorld
std::string_view cellName = ""; std::string_view cellName = "";
if (!closestMarker.mCell->isExterior()) if (!closestMarker.mCell->isExterior())
cellName = closestMarker.mCell->getCell()->mName; cellName = closestMarker.mCell->getCell()->getEditorName();
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false);
action.execute(ptr); action.execute(ptr);
@ -3436,7 +3438,7 @@ namespace MWWorld
{ {
mPlayer->setTeleported(false); mPlayer->setTeleported(false);
const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->mRegion; const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->getRegion();
mWeatherManager->playerTeleported(playerRegion, isExterior); mWeatherManager->playerTeleported(playerRegion, isExterior);
} }

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::Cell* cell) const override; std::string_view getCellName(const ESM::CellVariant& 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(cell, mStore, mReaders)).first; result = mInteriors.emplace(cell->mName, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first;
return &result->second; return &result->second;
} }
@ -78,7 +78,8 @@ 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()), CellStore(cell, mStore, mReaders)) .emplace(std::make_pair(cell->getGridX(), cell->getGridY()),
CellStore(ESM::CellVariant(cell), mStore, mReaders))
.first; .first;
return &result->second; return &result->second;
@ -185,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(cell, mStore, mReaders)).first; result = mExteriors.emplace(std::make_pair(x, y), CellStore(ESM::CellVariant(cell), mStore, mReaders)).first;
} }
if (result->second.getState() != CellStore::State_Loaded) if (result->second.getState() != CellStore::State_Loaded)
@ -207,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(cell, mStore, mReaders)).first; result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first;
} }
else else
{ {
result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first; result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell4), mStore, mReaders)).first;
} }
} }
@ -261,14 +262,14 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name)
return cell; return cell;
} }
MWWorld::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name)
{ {
const ESM::Cell* cellEsm3 = getESMCellByName(name); const ESM::Cell* cellEsm3 = getESMCellByName(name);
return cellEsm3; return ESM::CellVariant(cellEsm3);
if (!cellEsm3) if (!cellEsm3)
{ {
const ESM4::Cell* cellESM4 = mStore.get<ESM4::Cell>().searchCellName(name); const ESM4::Cell* cellESM4 = mStore.get<ESM4::Cell>().searchCellName(name);
return cellESM4; return ESM::CellVariant(cellESM4);
} }
} }

View file

@ -51,7 +51,7 @@ namespace MWWorld
WorldModel& operator=(const WorldModel&); WorldModel& operator=(const WorldModel&);
const ESM::Cell* getESMCellByName(std::string_view name); const ESM::Cell* getESMCellByName(std::string_view name);
CellVariant getCellByName(std::string_view name); ESM::CellVariant getCellByName(std::string_view name);
CellStore* getCellStore(const ESM::Cell* cell); CellStore* getCellStore(const ESM::Cell* cell);
Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore); Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore);

View file

@ -5,6 +5,7 @@
#include <boost/program_options/options_description.hpp> #include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp> #include <boost/program_options/variables_map.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp> #include <components/esm3/esmwriter.hpp>
@ -316,7 +317,7 @@ static void testRecNameIntCount(const MWWorld::Store<T>& store, const MWWorld::E
const unsigned int recordIdCount const unsigned int recordIdCount
= std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores);
ASSERT_EQ(recordIdCount, static_cast<unsigned int>(1)) ASSERT_EQ(recordIdCount, static_cast<unsigned int>(1))
<< "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView(); << "The same RecNameInt is used twice ESM::REC_" << ESM::getRecNameString(T::sRecordId).toStringView();
} }
} }

View file

@ -80,7 +80,7 @@ add_component_dir (to_utf8
to_utf8 to_utf8
) )
add_component_dir(esm attr common defs esmcommon records util luascripts format refid) add_component_dir(esm attr common defs esmcommon records util luascripts format refid cellcommon)
add_component_dir(fx pass technique lexer widgets stateupdater) add_component_dir(fx pass technique lexer widgets stateupdater)

View file

@ -0,0 +1,15 @@
#include <components/esm/cellcommon.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
namespace ESM
{
const ESM::CellCommon* CellVariant::getCommon() const
{
auto cell3 = getEsm3();
if (cell3)
return cell3;
else
return getEsm4();
}
}

View file

@ -0,0 +1,68 @@
#ifndef COMPONENTS_ESM_CELLCOMMON
#define COMPONENTS_ESM_CELLCOMMON
#include <string>
#include <string_view>
#include <variant>
namespace ESM4
{
struct Cell;
}
namespace ESM
{
struct Cell;
struct CellId;
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
{
std::variant<const ESM4::Cell*, const ESM::Cell*> mVariant;
explicit CellVariant(const ESM4::Cell* cell)
: mVariant(cell)
{
}
explicit CellVariant(const ESM::Cell* cell)
: mVariant(cell)
{
}
bool isEsm4() const { return getEsm4(); }
const ESM4::Cell* getEsm4() const
{
auto cell4 = std::get_if<const ESM4::Cell*>(&mVariant);
if (cell4)
return *cell4;
return nullptr;
}
const ESM::Cell* getEsm3() const
{
auto cell3 = std::get_if<const ESM::Cell*>(&mVariant);
if (cell3)
return *cell3;
return nullptr;
}
const ESM::CellCommon* getCommon() const;
};
}
#endif

View file

@ -31,7 +31,7 @@ namespace ESM
bool operator==(const CellId& left, const CellId& right) bool operator==(const CellId& left, const CellId& right)
{ {
return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged return left.mWorld == right.mWorld && left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged
&& (!left.mPaged || (left.mIndex.mX == right.mIndex.mX && left.mIndex.mY == right.mIndex.mY)); && (!left.mPaged || (left.mIndex.mX == right.mIndex.mX && left.mIndex.mY == right.mIndex.mY));
} }

View file

@ -17,6 +17,7 @@ namespace ESM
int mY; int mY;
}; };
ESM::RefId mWorld;
std::string mWorldspace; std::string mWorldspace;
CellIndex mIndex; CellIndex mIndex;
bool mPaged; bool mPaged;

View file

@ -7,6 +7,7 @@
#include "cellid.hpp" #include "cellid.hpp"
#include "cellref.hpp" #include "cellref.hpp"
#include "components/esm/cellcommon.hpp"
#include "components/esm/defs.hpp" #include "components/esm/defs.hpp"
#include "components/esm/esmcommon.hpp" #include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp" #include "components/esm/refid.hpp"
@ -65,7 +66,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 struct Cell : public CellCommon
{ {
constexpr static RecNameInts sRecordId = REC_CELL; constexpr static RecNameInts sRecordId = REC_CELL;
@ -150,13 +151,14 @@ 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 { return !(mData.mFlags & Interior); } bool isExterior() const override { return !(mData.mFlags & Interior); }
bool isQuasiExterior() const override { return mData.mFlags & QuasiEx; }
int getGridX() const { return mData.mX; } int getGridX() const override { return mData.mX; }
int getGridY() const { return mData.mY; } int getGridY() const override { return mData.mY; }
bool hasWater() const { return ((mData.mFlags & HasWater) != 0) || isExterior(); } bool hasWater() const override { return ((mData.mFlags & HasWater) != 0) || isExterior(); }
bool hasAmbient() const { return mHasAmbi; } bool hasAmbient() const { return mHasAmbi; }
@ -169,7 +171,7 @@ namespace ESM
// exactly. // exactly.
void restore(ESMReader& esm, int iCtx) const; void restore(ESMReader& esm, int iCtx) const;
std::string getDescription() const; std::string getDescription() const override;
///< 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
@ -191,7 +193,10 @@ 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; const CellId& getCellId() const override;
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

@ -39,6 +39,7 @@
// #include "writer.hpp" // #include "writer.hpp"
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include <components/misc/algorithm.hpp>
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
// //
@ -77,6 +78,12 @@ void ESM4::Cell::load(ESM4::Reader& reader)
std::uint32_t esmVer = reader.esmVersion(); std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
mCellId.mWorldspace = Misc::StringUtils::lowerCase(mEditorId);
mCellId.mWorld = ESM::RefId::sEmpty;
mCellId.mIndex.mX = getGridX();
mCellId.mIndex.mX = getGridY();
mCellId.mPaged = isExterior();
while (reader.getSubRecordHeader()) while (reader.getSubRecordHeader())
{ {
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();

View file

@ -34,8 +34,10 @@
#include "formid.hpp" #include "formid.hpp"
#include "lighting.hpp" #include "lighting.hpp"
#include <components/esm/cellcommon.hpp>
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include <components/esm3/cellid.hpp>
namespace ESM4 namespace ESM4
{ {
@ -60,7 +62,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 struct Cell final : public ESM::CellCommon
{ {
FormId mParent; // world formId (for grouping cells), from the loading sequence FormId mParent; // world formId (for grouping cells), from the loading sequence
@ -94,12 +96,24 @@ 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;
void blank(); void blank();
static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4; static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4;
int getGridX() const override { return mX; }
int getGridY() const override { return mY; }
bool isExterior() const override { return false; /*unimplemented for now*/ }
virtual bool isQuasiExterior() const override { return false; /*unimplemented for now*/ }
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

@ -17,8 +17,8 @@ namespace Misc
{ {
} }
explicit CoordinateConverter(const ESM::Cell* cell) explicit CoordinateConverter(const ESM::CellCommon* cell)
: CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY) : CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY())
{ {
} }