1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-06 08:45:33 +00:00

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:
{
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<ESM::Pathgrid>().search(
cellVariant->getEsm3());
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cellVariant);
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)
{
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.

View file

@ -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<AiWanderStorage>();
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<ESM::Pathgrid>().search(cell3);
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().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

View file

@ -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<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);

View file

@ -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<ESM::Pathgrid>().search(*mCell);
if (!mPathgrid)

View file

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

View file

@ -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<ESM::Pathgrid>().search(store->getCell()->getEsm3());
const ESM::Pathgrid* pathgrid = world->getStore().get<ESM::Pathgrid>().search(*store->getCell());
if (!pathgrid)
return;

View file

@ -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::WaterSoundAction, Sound_Buffer*> SoundManager::getWaterSoundAction(
const WaterSoundUpdate& update, const ESM::Cell* cell) const
const WaterSoundUpdate& update, const MWWorld::Cell* cell) const
{
if (mNearWaterSound)
{

View file

@ -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<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& operator=(const SoundManager& rhs);

View file

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

View file

@ -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;
};
}

View file

@ -7,16 +7,6 @@
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)
: 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; },
},

View file

@ -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<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);
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<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());
}
@ -834,7 +844,7 @@ namespace MWWorld
{
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();
}
@ -930,9 +940,6 @@ namespace MWWorld
void CellStore::loadState(const ESM::CellState& state)
{
if (mCellVariant.isEsm4())
return;
mHasState = true;
if (!mCellVariant.isExterior() && mCellVariant.hasWater())

View file

@ -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<ESM::RefNum, ESM::RefId>& refNumToID);

View file

@ -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<ESM::Pathgrid>().search(cell->getCell()->getEsm3()))
mNavigator.removePathgrid(*pathgrid);
}
ESM::visit(ESM::VisitOverload{
[&](const ESM::Cell& cell) {
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().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<ESM::Pathgrid>().search(cell3))
mNavigator.addPathgrid(cell3, *pathgrid);
}
ESM::visit(ESM::VisitOverload{
[&](const ESM::Cell& cell) {
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().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(

View file

@ -14,6 +14,8 @@
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp>
#include <apps/openmw/mwworld/cell.hpp>
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<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
{
if (!(cell.mData.mFlags & ESM::Cell::Interior))

View file

@ -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;
};

View file

@ -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<ESM::GameSetting>().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<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
},
},
cell);
}
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...);
}
template <class... Ts>
struct VisitOverload : Ts...
{
using Ts::operator()...;
};
template <class... Ts>
VisitOverload(Ts...) -> VisitOverload<Ts...>;
}
#endif