From 084207af644fa0cba3e0835b53f52b95efadc0aa Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 4 Feb 2023 18:45:53 +0100 Subject: [PATCH] Avoids a lot a special cases for ESM3 vs ESM4 cells. --- apps/openmw/mwmechanics/aicombat.cpp | 8 ++--- apps/openmw/mwmechanics/aipackage.cpp | 7 ++-- apps/openmw/mwmechanics/aiwander.cpp | 18 ++++------ apps/openmw/mwmechanics/aiwander.hpp | 6 +++- apps/openmw/mwmechanics/pathgrid.cpp | 4 +-- apps/openmw/mwmechanics/pathgrid.hpp | 3 +- apps/openmw/mwrender/pathgrid.cpp | 5 ++- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 9 +++-- apps/openmw/mwworld/cell.cpp | 8 ++++- apps/openmw/mwworld/cell.hpp | 3 ++ apps/openmw/mwworld/cellref.cpp | 48 +++++++++++-------------- apps/openmw/mwworld/cellstore.cpp | 47 +++++++++++++----------- apps/openmw/mwworld/cellstore.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 31 +++++++++------- apps/openmw/mwworld/store.cpp | 10 ++++++ apps/openmw/mwworld/store.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 12 ++++--- components/esm/esmbridge.hpp | 9 +++++ 19 files changed, 137 insertions(+), 101 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index e558eedc66..499bc56fc5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -357,13 +357,11 @@ namespace MWMechanics case AiCombatStorage::FleeState_Idle: { float triggerDist = getMaxAttackDistance(target); - auto cellVariant = storage.mCell->getCell(); - if (!cellVariant->isEsm4() && storage.mLOS - && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) + const MWWorld::Cell* cellVariant = storage.mCell->getCell(); + if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search( - cellVariant->getEsm3()); + = MWBase::Environment::get().getWorld()->getStore().get().search(*cellVariant); bool runFallback = true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 8e7b38fa2f..4cb4ca6d6e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -411,14 +411,11 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) { - if (getPlayer().getCell()->getCell()->isEsm4()) - return false; - - const ESM::Cell* playerCell(&getPlayer().getCell()->getCell()->getEsm3()); + const MWWorld::Cell* playerCell = getPlayer().getCell()->getCell(); if (playerCell->isExterior()) { // get actor's distance from origin of center cell - Misc::CoordinateConverter(playerCell).toLocal(position); + Misc::CoordinateConverter(*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. diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f7a7141ecd..7441bf0c86 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -271,9 +271,9 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if (!actor.getCell()->getCell()->isEsm4() && storage.mPopulateAvailableNodes) + if (storage.mPopulateAvailableNodes) { - getAllowedNodes(actor, &actor.getCell()->getCell()->getEsm3(), storage); + getAllowedNodes(actor, actor.getCell()->getCell(), storage); } auto& prng = MWBase::Environment::get().getWorld()->getPrng(); @@ -721,8 +721,8 @@ namespace MWMechanics return; AiWanderStorage& storage = state.get(); - if (!actor.getCell()->getCell()->isEsm4() && storage.mPopulateAvailableNodes) - getAllowedNodes(actor, &actor.getCell()->getCell()->getEsm3(), storage); + if (storage.mPopulateAvailableNodes) + getAllowedNodes(actor, actor.getCell()->getCell(), storage); if (storage.mAllowedNodes.empty()) return; @@ -800,12 +800,8 @@ namespace MWMechanics void AiWander::getNeighbouringNodes( ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { - if (currentCell->getCell()->isEsm4()) - return; - auto cell3 = currentCell->getCell()->getEsm3(); - const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search(cell3); + = MWBase::Environment::get().getWorld()->getStore().get().search(*currentCell->getCell()); if (pathgrid == nullptr || pathgrid->mPoints.empty()) return; @@ -815,7 +811,7 @@ namespace MWMechanics getPathGridGraph(currentCell).getNeighbouringPoints(index, points); } - void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage) + void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const MWWorld::Cell* cell, AiWanderStorage& storage) { // infrequently used, therefore no benefit in caching it as a member const ESM::Pathgrid* pathgrid @@ -839,7 +835,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(*cell); const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); // Find closest pathgrid point diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b5a7aed42..dec80a6d33 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -23,6 +23,10 @@ namespace Misc class CoordinateConverter; } +namespace MWWorld +{ + class Cell; +} namespace MWMechanics { /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. @@ -147,7 +151,7 @@ namespace MWMechanics void getNeighbouringNodes( ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points); - void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage); + void getAllowedNodes(const MWWorld::Ptr& actor, const MWWorld::Cell* cell, AiWanderStorage& storage); void trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder); diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 8c270b8af9..4673045495 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -104,9 +104,7 @@ namespace MWMechanics if (mIsGraphConstructed) return true; - if (cell->getCell()->isEsm4()) - return false; - mCell = &cell->getCell()->getEsm3(); + mCell = cell->getCell(); mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell); if (!mPathgrid) diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index a681033dca..9dd3745a2d 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -13,6 +13,7 @@ namespace ESM namespace MWWorld { class CellStore; + class Cell; } namespace MWMechanics @@ -41,7 +42,7 @@ namespace MWMechanics std::deque aStarSearch(const int start, const int end) const; private: - const ESM::Cell* mCell; + const MWWorld::Cell* mCell; const ESM::Pathgrid* mPathgrid; struct ConnectedPoint // edge diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 8e4db52726..7e4d85bcce 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -102,9 +102,8 @@ namespace MWRender void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) { MWBase::World* world = MWBase::Environment::get().getWorld(); - if (store->getCell()->isEsm4()) - return; - const ESM::Pathgrid* pathgrid = world->getStore().get().search(store->getCell()->getEsm3()); + + const ESM::Pathgrid* pathgrid = world->getStore().get().search(*store->getCell()); if (!pathgrid) return; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 3ef3a19353..1a9680c7d2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -781,10 +781,8 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - if (player.getCell()->getCell()->isEsm4()) - return; - const ESM::Cell* curcell = &player.getCell()->getCell()->getEsm3(); + const MWWorld::Cell* curcell = player.getCell()->getCell(); const auto update = mWaterSoundUpdater.update(player, *world); WaterSoundAction action; @@ -813,7 +811,7 @@ namespace MWSound } std::pair SoundManager::getWaterSoundAction( - const WaterSoundUpdate& update, const ESM::Cell* cell) const + const WaterSoundUpdate& update, const MWWorld::Cell* cell) const { if (mNearWaterSound) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 4cf0b980a8..474c8f50b1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -30,6 +30,11 @@ namespace ESM struct Cell; } +namespace MWWorld +{ + class Cell; +} + namespace MWSound { class Sound_Output; @@ -107,7 +112,7 @@ namespace MWSound float mTimePassed; - const ESM::Cell* mLastCell; + const MWWorld::Cell* mLastCell; Sound* mCurrentRegionSound; @@ -143,7 +148,7 @@ namespace MWSound }; std::pair getWaterSoundAction( - const WaterSoundUpdate& update, const ESM::Cell* cell) const; + const WaterSoundUpdate& update, const MWWorld::Cell* cell) const; SoundManager(const SoundManager& rhs); SoundManager& operator=(const SoundManager& rhs); diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 9444e42136..696e1d21d5 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -25,6 +25,7 @@ namespace MWWorld .mDirectionalColor = cell.mLighting.directional, .mFogColor = cell.mLighting.fogColor, .mFogDensity = cell.mLighting.fogPower,} + ,mWaterHeight(cell.mWaterHeight) { } @@ -45,11 +46,16 @@ namespace MWWorld .mFogColor = cell.mAmbi.mFog, .mFogDensity = cell.mAmbi.mFogDensity, } + ,mWaterHeight(cell.mWater) { } std::string Cell::getDescription() const { - return isEsm4() ? mNameID : getEsm3().getDescription(); + return ESM::visit(ESM::VisitOverload{ + [&](const ESM::Cell& cell) { return cell.getDescription(); }, + [&](const ESM4::Cell& cell) { return cell.mEditorId; }, + }, + *this); } } diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index b90fed31f8..52823d4dab 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -48,6 +48,7 @@ namespace MWWorld std::string_view getDisplayName() const { return mDisplayname; } std::string getDescription() const; const MoodData& getMood() const { return mMood; } + float getWaterHeight() const { return mWaterHeight; } private: bool mIsExterior; @@ -61,6 +62,8 @@ namespace MWWorld ESM::RefId mRegion; ESM::CellId mCellId; MoodData mMood; + + float mWaterHeight; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 34884f8b52..2221ff0dec 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -7,16 +7,6 @@ namespace MWWorld { - // makes it easier to use std visit with a variant - template - struct RefVisit : Ts... - { - using Ts::operator()...; - }; - - template - RefVisit(Ts...) -> RefVisit; - CellRef::CellRef(const ESM::CellRef& ref) : mCellRef(ESM::ReferenceVariant(ref)) { @@ -31,7 +21,7 @@ namespace MWWorld const ESM::RefNum& CellRef::getRefNum() const { - return std::visit(RefVisit{ + return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; }, }, @@ -59,7 +49,7 @@ namespace MWWorld return ref.mRefNum; }; return std::visit( - RefVisit{ + ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, esm3Visit, }, @@ -68,7 +58,7 @@ namespace MWWorld void CellRef::unsetRefNum() { - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; }, }, @@ -79,7 +69,11 @@ namespace MWWorld const std::string& CellRef::getDestCell() const { - return mCellRef.isESM4() ? emptyString : mCellRef.getEsm3().mDestCell; + return std::visit(ESM::VisitOverload{ + [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, + [&](const ESM::CellRef& ref) -> const std::string& { return ref.mDestCell; }, + }, + mCellRef.mVariant); } void CellRef::setScale(float scale) @@ -99,7 +93,7 @@ namespace MWWorld float CellRef::getEnchantmentCharge() const { - return std::visit(RefVisit{ + return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) { return 0.f; }, [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; }, }, @@ -128,7 +122,7 @@ namespace MWWorld { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; }, }, @@ -138,7 +132,7 @@ namespace MWWorld void CellRef::setCharge(int charge) { - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mChargeInt = charge; }, }, @@ -164,7 +158,7 @@ namespace MWWorld } }; std::visit( - RefVisit{ + ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, esm3Visit, }, @@ -173,7 +167,7 @@ namespace MWWorld void CellRef::setChargeFloat(float charge) { - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; }, }, @@ -182,7 +176,7 @@ namespace MWWorld const std::string& CellRef::getGlobalVariable() const { - return std::visit(RefVisit{ + return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; }, }, @@ -194,7 +188,7 @@ namespace MWWorld if (!getGlobalVariable().empty()) { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); }, }, @@ -215,7 +209,7 @@ namespace MWWorld { if (owner != getOwner()) { - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mOwner = owner; }, }, @@ -228,7 +222,7 @@ namespace MWWorld if (soul != getSoul()) { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mSoul = soul; }, }, @@ -241,7 +235,7 @@ namespace MWWorld if (faction != getFaction()) { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mFaction = faction; }, }, @@ -276,7 +270,7 @@ namespace MWWorld if (trap != getTrap()) { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mTrap = trap; }, }, @@ -289,7 +283,7 @@ namespace MWWorld if (value != getGoldValue()) { mChanged = true; - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mGoldValue = value; }, }, @@ -299,7 +293,7 @@ namespace MWWorld void CellRef::writeState(ESM::ObjectState& state) const { - std::visit(RefVisit{ + std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) {}, [&](const ESM::CellRef& ref) { state.mRef = ref; }, }, diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 40bd9107a1..6078feba4c 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -540,8 +540,7 @@ namespace MWWorld { std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); - if (!mCellVariant.isEsm4()) - mWaterLevel = mCellVariant.getEsm3().mWater; + mWaterLevel = mCellVariant.getWaterHeight(); } CellStore::~CellStore() = default; @@ -703,26 +702,20 @@ namespace MWWorld } } - void CellStore::listRefs() + void CellStore::listRefs(const ESM::Cell& cell) { - - if (mCellVariant.isEsm4()) - return; - - const ESM::Cell& cell3 = mCellVariant.getEsm3(); - - if (cell3.mContextList.empty()) + if (cell.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 < cell3.mContextList.size(); i++) + for (size_t i = 0; i < cell.mContextList.size(); i++) { try { // Reopen the ESM reader and seek to the right position. - const std::size_t index = static_cast(cell3.mContextList[i].index); + const std::size_t index = static_cast(cell.mContextList[i].index); const ESM::ReadersCache::BusyItem reader = mReaders.get(index); - cell3.restore(*reader, i); + cell.restore(*reader, i); ESM::CellRef ref; @@ -738,8 +731,8 @@ namespace MWWorld // Don't list reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter - = std::find(cell3.mMovedRefs.begin(), cell3.mMovedRefs.end(), ref.mRefNum); - if (iter != cell3.mMovedRefs.end()) + = std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum); + if (iter != cell.mMovedRefs.end()) { continue; } @@ -755,12 +748,29 @@ namespace MWWorld } // List moved references, from separately tracked list. - for (const auto& [ref, deleted] : cell3.mLeasedRefs) + for (const auto& [ref, deleted] : cell.mLeasedRefs) { if (!deleted) mIds.push_back(ref.mRefID); } + } + void CellStore::listRefs(const ESM4::Cell& cell) + { + auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); + + for (const auto& ref : refs) + { + if (ref.mParent == cell.mId) + { + mIds.push_back(ref.mBaseObj); + } + } + } + + void CellStore::listRefs() + { + ESM::visit([&](auto&& cell) { listRefs(cell); }, mCellVariant); std::sort(mIds.begin(), mIds.end()); } @@ -834,7 +844,7 @@ namespace MWWorld { std::map refNumToID; // used to detect refID modifications - ESM::visit([&refNumToID, this](auto&& cell) { this->loadRefs(cell, refNumToID); }, mCellVariant); + ESM::visit([&](auto&& cell) { loadRefs(cell, refNumToID); }, mCellVariant); updateMergedRefs(); } @@ -930,9 +940,6 @@ namespace MWWorld void CellStore::loadState(const ESM::CellState& state) { - if (mCellVariant.isEsm4()) - return; - mHasState = true; if (!mCellVariant.isExterior() && mCellVariant.hasWater()) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 720aa394b5..9843c8a06a 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -383,6 +383,8 @@ namespace MWWorld private: /// Run through references and store IDs + void listRefs(const ESM::Cell& cell); + void listRefs(const ESM4::Cell& cell); void listRefs(); void loadRefs(const ESM::Cell& cell, std::map& refNumToID); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c3b1ec1ec6..754defc271 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -354,11 +354,14 @@ namespace MWWorld if (cell->getCell()->hasWater()) mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); - if (!cell->getCell()->isEsm4()) - { - if (const auto pathgrid = mWorld.getStore().get().search(cell->getCell()->getEsm3())) - mNavigator.removePathgrid(*pathgrid); - } + ESM::visit(ESM::VisitOverload{ + [&](const ESM::Cell& cell) { + if (const auto pathgrid = mWorld.getStore().get().search(cell)) + mNavigator.removePathgrid(*pathgrid); + }, + [&](const ESM4::Cell& cell) {}, + }, + *cell->getCell()); MWBase::Environment::get().getMechanicsManager()->drop(cell); @@ -430,12 +433,14 @@ namespace MWWorld } } - if (!cellVariant.isEsm4()) - { - const ESM::Cell& cell3 = cellVariant.getEsm3(); - if (const auto pathgrid = mWorld.getStore().get().search(cell3)) - mNavigator.addPathgrid(cell3, *pathgrid); - } + ESM::visit(ESM::VisitOverload{ + [&](const ESM::Cell& cell) { + if (const auto pathgrid = mWorld.getStore().get().search(cell)) + mNavigator.addPathgrid(cell, *pathgrid); + }, + [&](const ESM4::Cell& cell) {}, + }, + *cell->getCell()); // register local scripts // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice @@ -449,7 +454,7 @@ namespace MWWorld mRendering.addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell); - bool waterEnabled = (!cellVariant.isEsm4()) && (cellVariant.hasWater() || cell->isExterior()); + bool waterEnabled = cellVariant.hasWater() || cell->isExterior(); float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) @@ -457,7 +462,7 @@ namespace MWWorld mPhysics->enableWater(waterLevel); mRendering.setWaterHeight(waterLevel); - if (cellVariant.getEsm3().isExterior()) + if (cellVariant.isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) mNavigator.addWater( diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index e995a6c1ab..19b07c0725 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace { // TODO: Switch to C++23 to get a working version of std::unordered_map::erase @@ -961,6 +963,14 @@ namespace MWWorld else return search(ESM::RefId::stringRefId(cell.mName)); } + const ESM::Pathgrid* Store::search(const MWWorld::Cell& cellVariant) const + { + return ESM::visit(ESM::VisitOverload{ + [&](const ESM::Cell& cell) { return search(cell); }, + [&](const ESM4::Cell& cell) -> const ESM::Pathgrid* { return nullptr; }, + }, + cellVariant); + } const ESM::Pathgrid* Store::find(const ESM::Cell& cell) const { if (!(cell.mData.mFlags & ESM::Cell::Interior)) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 59b3b8a172..bb511f9635 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -39,6 +39,7 @@ namespace Loading namespace MWWorld { + class Cell; struct RecordId { ESM::RefId mId; @@ -430,6 +431,7 @@ namespace MWWorld const ESM::Pathgrid* find(int x, int y) const; const ESM::Pathgrid* find(const ESM::RefId& name) const; const ESM::Pathgrid* search(const ESM::Cell& cell) const; + const ESM::Pathgrid* search(const MWWorld::Cell& cell) const; const ESM::Pathgrid* find(const ESM::Cell& cell) const; }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8f213df71f..144a7df4c5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -642,11 +642,13 @@ namespace MWWorld if (!cell.isExterior() || !cell.getNameId().empty()) return cell.getNameId(); - if (!cell.isEsm4()) - { - return getCellName(&cell.getEsm3()); - } - return mStore.get().find("sDefaultCellname")->mValue.getString(); + return ESM::visit(ESM::VisitOverload{ + [&](const ESM::Cell& cellIn) -> std::string_view { return getCellName(&cellIn); }, + [&](const ESM4::Cell& cellIn) -> std::string_view { + return mStore.get().find("sDefaultCellname")->mValue.getString(); + }, + }, + cell); } std::string_view World::getCellName(const ESM::Cell* cell) const diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index 83e858d7b6..5576fccc03 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -70,5 +70,14 @@ namespace ESM { return std::visit([&](auto*... ptr) { return std::forward(f)(*ptr...); }, std::forward(v).mVariant...); } + + template + struct VisitOverload : Ts... + { + using Ts::operator()...; + }; + + template + VisitOverload(Ts...) -> VisitOverload; } #endif