Avoids a lot a special cases for ESM3 vs ESM4 cells.

This commit is contained in:
florent.teppe 2023-02-04 18:45:53 +01:00
parent f3d5f6345e
commit 084207af64
19 changed files with 137 additions and 101 deletions

View file

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

View file

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

View file

@ -271,9 +271,9 @@ namespace MWMechanics
} }
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed node points for this actor.
if (!actor.getCell()->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(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
@ -721,8 +721,8 @@ namespace MWMechanics
return; return;
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
if (!actor.getCell()->getCell()->isEsm4() && storage.mPopulateAvailableNodes) if (storage.mPopulateAvailableNodes)
getAllowedNodes(actor, &actor.getCell()->getCell()->getEsm3(), storage); getAllowedNodes(actor, actor.getCell()->getCell(), storage);
if (storage.mAllowedNodes.empty()) if (storage.mAllowedNodes.empty())
return; return;
@ -800,12 +800,8 @@ namespace MWMechanics
void AiWander::getNeighbouringNodes( void AiWander::getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
{ {
if (currentCell->getCell()->isEsm4())
return;
auto cell3 = currentCell->getCell()->getEsm3();
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(cell3); = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*currentCell->getCell());
if (pathgrid == nullptr || pathgrid->mPoints.empty()) if (pathgrid == nullptr || pathgrid->mPoints.empty())
return; return;
@ -815,7 +811,7 @@ namespace MWMechanics
getPathGridGraph(currentCell).getNeighbouringPoints(index, points); 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 // infrequently used, therefore no benefit in caching it as a member
const ESM::Pathgrid* pathgrid const ESM::Pathgrid* pathgrid
@ -839,7 +835,7 @@ namespace MWMechanics
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor)) if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
{ {
// get NPC's position in local (i.e. cell) coordinates // get NPC's position in local (i.e. cell) coordinates
auto converter = Misc::CoordinateConverter(cell); auto converter = Misc::CoordinateConverter(*cell);
const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition);
// Find closest pathgrid point // Find closest pathgrid point

View file

@ -23,6 +23,10 @@ namespace Misc
class CoordinateConverter; class CoordinateConverter;
} }
namespace MWWorld
{
class Cell;
}
namespace MWMechanics namespace MWMechanics
{ {
/// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
@ -147,7 +151,7 @@ namespace MWMechanics
void getNeighbouringNodes( void getNeighbouringNodes(
ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points); ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points);
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<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder); void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);

View file

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

View file

@ -13,6 +13,7 @@ namespace ESM
namespace MWWorld namespace MWWorld
{ {
class CellStore; class CellStore;
class Cell;
} }
namespace MWMechanics namespace MWMechanics
@ -41,7 +42,7 @@ namespace MWMechanics
std::deque<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const; std::deque<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
private: private:
const ESM::Cell* mCell; const MWWorld::Cell* mCell;
const ESM::Pathgrid* mPathgrid; const ESM::Pathgrid* mPathgrid;
struct ConnectedPoint // edge struct ConnectedPoint // edge

View file

@ -102,9 +102,8 @@ namespace MWRender
void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store)
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
if (store->getCell()->isEsm4())
return; const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*store->getCell());
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(store->getCell()->getEsm3());
if (!pathgrid) if (!pathgrid)
return; return;

View file

@ -781,10 +781,8 @@ namespace MWSound
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::ConstPtr player = world->getPlayerPtr(); const MWWorld::ConstPtr player = world->getPlayerPtr();
if (player.getCell()->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); const auto update = mWaterSoundUpdater.update(player, *world);
WaterSoundAction action; WaterSoundAction action;
@ -813,7 +811,7 @@ namespace MWSound
} }
std::pair<SoundManager::WaterSoundAction, Sound_Buffer*> SoundManager::getWaterSoundAction( std::pair<SoundManager::WaterSoundAction, Sound_Buffer*> SoundManager::getWaterSoundAction(
const WaterSoundUpdate& update, const ESM::Cell* cell) const const WaterSoundUpdate& update, const MWWorld::Cell* cell) const
{ {
if (mNearWaterSound) if (mNearWaterSound)
{ {

View file

@ -30,6 +30,11 @@ namespace ESM
struct Cell; struct Cell;
} }
namespace MWWorld
{
class Cell;
}
namespace MWSound namespace MWSound
{ {
class Sound_Output; class Sound_Output;
@ -107,7 +112,7 @@ namespace MWSound
float mTimePassed; float mTimePassed;
const ESM::Cell* mLastCell; const MWWorld::Cell* mLastCell;
Sound* mCurrentRegionSound; Sound* mCurrentRegionSound;
@ -143,7 +148,7 @@ namespace MWSound
}; };
std::pair<WaterSoundAction, Sound_Buffer*> getWaterSoundAction( std::pair<WaterSoundAction, Sound_Buffer*> getWaterSoundAction(
const WaterSoundUpdate& update, const ESM::Cell* cell) const; const WaterSoundUpdate& update, const MWWorld::Cell* cell) const;
SoundManager(const SoundManager& rhs); SoundManager(const SoundManager& rhs);
SoundManager& operator=(const SoundManager& rhs); SoundManager& operator=(const SoundManager& rhs);

View file

@ -25,6 +25,7 @@ namespace MWWorld
.mDirectionalColor = cell.mLighting.directional, .mDirectionalColor = cell.mLighting.directional,
.mFogColor = cell.mLighting.fogColor, .mFogColor = cell.mLighting.fogColor,
.mFogDensity = cell.mLighting.fogPower,} .mFogDensity = cell.mLighting.fogPower,}
,mWaterHeight(cell.mWaterHeight)
{ {
} }
@ -45,11 +46,16 @@ namespace MWWorld
.mFogColor = cell.mAmbi.mFog, .mFogColor = cell.mAmbi.mFog,
.mFogDensity = cell.mAmbi.mFogDensity, .mFogDensity = cell.mAmbi.mFogDensity,
} }
,mWaterHeight(cell.mWater)
{ {
} }
std::string Cell::getDescription() const 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);
} }
} }

View file

@ -48,6 +48,7 @@ namespace MWWorld
std::string_view getDisplayName() const { return mDisplayname; } std::string_view getDisplayName() const { return mDisplayname; }
std::string getDescription() const; std::string getDescription() const;
const MoodData& getMood() const { return mMood; } const MoodData& getMood() const { return mMood; }
float getWaterHeight() const { return mWaterHeight; }
private: private:
bool mIsExterior; bool mIsExterior;
@ -61,6 +62,8 @@ namespace MWWorld
ESM::RefId mRegion; ESM::RefId mRegion;
ESM::CellId mCellId; ESM::CellId mCellId;
MoodData mMood; MoodData mMood;
float mWaterHeight;
}; };
} }

View file

@ -7,16 +7,6 @@
namespace MWWorld namespace MWWorld
{ {
// makes it easier to use std visit with a variant
template <class... Ts>
struct RefVisit : Ts...
{
using Ts::operator()...;
};
template <class... Ts>
RefVisit(Ts...) -> RefVisit<Ts...>;
CellRef::CellRef(const ESM::CellRef& ref) CellRef::CellRef(const ESM::CellRef& ref)
: mCellRef(ESM::ReferenceVariant(ref)) : mCellRef(ESM::ReferenceVariant(ref))
{ {
@ -31,7 +21,7 @@ namespace MWWorld
const ESM::RefNum& CellRef::getRefNum() const 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 ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; },
[&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; }, [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; },
}, },
@ -59,7 +49,7 @@ namespace MWWorld
return ref.mRefNum; return ref.mRefNum;
}; };
return std::visit( return std::visit(
RefVisit{ ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, [&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; },
esm3Visit, esm3Visit,
}, },
@ -68,7 +58,7 @@ namespace MWWorld
void CellRef::unsetRefNum() void CellRef::unsetRefNum()
{ {
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; }, [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; },
}, },
@ -79,7 +69,11 @@ namespace MWWorld
const std::string& CellRef::getDestCell() const 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) void CellRef::setScale(float scale)
@ -99,7 +93,7 @@ namespace MWWorld
float CellRef::getEnchantmentCharge() const float CellRef::getEnchantmentCharge() const
{ {
return std::visit(RefVisit{ return std::visit(ESM::VisitOverload{
[&](const ESM4::Reference& /*ref*/) { return 0.f; }, [&](const ESM4::Reference& /*ref*/) { return 0.f; },
[&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; }, [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; },
}, },
@ -128,7 +122,7 @@ namespace MWWorld
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; }, [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; },
}, },
@ -138,7 +132,7 @@ namespace MWWorld
void CellRef::setCharge(int charge) void CellRef::setCharge(int charge)
{ {
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mChargeInt = charge; }, [&](ESM::CellRef& ref) { ref.mChargeInt = charge; },
}, },
@ -164,7 +158,7 @@ namespace MWWorld
} }
}; };
std::visit( std::visit(
RefVisit{ ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
esm3Visit, esm3Visit,
}, },
@ -173,7 +167,7 @@ namespace MWWorld
void CellRef::setChargeFloat(float charge) void CellRef::setChargeFloat(float charge)
{ {
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mChargeFloat = charge; }, [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; },
}, },
@ -182,7 +176,7 @@ namespace MWWorld
const std::string& CellRef::getGlobalVariable() const 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 ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; },
[&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; }, [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; },
}, },
@ -194,7 +188,7 @@ namespace MWWorld
if (!getGlobalVariable().empty()) if (!getGlobalVariable().empty())
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); }, [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); },
}, },
@ -215,7 +209,7 @@ namespace MWWorld
{ {
if (owner != getOwner()) if (owner != getOwner())
{ {
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mOwner = owner; }, [&](ESM::CellRef& ref) { ref.mOwner = owner; },
}, },
@ -228,7 +222,7 @@ namespace MWWorld
if (soul != getSoul()) if (soul != getSoul())
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mSoul = soul; }, [&](ESM::CellRef& ref) { ref.mSoul = soul; },
}, },
@ -241,7 +235,7 @@ namespace MWWorld
if (faction != getFaction()) if (faction != getFaction())
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mFaction = faction; }, [&](ESM::CellRef& ref) { ref.mFaction = faction; },
}, },
@ -276,7 +270,7 @@ namespace MWWorld
if (trap != getTrap()) if (trap != getTrap())
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mTrap = trap; }, [&](ESM::CellRef& ref) { ref.mTrap = trap; },
}, },
@ -289,7 +283,7 @@ namespace MWWorld
if (value != getGoldValue()) if (value != getGoldValue())
{ {
mChanged = true; mChanged = true;
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& /*ref*/) {},
[&](ESM::CellRef& ref) { ref.mGoldValue = value; }, [&](ESM::CellRef& ref) { ref.mGoldValue = value; },
}, },
@ -299,7 +293,7 @@ namespace MWWorld
void CellRef::writeState(ESM::ObjectState& state) const void CellRef::writeState(ESM::ObjectState& state) const
{ {
std::visit(RefVisit{ std::visit(ESM::VisitOverload{
[&](const ESM4::Reference& /*ref*/) {}, [&](const ESM4::Reference& /*ref*/) {},
[&](const ESM::CellRef& ref) { state.mRef = ref; }, [&](const ESM::CellRef& ref) { state.mRef = ref; },
}, },

View file

@ -540,8 +540,7 @@ namespace MWWorld
{ {
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
if (!mCellVariant.isEsm4()) mWaterLevel = mCellVariant.getWaterHeight();
mWaterLevel = mCellVariant.getEsm3().mWater;
} }
CellStore::~CellStore() = default; CellStore::~CellStore() = default;
@ -703,26 +702,20 @@ namespace MWWorld
} }
} }
void CellStore::listRefs() void CellStore::listRefs(const ESM::Cell& cell)
{ {
if (cell.mContextList.empty())
if (mCellVariant.isEsm4())
return;
const ESM::Cell& cell3 = mCellVariant.getEsm3();
if (cell3.mContextList.empty())
return; // this is a dynamically generated cell -> skipping. return; // this is a dynamically generated cell -> skipping.
// Load references from all plugins that do something with this cell. // Load references from all plugins that do something with this cell.
for (size_t i = 0; i < cell3.mContextList.size(); i++) for (size_t i = 0; i < cell.mContextList.size(); i++)
{ {
try try
{ {
// Reopen the ESM reader and seek to the right position. // Reopen the ESM reader and seek to the right position.
const std::size_t index = static_cast<std::size_t>(cell3.mContextList[i].index); const std::size_t index = static_cast<std::size_t>(cell.mContextList[i].index);
const ESM::ReadersCache::BusyItem reader = mReaders.get(index); const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
cell3.restore(*reader, i); cell.restore(*reader, i);
ESM::CellRef ref; ESM::CellRef ref;
@ -738,8 +731,8 @@ namespace MWWorld
// Don't list reference if it was moved to a different cell. // Don't list reference if it was moved to a different cell.
ESM::MovedCellRefTracker::const_iterator iter ESM::MovedCellRefTracker::const_iterator iter
= std::find(cell3.mMovedRefs.begin(), cell3.mMovedRefs.end(), ref.mRefNum); = std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum);
if (iter != cell3.mMovedRefs.end()) if (iter != cell.mMovedRefs.end())
{ {
continue; continue;
} }
@ -755,12 +748,29 @@ namespace MWWorld
} }
// List moved references, from separately tracked list. // List moved references, from separately tracked list.
for (const auto& [ref, deleted] : cell3.mLeasedRefs) for (const auto& [ref, deleted] : cell.mLeasedRefs)
{ {
if (!deleted) if (!deleted)
mIds.push_back(ref.mRefID); mIds.push_back(ref.mRefID);
} }
}
void CellStore::listRefs(const ESM4::Cell& cell)
{
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
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()); std::sort(mIds.begin(), mIds.end());
} }
@ -834,7 +844,7 @@ namespace MWWorld
{ {
std::map<ESM::RefNum, ESM::RefId> refNumToID; // used to detect refID modifications std::map<ESM::RefNum, ESM::RefId> 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(); updateMergedRefs();
} }
@ -930,9 +940,6 @@ namespace MWWorld
void CellStore::loadState(const ESM::CellState& state) void CellStore::loadState(const ESM::CellState& state)
{ {
if (mCellVariant.isEsm4())
return;
mHasState = true; mHasState = true;
if (!mCellVariant.isExterior() && mCellVariant.hasWater()) if (!mCellVariant.isExterior() && mCellVariant.hasWater())

View file

@ -383,6 +383,8 @@ namespace MWWorld
private: private:
/// Run through references and store IDs /// Run through references and store IDs
void listRefs(const ESM::Cell& cell);
void listRefs(const ESM4::Cell& cell);
void listRefs(); void listRefs();
void loadRefs(const ESM::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID); void loadRefs(const ESM::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID);

View file

@ -354,11 +354,14 @@ namespace MWWorld
if (cell->getCell()->hasWater()) if (cell->getCell()->hasWater())
mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard);
if (!cell->getCell()->isEsm4()) ESM::visit(ESM::VisitOverload{
{ [&](const ESM::Cell& cell) {
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell->getCell()->getEsm3())) if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell))
mNavigator.removePathgrid(*pathgrid); mNavigator.removePathgrid(*pathgrid);
} },
[&](const ESM4::Cell& cell) {},
},
*cell->getCell());
MWBase::Environment::get().getMechanicsManager()->drop(cell); MWBase::Environment::get().getMechanicsManager()->drop(cell);
@ -430,12 +433,14 @@ namespace MWWorld
} }
} }
if (!cellVariant.isEsm4()) ESM::visit(ESM::VisitOverload{
{ [&](const ESM::Cell& cell) {
const ESM::Cell& cell3 = cellVariant.getEsm3(); if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell))
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(cell3)) mNavigator.addPathgrid(cell, *pathgrid);
mNavigator.addPathgrid(cell3, *pathgrid); },
} [&](const ESM4::Cell& cell) {},
},
*cell->getCell());
// register local scripts // register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice // 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); mRendering.addCell(cell);
MWBase::Environment::get().getWindowManager()->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(); float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled); mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled) if (waterEnabled)
@ -457,7 +462,7 @@ namespace MWWorld
mPhysics->enableWater(waterLevel); mPhysics->enableWater(waterLevel);
mRendering.setWaterHeight(waterLevel); mRendering.setWaterHeight(waterLevel);
if (cellVariant.getEsm3().isExterior()) if (cellVariant.isExterior())
{ {
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
mNavigator.addWater( mNavigator.addWater(

View file

@ -14,6 +14,8 @@
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <apps/openmw/mwworld/cell.hpp>
namespace namespace
{ {
// TODO: Switch to C++23 to get a working version of std::unordered_map::erase // TODO: Switch to C++23 to get a working version of std::unordered_map::erase
@ -961,6 +963,14 @@ namespace MWWorld
else else
return search(ESM::RefId::stringRefId(cell.mName)); return search(ESM::RefId::stringRefId(cell.mName));
} }
const ESM::Pathgrid* Store<ESM::Pathgrid>::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<ESM::Pathgrid>::find(const ESM::Cell& cell) const const ESM::Pathgrid* Store<ESM::Pathgrid>::find(const ESM::Cell& cell) const
{ {
if (!(cell.mData.mFlags & ESM::Cell::Interior)) if (!(cell.mData.mFlags & ESM::Cell::Interior))

View file

@ -39,6 +39,7 @@ namespace Loading
namespace MWWorld namespace MWWorld
{ {
class Cell;
struct RecordId struct RecordId
{ {
ESM::RefId mId; ESM::RefId mId;
@ -430,6 +431,7 @@ namespace MWWorld
const ESM::Pathgrid* find(int x, int y) const; const ESM::Pathgrid* find(int x, int y) const;
const ESM::Pathgrid* find(const ESM::RefId& name) const; const ESM::Pathgrid* find(const ESM::RefId& name) const;
const ESM::Pathgrid* search(const ESM::Cell& cell) 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; const ESM::Pathgrid* find(const ESM::Cell& cell) const;
}; };

View file

@ -642,11 +642,13 @@ namespace MWWorld
if (!cell.isExterior() || !cell.getNameId().empty()) if (!cell.isExterior() || !cell.getNameId().empty())
return cell.getNameId(); return cell.getNameId();
if (!cell.isEsm4()) return ESM::visit(ESM::VisitOverload{
{ [&](const ESM::Cell& cellIn) -> std::string_view { return getCellName(&cellIn); },
return getCellName(&cell.getEsm3()); [&](const ESM4::Cell& cellIn) -> std::string_view {
} return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString(); },
},
cell);
} }
std::string_view World::getCellName(const ESM::Cell* cell) const std::string_view World::getCellName(const ESM::Cell* cell) const

View file

@ -70,5 +70,14 @@ namespace ESM
{ {
return std::visit([&](auto*... ptr) { return std::forward<F>(f)(*ptr...); }, std::forward<T>(v).mVariant...); return std::visit([&](auto*... ptr) { return std::forward<F>(f)(*ptr...); }, std::forward<T>(v).mVariant...);
} }
template <class... Ts>
struct VisitOverload : Ts...
{
using Ts::operator()...;
};
template <class... Ts>
VisitOverload(Ts...) -> VisitOverload<Ts...>;
} }
#endif #endif