1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-31 04:36:40 +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 TimeStamp;
struct RefId;
struct CellVariant;
}
namespace MWPhysics
@ -179,7 +181,7 @@ namespace MWBase
///
/// \note If cell==0, the cell the player is currently in will be used instead to
/// 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;
//< Remove the script attached to ref from mLocalScripts

View file

@ -307,7 +307,7 @@ namespace MWClass
const osg::Vec2i index
= 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());
dest = world->getCellName(cell);
dest = world->getCellName(ESM::CellVariant(cell));
}
return "#{sCell=" + std::string{ dest } + "}";

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
#include "luabindings.hpp"
#include <components/esm/cellcommon.hpp>
#include <components/esm/records.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::to_string] = [](const CellT& c) {
const ESM::Cell* cell = c.mStore->getCell();
auto cell = c.mStore->getCell();
std::stringstream res;
if (cell->isExterior())
res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")";
else
res << "interior(" << cell->mName << ")";
res << "interior(" << cell->getEditorName() << ")";
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"]
= 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["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["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(); });
// deprecated, use cell:hasTag("QuasiExterior") instead
cellT["isQuasiExterior"] = sol::readonly_property(
[](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; });
cellT["isQuasiExterior"]
= sol::readonly_property([](const CellT& c) { return (c.mStore->getCell()->isQuasiExterior()) != 0; });
cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool {
if (tag == "NoSleep")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0;
return (c.mStore->getCell()->noSleep()) != 0;
else if (tag == "QuasiExterior")
return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0;
return (c.mStore->getCell()->isQuasiExterior()) != 0;
return false;
};

View file

@ -176,12 +176,12 @@ namespace MWLua
// TODO: change AiEscort implementation to accept ptr instead of a non-unique refId.
const ESM::RefId& refId = target.ptr().getCellRef().getRefId();
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())
ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
else
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);
};
selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) {

View file

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

View file

@ -357,12 +357,12 @@ namespace MWMechanics
case AiCombatStorage::FleeState_Idle:
{
float triggerDist = getMaxAttackDistance(target);
if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
auto cell3 = storage.mCell->getCellVariant().getEsm3();
if (cell3 && storage.mLOS
&& (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
{
const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(
*storage.mCell->getCell());
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell3);
bool runFallback = true;

View file

@ -174,7 +174,8 @@ namespace MWMechanics
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;
return true;

View file

@ -411,7 +411,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const
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())
{
// 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.
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();
@ -721,8 +722,9 @@ namespace MWMechanics
return;
AiWanderStorage& storage = state.get<AiWanderStorage>();
if (storage.mPopulateAvailableNodes)
getAllowedNodes(actor, actor.getCell()->getCell(), storage);
auto cell3 = actor.getCell()->getCellVariant().getEsm3();
if (cell3 && storage.mPopulateAvailableNodes)
getAllowedNodes(actor, cell3, storage);
if (storage.mAllowedNodes.empty())
return;
@ -800,8 +802,11 @@ namespace MWMechanics
void AiWander::getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
{
auto cell3 = currentCell->getCellVariant().getEsm3();
if (!cell3)
return;
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())
return;

View file

@ -12,6 +12,7 @@
namespace ESM
{
struct Cell;
struct CellCommon;
namespace AiSequence
{
struct AiWander;
@ -158,6 +159,8 @@ namespace MWMechanics
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 addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage,

View file

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

View file

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

View file

@ -2,7 +2,9 @@
#include <algorithm>
#include <components/esm/cellcommon.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/fallback/fallback.hpp>
#include <components/sceneutil/util.hpp>
#include <components/settings/settings.hpp>
@ -38,13 +40,17 @@ namespace MWRender
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)
{
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
float density = std::max(0.2f, fogDensity);
mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density;
mLandFogEnd = DLInteriorFogEnd;
mUnderwaterFogStart = DLUnderwaterFogStart;
@ -52,7 +58,7 @@ namespace MWRender
mFogColor = color;
}
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,

View file

@ -5,7 +5,7 @@
namespace ESM
{
struct Cell;
struct CellVariant;
}
namespace MWRender
@ -15,7 +15,7 @@ namespace MWRender
public:
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,
const osg::Vec4f& color);

View file

@ -102,7 +102,10 @@ namespace MWRender
void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store)
{
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)
return;

View file

@ -49,6 +49,7 @@
#include <components/terrain/terraingrid.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/debug/debugdraw.hpp>
#include <components/detournavigator/navigator.hpp>
@ -739,14 +740,24 @@ namespace MWRender
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;
if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP)
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)
{
@ -770,7 +781,9 @@ namespace MWRender
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);
const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f);
@ -890,7 +903,7 @@ namespace MWRender
return false;
}
void RenderingManager::configureFog(const ESM::Cell* cell)
void RenderingManager::configureFog(const ESM::CellVariant& cell)
{
mFog->configure(mViewDistance, cell);
}
@ -1424,7 +1437,7 @@ namespace MWRender
mMinimumAmbientLuminance
= std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
if (MWMechanics::getPlayer().isInCell())
configureAmbient(MWMechanics::getPlayer().getCell()->getCell());
configureAmbient(MWMechanics::getPlayer().getCell()->getCellVariant());
}
else if (it->first == "Shaders"
&& (it->second == "light bounds multiplier" || it->second == "maximum light distance"

View file

@ -43,6 +43,7 @@ namespace ESM
{
struct Cell;
struct RefNum;
struct CellVariant;
}
namespace Terrain
@ -140,8 +141,8 @@ namespace MWRender
void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis);
void setNight(bool isNight) { mNight = isNight; }
void configureAmbient(const ESM::Cell* cell);
void configureFog(const ESM::Cell* cell);
void configureAmbient(const ESM::CellVariant& cell);
void configureFog(const ESM::CellVariant& cell);
void configureFog(
float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour);

View file

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

View file

@ -766,14 +766,14 @@ namespace MWSound
{
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::ConstPtr player = world->getPlayerPtr();
const ESM::Cell* cell = player.getCell()->getCell();
auto cell = player.getCell()->getCell();
if (!cell->isExterior())
return;
if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound))
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);
}
@ -781,7 +781,7 @@ namespace MWSound
{
MWBase::World* world = MWBase::Environment::get().getWorld();
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);
WaterSoundAction action;

View file

@ -505,7 +505,7 @@ namespace MWWorld
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)
, mReaders(readers)
, mCellVariant(cell)
@ -526,12 +526,12 @@ namespace MWWorld
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;
}
@ -1087,8 +1087,11 @@ namespace MWWorld
auto cell4Left = mCellVariant.getEsm4();
auto cell4Right = right.mCellVariant.getEsm4();
auto cell3Left = mCellVariant.getEsm3();
auto cell3Right = right.mCellVariant.getEsm3();
if (!cell4Left && !cell4Right)
return getCell()->getCellId() == right.getCell()->getCellId();
return cell3Left->getCellId() == cell3Right->getCellId();
else if (cell4Left && cell4Right)
return cell4Left->mId == cell4Right->mId;
else
@ -1299,4 +1302,5 @@ namespace MWWorld
}
return {};
}
}

View file

@ -9,11 +9,13 @@
#include <string_view>
#include <tuple>
#include <typeinfo>
#include <variant>
#include <vector>
#include "cellreflist.hpp"
#include "livecellref.hpp"
#include <components/esm/cellcommon.hpp>
#include <components/esm/refid.hpp>
#include <components/esm3/fogstate.hpp>
#include <components/misc/tuplemeta.hpp>
@ -49,6 +51,7 @@ namespace ESM
struct Static;
struct Weapon;
struct BodyPart;
struct CellCommon;
}
namespace ESM4
@ -64,39 +67,6 @@ namespace MWWorld
class ESMStore;
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>,
CellRefList<ESM::Apparatus>, CellRefList<ESM::Armor>, CellRefList<ESM::Book>, CellRefList<ESM::Clothing>,
CellRefList<ESM::Container>, CellRefList<ESM::Creature>, CellRefList<ESM::Door>, CellRefList<ESM::Ingredient>,
@ -129,7 +99,7 @@ namespace MWWorld
std::unique_ptr<ESM::FogState> mFogState;
const ESM::Cell* mCell;
CellVariant mCellVariant;
ESM::CellVariant mCellVariant;
State mState;
bool mHasState;
std::vector<ESM::RefId> mIds;
@ -224,12 +194,12 @@ namespace MWWorld
}
/// @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();
const ESM::Cell* getCell() const;
CellVariant getCellVariant() const;
const ESM::CellCommon* getCell() const;
ESM::CellVariant getCellVariant() const;
std::string_view getEditorName() const;

View file

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

View file

@ -704,7 +704,7 @@ namespace MWWorld
if (!paused || mFastForward)
{
// 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);
if (it != mRegions.end())

View file

@ -23,7 +23,7 @@
#include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadregn.hpp>
#include <components/esm3/loadstat.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/misc/constants.hpp>
@ -634,18 +634,22 @@ namespace MWWorld
{
if (!cell)
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())
return cell->mName;
if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty())
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 mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
@ -1139,7 +1143,7 @@ namespace MWWorld
{
if (!newCell->isExterior())
{
changeToInteriorCell(newCell->getCell()->mName, pos, false);
changeToInteriorCell(newCell->getCell()->getEditorName(), pos, false);
removeContainerScripts(getPlayerPtr());
}
else
@ -1400,7 +1404,7 @@ namespace MWWorld
esmPos.pos[2] = traced.z();
std::string_view cell;
if (!actor.getCell()->isExterior())
cell = actor.getCell()->getCell()->mName;
cell = actor.getCell()->getCell()->getEditorName();
MWWorld::ActionTeleport(cell, esmPos, false).execute(actor);
}
}
@ -1988,10 +1992,7 @@ namespace MWWorld
const CellStore* currentCell = mWorldScene->getCurrentCell();
if (currentCell)
{
if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
return false;
else
return true;
return currentCell->getCell()->isQuasiExterior();
}
return false;
}
@ -2312,7 +2313,7 @@ namespace MWWorld
if (!cell)
return false;
if (!(cell->getCell()->hasWater()))
if (!(cell->getCellVariant().getCommon()->hasWater()))
{
return false;
}
@ -2468,8 +2469,7 @@ namespace MWWorld
|| isFlying(player))
return Rest_PlayerIsInAir;
if ((currentCell->getCell()->mData.mFlags & ESM::Cell::NoSleep)
|| player.getClass().getNpcStats(player).isWerewolf())
if (currentCell->getCell()->noSleep() || player.getClass().getNpcStats(player).isWerewolf())
return Rest_OnlyWaiting;
return Rest_Allowed;
@ -2840,7 +2840,7 @@ namespace MWWorld
{
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
const ESM::Cell* ext = nullptr;
const ESM::CellCommon* ext = nullptr;
try
{
ext = mWorldModel.getCell(nameId)->getCell();
@ -3247,9 +3247,11 @@ namespace MWWorld
}
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);
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;
MWWorld::ConstPtr closestMarker;
nextCells.insert(ptr.getCell()->getCell()->mName);
nextCells.insert(ptr.getCell()->getCell()->getEditorName());
while (!nextCells.empty())
{
currentCells = nextCells;
@ -3423,7 +3425,7 @@ namespace MWWorld
std::string_view cellName = "";
if (!closestMarker.mCell->isExterior())
cellName = closestMarker.mCell->getCell()->mName;
cellName = closestMarker.mCell->getCell()->getEditorName();
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false);
action.execute(ptr);
@ -3436,7 +3438,7 @@ namespace MWWorld
{
mPlayer->setTeleported(false);
const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->mRegion;
const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->getRegion();
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
/// 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;
//< 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);
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;
}
@ -78,7 +78,8 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
if (result == mExteriors.end())
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;
return &result->second;
@ -185,7 +186,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
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)
@ -207,11 +208,11 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
if (!cell4)
{
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
{
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;
}
MWWorld::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name)
ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name)
{
const ESM::Cell* cellEsm3 = getESMCellByName(name);
return cellEsm3;
return ESM::CellVariant(cellEsm3);
if (!cellEsm3)
{
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&);
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);
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/variables_map.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.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
= std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores);
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
)
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)

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

View file

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

View file

@ -7,6 +7,7 @@
#include "cellid.hpp"
#include "cellref.hpp"
#include "components/esm/cellcommon.hpp"
#include "components/esm/defs.hpp"
#include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp"
@ -65,7 +66,7 @@ namespace ESM
(using ESMReader::getContext()) and jumping back into place
whenever we need to load a given cell.
*/
struct Cell
struct Cell : public CellCommon
{
constexpr static RecNameInts sRecordId = REC_CELL;
@ -150,13 +151,14 @@ namespace ESM
void save(ESMWriter& esm, bool isDeleted = false) 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; }
@ -169,7 +171,7 @@ namespace ESM
// exactly.
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)
/* Get the next reference in this cell, if any. Returns false when
@ -191,7 +193,10 @@ namespace ESM
void blank();
///< 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

View file

@ -39,6 +39,7 @@
// #include "writer.hpp"
#include <components/esm/refid.hpp>
#include <components/misc/algorithm.hpp>
// 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();
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())
{
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();

View file

@ -34,8 +34,10 @@
#include "formid.hpp"
#include "lighting.hpp"
#include <components/esm/cellcommon.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#include <components/esm3/cellid.hpp>
namespace ESM4
{
@ -60,7 +62,7 @@ namespace ESM4
// Unlike TES3, multiple cells can have the same exterior co-ordinates.
// 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
@ -94,12 +96,24 @@ namespace ESM4
CellGroup* mCellGroup;
ESM::CellId mCellId;
void load(ESM4::Reader& reader);
// void save(ESM4::Writer& writer) const;
void blank();
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)
: CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY)
explicit CoordinateConverter(const ESM::CellCommon* cell)
: CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY())
{
}