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

Better handling of the esm3 vs esm4 cell problem

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

View File

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

View File

@ -94,6 +94,7 @@ namespace MWWorld
class TimeStamp;
class ESMStore;
class RefData;
struct Cell;
typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList;
}
@ -181,7 +182,7 @@ namespace MWBase
///
/// \note If cell==0, the cell the player is currently in will be used instead to
/// generate a name.
virtual std::string_view getCellName(const ESM::CellVariant& cell) const = 0;
virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0;
virtual void removeRefScript(MWWorld::RefData* ref) = 0;
//< 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(ESM::CellVariant(cell));
dest = world->getCellName(MWWorld::Cell(cell));
}
return "#{sCell=" + std::string{ dest } + "}";

View File

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

View File

@ -176,7 +176,7 @@ 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::CellCommon* esmCell = cell.mStore->getCell();
auto* esmCell = cell.mStore->getCell();
if (esmCell->isExterior())
ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
else

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,6 +74,7 @@ namespace DetourNavigator
namespace MWWorld
{
class GroundcoverStore;
struct Cell;
}
namespace Debug
@ -141,8 +142,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::CellVariant& cell);
void configureFog(const ESM::CellVariant& cell);
void configureAmbient(const MWWorld::Cell& cell);
void configureFog(const MWWorld::Cell& cell);
void configureFog(
float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -269,7 +269,7 @@ namespace MWWorld
///
/// \note If cell==0, the cell the player is currently in will be used instead to
/// generate a name.
std::string_view getCellName(const ESM::CellVariant& cell) const override;
std::string_view getCellName(const MWWorld::Cell& cell) const override;
void removeRefScript(MWWorld::RefData* ref) override;
//< 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(ESM::CellVariant(cell), mStore, mReaders)).first;
result = mInteriors.emplace(cell->mName, CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
return &result->second;
}
@ -79,7 +79,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
if (result == mExteriors.end())
result = mExteriors
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()),
CellStore(ESM::CellVariant(cell), mStore, mReaders))
CellStore(MWWorld::Cell(cell), mStore, mReaders))
.first;
return &result->second;
@ -186,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(ESM::CellVariant(cell), mStore, mReaders)).first;
result = mExteriors.emplace(std::make_pair(x, y), CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
}
if (result->second.getState() != CellStore::State_Loaded)
@ -208,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(ESM::CellVariant(cell), mStore, mReaders)).first;
result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell), mStore, mReaders)).first;
}
else
{
result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell4), mStore, mReaders)).first;
result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell4), mStore, mReaders)).first;
}
}

View File

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

View File

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

View File

@ -16,20 +16,6 @@ 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
{
@ -61,8 +47,6 @@ namespace ESM
const ESM4::Cell& getEsm4() const;
const ESM::Cell& getEsm3() const;
const ESM::CellCommon* getCommon() const;
};
}

View File

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

View File

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

View File

@ -35,7 +35,6 @@
#include "lighting.hpp"
#include <components/esm/defs.hpp>
#include <components/esm/esm3esm4bridge.hpp>
#include <components/esm/refid.hpp>
#include <components/esm3/cellid.hpp>
@ -62,7 +61,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 final : public ESM::CellCommon
struct Cell
{
FormId mParent; // world formId (for grouping cells), from the loading sequence
@ -96,8 +95,6 @@ namespace ESM4
CellGroup* mCellGroup;
ESM::CellId mCellId;
void load(ESM4::Reader& reader);
// void save(ESM4::Writer& writer) const;
@ -105,15 +102,9 @@ namespace ESM4
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 !(mCellFlags & CELL_Interior); }
virtual bool isQuasiExterior() const override { return mCellFlags & CELL_QuasiExt; }
virtual bool hasWater() const override { return false; /*unimplemented for now*/ }
const ESM::CellId& getCellId() const override { return mCellId; }
const ESM::RefId& getRegion() const override { return ESM::RefId::sEmpty; }
std::string_view getEditorName() const override { return mEditorId; }
std::string getDescription() const override { return mEditorId; }
int getGridX() const { return mX; }
int getGridY() const { return mY; }
bool isExterior() const { return !(mCellFlags & CELL_Interior); }
};
}

View File

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