From cddf6f29d6b48f5a7a7bee17541d86fb82760438 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 22 Jan 2023 12:18:20 +0100 Subject: [PATCH 01/25] Nothing can be loaded yet. Just foundations. --- apps/openmw/mwworld/cellstore.hpp | 8 ++++++++ apps/openmw/mwworld/store.cpp | 25 +++++++++++++++++++++++++ apps/openmw/mwworld/store.hpp | 14 ++++++++++++++ apps/openmw/mwworld/worldmodel.cpp | 11 +++++++++++ apps/openmw/mwworld/worldmodel.hpp | 9 ++++++++- 5 files changed, 66 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ae03e8c4e7..ebe6febf72 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -51,10 +51,17 @@ namespace ESM struct BodyPart; } +namespace ESM4 +{ + class Reader; + struct Cell; +} + namespace MWWorld { class ESMStore; struct CellStoreImp; + typedef std::variant CellVariant; using CellStoreTuple = std::tuple, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, @@ -86,6 +93,7 @@ namespace MWWorld std::unique_ptr mFogState; const ESM::Cell* mCell; + CellVariant mCellVariant; State mState; bool mHasState; std::vector mIds; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index fb3774bcbf..2265712509 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1183,6 +1183,31 @@ namespace MWWorld } return name; } + + // ESM4 Cell + //========================================================================= + + const ESM4::Cell* Store::searchCellName(std::string_view cellName) const + { + const auto foundCell = mCellNameIndex.find(cellName); + if (foundCell == mCellNameIndex.end()) + return nullptr; + return foundCell->second; + } + + ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) + { + auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); + mCellNameIndex[cellPtr->mEditorId] = cellPtr; + return cellPtr; + } + + ESM4::Cell* Store::insertStatic(const ESM4::Cell& item) + { + auto cellPtr = TypedDynamicStore::insertStatic(item); + mCellNameIndex[cellPtr->mEditorId] = cellPtr; + return cellPtr; + } } template class MWWorld::TypedDynamicStore; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 0b9ef56113..1b89604e0a 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -268,6 +269,19 @@ namespace MWWorld const ESM::GameSetting* find(const std::string_view id) const; const ESM::GameSetting* search(const std::string_view id) const; }; + + template <> + class Store : public TypedDynamicStore + { + std::unordered_map + mCellNameIndex; + + public: + const ESM4::Cell* searchCellName(std::string_view) const; + ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); + ESM4::Cell* insertStatic(const ESM4::Cell& item); + }; + template <> class Store : public DynamicStore { diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 781b5b7ff6..66156a2a5e 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -253,6 +253,17 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name) return cell; } +MWWorld::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) +{ + const ESM::Cell* cellEsm3 = getESMCellByName(name); + return cellEsm3; + if (!cellEsm3) + { + const ESM4::Cell* cellESM4 = mStore.get().searchCellName(name); + return cellESM4; + } +} + MWWorld::CellStore* MWWorld::WorldModel::getCell(std::string_view name) { const ESM::Cell* cell = getESMCellByName(name); diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 6536c063fe..9caada64c0 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -21,6 +22,11 @@ namespace ESM struct RefNum; } +namespace ESM4 +{ + struct Cell; +} + namespace Loading { class Listener; @@ -45,8 +51,9 @@ namespace MWWorld WorldModel& operator=(const WorldModel&); const ESM::Cell* getESMCellByName(std::string_view name); - CellStore* getCellStore(const ESM::Cell* cell); + CellVariant getCellByName(std::string_view name); + CellStore* getCellStore(const ESM::Cell* cell); Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore); Ptr getPtr(CellStore& cellStore, const ESM::RefId& id, const ESM::RefNum& refNum); From 08b68fcd48762582b4f4bd5f57e1aa735f1978f1 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 22 Jan 2023 19:03:19 +0100 Subject: [PATCH 02/25] Cannot load a cell yet, but getting more necessary parts in --- apps/openmw/mwclass/classes.cpp | 2 + apps/openmw/mwclass/static.cpp | 50 +++++++++++++ apps/openmw/mwclass/static.hpp | 27 +++++++ apps/openmw/mwworld/cellstore.cpp | 97 +++++++++++++++++++++---- apps/openmw/mwworld/cellstore.hpp | 52 ++++++++++++-- apps/openmw/mwworld/livecellref.hpp | 14 +++- apps/openmw/mwworld/scene.cpp | 106 +++++++++++++++------------- apps/openmw/mwworld/store.cpp | 14 ---- apps/openmw/mwworld/store.hpp | 2 - apps/openmw/mwworld/worldimp.cpp | 22 +++++- apps/openmw/mwworld/worldmodel.cpp | 12 +++- components/esm/defs.hpp | 15 ++++ 12 files changed, 322 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index 8303a3a74d..e96350294e 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -47,5 +47,7 @@ namespace MWClass Repair::registerSelf(); Static::registerSelf(); BodyPart::registerSelf(); + + ESM4Static::registerSelf(); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index c54e1088d3..0f29fa4e22 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,6 +1,7 @@ #include "static.hpp" #include +#include #include #include "../mwphysics/physicssystem.hpp" @@ -63,4 +64,53 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + + ESM4Static::ESM4Static() + : MWWorld::RegisteredClass(ESM4::Static::sRecordId) + { + } + + void ESM4Static ::insertObjectRendering( + const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const + { + if (!model.empty()) + { + renderingInterface.getObjects().insertModel(ptr, model); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); + } + } + + void ESM4Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + insertObjectPhysics(ptr, model, rotation, physics); + } + + void ESM4Static::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); + } + + std::string ESM4Static::getModel(const MWWorld::ConstPtr& ptr) const + { + return getClassModel(ptr); + } + + std::string_view ESM4Static ::getName(const MWWorld::ConstPtr& ptr) const + { + return {}; + } + + bool ESM4Static::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + + MWWorld::Ptr ESM4Static::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const + { + const MWWorld::LiveCellRef* ref = ptr.get(); + + return MWWorld::Ptr(cell.insert(ref), &cell); + } } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index c6b2c3e6f9..f16dfdd2a6 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -31,6 +31,33 @@ namespace MWClass std::string getModel(const MWWorld::ConstPtr& ptr) const override; }; + + class ESM4Static : public MWWorld::RegisteredClass + { + friend MWWorld::RegisteredClass; + + ESM4Static(); + + MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override; + + public: + void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model, + MWRender::RenderingInterface& renderingInterface) const override; + ///< Add reference into a cell for rendering + + void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + + std::string_view getName(const MWWorld::ConstPtr& ptr) const override; + ///< \return name or ID; can return an empty string. + + bool hasToolTip(const MWWorld::ConstPtr& ptr) const override; + ///< @return true if this object has a tooltip when focused (default implementation: true) + + std::string getModel(const MWWorld::ConstPtr& ptr) const override; + }; } #endif diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ee8f90ef9f..0e69961758 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include "../mwbase/environment.hpp" @@ -503,18 +505,22 @@ namespace MWWorld return false; } - CellStore::CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) + CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) : mStore(esmStore) , mReaders(readers) - , mCell(cell) + , mCellVariant(cell) , mState(State_Unloaded) , mHasState(false) , mLastRespawn(0, 0) , mCellStoreImp(std::make_unique()) , mRechargingItemsUpToDate(false) { + + mCell = mCellVariant.getEsm3(); + std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); - mWaterLevel = cell->mWater; + if (mCell) + mWaterLevel = mCell->mWater; } CellStore::~CellStore() = default; @@ -525,6 +531,24 @@ namespace MWWorld return mCell; } + CellVariant CellStore::getCellVariant() const + { + return mCellVariant; + } + + std::string_view CellStore::getEditorName() const + { + const ESM4::Cell* cell4 = mCellVariant.getEsm4(); + if (cell4) + { + return cell4->mEditorId; + } + else + { + return mCellVariant.getEsm3()->mName; + } + } + CellStore::State CellStore::getState() const { return mState; @@ -735,7 +759,24 @@ namespace MWWorld void CellStore::loadRefs() { - assert(mCell); + assert(mCellVariant.getEsm4() || mCellVariant.getEsm3()); + const ESM4::Cell* cell4 = mCellVariant.getEsm4(); + if (cell4) + { + + auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); + auto it = refs.begin(); + + while (it != refs.end()) + { + if (it->mParent == cell4->mId) + { + loadRef(*it, false); + } + ++it; + } + return; + } if (mCell->mContextList.empty()) return; // this is a dynamically generated cell -> skipping. @@ -795,12 +836,15 @@ namespace MWWorld bool CellStore::isExterior() const { - return mCell->isExterior(); + auto cell3 = mCellVariant.getEsm3(); + return cell3 ? cell3->isExterior() : false; } bool CellStore::isQuasiExterior() const { - return (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0; + auto cell3 = mCellVariant.getEsm3(); + + return cell3 ? (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0 : false; } Ptr CellStore::searchInContainer(const ESM::RefId& id) @@ -823,6 +867,28 @@ namespace MWWorld return Ptr(); } + template + static void loadRefESM4( + const MWWorld::ESMStore& store, const ESM4::Reference& ref, MWWorld::CellRefList& storeIn, bool deleted) + { + if constexpr (ESM::isESM4Rec(T::sRecordId)) + { + // storeIn.load(ref, deleted, store); + } + } + + void CellStore::loadRef(const ESM4::Reference& ref, bool deleted) + { + const MWWorld::ESMStore& store = mStore; + + ESM::RecNameInts foundType = static_cast(store.find(ref.mBaseObj)); + + Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType](auto& x) { + recNameSwitcher( + x, foundType, [&ref, &deleted, &store](auto& storeIn) { loadRefESM4(store, ref, storeIn, deleted); }); + }); + } + void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID) { const MWWorld::ESMStore& store = mStore; @@ -999,8 +1065,8 @@ namespace MWWorld Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location."; - // Note by dropping tag the object will automatically re-appear in its original cell, though potentially - // at inapproriate coordinates. Restore original coordinates: + // Note by dropping tag the object will automatically re-appear in its original cell, though + // potentially at inapproriate coordinates. Restore original coordinates: movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition()); continue; } @@ -1016,14 +1082,17 @@ namespace MWWorld } } - bool operator==(const CellStore& left, const CellStore& right) + bool CellStore::operator==(const CellStore& right) const { - return left.getCell()->getCellId() == right.getCell()->getCellId(); - } + auto cell4Left = mCellVariant.getEsm4(); + auto cell4Right = right.mCellVariant.getEsm4(); - bool operator!=(const CellStore& left, const CellStore& right) - { - return !(left == right); + if (!cell4Left && !cell4Right) + return getCell()->getCellId() == right.getCell()->getCellId(); + else if (cell4Left && cell4Right) + return cell4Left->mId == cell4Right->mId; + else + return false; } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ebe6febf72..76b2485cd4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -55,20 +55,56 @@ namespace ESM4 { class Reader; struct Cell; + struct Reference; + struct Static; } namespace MWWorld { class ESMStore; struct CellStoreImp; - typedef std::variant CellVariant; + + struct CellVariant + { + std::variant mVariant; + + CellVariant(const ESM4::Cell* cell) + : mVariant(cell) + { + } + + CellVariant(const ESM::Cell* cell) + : mVariant(cell) + { + } + + bool isEsm4() const { return getEsm4(); } + + const ESM4::Cell* getEsm4() const + { + auto cell4 = std::get_if(&mVariant); + if (cell4) + return *cell4; + return nullptr; + } + + const ESM::Cell* getEsm3() const + { + auto cell3 = std::get_if(&mVariant); + if (cell3) + return *cell3; + return nullptr; + } + }; using CellStoreTuple = std::tuple, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, - CellRefList, CellRefList, CellRefList, CellRefList>; + CellRefList, CellRefList, CellRefList, CellRefList, + + CellRefList>; /// \brief Mutable state of a cell class CellStore @@ -188,11 +224,14 @@ namespace MWWorld } /// @param readerList The readers to use for loading of the cell on-demand. - CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); + CellStore(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(CellStore&&); ~CellStore(); const ESM::Cell* getCell() const; + CellVariant getCellVariant() const; + + std::string_view getEditorName() const; State getState() const; @@ -339,6 +378,7 @@ namespace MWWorld // Should be phased out when we have const version of forEach inline const CellRefList& getReadOnlyDoors() const { return get(); } inline const CellRefList& getReadOnlyStatics() const { return get(); } + inline const CellRefList& getReadOnlyEsm4Statics() const { return get(); } bool isExterior() const; @@ -374,20 +414,22 @@ namespace MWWorld Ptr getMovedActor(int actorId) const; + bool operator==(const CellStore& right) const; + private: /// Run through references and store IDs void listRefs(); void loadRefs(); + void loadRef(const ESM4::Reference& ref, bool deleted); void loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. + /// }; - bool operator==(const CellStore& left, const CellStore& right); - bool operator!=(const CellStore& left, const CellStore& right); } #endif diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 128546bb65..4e3cb322cc 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -87,7 +87,8 @@ namespace MWWorld { if (const LiveCellRef* ref = dynamic_cast*>(value)) return ref; - throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType())); + throw std::runtime_error( + makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView())); } template @@ -95,7 +96,8 @@ namespace MWWorld { if (LiveCellRef* ref = dynamic_cast*>(value)) return ref; - throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType())); + throw std::runtime_error( + makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView())); } /// A reference to one object (of any type) in a cell. @@ -130,7 +132,13 @@ namespace MWWorld void save(ESM::ObjectState& state) const override; ///< Save LiveCellRef state into \a state. - std::string_view getTypeDescription() const override { return X::getRecordType(); } + std::string_view getTypeDescription() const override + { + if constexpr (ESM::isESM4Rec(X::sRecordId)) + return ESM::getRecNameString(X::sRecordId).toStringView(); + else + return X::getRecordType(); + } static bool checkState(const ESM::ObjectState& state); ///< Check if state is valid and report errors. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aab2c4fc7f..b776a76856 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -380,55 +380,62 @@ namespace MWWorld assert(mActiveCells.find(cell) == mActiveCells.end()); mActiveCells.insert(cell); - Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription(); + Log(Debug::Info) << "Loading cell " << cell->getEditorName(); - const int cellX = cell->getCell()->getGridX(); - const int cellY = cell->getCell()->getGridY(); - - if (cell->getCell()->isExterior()) + auto cell3 = cell->getCellVariant().getEsm3(); + int cellX = 0; + int cellY = 0; + if (cell3 != nullptr) { - osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); - const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; - const int verts = ESM::Land::LAND_SIZE; - const int worldsize = ESM::Land::REAL_SIZE; - if (data) - { - mPhysics->addHeightField( - data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); - } - else - { - static std::vector defaultHeight; - defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); - mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, - ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); - } - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + + int cellX = cell3->getGridX(); + int cellY = cell3->getGridY(); + + if (cell3->isExterior()) { - const osg::Vec2i cellPosition(cellX, cellY); - const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); - const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); - const HeightfieldShape shape = [&]() -> HeightfieldShape { - if (data == nullptr) - { - return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; - } - else - { - DetourNavigator::HeightfieldSurface heights; - heights.mHeights = data->mHeights; - heights.mSize = static_cast(ESM::Land::LAND_SIZE); - heights.mMinHeight = data->mMinHeight; - heights.mMaxHeight = data->mMaxHeight; - return heights; - } - }(); - mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); + osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; + const int verts = ESM::Land::LAND_SIZE; + const int worldsize = ESM::Land::REAL_SIZE; + if (data) + { + mPhysics->addHeightField( + data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); + } + else + { + static std::vector defaultHeight; + defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); + mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, + ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); + } + if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + { + const osg::Vec2i cellPosition(cellX, cellY); + const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); + const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); + const HeightfieldShape shape = [&]() -> HeightfieldShape { + if (data == nullptr) + { + return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; + } + else + { + DetourNavigator::HeightfieldSurface heights; + heights.mHeights = data->mHeights; + heights.mSize = static_cast(ESM::Land::LAND_SIZE); + heights.mMinHeight = data->mMinHeight; + heights.mMaxHeight = data->mMaxHeight; + return heights; + } + }(); + mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); + } } - } - if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) - mNavigator.addPathgrid(*cell->getCell(), *pathgrid); + if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) + mNavigator.addPathgrid(*cell3, *pathgrid); + } // register local scripts // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice @@ -442,7 +449,7 @@ namespace MWWorld mRendering.addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell); - bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); + bool waterEnabled = cell3 && (cell3->hasWater() || cell->isExterior()); float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) @@ -450,7 +457,7 @@ namespace MWWorld mPhysics->enableWater(waterLevel); mRendering.setWaterHeight(waterLevel); - if (cell->getCell()->isExterior()) + if (cell3->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) mNavigator.addWater( @@ -465,8 +472,8 @@ namespace MWWorld else mPhysics->disableWater(); - if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) - mRendering.configureAmbient(cell->getCell()); + if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx)) + mRendering.configureAmbient(cell3); mPreloader->notifyLoaded(cell); } @@ -879,8 +886,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getEditorName()), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2265712509..e995a6c1ab 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1170,20 +1170,6 @@ namespace MWWorld return mKeywordSearch; } - ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName) - { - ESM::FixedString<6> name; - name.assign(""); - ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag); - for (int i = 0; i < 4; i++) - name.mData[i] = fourCCName.mData[i]; - if (ESM::isESM4Rec(recName)) - { - name.mData[4] = '4'; - } - return name; - } - // ESM4 Cell //========================================================================= diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 1b89604e0a..59b3b8a172 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -533,8 +533,6 @@ namespace MWWorld const MWDialogue::KeywordSearch& getDialogIdKeywordSearch() const; }; - ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName); - } // end namespace #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0e415739d9..cec624898d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include #include @@ -2804,6 +2806,24 @@ namespace MWWorld } } } + for (const MWWorld::LiveCellRef& stat4 : cellStore->getReadOnlyEsm4Statics().mList) + { + if (Misc::StringUtils::lowerCase(stat4.mBase->mEditorId) == "cocmarkerheading") + { + // found the COC position? + pos = stat4.mRef.getPosition(); + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + return true; + } + } + // Fall back to the first static location. + const MWWorld::CellRefList::List& statics4 = cellStore->getReadOnlyEsm4Statics().mList; + if (!statics4.empty()) + { + pos = statics4.begin()->mRef.getPosition(); + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + return true; + } // Fall back to the first static location. const MWWorld::CellRefList::List& statics = cellStore->getReadOnlyStatics().mList; if (!statics.empty()) @@ -3253,7 +3273,7 @@ namespace MWWorld std::set checkedCells; std::set currentCells; std::set nextCells; - nextCells.insert(cell->getCell()->mName); + nextCells.insert(cell->getEditorName()); while (!nextCells.empty()) { diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 66156a2a5e..ac754eae60 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -202,9 +202,17 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) if (result == mInteriors.end()) { - const ESM::Cell* cell = mStore.get().find(name); + const ESM4::Cell* cell4 = mStore.get().searchCellName(name); - result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + if (!cell4) + { + const ESM::Cell* cell = mStore.get().find(name); + result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + } + else + { + result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first; + } } if (result->second.getState() != CellStore::State_Loaded) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 431b85b9ae..122f922837 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -9,6 +9,7 @@ #include #include "components/esm/fourcc.hpp" +#include #include namespace ESM @@ -338,6 +339,20 @@ namespace ESM return RecName & sEsm4RecnameFlag; } + inline FixedString<6> getRecNameString(ESM::RecNameInts recName) + { + ESM::FixedString<6> name; + name.assign(""); + ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag); + for (int i = 0; i < 4; i++) + name.mData[i] = fourCCName.mData[i]; + if (ESM::isESM4Rec(recName)) + { + name.mData[4] = '4'; + } + return name; + } + /// Common subrecords enum SubRecNameInts { From 562e129bd02460898e1c4d3a1eeb16ce7f9405b9 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 22 Jan 2023 23:40:55 +0100 Subject: [PATCH 03/25] encapsulations of esm3 cell and esm4 cells. --- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++-- apps/openmw/mwlua/cellbindings.cpp | 19 +++--- apps/openmw/mwlua/localscripts.cpp | 4 +- apps/openmw/mwmechanics/actors.cpp | 4 +- apps/openmw/mwmechanics/aicombat.cpp | 8 +-- apps/openmw/mwmechanics/aifollow.cpp | 3 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 15 ++-- apps/openmw/mwmechanics/aiwander.hpp | 3 + apps/openmw/mwmechanics/pathgrid.cpp | 6 +- apps/openmw/mwmechanics/spelleffects.cpp | 2 +- apps/openmw/mwrender/fogmanager.cpp | 14 ++-- apps/openmw/mwrender/fogmanager.hpp | 4 +- apps/openmw/mwrender/pathgrid.cpp | 5 +- apps/openmw/mwrender/renderingmanager.cpp | 25 +++++-- apps/openmw/mwrender/renderingmanager.hpp | 5 +- apps/openmw/mwrender/water.cpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +- apps/openmw/mwworld/cellstore.cpp | 14 ++-- apps/openmw/mwworld/cellstore.hpp | 44 ++---------- apps/openmw/mwworld/scene.cpp | 37 +++++----- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 46 +++++++------ apps/openmw/mwworld/worldimp.hpp | 2 +- apps/openmw/mwworld/worldmodel.cpp | 17 ++--- apps/openmw/mwworld/worldmodel.hpp | 2 +- apps/openmw_test_suite/mwworld/test_store.cpp | 3 +- components/CMakeLists.txt | 2 +- components/esm/cellcommon.cpp | 15 ++++ components/esm/cellcommon.hpp | 68 +++++++++++++++++++ components/esm3/cellid.cpp | 2 +- components/esm3/cellid.hpp | 1 + components/esm3/loadcell.hpp | 19 ++++-- components/esm4/loadcell.cpp | 7 ++ components/esm4/loadcell.hpp | 16 ++++- components/misc/coordinateconverter.hpp | 4 +- 40 files changed, 292 insertions(+), 162 deletions(-) create mode 100644 components/esm/cellcommon.cpp create mode 100644 components/esm/cellcommon.hpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index dc25b4f652..202af249f5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -57,6 +57,8 @@ namespace ESM struct ItemLevList; struct TimeStamp; struct RefId; + struct CellVariant; + } namespace MWPhysics @@ -179,7 +181,7 @@ namespace MWBase /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual std::string_view getCellName(const ESM::Cell* cell) const = 0; + virtual std::string_view getCellName(const ESM::CellVariant& cell) const = 0; virtual void removeRefScript(MWWorld::RefData* ref) = 0; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 075b2cffa8..56fbdeabe6 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -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().search(index.x(), index.y()); - dest = world->getCellName(cell); + dest = world->getCellName(ESM::CellVariant(cell)); } return "#{sCell=" + std::string{ dest } + "}"; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c79059d022..c64489bae5 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -705,7 +705,7 @@ namespace MWGui ESM::Position markedPosition; MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); if (markedCell && markedCell->isExterior() == !mInterior - && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) + && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getEditorName(), mPrefix))) { MarkerUserData markerPos(mLocalMapRender); MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 49ef0bb4dc..e9d92e7c7a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -200,7 +200,7 @@ namespace MWGui MWWorld::Ptr player = world->getPlayerPtr(); if (mSleeping && player.getCell()->isExterior()) { - const ESM::RefId& regionstr = player.getCell()->getCell()->mRegion; + const ESM::RefId& regionstr = player.getCell()->getCell()->getRegion(); if (!regionstr.empty()) { const ESM::Region* region = world->getStore().get().find(regionstr); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6b4e7a58c3..b31b0adaf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -954,20 +954,21 @@ namespace MWGui mMap->setCellName(name); mHud->setCellName(name); + auto cellCommon = cell->getCellVariant().getCommon(); - if (cell->getCell()->isExterior()) + if (cellCommon->isExterior()) { - if (!cell->getCell()->mName.empty()) - mMap->addVisitedLocation(name, cell->getCell()->getGridX(), cell->getCell()->getGridY()); + if (!cellCommon->getEditorName().empty()) + mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY()); - mMap->cellExplored(cell->getCell()->getGridX(), cell->getCell()->getGridY()); + mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY()); - setActiveMap(cell->getCell()->getGridX(), cell->getCell()->getGridY(), false); + setActiveMap(cellCommon->getGridX(), cellCommon->getGridY(), false); } else { - mMap->setCellPrefix(cell->getCell()->mName); - mHud->setCellPrefix(cell->getCell()->mName); + mMap->setCellPrefix(std::string(cellCommon->getEditorName())); + mHud->setCellPrefix(std::string(cellCommon->getEditorName())); osg::Vec3f worldPos; if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 931142d371..a1d4b3991d 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -1,5 +1,6 @@ #include "luabindings.hpp" +#include #include #include "../mwworld/cellstore.hpp" @@ -29,35 +30,35 @@ namespace MWLua cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; }; cellT[sol::meta_function::to_string] = [](const CellT& c) { - const ESM::Cell* cell = c.mStore->getCell(); + auto cell = c.mStore->getCell(); std::stringstream res; if (cell->isExterior()) res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")"; else - res << "interior(" << cell->mName << ")"; + res << "interior(" << cell->getEditorName() << ")"; return res.str(); }; - cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName; }); + cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getEditorName(); }); cellT["region"] - = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion.getRefIdString(); }); + = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); cellT["hasSky"] = sol::readonly_property([](const CellT& c) { - return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; + return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->isQuasiExterior()) != 0; }); cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); }); // deprecated, use cell:hasTag("QuasiExterior") instead - cellT["isQuasiExterior"] = sol::readonly_property( - [](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; }); + cellT["isQuasiExterior"] + = sol::readonly_property([](const CellT& c) { return (c.mStore->getCell()->isQuasiExterior()) != 0; }); cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool { if (tag == "NoSleep") - return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0; + return (c.mStore->getCell()->noSleep()) != 0; else if (tag == "QuasiExterior") - return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; + return (c.mStore->getCell()->isQuasiExterior()) != 0; return false; }; diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 655fa1978a..6cdfff0fea 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -176,12 +176,12 @@ namespace MWLua // TODO: change AiEscort implementation to accept ptr instead of a non-unique refId. const ESM::RefId& refId = target.ptr().getCellRef().getRefId(); int gameHoursDuration = static_cast(std::ceil(duration / 3600.0)); - const ESM::Cell* esmCell = cell.mStore->getCell(); + const ESM::CellCommon* esmCell = cell.mStore->getCell(); if (esmCell->isExterior()) ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); else ai.stack(MWMechanics::AiEscort( - refId, esmCell->mName, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), + refId, esmCell->getEditorName(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); }; selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) { diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8d919b5aec..e41885c8d1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -274,8 +274,8 @@ namespace MWMechanics .find("fInteriorHeadTrackMult") ->mValue.getFloat(); float maxDistance = fMaxHeadTrackDistance; - const ESM::Cell* currentCell = actor.getCell()->getCell(); - if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx)) + auto currentCell = actor.getCell()->getCell(); + if (!currentCell->isExterior() && !(currentCell->isQuasiExterior())) maxDistance *= fInteriorHeadTrackMult; const osg::Vec3f actor1Pos(actorRefData.getPosition().asVec3()); diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5ab2974def..d9358a0e56 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -357,12 +357,12 @@ namespace MWMechanics case AiCombatStorage::FleeState_Idle: { float triggerDist = getMaxAttackDistance(target); - - if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) + auto cell3 = storage.mCell->getCellVariant().getEsm3(); + if (cell3 && storage.mLOS + && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search( - *storage.mCell->getCell()); + = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); bool runFallback = true; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 12b19611e0..6185535a67 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -174,7 +174,8 @@ namespace MWMechanics return true; } } - else if (Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->mName)) // Cell to travel to + else if (Misc::StringUtils::ciEqual( + mCellId, actor.getCell()->getCell()->getEditorName())) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 25ba126ee8..1233e16a39 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -411,7 +411,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) { - const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + const ESM::Cell* playerCell(getPlayer().getCell()->getCellVariant().getEsm3()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 58b8a13b13..6043759b3e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -271,9 +271,10 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if (storage.mPopulateAvailableNodes) + auto cell3 = actor.getCell()->getCellVariant().getEsm3(); + if (cell3 && storage.mPopulateAvailableNodes) { - getAllowedNodes(actor, actor.getCell()->getCell(), storage); + getAllowedNodes(actor, cell3, storage); } auto& prng = MWBase::Environment::get().getWorld()->getPrng(); @@ -721,8 +722,9 @@ namespace MWMechanics return; AiWanderStorage& storage = state.get(); - if (storage.mPopulateAvailableNodes) - getAllowedNodes(actor, actor.getCell()->getCell(), storage); + auto cell3 = actor.getCell()->getCellVariant().getEsm3(); + if (cell3 && storage.mPopulateAvailableNodes) + getAllowedNodes(actor, cell3, storage); if (storage.mAllowedNodes.empty()) return; @@ -800,8 +802,11 @@ namespace MWMechanics void AiWander::getNeighbouringNodes( ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { + auto cell3 = currentCell->getCellVariant().getEsm3(); + if (!cell3) + return; const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search(*currentCell->getCell()); + = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); if (pathgrid == nullptr || pathgrid->mPoints.empty()) return; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b5a7aed42..f956367321 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -12,6 +12,7 @@ namespace ESM { struct Cell; + struct CellCommon; namespace AiSequence { struct AiWander; @@ -158,6 +159,8 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + /// convert point from local (i.e. cell) to world coordinates + void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::CellCommon* cell); void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage, diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 6cac10c1be..ceaf513937 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -104,8 +104,10 @@ namespace MWMechanics if (mIsGraphConstructed) return true; - mCell = cell->getCell(); - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell()); + mCell = cell->getCellVariant().getEsm3(); + if (!mCell) + return false; + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell); if (!mPathgrid) return false; diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index c32701c310..66b572f1d3 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -489,7 +489,7 @@ namespace MWMechanics { std::string_view dest; if (!markedCell->isExterior()) - dest = markedCell->getCell()->mName; + dest = markedCell->getCell()->getEditorName(); MWWorld::ActionTeleport action(dest, markedPosition, false); action.execute(target); if (!caster.isEmpty()) diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index cfbad67076..6b56bc81a2 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -2,7 +2,9 @@ #include +#include #include +#include #include #include #include @@ -38,13 +40,17 @@ namespace MWRender DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog"); } - void FogManager::configure(float viewDistance, const ESM::Cell* cell) + void FogManager::configure(float viewDistance, const ESM::CellVariant& cell) { - osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); + auto cell3 = cell.getEsm3(); + auto cell4 = cell.getEsm4(); + osg::Vec4f color = SceneUtil::colourFromRGB(cell3 ? cell3->mAmbi.mFog : cell4->mLighting.fogColor); + + const float fogDensity = cell3 ? cell3->mAmbi.mFogDensity : cell4->mLighting.fogPower; if (mDistantFog) { - float density = std::max(0.2f, cell->mAmbi.mFogDensity); + float density = std::max(0.2f, fogDensity); mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density; mLandFogEnd = DLInteriorFogEnd; mUnderwaterFogStart = DLUnderwaterFogStart; @@ -52,7 +58,7 @@ namespace MWRender mFogColor = color; } else - configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); + configure(viewDistance, fogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); } void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, diff --git a/apps/openmw/mwrender/fogmanager.hpp b/apps/openmw/mwrender/fogmanager.hpp index 6f91e2ff30..a1759d5963 100644 --- a/apps/openmw/mwrender/fogmanager.hpp +++ b/apps/openmw/mwrender/fogmanager.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct Cell; + struct CellVariant; } namespace MWRender @@ -15,7 +15,7 @@ namespace MWRender public: FogManager(); - void configure(float viewDistance, const ESM::Cell* cell); + void configure(float viewDistance, const ESM::CellVariant& cell); void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& color); diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 115ab80560..85d8f7a295 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -102,7 +102,10 @@ namespace MWRender void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) { MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Pathgrid* pathgrid = world->getStore().get().search(*store->getCell()); + auto cell3 = store->getCellVariant().getEsm3(); + if (!cell3) + return; + const ESM::Pathgrid* pathgrid = world->getStore().get().search(*cell3); if (!pathgrid) return; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ad55dd5c04..7f03d4707c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -739,14 +740,24 @@ namespace MWRender mSky->setMoonColour(red); } - void RenderingManager::configureAmbient(const ESM::Cell* cell) + void RenderingManager::configureAmbient(const ESM::CellVariant& cell) { - bool isInterior = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx); + bool isInterior = !cell.getCommon()->isExterior() && !cell.getCommon()->isQuasiExterior(); bool needsAdjusting = false; if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP) needsAdjusting = isInterior; - auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient); + osg::Vec4f ambient; + auto cell3 = cell.getEsm3(); + auto cell4 = cell.getEsm4(); + if (cell3) + { + ambient = SceneUtil::colourFromRGB(cell3->mAmbi.mAmbient); + } + else + { + ambient = SceneUtil::colourFromRGB(cell4->mLighting.ambient); + } if (needsAdjusting) { @@ -770,7 +781,9 @@ namespace MWRender setAmbientColour(ambient); - osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); + osg::Vec4f diffuse = cell3 ? SceneUtil::colourFromRGB(cell3->mAmbi.mSunlight) + : SceneUtil::colourFromRGB(cell4->mLighting.directional); + setSunColour(diffuse, diffuse, 1.f); const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f); @@ -890,7 +903,7 @@ namespace MWRender return false; } - void RenderingManager::configureFog(const ESM::Cell* cell) + void RenderingManager::configureFog(const ESM::CellVariant& cell) { mFog->configure(mViewDistance, cell); } @@ -1424,7 +1437,7 @@ namespace MWRender mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); if (MWMechanics::getPlayer().isInCell()) - configureAmbient(MWMechanics::getPlayer().getCell()->getCell()); + configureAmbient(MWMechanics::getPlayer().getCell()->getCellVariant()); } else if (it->first == "Shaders" && (it->second == "light bounds multiplier" || it->second == "maximum light distance" diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ff1d96adcc..e4791df71a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,6 +43,7 @@ namespace ESM { struct Cell; struct RefNum; + struct CellVariant; } namespace Terrain @@ -140,8 +141,8 @@ namespace MWRender void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis); void setNight(bool isNight) { mNight = isNight; } - void configureAmbient(const ESM::Cell* cell); - void configureFog(const ESM::Cell* cell); + void configureAmbient(const ESM::CellVariant& cell); + void configureFog(const ESM::CellVariant& cell); void configureFog( float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 513b0eb261..f77a6641b2 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -772,7 +772,8 @@ namespace MWRender bool wasInterior = mInterior; if (!isInterior) { - mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + mWaterNode->setPosition( + getSceneNodeCoordinates(store->getCell()->getGridX(), store->getCell()->getGridY())); mInterior = false; } else diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f7e3524d8c..06f889d58a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -766,14 +766,14 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - const ESM::Cell* cell = player.getCell()->getCell(); + auto cell = player.getCell()->getCell(); if (!cell->isExterior()) return; if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound)) return; - if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->mRegion, *world)) + if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion(), *world)) mCurrentRegionSound = playSound(*next, 1.0f, 1.0f); } @@ -781,7 +781,7 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - const ESM::Cell* curcell = player.getCell()->getCell(); + const ESM::Cell* curcell = player.getCell()->getCellVariant().getEsm3(); const auto update = mWaterSoundUpdater.update(player, *world); WaterSoundAction action; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0e69961758..0fe281dcc6 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -505,7 +505,7 @@ namespace MWWorld return false; } - CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) + CellStore::CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) : mStore(esmStore) , mReaders(readers) , mCellVariant(cell) @@ -526,12 +526,12 @@ namespace MWWorld CellStore::~CellStore() = default; CellStore::CellStore(CellStore&&) = default; - const ESM::Cell* CellStore::getCell() const + const ESM::CellCommon* CellStore::getCell() const { - return mCell; + return mCellVariant.getCommon(); } - CellVariant CellStore::getCellVariant() const + ESM::CellVariant CellStore::getCellVariant() const { return mCellVariant; } @@ -1087,8 +1087,11 @@ namespace MWWorld auto cell4Left = mCellVariant.getEsm4(); auto cell4Right = right.mCellVariant.getEsm4(); + auto cell3Left = mCellVariant.getEsm3(); + auto cell3Right = right.mCellVariant.getEsm3(); + if (!cell4Left && !cell4Right) - return getCell()->getCellId() == right.getCell()->getCellId(); + return cell3Left->getCellId() == cell3Right->getCellId(); else if (cell4Left && cell4Right) return cell4Left->mId == cell4Right->mId; else @@ -1299,4 +1302,5 @@ namespace MWWorld } return {}; } + } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 76b2485cd4..76b822d8b8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,11 +9,13 @@ #include #include #include +#include #include #include "cellreflist.hpp" #include "livecellref.hpp" +#include #include #include #include @@ -49,6 +51,7 @@ namespace ESM struct Static; struct Weapon; struct BodyPart; + struct CellCommon; } namespace ESM4 @@ -64,39 +67,6 @@ namespace MWWorld class ESMStore; struct CellStoreImp; - struct CellVariant - { - std::variant mVariant; - - CellVariant(const ESM4::Cell* cell) - : mVariant(cell) - { - } - - CellVariant(const ESM::Cell* cell) - : mVariant(cell) - { - } - - bool isEsm4() const { return getEsm4(); } - - const ESM4::Cell* getEsm4() const - { - auto cell4 = std::get_if(&mVariant); - if (cell4) - return *cell4; - return nullptr; - } - - const ESM::Cell* getEsm3() const - { - auto cell3 = std::get_if(&mVariant); - if (cell3) - return *cell3; - return nullptr; - } - }; - using CellStoreTuple = std::tuple, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, @@ -129,7 +99,7 @@ namespace MWWorld std::unique_ptr mFogState; const ESM::Cell* mCell; - CellVariant mCellVariant; + ESM::CellVariant mCellVariant; State mState; bool mHasState; std::vector mIds; @@ -224,12 +194,12 @@ namespace MWWorld } /// @param readerList The readers to use for loading of the cell on-demand. - CellStore(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); + CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(CellStore&&); ~CellStore(); - const ESM::Cell* getCell() const; - CellVariant getCellVariant() const; + const ESM::CellCommon* getCell() const; + ESM::CellVariant getCellVariant() const; std::string_view getEditorName() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b776a76856..6c817f3b56 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -317,8 +317,8 @@ namespace MWWorld { if (mActiveCells.find(cell) == mActiveCells.end()) return; - - Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription(); + std::string description = cell->getCell()->getDescription(); + Log(Debug::Info) << "Unloading cell " << description; ListAndResetObjectsVisitor visitor; @@ -355,8 +355,12 @@ namespace MWWorld if (cell->getCell()->hasWater()) mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); - if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) - mNavigator.removePathgrid(*pathgrid); + auto cell3 = cell->getCellVariant().getEsm3(); + if (cell3) + { + if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) + mNavigator.removePathgrid(*pathgrid); + } MWBase::Environment::get().getMechanicsManager()->drop(cell); @@ -383,14 +387,11 @@ namespace MWWorld Log(Debug::Info) << "Loading cell " << cell->getEditorName(); auto cell3 = cell->getCellVariant().getEsm3(); - int cellX = 0; - int cellY = 0; + const int cellX = cell->getCellVariant().getCommon()->getGridX(); + const int cellY = cell->getCellVariant().getCommon()->getGridY(); if (cell3 != nullptr) { - int cellX = cell3->getGridX(); - int cellY = cell3->getGridY(); - if (cell3->isExterior()) { osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); @@ -472,8 +473,10 @@ namespace MWWorld else mPhysics->disableWater(); - if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx)) - mRendering.configureAmbient(cell3); + const auto cellVariant = cell->getCellVariant(); + + if (!cell->isExterior() && !cellVariant.getCommon()->isQuasiExterior()) + mRendering.configureAmbient(cellVariant); mPreloader->notifyLoaded(cell); } @@ -549,7 +552,7 @@ namespace MWWorld mNavigator.setWorldspace( Misc::StringUtils::lowerCase( - mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace), + mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -672,7 +675,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -730,7 +733,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -746,7 +749,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->mName) + if (it->mName == (*iter)->getCell()->getEditorName()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; @@ -898,7 +901,7 @@ namespace MWWorld changePlayerCell(cell, position, adjustPlayerPos); // adjust fog - mRendering.configureFog(mCurrentCell->getCell()); + mRendering.configureFog(mCurrentCell->getCellVariant()); // Sky system mWorld.adjustSky(); @@ -914,7 +917,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag( - cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx); + cell->getCellVariant().getCommon()->isQuasiExterior()); } void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d4d74dd5ec..b7ddd6e924 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -704,7 +704,7 @@ namespace MWWorld if (!paused || mFastForward) { // Add new transitions when either the player's current external region changes. - if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->mRegion)) + if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->getRegion())) { auto it = mRegions.find(mCurrentRegion); if (it != mRegions.end()) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cec624898d..1b4a37b1eb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include @@ -634,18 +634,22 @@ namespace MWWorld { if (!cell) cell = mWorldScene->getCurrentCell(); - return getCellName(cell->getCell()); + return getCellName(cell->getCellVariant()); } - std::string_view World::getCellName(const ESM::Cell* cell) const + std::string_view World::getCellName(const ESM::CellVariant& cell) const { - if (cell) + auto cellCommon = cell.getCommon(); + if (cellCommon) { - if (!cell->isExterior() || !cell->mName.empty()) - return cell->mName; + if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty()) + return cellCommon->getEditorName(); - if (const ESM::Region* region = mStore.get().search(cell->mRegion)) + if (cell.getEsm3()) + { + const ESM::Region* region = mStore.get().search(cell.getEsm3()->mRegion); return region->mName; + } } return mStore.get().find("sDefaultCellname")->mValue.getString(); @@ -1139,7 +1143,7 @@ namespace MWWorld { if (!newCell->isExterior()) { - changeToInteriorCell(newCell->getCell()->mName, pos, false); + changeToInteriorCell(newCell->getCell()->getEditorName(), pos, false); removeContainerScripts(getPlayerPtr()); } else @@ -1400,7 +1404,7 @@ namespace MWWorld esmPos.pos[2] = traced.z(); std::string_view cell; if (!actor.getCell()->isExterior()) - cell = actor.getCell()->getCell()->mName; + cell = actor.getCell()->getCell()->getEditorName(); MWWorld::ActionTeleport(cell, esmPos, false).execute(actor); } } @@ -1988,10 +1992,7 @@ namespace MWWorld const CellStore* currentCell = mWorldScene->getCurrentCell(); if (currentCell) { - if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) - return false; - else - return true; + return currentCell->getCell()->isQuasiExterior(); } return false; } @@ -2312,7 +2313,7 @@ namespace MWWorld if (!cell) return false; - if (!(cell->getCell()->hasWater())) + if (!(cell->getCellVariant().getCommon()->hasWater())) { return false; } @@ -2468,8 +2469,7 @@ namespace MWWorld || isFlying(player)) return Rest_PlayerIsInAir; - if ((currentCell->getCell()->mData.mFlags & ESM::Cell::NoSleep) - || player.getClass().getNpcStats(player).isWerewolf()) + if (currentCell->getCell()->noSleep() || player.getClass().getNpcStats(player).isWerewolf()) return Rest_OnlyWaiting; return Rest_Allowed; @@ -2840,7 +2840,7 @@ namespace MWWorld { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - const ESM::Cell* ext = nullptr; + const ESM::CellCommon* ext = nullptr; try { ext = mWorldModel.getCell(nameId)->getCell(); @@ -3247,9 +3247,11 @@ namespace MWWorld } else { - uint32_t ambient = cell->getCell()->mAmbi.mAmbient; + auto cellVariant = cell->getCellVariant(); + uint32_t ambient = cellVariant.getEsm3() ? cellVariant.getEsm3()->mAmbi.mAmbient + : cellVariant.getEsm4()->mLighting.ambient; int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff); - return !(cell->getCell()->mData.mFlags & ESM::Cell::NoSleep) && ambientTotal <= 201; + return !cell->getCell()->noSleep() && ambientTotal <= 201; } } @@ -3328,7 +3330,7 @@ namespace MWWorld std::set nextCells; MWWorld::ConstPtr closestMarker; - nextCells.insert(ptr.getCell()->getCell()->mName); + nextCells.insert(ptr.getCell()->getCell()->getEditorName()); while (!nextCells.empty()) { currentCells = nextCells; @@ -3423,7 +3425,7 @@ namespace MWWorld std::string_view cellName = ""; if (!closestMarker.mCell->isExterior()) - cellName = closestMarker.mCell->getCell()->mName; + cellName = closestMarker.mCell->getCell()->getEditorName(); MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); @@ -3436,7 +3438,7 @@ namespace MWWorld { mPlayer->setTeleported(false); - const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->mRegion; + const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->getRegion(); mWeatherManager->playerTeleported(playerRegion, isExterior); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index df2ee69fbf..809daf95d8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -269,7 +269,7 @@ namespace MWWorld /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - std::string_view getCellName(const ESM::Cell* cell) const override; + std::string_view getCellName(const ESM::CellVariant& cell) const override; void removeRefScript(MWWorld::RefData* ref) override; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index ac754eae60..1dc935af3b 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -67,7 +67,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) auto result = mInteriors.find(cell->mName); if (result == mInteriors.end()) - result = mInteriors.emplace(cell->mName, CellStore(cell, mStore, mReaders)).first; + result = mInteriors.emplace(cell->mName, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; return &result->second; } @@ -78,7 +78,8 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) if (result == mExteriors.end()) result = mExteriors - .emplace(std::make_pair(cell->getGridX(), cell->getGridY()), CellStore(cell, mStore, mReaders)) + .emplace(std::make_pair(cell->getGridX(), cell->getGridY()), + CellStore(ESM::CellVariant(cell), mStore, mReaders)) .first; return &result->second; @@ -185,7 +186,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) cell = MWBase::Environment::get().getWorld()->createRecord(record); } - result = mExteriors.emplace(std::make_pair(x, y), CellStore(cell, mStore, mReaders)).first; + result = mExteriors.emplace(std::make_pair(x, y), CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; } if (result->second.getState() != CellStore::State_Loaded) @@ -207,11 +208,11 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) if (!cell4) { const ESM::Cell* cell = mStore.get().find(name); - result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; } else { - result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell4), mStore, mReaders)).first; } } @@ -261,14 +262,14 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name) return cell; } -MWWorld::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) +ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) { const ESM::Cell* cellEsm3 = getESMCellByName(name); - return cellEsm3; + return ESM::CellVariant(cellEsm3); if (!cellEsm3) { const ESM4::Cell* cellESM4 = mStore.get().searchCellName(name); - return cellESM4; + return ESM::CellVariant(cellESM4); } } diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 9caada64c0..aa21eedc2d 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -51,7 +51,7 @@ namespace MWWorld WorldModel& operator=(const WorldModel&); const ESM::Cell* getESMCellByName(std::string_view name); - CellVariant getCellByName(std::string_view name); + ESM::CellVariant getCellByName(std::string_view name); CellStore* getCellStore(const ESM::Cell* cell); Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index d2163520f7..795a9932ae 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -316,7 +317,7 @@ static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::E const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); ASSERT_EQ(recordIdCount, static_cast(1)) - << "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView(); + << "The same RecNameInt is used twice ESM::REC_" << ESM::getRecNameString(T::sRecordId).toStringView(); } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f863f246d0..9c7e6e61a5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon records util luascripts format refid) +add_component_dir(esm attr common defs esmcommon records util luascripts format refid cellcommon) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/cellcommon.cpp b/components/esm/cellcommon.cpp new file mode 100644 index 0000000000..42c93f0b83 --- /dev/null +++ b/components/esm/cellcommon.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +namespace ESM +{ + const ESM::CellCommon* CellVariant::getCommon() const + { + auto cell3 = getEsm3(); + if (cell3) + return cell3; + else + return getEsm4(); + } +} diff --git a/components/esm/cellcommon.hpp b/components/esm/cellcommon.hpp new file mode 100644 index 0000000000..ec2d0559ec --- /dev/null +++ b/components/esm/cellcommon.hpp @@ -0,0 +1,68 @@ +#ifndef COMPONENTS_ESM_CELLCOMMON +#define COMPONENTS_ESM_CELLCOMMON +#include +#include +#include + +namespace ESM4 +{ + struct Cell; +} + +namespace ESM +{ + struct Cell; + struct CellId; + struct RefId; + // Common interface for esm3 and esm4 cells + struct CellCommon + { + virtual int getGridX() const = 0; + virtual int getGridY() const = 0; + virtual bool isExterior() const = 0; + virtual bool isQuasiExterior() const = 0; + virtual bool hasWater() const = 0; + virtual bool noSleep() const { return false; } + virtual const ESM::CellId& getCellId() const = 0; + virtual const ESM::RefId& getRegion() const = 0; + virtual std::string_view getEditorName() const = 0; + virtual std::string getDescription() const = 0; + }; + + struct CellVariant + { + std::variant mVariant; + + explicit CellVariant(const ESM4::Cell* cell) + : mVariant(cell) + { + } + + explicit CellVariant(const ESM::Cell* cell) + : mVariant(cell) + { + } + + bool isEsm4() const { return getEsm4(); } + + const ESM4::Cell* getEsm4() const + { + auto cell4 = std::get_if(&mVariant); + if (cell4) + return *cell4; + return nullptr; + } + + const ESM::Cell* getEsm3() const + { + auto cell3 = std::get_if(&mVariant); + if (cell3) + return *cell3; + return nullptr; + } + + const ESM::CellCommon* getCommon() const; + }; +} + +#endif diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index a63a1bfad6..f5318cbbd7 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -31,7 +31,7 @@ namespace ESM bool operator==(const CellId& left, const CellId& right) { - return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged + return left.mWorld == right.mWorld && left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged && (!left.mPaged || (left.mIndex.mX == right.mIndex.mX && left.mIndex.mY == right.mIndex.mY)); } diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 33db9e7432..8d2418790f 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -17,6 +17,7 @@ namespace ESM int mY; }; + ESM::RefId mWorld; std::string mWorldspace; CellIndex mIndex; bool mPaged; diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 3cf1834dfa..7518d81b3c 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -7,6 +7,7 @@ #include "cellid.hpp" #include "cellref.hpp" +#include "components/esm/cellcommon.hpp" #include "components/esm/defs.hpp" #include "components/esm/esmcommon.hpp" #include "components/esm/refid.hpp" @@ -65,7 +66,7 @@ namespace ESM (using ESMReader::getContext()) and jumping back into place whenever we need to load a given cell. */ - struct Cell + struct Cell : public CellCommon { constexpr static RecNameInts sRecordId = REC_CELL; @@ -150,13 +151,14 @@ namespace ESM void save(ESMWriter& esm, bool isDeleted = false) const; void saveTempMarker(ESMWriter& esm, int tempCount) const; - bool isExterior() const { return !(mData.mFlags & Interior); } + bool isExterior() const override { return !(mData.mFlags & Interior); } + bool isQuasiExterior() const override { return mData.mFlags & QuasiEx; } - int getGridX() const { return mData.mX; } + int getGridX() const override { return mData.mX; } - int getGridY() const { return mData.mY; } + int getGridY() const override { return mData.mY; } - bool hasWater() const { return ((mData.mFlags & HasWater) != 0) || isExterior(); } + bool hasWater() const override { return ((mData.mFlags & HasWater) != 0) || isExterior(); } bool hasAmbient() const { return mHasAmbi; } @@ -169,7 +171,7 @@ namespace ESM // exactly. void restore(ESMReader& esm, int iCtx) const; - std::string getDescription() const; + std::string getDescription() const override; ///< Return a short string describing the cell (mostly used for debugging/logging purpose) /* Get the next reference in this cell, if any. Returns false when @@ -191,7 +193,10 @@ namespace ESM void blank(); ///< Set record to default state (does not touch the ID/index). - const CellId& getCellId() const; + const CellId& getCellId() const override; + const ESM::RefId& getRegion() const override { return mRegion; } + bool noSleep() const override { return mData.mFlags & ESM::Cell::NoSleep; } + std::string_view getEditorName() const override { return mName; } }; } #endif diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 0b829d657f..22d6a46865 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -39,6 +39,7 @@ // #include "writer.hpp" #include +#include // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // @@ -77,6 +78,12 @@ void ESM4::Cell::load(ESM4::Reader& reader) std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; + mCellId.mWorldspace = Misc::StringUtils::lowerCase(mEditorId); + mCellId.mWorld = ESM::RefId::sEmpty; + mCellId.mIndex.mX = getGridX(); + mCellId.mIndex.mX = getGridY(); + mCellId.mPaged = isExterior(); + while (reader.getSubRecordHeader()) { const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 49e5d048b0..5be37cad11 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -34,8 +34,10 @@ #include "formid.hpp" #include "lighting.hpp" +#include #include #include +#include namespace ESM4 { @@ -60,7 +62,7 @@ namespace ESM4 // Unlike TES3, multiple cells can have the same exterior co-ordinates. // The cells need to be organised under world spaces. - struct Cell + struct Cell final : public ESM::CellCommon { FormId mParent; // world formId (for grouping cells), from the loading sequence @@ -94,12 +96,24 @@ namespace ESM4 CellGroup* mCellGroup; + ESM::CellId mCellId; + void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const; void blank(); static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4; + + int getGridX() const override { return mX; } + int getGridY() const override { return mY; } + bool isExterior() const override { return false; /*unimplemented for now*/ } + virtual bool isQuasiExterior() const override { return false; /*unimplemented for now*/ } + virtual bool hasWater() const override { return false; /*unimplemented for now*/ } + const ESM::CellId& getCellId() const override { return mCellId; } + const ESM::RefId& getRegion() const override { return ESM::RefId::sEmpty; } + std::string_view getEditorName() const override { return mEditorId; } + std::string getDescription() const override { return mEditorId; }; }; } diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp index 9adc7a92d7..bc9ef6d427 100644 --- a/components/misc/coordinateconverter.hpp +++ b/components/misc/coordinateconverter.hpp @@ -17,8 +17,8 @@ namespace Misc { } - explicit CoordinateConverter(const ESM::Cell* cell) - : CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY) + explicit CoordinateConverter(const ESM::CellCommon* cell) + : CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY()) { } From e81e2783633f58e4939fa015e9dd219d74f3bfd8 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 23 Jan 2023 13:50:41 +0100 Subject: [PATCH 04/25] Implements some cell params + linux compile fix --- components/esm4/loadcell.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 5be37cad11..90215ec88f 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -107,13 +107,13 @@ namespace ESM4 int getGridX() const override { return mX; } int getGridY() const override { return mY; } - bool isExterior() const override { return false; /*unimplemented for now*/ } - virtual bool isQuasiExterior() const override { return false; /*unimplemented for now*/ } + bool isExterior() const override { return !(mFlags & CELL_Interior); } + virtual bool isQuasiExterior() const override { return mFlags & 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; }; + std::string getDescription() const override { return mEditorId; } }; } From 0018bcf7dedf2b8a513acd2dacb0e6eff77f1cf6 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 23 Jan 2023 19:08:52 +0100 Subject: [PATCH 05/25] Should make cellvariant safer to use. Hopefully clang tidy agrees. --- apps/openmw/mwmechanics/aicombat.cpp | 7 ++-- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 17 +++++----- apps/openmw/mwmechanics/pathgrid.cpp | 4 +-- apps/openmw/mwrender/fogmanager.cpp | 5 +-- apps/openmw/mwrender/pathgrid.cpp | 6 ++-- apps/openmw/mwrender/renderingmanager.cpp | 17 +++------- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 40 ++++++++++------------- apps/openmw/mwworld/scene.cpp | 22 ++++++------- apps/openmw/mwworld/worldimp.cpp | 8 ++--- components/esm/cellcommon.cpp | 22 +++++++++++-- components/esm/cellcommon.hpp | 31 +++++++++--------- 13 files changed, 92 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index d9358a0e56..bf5f7cebc0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -357,12 +357,13 @@ namespace MWMechanics case AiCombatStorage::FleeState_Idle: { float triggerDist = getMaxAttackDistance(target); - auto cell3 = storage.mCell->getCellVariant().getEsm3(); - if (cell3 && storage.mLOS + auto cellVariant = storage.mCell->getCellVariant(); + if (!cellVariant.isEsm4() && storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); + = MWBase::Environment::get().getWorld()->getStore().get().search( + cellVariant.getEsm3()); bool runFallback = true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1233e16a39..ac96765a3a 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -411,7 +411,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) { - const ESM::Cell* playerCell(getPlayer().getCell()->getCellVariant().getEsm3()); + const ESM::Cell* playerCell(&getPlayer().getCell()->getCellVariant().getEsm3()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6043759b3e..1ff9cf0c54 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -271,10 +271,9 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - auto cell3 = actor.getCell()->getCellVariant().getEsm3(); - if (cell3 && storage.mPopulateAvailableNodes) + if (!actor.getCell()->getCellVariant().isEsm4() && storage.mPopulateAvailableNodes) { - getAllowedNodes(actor, cell3, storage); + getAllowedNodes(actor, &actor.getCell()->getCellVariant().getEsm3(), storage); } auto& prng = MWBase::Environment::get().getWorld()->getPrng(); @@ -722,9 +721,8 @@ namespace MWMechanics return; AiWanderStorage& storage = state.get(); - auto cell3 = actor.getCell()->getCellVariant().getEsm3(); - if (cell3 && storage.mPopulateAvailableNodes) - getAllowedNodes(actor, cell3, storage); + if (!actor.getCell()->getCellVariant().isEsm4() && storage.mPopulateAvailableNodes) + getAllowedNodes(actor, &actor.getCell()->getCellVariant().getEsm3(), storage); if (storage.mAllowedNodes.empty()) return; @@ -802,11 +800,12 @@ namespace MWMechanics void AiWander::getNeighbouringNodes( ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { - auto cell3 = currentCell->getCellVariant().getEsm3(); - if (!cell3) + if (currentCell->getCellVariant().isEsm4()) return; + auto cell3 = currentCell->getCellVariant().getEsm3(); + const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); + = MWBase::Environment::get().getWorld()->getStore().get().search(cell3); if (pathgrid == nullptr || pathgrid->mPoints.empty()) return; diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index ceaf513937..282ac4e381 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -98,13 +98,13 @@ namespace MWMechanics */ bool PathgridGraph::load(const MWWorld::CellStore* cell) { - if (!cell) + if (!cell || !cell->getCellVariant().isValid()) return false; if (mIsGraphConstructed) return true; - mCell = cell->getCellVariant().getEsm3(); + mCell = cell->getCellVariant().isEsm4() ? nullptr : &cell->getCellVariant().getEsm3(); if (!mCell) return false; mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell); diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index 6b56bc81a2..c87ef8757f 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -45,9 +45,10 @@ namespace MWRender auto cell3 = cell.getEsm3(); auto cell4 = cell.getEsm4(); - osg::Vec4f color = SceneUtil::colourFromRGB(cell3 ? cell3->mAmbi.mFog : cell4->mLighting.fogColor); + osg::Vec4f color + = SceneUtil::colourFromRGB(cell.isEsm4() ? cell.getEsm4().mLighting.fogColor : cell.getEsm3().mAmbi.mFog); - const float fogDensity = cell3 ? cell3->mAmbi.mFogDensity : cell4->mLighting.fogPower; + const float fogDensity = !cell.isEsm4() ? cell.getEsm3().mAmbi.mFogDensity : cell.getEsm4().mLighting.fogPower; if (mDistantFog) { float density = std::max(0.2f, fogDensity); diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 85d8f7a295..f449861a07 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -102,10 +102,10 @@ namespace MWRender void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) { MWBase::World* world = MWBase::Environment::get().getWorld(); - auto cell3 = store->getCellVariant().getEsm3(); - if (!cell3) + if (store->getCellVariant().isEsm4()) return; - const ESM::Pathgrid* pathgrid = world->getStore().get().search(*cell3); + const ESM::Pathgrid* pathgrid + = world->getStore().get().search(store->getCellVariant().getEsm3()); if (!pathgrid) return; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7f03d4707c..ef09d38df0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -747,17 +747,8 @@ namespace MWRender if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP) needsAdjusting = isInterior; - osg::Vec4f ambient; - auto cell3 = cell.getEsm3(); - auto cell4 = cell.getEsm4(); - if (cell3) - { - ambient = SceneUtil::colourFromRGB(cell3->mAmbi.mAmbient); - } - else - { - ambient = SceneUtil::colourFromRGB(cell4->mLighting.ambient); - } + osg::Vec4f ambient = SceneUtil::colourFromRGB( + cell.isEsm4() ? cell.getEsm4().mLighting.ambient : cell.getEsm3().mAmbi.mAmbient); if (needsAdjusting) { @@ -781,8 +772,8 @@ namespace MWRender setAmbientColour(ambient); - osg::Vec4f diffuse = cell3 ? SceneUtil::colourFromRGB(cell3->mAmbi.mSunlight) - : SceneUtil::colourFromRGB(cell4->mLighting.directional); + osg::Vec4f diffuse = SceneUtil::colourFromRGB( + !cell.isEsm4() ? cell.getEsm3().mAmbi.mSunlight : cell.getEsm4().mLighting.directional); setSunColour(diffuse, diffuse, 1.f); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 06f889d58a..e0b905a228 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -781,7 +781,7 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - const ESM::Cell* curcell = player.getCell()->getCellVariant().getEsm3(); + const ESM::Cell* curcell = &player.getCell()->getCellVariant().getEsm3(); const auto update = mWaterSoundUpdater.update(player, *world); WaterSoundAction action; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0fe281dcc6..8e09c7953b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -516,7 +516,7 @@ namespace MWWorld , mRechargingItemsUpToDate(false) { - mCell = mCellVariant.getEsm3(); + mCell = mCellVariant.isEsm4() ? nullptr : &mCellVariant.getEsm3(); std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); if (mCell) @@ -538,14 +538,13 @@ namespace MWWorld std::string_view CellStore::getEditorName() const { - const ESM4::Cell* cell4 = mCellVariant.getEsm4(); - if (cell4) + if (mCellVariant.isEsm4()) { - return cell4->mEditorId; + return mCellVariant.getEsm4().mEditorId; } else { - return mCellVariant.getEsm3()->mName; + return mCellVariant.getEsm3().mName; } } @@ -759,17 +758,17 @@ namespace MWWorld void CellStore::loadRefs() { - assert(mCellVariant.getEsm4() || mCellVariant.getEsm3()); - const ESM4::Cell* cell4 = mCellVariant.getEsm4(); - if (cell4) - { + assert(mCellVariant.isValid()); + if (mCellVariant.isEsm4()) + { + auto cell4 = mCellVariant.getEsm4(); auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); auto it = refs.begin(); while (it != refs.end()) { - if (it->mParent == cell4->mId) + if (it->mParent == cell4.mId) { loadRef(*it, false); } @@ -836,15 +835,12 @@ namespace MWWorld bool CellStore::isExterior() const { - auto cell3 = mCellVariant.getEsm3(); - return cell3 ? cell3->isExterior() : false; + return mCellVariant.getCommon()->isExterior(); } bool CellStore::isQuasiExterior() const { - auto cell3 = mCellVariant.getEsm3(); - - return cell3 ? (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0 : false; + return mCellVariant.getCommon()->isExterior(); } Ptr CellStore::searchInContainer(const ESM::RefId& id) @@ -1084,16 +1080,14 @@ namespace MWWorld bool CellStore::operator==(const CellStore& right) const { - auto cell4Left = mCellVariant.getEsm4(); - auto cell4Right = right.mCellVariant.getEsm4(); - auto cell3Left = mCellVariant.getEsm3(); - auto cell3Right = right.mCellVariant.getEsm3(); + bool bothCell4 = mCellVariant.isEsm4() && right.mCellVariant.isEsm4(); + bool bothCell3 = !mCellVariant.isEsm4() && !right.mCellVariant.isEsm4(); - if (!cell4Left && !cell4Right) - return cell3Left->getCellId() == cell3Right->getCellId(); - else if (cell4Left && cell4Right) - return cell4Left->mId == cell4Right->mId; + if (bothCell3) + return mCellVariant.getEsm3().getCellId() == right.mCellVariant.getEsm3().getCellId(); + else if (bothCell4) + return mCellVariant.getEsm4().mId == right.mCellVariant.getEsm4().mId; else return false; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6c817f3b56..0c5f72b107 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -355,10 +355,9 @@ namespace MWWorld if (cell->getCell()->hasWater()) mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); - auto cell3 = cell->getCellVariant().getEsm3(); - if (cell3) + if (!cell->getCellVariant().isEsm4()) { - if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) + if (const auto pathgrid = mWorld.getStore().get().search(cell->getCellVariant().getEsm3())) mNavigator.removePathgrid(*pathgrid); } @@ -386,13 +385,14 @@ namespace MWWorld Log(Debug::Info) << "Loading cell " << cell->getEditorName(); - auto cell3 = cell->getCellVariant().getEsm3(); const int cellX = cell->getCellVariant().getCommon()->getGridX(); const int cellY = cell->getCellVariant().getCommon()->getGridY(); - if (cell3 != nullptr) + auto cellVariant = cell->getCellVariant(); + if (!cellVariant.isEsm4()) { + auto cell3 = cellVariant.getEsm3(); - if (cell3->isExterior()) + if (cell3.isExterior()) { osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; @@ -434,8 +434,8 @@ namespace MWWorld } } - if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) - mNavigator.addPathgrid(*cell3, *pathgrid); + if (const auto pathgrid = mWorld.getStore().get().search(cell3)) + mNavigator.addPathgrid(cell3, *pathgrid); } // register local scripts @@ -450,7 +450,7 @@ namespace MWWorld mRendering.addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell); - bool waterEnabled = cell3 && (cell3->hasWater() || cell->isExterior()); + bool waterEnabled = (!cellVariant.isEsm4()) && (cellVariant.getEsm3().hasWater() || cell->isExterior()); float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) @@ -458,7 +458,7 @@ namespace MWWorld mPhysics->enableWater(waterLevel); mRendering.setWaterHeight(waterLevel); - if (cell3->isExterior()) + if (cellVariant.getEsm3().isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) mNavigator.addWater( @@ -473,8 +473,6 @@ namespace MWWorld else mPhysics->disableWater(); - const auto cellVariant = cell->getCellVariant(); - if (!cell->isExterior() && !cellVariant.getCommon()->isQuasiExterior()) mRendering.configureAmbient(cellVariant); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1b4a37b1eb..5bee6c554a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -645,9 +645,9 @@ namespace MWWorld if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty()) return cellCommon->getEditorName(); - if (cell.getEsm3()) + if (!cell.isEsm4()) { - const ESM::Region* region = mStore.get().search(cell.getEsm3()->mRegion); + const ESM::Region* region = mStore.get().search(cell.getEsm3().mRegion); return region->mName; } } @@ -3248,8 +3248,8 @@ namespace MWWorld else { auto cellVariant = cell->getCellVariant(); - uint32_t ambient = cellVariant.getEsm3() ? cellVariant.getEsm3()->mAmbi.mAmbient - : cellVariant.getEsm4()->mLighting.ambient; + uint32_t ambient = !cellVariant.isEsm4() ? cellVariant.getEsm3().mAmbi.mAmbient + : cellVariant.getEsm4().mLighting.ambient; int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff); return !cell->getCell()->noSleep() && ambientTotal <= 201; } diff --git a/components/esm/cellcommon.cpp b/components/esm/cellcommon.cpp index 42c93f0b83..ce3f50c726 100644 --- a/components/esm/cellcommon.cpp +++ b/components/esm/cellcommon.cpp @@ -7,9 +7,25 @@ namespace ESM const ESM::CellCommon* CellVariant::getCommon() const { auto cell3 = getEsm3(); - if (cell3) - return cell3; + if (isEsm4()) + return &getEsm4(); else - return getEsm4(); + return &getEsm3(); + } + + const ESM4::Cell& CellVariant::getEsm4() const + { + auto cell4 = std::get<0>(mVariant); + if (!cell4) + throw std::runtime_error("invalid variant acess"); + return *cell4; + } + + const ESM::Cell& CellVariant::getEsm3() const + { + auto cell = std::get<1>(mVariant); + if (!cell) + throw std::runtime_error("invalid variant acess"); + return *cell; } } diff --git a/components/esm/cellcommon.hpp b/components/esm/cellcommon.hpp index ec2d0559ec..a8067c11a1 100644 --- a/components/esm/cellcommon.hpp +++ b/components/esm/cellcommon.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace ESM4 { struct Cell; @@ -31,7 +33,12 @@ namespace ESM struct CellVariant { - std::variant mVariant; + std::variant mVariant; + + CellVariant() + : mVariant((void*)(nullptr)) + { + } explicit CellVariant(const ESM4::Cell* cell) : mVariant(cell) @@ -43,23 +50,17 @@ namespace ESM { } - bool isEsm4() const { return getEsm4(); } - - const ESM4::Cell* getEsm4() const + bool isValid() const { - auto cell4 = std::get_if(&mVariant); - if (cell4) - return *cell4; - return nullptr; + return std::holds_alternative(mVariant) + || std::holds_alternative(mVariant); } - const ESM::Cell* getEsm3() const - { - auto cell3 = std::get_if(&mVariant); - if (cell3) - return *cell3; - return nullptr; - } + bool isEsm4() const { return std::holds_alternative(mVariant); } + + const ESM4::Cell& getEsm4() const; + + const ESM::Cell& getEsm3() const; const ESM::CellCommon* getCommon() const; }; From c896a2ca48a7884354f8bde926628411c2883a11 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 23 Jan 2023 21:44:49 +0100 Subject: [PATCH 06/25] Crashfix on launch --- apps/openmw/mwlua/cellbindings.cpp | 2 +- apps/openmw/mwrender/fogmanager.cpp | 5 +---- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +++ apps/openmw/mwworld/cellstore.hpp | 2 +- components/CMakeLists.txt | 2 +- .../esm/{cellcommon.cpp => esm3esm4bridge.cpp} | 3 +-- .../esm/{cellcommon.hpp => esm3esm4bridge.hpp} | 0 components/esm3/loadcell.hpp | 2 +- components/esm4/loadcell.cpp | 12 ++++++------ components/esm4/loadcell.hpp | 6 +++--- 10 files changed, 18 insertions(+), 19 deletions(-) rename components/esm/{cellcommon.cpp => esm3esm4bridge.cpp} (90%) rename components/esm/{cellcommon.hpp => esm3esm4bridge.hpp} (100%) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index a1d4b3991d..c45ea3a8ca 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -1,6 +1,6 @@ #include "luabindings.hpp" -#include +#include #include #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index c87ef8757f..8752196dc6 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include #include @@ -42,9 +42,6 @@ namespace MWRender void FogManager::configure(float viewDistance, const ESM::CellVariant& cell) { - auto cell3 = cell.getEsm3(); - auto cell4 = cell.getEsm4(); - osg::Vec4f color = SceneUtil::colourFromRGB(cell.isEsm4() ? cell.getEsm4().mLighting.fogColor : cell.getEsm3().mAmbi.mFog); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index e0b905a228..a54b3e40d7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -781,6 +781,9 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); + if (player.getCell()->getCellVariant().isEsm4()) + return; + const ESM::Cell* curcell = &player.getCell()->getCellVariant().getEsm3(); const auto update = mWaterSoundUpdater.update(player, *world); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 76b822d8b8..736470f15b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -15,7 +15,7 @@ #include "cellreflist.hpp" #include "livecellref.hpp" -#include +#include #include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9c7e6e61a5..7fd42de677 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon records util luascripts format refid cellcommon) +add_component_dir(esm attr common defs esmcommon records util luascripts format refid esm3esm4bridge) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/cellcommon.cpp b/components/esm/esm3esm4bridge.cpp similarity index 90% rename from components/esm/cellcommon.cpp rename to components/esm/esm3esm4bridge.cpp index ce3f50c726..ec76b19fc6 100644 --- a/components/esm/cellcommon.cpp +++ b/components/esm/esm3esm4bridge.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,7 +6,6 @@ namespace ESM { const ESM::CellCommon* CellVariant::getCommon() const { - auto cell3 = getEsm3(); if (isEsm4()) return &getEsm4(); else diff --git a/components/esm/cellcommon.hpp b/components/esm/esm3esm4bridge.hpp similarity index 100% rename from components/esm/cellcommon.hpp rename to components/esm/esm3esm4bridge.hpp diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 7518d81b3c..c957dc493a 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -7,8 +7,8 @@ #include "cellid.hpp" #include "cellref.hpp" -#include "components/esm/cellcommon.hpp" #include "components/esm/defs.hpp" +#include "components/esm/esm3esm4bridge.hpp" #include "components/esm/esmcommon.hpp" #include "components/esm/refid.hpp" diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 22d6a46865..fed031ed16 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -78,12 +78,6 @@ void ESM4::Cell::load(ESM4::Reader& reader) std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; - mCellId.mWorldspace = Misc::StringUtils::lowerCase(mEditorId); - mCellId.mWorld = ESM::RefId::sEmpty; - mCellId.mIndex.mX = getGridX(); - mCellId.mIndex.mX = getGridY(); - mCellId.mPaged = isExterior(); - while (reader.getSubRecordHeader()) { const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); @@ -247,6 +241,12 @@ 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 diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 90215ec88f..631aa1c94a 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -34,8 +34,8 @@ #include "formid.hpp" #include "lighting.hpp" -#include #include +#include #include #include @@ -107,8 +107,8 @@ namespace ESM4 int getGridX() const override { return mX; } int getGridY() const override { return mY; } - bool isExterior() const override { return !(mFlags & CELL_Interior); } - virtual bool isQuasiExterior() const override { return mFlags & CELL_QuasiExt; } + 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; } From 3515c8e61a246d2f1f2769ab509a1c5faedb64f5 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 23 Jan 2023 23:51:45 +0100 Subject: [PATCH 07/25] Static references are created as refcells, nothing displayed yet. --- apps/openmw/mwworld/cellref.hpp | 31 +++++++++++++++++++-- apps/openmw/mwworld/cellreflist.hpp | 2 ++ apps/openmw/mwworld/cellstore.cpp | 43 +++++++++++++++++++++-------- apps/openmw/mwworld/esmstore.cpp | 9 +++--- apps/openmw/mwworld/livecellref.cpp | 7 +++++ apps/openmw/mwworld/livecellref.hpp | 7 +++++ apps/openmw/mwworld/manualref.cpp | 5 +++- apps/openmw/mwworld/refdata.cpp | 14 ++++++++++ apps/openmw/mwworld/refdata.hpp | 6 ++++ components/esm/esm3esm4bridge.hpp | 4 +-- 10 files changed, 108 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index e0b589c408..ac9cf7a3ee 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -3,7 +3,9 @@ #include +#include #include +#include namespace ESM { @@ -20,9 +22,19 @@ namespace MWWorld CellRef(const ESM::CellRef& ref) : mCellRef(ref) { + mIsEsm4 = false; mChanged = false; } + CellRef(const ESM4::Reference& ref) + : mCellRef4(ref) + { + mRefrPos = { { mCellRef4.mPlacement.pos.x, mCellRef4.mPlacement.pos.y, mCellRef4.mPlacement.pos.z }, + { mCellRef4.mPlacement.rot.x, mCellRef4.mPlacement.rot.y, mCellRef4.mPlacement.rot.z } }; + mChanged = false; + mIsEsm4 = true; + } + // Note: Currently unused for items in containers const ESM::RefNum& getRefNum() const { return mCellRef.mRefNum; } @@ -50,12 +62,24 @@ namespace MWWorld const std::string& getDestCell() const { return mCellRef.mDestCell; } // Scale applied to mesh - float getScale() const { return mCellRef.mScale; } + float getScale() const + { + if (mIsEsm4) + return mCellRef4.mScale; + else + return mCellRef.mScale; + } void setScale(float scale); // The *original* position and rotation as it was given in the Construction Set. // Current position and rotation of the object is stored in RefData. - const ESM::Position& getPosition() const { return mCellRef.mPos; } + const ESM::Position& getPosition() const + { + if (mIsEsm4) + return mRefrPos; + else + return mCellRef.mPos; + } void setPosition(const ESM::Position& position); // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). @@ -124,6 +148,9 @@ namespace MWWorld private: bool mChanged; ESM::CellRef mCellRef; + ESM4::Reference mCellRef4; + ESM::Position mRefrPos; + bool mIsEsm4; }; } diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 8f0a31b5e3..51e1d7df05 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -28,6 +28,8 @@ namespace MWWorld /// all methods are known. void load(ESM::CellRef& ref, bool deleted, const MWWorld::ESMStore& esmStore); + void load(const ESM4::Reference& ref, bool deleted, const MWWorld::ESMStore& esmStore); + LiveRef& insert(const LiveRef& item) { mList.push_back(item); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 8e09c7953b..88d076a8f9 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -371,6 +371,37 @@ namespace MWWorld } } + template + void CellRefList::load(const ESM4::Reference& ref, bool deleted, const MWWorld::ESMStore& esmStore) + { + + if constexpr (!ESM::isESM4Rec(X::sRecordId)) + return; + + const MWWorld::Store& store = esmStore.get(); + + if (const X* ptr = store.search(ref.mBaseObj)) + { + // typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.); + + LiveRef liveCellRef(ref, ptr); + + if (deleted) + liveCellRef.mData.setDeletedByContentFile(true); + + /*if (iter != mList.end()) + *iter = liveCellRef; + else + */ + mList.push_back(liveCellRef); + } + else + { + Log(Debug::Warning) << "Warning: could not resolve cell reference '" << ref.mId << "'" + << " (dropping reference)"; + } + } + template bool operator==(const LiveCellRef& ref, int pRefnum) { @@ -863,16 +894,6 @@ namespace MWWorld return Ptr(); } - template - static void loadRefESM4( - const MWWorld::ESMStore& store, const ESM4::Reference& ref, MWWorld::CellRefList& storeIn, bool deleted) - { - if constexpr (ESM::isESM4Rec(T::sRecordId)) - { - // storeIn.load(ref, deleted, store); - } - } - void CellStore::loadRef(const ESM4::Reference& ref, bool deleted) { const MWWorld::ESMStore& store = mStore; @@ -881,7 +902,7 @@ namespace MWWorld Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType](auto& x) { recNameSwitcher( - x, foundType, [&ref, &deleted, &store](auto& storeIn) { loadRefESM4(store, ref, storeIn, deleted); }); + x, foundType, [&ref, &deleted, &store](auto& storeIn) { storeIn.load(ref, deleted, store); }); }); } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index aa5185149b..7d9fda7273 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -210,8 +210,8 @@ namespace MWWorld static bool readRecord(ESM4::Reader& reader, ESMStore& store) { - return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); }, - store.mStoreImp->mStores); + return std::apply( + [&reader](auto&... x) { return (typedReadRecordESM4(reader, x) || ...); }, store.mStoreImp->mStores); } }; @@ -278,6 +278,7 @@ namespace MWWorld case ESM::REC_STAT: case ESM::REC_WEAP: case ESM::REC_BODY: + case ESM::REC_STAT4: return true; break; } @@ -595,8 +596,8 @@ namespace MWWorld removeMissingObjects(getWritable()); } - // Leveled lists can be modified by scripts. This removes items that no longer exist (presumably because the plugin - // was removed) from modified lists + // Leveled lists can be modified by scripts. This removes items that no longer exist (presumably because the + // plugin was removed) from modified lists template void ESMStore::removeMissingObjects(Store& store) { diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 66e31be635..88218429e1 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -22,6 +22,13 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM::CellRef& { } +MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Reference& cref) + : mClass(&Class::get(type)) + , mRef(cref) + , mData(cref) +{ +} + void MWWorld::LiveCellRefBase::loadImp(const ESM::ObjectState& state) { mRef = state.mRef; diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 4e3cb322cc..dc38ff9830 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -35,6 +35,7 @@ namespace MWWorld RefData mData; LiveCellRefBase(unsigned int type, const ESM::CellRef& cref = ESM::CellRef()); + LiveCellRefBase(unsigned int type, const ESM4::Reference& cref); /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() {} @@ -115,6 +116,12 @@ namespace MWWorld { } + LiveCellRef(const ESM4::Reference& cref, const X* b = nullptr) + : LiveCellRefBase(X::sRecordId, cref) + , mBase(b) + { + } + LiveCellRef(const X* b = nullptr) : LiveCellRefBase(X::sRecordId) , mBase(b) diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index ec5a3f5e77..741e036154 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -1,5 +1,6 @@ #include "manualref.hpp" #include +#include #include "esmstore.hpp" @@ -89,7 +90,9 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& case ESM::REC_BODY: create(store.get(), name, mRef, mPtr); break; - + case ESM::REC_STAT4: + create(store.get(), name, mRef, mPtr); + break; case 0: throw std::logic_error("failed to create manual cell ref for " + name.getRefIdString() + " (unknown ID)"); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index ffc5af7ff9..b1e03a5722 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -85,6 +85,20 @@ namespace MWWorld { } + RefData::RefData(const ESM4::Reference& cellRef) + : mBaseNode(nullptr) + , mDeletedByContentFile(false) + , mEnabled(true) + , mPhysicsPostponed(false) + , mCount(1) + , mPosition{ { cellRef.mPlacement.pos.x, cellRef.mPlacement.pos.y, cellRef.mPlacement.pos.z }, + { cellRef.mPlacement.rot.x, cellRef.mPlacement.rot.y, cellRef.mPlacement.rot.z } } + , mCustomData(nullptr) + , mChanged(false) + , mFlags(0) + { + } + RefData::RefData(const ESM::ObjectState& objectState, bool deletedByContentFile) : mBaseNode(nullptr) , mDeletedByContentFile(deletedByContentFile) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 1abc2264bf..0ceb951335 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -25,6 +25,11 @@ namespace ESM struct ObjectState; } +namespace ESM4 +{ + struct Reference; +} + namespace MWLua { class LocalScripts; @@ -76,6 +81,7 @@ namespace MWWorld /// be altered without affecting the original data. This makes it possible /// to reset the position as the original data is still held in the CellRef RefData(const ESM::CellRef& cellRef); + RefData(const ESM4::Reference& cellRef); RefData(const ESM::ObjectState& objectState, bool deletedByContentFile); ///< Ignores local variables and custom data (not enough context available here to diff --git a/components/esm/esm3esm4bridge.hpp b/components/esm/esm3esm4bridge.hpp index a8067c11a1..4c6eaf5875 100644 --- a/components/esm/esm3esm4bridge.hpp +++ b/components/esm/esm3esm4bridge.hpp @@ -1,5 +1,5 @@ -#ifndef COMPONENTS_ESM_CELLCOMMON -#define COMPONENTS_ESM_CELLCOMMON +#ifndef COMPONENTS_ESM_ESMBRIDGE +#define COMPONENTS_ESM_ESMBRIDGE #include #include #include From 6d25d4bc1349a10833aa9198e3323a54e06a7838 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 24 Jan 2023 23:17:04 +0100 Subject: [PATCH 08/25] It loads cells and palce sstatics in them Many missing meshes, no lights etc... But can coc into interior cells and see them. --- apps/openmw/mwworld/cellstore.cpp | 87 +++++++++++++++---------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 88d076a8f9..29c05e72b5 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -790,6 +790,7 @@ namespace MWWorld void CellStore::loadRefs() { assert(mCellVariant.isValid()); + std::map refNumToID; // used to detect refID modifications if (mCellVariant.isEsm4()) { @@ -805,60 +806,58 @@ namespace MWWorld } ++it; } - return; } - - if (mCell->mContextList.empty()) - return; // this is a dynamically generated cell -> skipping. - - std::map refNumToID; // used to detect refID modifications - - // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < mCell->mContextList.size(); i++) + else { - try - { - // Reopen the ESM reader and seek to the right position. - const std::size_t index = static_cast(mCell->mContextList[i].index); - const ESM::ReadersCache::BusyItem reader = mReaders.get(index); - mCell->restore(*reader, i); + if (mCell->mContextList.empty()) + return; // this is a dynamically generated cell -> skipping. - ESM::CellRef ref; - // Get each reference in turn - ESM::MovedCellRef cMRef; - bool deleted = false; - bool moved = false; - while (ESM::Cell::getNextRef( - *reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved)) + // Load references from all plugins that do something with this cell. + for (size_t i = 0; i < mCell->mContextList.size(); i++) + { + try { - if (moved) - continue; - - // 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()) + // Reopen the ESM reader and seek to the right position. + const std::size_t index = static_cast(mCell->mContextList[i].index); + const ESM::ReadersCache::BusyItem reader = mReaders.get(index); + mCell->restore(*reader, i); + + ESM::CellRef ref; + // Get each reference in turn + ESM::MovedCellRef cMRef; + bool deleted = false; + bool moved = false; + while (ESM::Cell::getNextRef( + *reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved)) { - continue; + if (moved) + continue; + + // 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()) + { + continue; + } + + loadRef(ref, deleted, refNumToID); } - - loadRef(ref, deleted, refNumToID); + } + catch (std::exception& e) + { + Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription() + << ": " << e.what(); } } - catch (std::exception& e) + // Load moved references, from separately tracked list. + for (const auto& leasedRef : mCell->mLeasedRefs) { - Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription() - << ": " << e.what(); - } - } + ESM::CellRef& ref = const_cast(leasedRef.first); + bool deleted = leasedRef.second; - // Load moved references, from separately tracked list. - for (const auto& leasedRef : mCell->mLeasedRefs) - { - ESM::CellRef& ref = const_cast(leasedRef.first); - bool deleted = leasedRef.second; - - loadRef(ref, deleted, refNumToID); + loadRef(ref, deleted, refNumToID); + } } updateMergedRefs(); From 531e55e04c5440b23897ec954ecca4e30715645b Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 01:13:17 +0100 Subject: [PATCH 09/25] 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 --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwlua/localscripts.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 8 +- apps/openmw/mwmechanics/aipackage.cpp | 7 +- apps/openmw/mwmechanics/aiwander.cpp | 16 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- apps/openmw/mwmechanics/pathgrid.cpp | 4 +- apps/openmw/mwrender/fogmanager.cpp | 9 ++- apps/openmw/mwrender/fogmanager.hpp | 6 +- apps/openmw/mwrender/pathgrid.cpp | 7 +- apps/openmw/mwrender/renderingmanager.cpp | 14 ++-- apps/openmw/mwrender/renderingmanager.hpp | 5 +- apps/openmw/mwsound/soundmanagerimp.cpp | 4 +- apps/openmw/mwworld/cell.cpp | 66 ++++++++++++++++ apps/openmw/mwworld/cell.hpp | 67 ++++++++++++++++ apps/openmw/mwworld/cellstore.cpp | 81 +++++++++----------- apps/openmw/mwworld/cellstore.hpp | 12 +-- apps/openmw/mwworld/scene.cpp | 24 +++--- apps/openmw/mwworld/worldimp.cpp | 31 ++++---- apps/openmw/mwworld/worldimp.hpp | 2 +- apps/openmw/mwworld/worldmodel.cpp | 10 +-- components/detournavigator/navigatorimpl.cpp | 2 +- components/esm/esm3esm4bridge.cpp | 8 -- components/esm/esm3esm4bridge.hpp | 16 ---- components/esm3/loadcell.hpp | 19 ++--- components/esm4/loadcell.cpp | 6 -- components/esm4/loadcell.hpp | 17 +--- components/misc/coordinateconverter.hpp | 8 +- 31 files changed, 268 insertions(+), 194 deletions(-) create mode 100644 apps/openmw/mwworld/cell.cpp create mode 100644 apps/openmw/mwworld/cell.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e9683cc40a..cf9d76be4e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 202af249f5..5219ab72cc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -94,6 +94,7 @@ namespace MWWorld class TimeStamp; class ESMStore; class RefData; + struct Cell; typedef std::vector> 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 diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 56fbdeabe6..2035ac3507 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -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().search(index.x(), index.y()); - dest = world->getCellName(ESM::CellVariant(cell)); + dest = world->getCellName(MWWorld::Cell(cell)); } return "#{sCell=" + std::string{ dest } + "}"; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b31b0adaf2..e22d1302b1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -954,7 +954,7 @@ namespace MWGui mMap->setCellName(name); mHud->setCellName(name); - auto cellCommon = cell->getCellVariant().getCommon(); + auto cellCommon = cell->getCell(); if (cellCommon->isExterior()) { diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 6cdfff0fea..88c824cc59 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -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(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 diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bf5f7cebc0..e558eedc66 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -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().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); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index ac96765a3a..5abc99dac9 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -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. diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1ff9cf0c54..3631cfb776 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()->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(); - 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().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 diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 6e9ea28f93..0180323ddd 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -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 diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 282ac4e381..ad1be1a94d 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -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().search(*mCell); diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index 8752196dc6..bb4abc3fa9 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + 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); diff --git a/apps/openmw/mwrender/fogmanager.hpp b/apps/openmw/mwrender/fogmanager.hpp index a1759d5963..258371bc9e 100644 --- a/apps/openmw/mwrender/fogmanager.hpp +++ b/apps/openmw/mwrender/fogmanager.hpp @@ -3,9 +3,9 @@ #include -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); diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index f449861a07..8e4db52726 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -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().search(store->getCellVariant().getEsm3()); + const ESM::Pathgrid* pathgrid = world->getStore().get().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 cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ef09d38df0..c1aa3055a6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -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" diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e4791df71a..70b40f6f67 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -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); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a54b3e40d7..3ef3a19353 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -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; diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp new file mode 100644 index 0000000000..6fdc5c4041 --- /dev/null +++ b/apps/openmw/mwworld/cell.cpp @@ -0,0 +1,66 @@ +#include "cell.hpp" + +#include +#include +#include + +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(); + } +} diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp new file mode 100644 index 0000000000..6761485f29 --- /dev/null +++ b/apps/openmw/mwworld/cell.hpp @@ -0,0 +1,67 @@ +#ifndef OPENW_MWORLD_CELL +#define OPENW_MWORLD_CELL + +#include +#include +#include + +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 diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 29c05e72b5..f820d551ab 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -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 - { - return mCellVariant.getCommon(); - } - - ESM::CellVariant CellStore::getCellVariant() const - { - return mCellVariant; - } - - std::string_view CellStore::getEditorName() const + const MWWorld::Cell* CellStore::getCell() 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(mCell->mContextList[i].index); + const std::size_t index = static_cast(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(mCell->mContextList[i].index); + const std::size_t index = static_cast(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(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()); } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 736470f15b..eaeeec42d3 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -12,10 +12,10 @@ #include #include +#include "cell.hpp" #include "cellreflist.hpp" #include "livecellref.hpp" -#include #include #include #include @@ -98,8 +98,7 @@ namespace MWWorld // Note this is nullptr until the cell is explored to save some memory std::unique_ptr mFogState; - const ESM::Cell* mCell; - ESM::CellVariant mCellVariant; + MWWorld::Cell mCellVariant; State mState; bool mHasState; std::vector 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; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0c5f72b107..089428fd26 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -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().search(cell->getCellVariant().getEsm3())) + if (const auto pathgrid = mWorld.getStore().get().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) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5bee6c554a..c7ec164348 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -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().search(cell.getEsm3().mRegion); - return region->mName; - } + if (!cell.isEsm4()) + { + const ESM::Region* region = mStore.get().search(cell.getEsm3().mRegion); + return region->mName; } return mStore.get().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 checkedCells; std::set currentCells; std::set nextCells; - nextCells.insert(cell->getEditorName()); + nextCells.insert(cell->getCell()->getEditorName()); while (!nextCells.empty()) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 809daf95d8..0d3a45e656 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -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 diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 1dc935af3b..7b89e12ff4 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -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().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; } } diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 0978f69c24..542818a151 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -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])); diff --git a/components/esm/esm3esm4bridge.cpp b/components/esm/esm3esm4bridge.cpp index ec76b19fc6..f804f437bc 100644 --- a/components/esm/esm3esm4bridge.cpp +++ b/components/esm/esm3esm4bridge.cpp @@ -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); diff --git a/components/esm/esm3esm4bridge.hpp b/components/esm/esm3esm4bridge.hpp index 4c6eaf5875..6152b0e610 100644 --- a/components/esm/esm3esm4bridge.hpp +++ b/components/esm/esm3esm4bridge.hpp @@ -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; }; } diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index c957dc493a..8bd707d825 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -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 diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index fed031ed16..09eef41679 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -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 diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 631aa1c94a..2573c08ae7 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -35,7 +35,6 @@ #include "lighting.hpp" #include -#include #include #include @@ -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); } }; } diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp index bc9ef6d427..12ea2d8c40 100644 --- a/components/misc/coordinateconverter.hpp +++ b/components/misc/coordinateconverter.hpp @@ -1,9 +1,11 @@ #ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H #define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H +#include #include #include #include +#include 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()) { } From cb8cdd88316d4afde10cc09a36abd1f7a134e6ed Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 14:07:50 +0100 Subject: [PATCH 10/25] ESM::CellVariant aans MWWorld:Cell now take reference in constructor: signals that nullptr isn't accepted. also applied other review comments. --- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwworld/cell.cpp | 59 +++++++------- apps/openmw/mwworld/cell.hpp | 4 +- apps/openmw/mwworld/scene.cpp | 86 ++++++++++---------- apps/openmw/mwworld/worldmodel.cpp | 14 ++-- components/detournavigator/navigatorimpl.cpp | 2 +- components/esm/esm3esm4bridge.cpp | 8 +- components/esm/esm3esm4bridge.hpp | 23 ++---- 10 files changed, 94 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 2035ac3507..0d27474428 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -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().search(index.x(), index.y()); - dest = world->getCellName(MWWorld::Cell(cell)); + dest = world->getCellName(MWWorld::Cell(*cell)); } return "#{sCell=" + std::string{ dest } + "}"; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 5abc99dac9..c966f704e9 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -418,7 +418,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) if (playerCell->isExterior()) { // get actor's distance from origin of center cell - Misc::CoordinateConverter(ESM::CellVariant(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. diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3631cfb776..a421f7e8cd 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -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(ESM::CellVariant(cell)); + auto converter = Misc::CoordinateConverter(ESM::CellVariant(*cell)); const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); // Find closest pathgrid point diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 6fdc5c4041..48b40069b4 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -6,57 +6,56 @@ namespace MWWorld { - Cell::Cell(const ESM4::Cell* cell) + 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; + 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.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.mWorldspace = Misc::StringUtils::lowerCase(cell.mEditorId); mCellId.mWorld = ESM::RefId::sEmpty; - mCellId.mIndex.mX = cell->getGridX(); - mCellId.mIndex.mX = cell->getGridY(); + 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; + 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) + 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(); + 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; + 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(); + mCellId = cell.getCellId(); - mMood.mAmbiantColor = cell->mAmbi.mAmbient; - mMood.mFogColor = cell->mAmbi.mFog; - mMood.mDirectionalColor = cell->mAmbi.mSunlight; - mMood.mFogDensity = cell->mAmbi.mFogDensity; + 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 diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 6761485f29..5067e223cf 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -30,8 +30,8 @@ namespace MWWorld }; public: - explicit Cell(const ESM4::Cell* cell); - explicit Cell(const ESM::Cell* cell); + explicit Cell(const ESM4::Cell& cell); + explicit Cell(const ESM::Cell& cell); int getGridX() const { return mGridPos.x(); } int getGridY() const { return mGridPos.y(); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 089428fd26..5772699e90 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -383,57 +383,57 @@ namespace MWWorld assert(mActiveCells.find(cell) == mActiveCells.end()); mActiveCells.insert(cell); - Log(Debug::Info) << "Loading cell " << cell->getCell()->getEditorName(); + Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription(); const int cellX = cell->getCell()->getGridX(); const int cellY = cell->getCell()->getGridY(); auto cellVariant = *cell->getCell(); - if (!cellVariant.isEsm4()) - { - auto cell3 = cellVariant.getEsm3(); - if (cell3.isExterior()) + if (cellVariant.isExterior()) + { + osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; + const int verts = ESM::Land::LAND_SIZE; + const int worldsize = ESM::Land::REAL_SIZE; + if (data) { - osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); - const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; - const int verts = ESM::Land::LAND_SIZE; - const int worldsize = ESM::Land::REAL_SIZE; - if (data) - { - mPhysics->addHeightField( - data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); - } - else - { - static std::vector defaultHeight; - defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); - mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, - ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); - } - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - { - const osg::Vec2i cellPosition(cellX, cellY); - const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); - const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); - const HeightfieldShape shape = [&]() -> HeightfieldShape { - if (data == nullptr) - { - return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; - } - else - { - DetourNavigator::HeightfieldSurface heights; - heights.mHeights = data->mHeights; - heights.mSize = static_cast(ESM::Land::LAND_SIZE); - heights.mMinHeight = data->mMinHeight; - heights.mMaxHeight = data->mMaxHeight; - return heights; - } - }(); - mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); - } + mPhysics->addHeightField( + data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); } + else + { + static std::vector defaultHeight; + defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); + mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, + ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); + } + if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + { + const osg::Vec2i cellPosition(cellX, cellY); + const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); + const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); + const HeightfieldShape shape = [&]() -> HeightfieldShape { + if (data == nullptr) + { + return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; + } + else + { + DetourNavigator::HeightfieldSurface heights; + heights.mHeights = data->mHeights; + heights.mSize = static_cast(ESM::Land::LAND_SIZE); + heights.mMinHeight = data->mMinHeight; + heights.mMaxHeight = data->mMaxHeight; + return heights; + } + }(); + mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); + } + } + if (!cellVariant.isEsm4()) + { + auto cell3 = cellVariant.getEsm3(); if (const auto pathgrid = mWorld.getStore().get().search(cell3)) mNavigator.addPathgrid(cell3, *pathgrid); } diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 7b89e12ff4..c6d7d33ebb 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -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(MWWorld::Cell(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(MWWorld::Cell(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(MWWorld::Cell(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().find(name); - result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell), mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first; } else { - result = mInteriors.emplace(name, CellStore(MWWorld::Cell(cell4), mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first; } } @@ -265,12 +265,12 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name) ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) { const ESM::Cell* cellEsm3 = getESMCellByName(name); - return ESM::CellVariant(cellEsm3); if (!cellEsm3) { const ESM4::Cell* cellESM4 = mStore.get().searchCellName(name); - return ESM::CellVariant(cellESM4); + return ESM::CellVariant(*cellESM4); } + return ESM::CellVariant(*cellEsm3); } MWWorld::CellStore* MWWorld::WorldModel::getCell(std::string_view name) diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 542818a151..f064842f6b 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -134,7 +134,7 @@ namespace DetourNavigator void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) { - Misc::CoordinateConverter converter = Misc::CoordinateConverter(ESM::CellVariant(&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])); diff --git a/components/esm/esm3esm4bridge.cpp b/components/esm/esm3esm4bridge.cpp index f804f437bc..d38014e071 100644 --- a/components/esm/esm3esm4bridge.cpp +++ b/components/esm/esm3esm4bridge.cpp @@ -6,17 +6,13 @@ namespace ESM { const ESM4::Cell& CellVariant::getEsm4() const { - auto cell4 = std::get<0>(mVariant); - if (!cell4) - throw std::runtime_error("invalid variant acess"); + auto cell4 = std::get(mVariant); return *cell4; } const ESM::Cell& CellVariant::getEsm3() const { - auto cell = std::get<1>(mVariant); - if (!cell) - throw std::runtime_error("invalid variant acess"); + auto cell = std::get(mVariant); return *cell; } } diff --git a/components/esm/esm3esm4bridge.hpp b/components/esm/esm3esm4bridge.hpp index 6152b0e610..471ef96885 100644 --- a/components/esm/esm3esm4bridge.hpp +++ b/components/esm/esm3esm4bridge.hpp @@ -19,29 +19,20 @@ namespace ESM struct CellVariant { - std::variant mVariant; + private: + std::variant mVariant; - CellVariant() - : mVariant((void*)(nullptr)) + public: + explicit CellVariant(const ESM4::Cell& cell) + : mVariant(&cell) { } - explicit CellVariant(const ESM4::Cell* cell) - : mVariant(cell) + explicit CellVariant(const ESM::Cell& cell) + : mVariant(&cell) { } - explicit CellVariant(const ESM::Cell* cell) - : mVariant(cell) - { - } - - bool isValid() const - { - return std::holds_alternative(mVariant) - || std::holds_alternative(mVariant); - } - bool isEsm4() const { return std::holds_alternative(mVariant); } const ESM4::Cell& getEsm4() const; From 5037dcf9bc16ded70473a27aa82668b6aab0a49d Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 15:29:05 +0100 Subject: [PATCH 11/25] Fixes a crash on launch and some compile issue also uses std::visit in cellstore comparison to avoid missing combinasion split loadrefs in loadref of ESM4 and ESM3. --- apps/openmw/mwmechanics/pathgrid.cpp | 5 +- apps/openmw/mwworld/cell.cpp | 1 - apps/openmw/mwworld/cell.hpp | 6 +- apps/openmw/mwworld/cellstore.cpp | 138 ++++++++++++++------------- apps/openmw/mwworld/cellstore.hpp | 3 + apps/openmw/mwworld/scene.cpp | 2 +- components/esm/esm3esm4bridge.hpp | 2 +- 7 files changed, 82 insertions(+), 75 deletions(-) diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index ad1be1a94d..8c270b8af9 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -104,9 +104,10 @@ namespace MWMechanics if (mIsGraphConstructed) return true; - mCell = cell->getCell()->isEsm4() ? nullptr : &cell->getCell()->getEsm3(); - if (!mCell) + if (cell->getCell()->isEsm4()) return false; + mCell = &cell->getCell()->getEsm3(); + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell); if (!mPathgrid) return false; diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 48b40069b4..372f130fcd 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -37,7 +37,6 @@ namespace MWWorld Cell::Cell(const ESM::Cell& cell) : ESM::CellVariant(cell) { - assert(cell != nullptr); mNameID = cell.mName; mDisplayname = cell.mName; mGridPos.x() = cell.getGridX(); diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 5067e223cf..cd8ade5137 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -18,9 +18,11 @@ namespace ESM4 namespace MWWorld { + class CellStore; + struct Cell : public ESM::CellVariant { - + friend MWWorld::CellStore; struct MoodData { uint32_t mAmbiantColor; @@ -39,7 +41,7 @@ namespace MWWorld 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::CellId& getCellId() const { return mCellId; } const ESM::RefId& getRegion() const { return mRegion; } std::string_view getEditorName() const { return mNameID; } std::string getDescription() const; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f820d551ab..1dd43ed187 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -772,79 +772,78 @@ namespace MWWorld std::sort(mIds.begin(), mIds.end()); } - void CellStore::loadRefs() + void CellStore::loadRefs(const ESM::Cell& cell, std::map& refNumToID) { - assert(mCellVariant.isValid()); - std::map refNumToID; // used to detect refID modifications + if (cell.mContextList.empty()) + return; // this is a dynamically generated cell -> skipping. - if (mCellVariant.isEsm4()) + // Load references from all plugins that do something with this cell. + for (size_t i = 0; i < cell.mContextList.size(); i++) { - auto cell4 = mCellVariant.getEsm4(); - auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); - auto it = refs.begin(); - - while (it != refs.end()) + try { - if (it->mParent == cell4.mId) - { - loadRef(*it, false); - } - ++it; - } - } - else - { - auto cell3 = mCellVariant.getEsm3(); - if (cell3.mContextList.empty()) - return; // this is a dynamically generated cell -> skipping. + // Reopen the ESM reader and seek to the right position. + const std::size_t index = static_cast(cell.mContextList[i].index); + const ESM::ReadersCache::BusyItem reader = mReaders.get(index); + cell.restore(*reader, i); - // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < cell3.mContextList.size(); i++) - { - try + ESM::CellRef ref; + // Get each reference in turn + ESM::MovedCellRef cMRef; + bool deleted = false; + bool moved = false; + while (ESM::Cell::getNextRef( + *reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved)) { - // Reopen the ESM reader and seek to the right position. - const std::size_t index = static_cast(cell3.mContextList[i].index); - const ESM::ReadersCache::BusyItem reader = mReaders.get(index); - cell3.restore(*reader, i); - - ESM::CellRef ref; - // Get each reference in turn - ESM::MovedCellRef cMRef; - bool deleted = false; - bool moved = false; - while (ESM::Cell::getNextRef( - *reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved)) + if (moved) + continue; + + // Don't load reference if it was moved to a different cell. + ESM::MovedCellRefTracker::const_iterator iter + = std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum); + if (iter != cell.mMovedRefs.end()) { - if (moved) - continue; - - // Don't load 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()) - { - continue; - } - - loadRef(ref, deleted, refNumToID); + continue; } - } - catch (std::exception& e) - { - Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription() - << ": " << e.what(); + + loadRef(ref, deleted, refNumToID); } } - // Load moved references, from separately tracked list. - for (const auto& leasedRef : cell3.mLeasedRefs) + catch (std::exception& e) { - ESM::CellRef& ref = const_cast(leasedRef.first); - bool deleted = leasedRef.second; + Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription() + << ": " << e.what(); + } + } + // Load moved references, from separately tracked list. + for (const auto& leasedRef : cell.mLeasedRefs) + { + ESM::CellRef& ref = const_cast(leasedRef.first); + bool deleted = leasedRef.second; - loadRef(ref, deleted, refNumToID); + loadRef(ref, deleted, refNumToID); + } + } + + void CellStore::loadRefs(const ESM4::Cell& cell, std::map& refNumToID) + { + auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); + + for (const auto& ref : refs) + { + if (ref.mParent == cell.mId) + { + loadRef(ref, false); } } + } + + void CellStore::loadRefs() + { + assert(mCellVariant.isValid()); + std::map refNumToID; // used to detect refID modifications + + std::visit([&refNumToID, this](auto&& cell) { this->loadRefs(*cell, refNumToID); }, mCellVariant.mVariant); updateMergedRefs(); } @@ -1087,18 +1086,21 @@ namespace MWWorld } } - bool CellStore::operator==(const CellStore& right) const + struct Visitor { + bool operator()(const ESM::Cell* a, const ESM::Cell* b) const { return a->getCellId() == b->getCellId(); }; + bool operator()(const ESM4::Cell* a, const ESM4::Cell* b) const { return a->mId == b->mId; }; - bool bothCell4 = mCellVariant.isEsm4() && right.mCellVariant.isEsm4(); - bool bothCell3 = !mCellVariant.isEsm4() && !right.mCellVariant.isEsm4(); - - if (bothCell3) - return mCellVariant.getEsm3().getCellId() == right.mCellVariant.getEsm3().getCellId(); - else if (bothCell4) - return mCellVariant.getEsm4().mId == right.mCellVariant.getEsm4().mId; - else + template + bool operator()(L, R) const + { return false; + } + }; + + bool CellStore::operator==(const CellStore& right) const + { + return std::visit(Visitor{}, this->mCellVariant.mVariant, right.mCellVariant.mVariant); } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index eaeeec42d3..528ec2b902 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -386,6 +386,9 @@ namespace MWWorld /// Run through references and store IDs void listRefs(); + void loadRefs(const ESM::Cell& cell, std::map& refNumToID); + void loadRefs(const ESM4::Cell& cell, std::map& refNumToID); + void loadRefs(); void loadRef(const ESM4::Reference& ref, bool deleted); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 5772699e90..0075289808 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -888,7 +888,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getEditorName()), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/components/esm/esm3esm4bridge.hpp b/components/esm/esm3esm4bridge.hpp index 471ef96885..b63a89315a 100644 --- a/components/esm/esm3esm4bridge.hpp +++ b/components/esm/esm3esm4bridge.hpp @@ -19,7 +19,7 @@ namespace ESM struct CellVariant { - private: + protected: std::variant mVariant; public: From 23614ae2aec1891abdd65d3a01d0b1ba463e2fca Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 18:40:15 +0100 Subject: [PATCH 12/25] Renamed esm3esm4bridge => esmbridge --- apps/openmw/mwlua/cellbindings.cpp | 2 +- apps/openmw/mwrender/fogmanager.cpp | 2 +- apps/openmw/mwworld/cell.hpp | 2 +- apps/openmw/mwworld/cellref.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/{esm3esm4bridge.cpp => esmbridge.cpp} | 2 +- components/esm/{esm3esm4bridge.hpp => esmbridge.hpp} | 0 components/misc/coordinateconverter.hpp | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename components/esm/{esm3esm4bridge.cpp => esmbridge.cpp} (89%) rename components/esm/{esm3esm4bridge.hpp => esmbridge.hpp} (100%) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index c45ea3a8ca..c43f8dd21a 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -1,6 +1,6 @@ #include "luabindings.hpp" -#include +#include #include #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index bb4abc3fa9..68b615e565 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include #include diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index cd8ade5137..7507b76993 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -1,7 +1,7 @@ #ifndef OPENW_MWORLD_CELL #define OPENW_MWORLD_CELL -#include +#include #include #include diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index ac9cf7a3ee..822961e645 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7fd42de677..b47b21683b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon records util luascripts format refid esm3esm4bridge) +add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/esm3esm4bridge.cpp b/components/esm/esmbridge.cpp similarity index 89% rename from components/esm/esm3esm4bridge.cpp rename to components/esm/esmbridge.cpp index d38014e071..2470a837b0 100644 --- a/components/esm/esm3esm4bridge.cpp +++ b/components/esm/esmbridge.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/components/esm/esm3esm4bridge.hpp b/components/esm/esmbridge.hpp similarity index 100% rename from components/esm/esm3esm4bridge.hpp rename to components/esm/esmbridge.hpp diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp index 12ea2d8c40..7865ed9c5f 100644 --- a/components/misc/coordinateconverter.hpp +++ b/components/misc/coordinateconverter.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H #define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H -#include +#include #include #include #include From e6e27413d920dfdb0ffe7406fabab35e192023ab Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 19:40:45 +0100 Subject: [PATCH 13/25] gives MWWorld::CellRef the MWWorld::Cell treatment MWWorld::CellRef now has a variant, and datas that are part of the intersection of both ESM4::Reference and ESM::CellRef are part of MWWorld::CellRef For ESM4 most data isn't filled in, so it returns default values. --- apps/openmw/mwworld/cellref.cpp | 167 ++++++++++++++++++++++++-------- apps/openmw/mwworld/cellref.hpp | 84 +++++++--------- components/esm/esmbridge.hpp | 28 +++++- 3 files changed, 188 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index ef5d93827d..ffc98ef208 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -7,10 +7,54 @@ namespace MWWorld { + CellRef::CellRef(const ESM::CellRef& ref) + : mCellRef(ESM::ReferenceVariant(ref)) + { + mChanged = false; + mSoul = ref.mSoul; + mTrap = ref.mTrap; + mKey = ref.mKey; + mFaction = ref.mFaction; + mOwner = ref.mOwner; + mReferenceType = ref.mRefID; + mPos = ref.mPos; + mDoorDest = ref.mDoorDest; + mRefNum = ref.mRefNum; + mGlobalVariable = ref.mGlobalVariable; + mDestCell = ref.mDestCell; + + mLockLevel = ref.mLockLevel; + mGoldValue = ref.mGoldValue; + mFactionRank = ref.mFactionRank; + mEnchantmentCharge = ref.mEnchantmentCharge; + + mScale = ref.mScale; + } + + CellRef::CellRef(const ESM4::Reference& ref) + : mCellRef(ESM::ReferenceVariant(ref)) + { + + mChanged = false; + + mReferenceType = ref.mBaseObj; + mPos = { { ref.mPlacement.pos.x, ref.mPlacement.pos.y, ref.mPlacement.pos.z }, + { ref.mPlacement.rot.x, ref.mPlacement.rot.y, ref.mPlacement.rot.z } }; + + mRefNum = {}; + mDoorDest = {}; + + mLockLevel = ref.mLockLevel; + mFactionRank = ref.mFactionRank; + mGoldValue = 0; + mEnchantmentCharge = 0; + + mScale = ref.mScale; + } const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) { - if (!mCellRef.mRefNum.isSet()) + if (!mRefNum.isSet()) { // Generated RefNums have negative mContentFile assert(lastAssignedRefNum.mContentFile < 0); @@ -22,30 +66,38 @@ namespace MWWorld else Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; } - mCellRef.mRefNum = lastAssignedRefNum; + mRefNum = lastAssignedRefNum; mChanged = true; } - return mCellRef.mRefNum; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mRefNum = mRefNum; + return mRefNum; } void CellRef::unsetRefNum() { - mCellRef.mRefNum = ESM::RefNum{}; + mRefNum = ESM::RefNum{}; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mRefNum = mRefNum; } void CellRef::setScale(float scale) { - if (scale != mCellRef.mScale) + if (scale != mScale) { mChanged = true; - mCellRef.mScale = scale; + mScale = scale; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mScale = Scale; } void CellRef::setPosition(const ESM::Position& position) { mChanged = true; - mCellRef.mPos = position; + mPos = position; + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mPos = position; } float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const @@ -54,113 +106,140 @@ namespace MWWorld { return 0; } - else if (mCellRef.mEnchantmentCharge == -1) + else if (mEnchantmentCharge == -1) { return 1; } else { - return mCellRef.mEnchantmentCharge / static_cast(maxCharge); + return mEnchantmentCharge / static_cast(maxCharge); } } void CellRef::setEnchantmentCharge(float charge) { - if (charge != mCellRef.mEnchantmentCharge) + if (charge != mEnchantmentCharge) { mChanged = true; - mCellRef.mEnchantmentCharge = charge; + mEnchantmentCharge = charge; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mEnchantmentCharge = mEnchantmentCharge; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mChargeInt) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + if (charge != cellRef3.mChargeInt) { mChanged = true; - mCellRef.mChargeInt = charge; + cellRef3.mChargeInt = charge; } } void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) { - mCellRef.mChargeIntRemainder += std::abs(chargeRemainder); - if (mCellRef.mChargeIntRemainder > 1.0f) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); + if (cellRef3.mChargeIntRemainder > 1.0f) { - float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder)); - if (mCellRef.mChargeInt <= static_cast(mCellRef.mChargeIntRemainder)) + float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); + if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) { - mCellRef.mChargeInt = 0; + cellRef3.mChargeInt = 0; } else { - mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); + cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); } - mCellRef.mChargeIntRemainder = newChargeRemainder; + cellRef3.mChargeIntRemainder = newChargeRemainder; } } void CellRef::setChargeFloat(float charge) { - if (charge != mCellRef.mChargeFloat) + if (mCellRef.isESM4()) + return; + + auto& cellRef3 = mCellRef.getEsm3(); + if (charge != cellRef3.mChargeFloat) { mChanged = true; - mCellRef.mChargeFloat = charge; + cellRef3.mChargeFloat = charge; } } void CellRef::resetGlobalVariable() { - if (!mCellRef.mGlobalVariable.empty()) + if (!mGlobalVariable.empty()) { mChanged = true; - mCellRef.mGlobalVariable.erase(); + mGlobalVariable.erase(); } + + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mGlobalVariable = mGlobalVariable; } void CellRef::setFactionRank(int factionRank) { - if (factionRank != mCellRef.mFactionRank) + if (factionRank != mFactionRank) { mChanged = true; - mCellRef.mFactionRank = factionRank; + mFactionRank = factionRank; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mFactionRank = mFactionRank; } void CellRef::setOwner(const ESM::RefId& owner) { - if (owner != mCellRef.mOwner) + if (owner != mOwner) { mChanged = true; - mCellRef.mOwner = owner; + mOwner = owner; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mOwner = mOwner; } void CellRef::setSoul(const ESM::RefId& soul) { - if (soul != mCellRef.mSoul) + if (soul != mSoul) { mChanged = true; - mCellRef.mSoul = soul; + mSoul = soul; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mSoul = mSoul; } void CellRef::setFaction(const ESM::RefId& faction) { - if (faction != mCellRef.mFaction) + if (faction != mFaction) { mChanged = true; - mCellRef.mFaction = faction; + mFaction = faction; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mFaction = mFaction; } void CellRef::setLockLevel(int lockLevel) { - if (lockLevel != mCellRef.mLockLevel) + if (lockLevel != mLockLevel) { mChanged = true; - mCellRef.mLockLevel = lockLevel; + mLockLevel = lockLevel; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mLockLevel = mLockLevel; } void CellRef::lock(int lockLevel) @@ -173,30 +252,38 @@ namespace MWWorld void CellRef::unlock() { - setLockLevel(-abs(mCellRef.mLockLevel)); // Makes lockLevel negative + setLockLevel(-abs(mLockLevel)); // Makes lockLevel negative } void CellRef::setTrap(const ESM::RefId& trap) { - if (trap != mCellRef.mTrap) + if (trap != mTrap) { mChanged = true; - mCellRef.mTrap = trap; + mTrap = trap; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mTrap = mTrap; } void CellRef::setGoldValue(int value) { - if (value != mCellRef.mGoldValue) + if (value != mGoldValue) { mChanged = true; - mCellRef.mGoldValue = value; + mGoldValue = value; } + if (!mCellRef.isESM4()) + mCellRef.getEsm3().mGoldValue = mGoldValue; } void CellRef::writeState(ESM::ObjectState& state) const { - state.mRef = mCellRef; + if (!mCellRef.isESM4()) + { + auto& cellRef3 = mCellRef.getEsm3(); + state.mRef = cellRef3; + } } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 822961e645..b3f3e84125 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -19,24 +19,12 @@ namespace MWWorld class CellRef { public: - CellRef(const ESM::CellRef& ref) - : mCellRef(ref) - { - mIsEsm4 = false; - mChanged = false; - } + CellRef(const ESM::CellRef& ref); - CellRef(const ESM4::Reference& ref) - : mCellRef4(ref) - { - mRefrPos = { { mCellRef4.mPlacement.pos.x, mCellRef4.mPlacement.pos.y, mCellRef4.mPlacement.pos.z }, - { mCellRef4.mPlacement.rot.x, mCellRef4.mPlacement.rot.y, mCellRef4.mPlacement.rot.z } }; - mChanged = false; - mIsEsm4 = true; - } + CellRef(const ESM4::Reference& ref); // Note: Currently unused for items in containers - const ESM::RefNum& getRefNum() const { return mCellRef.mRefNum; } + const ESM::RefNum& getRefNum() const { return mRefNum; } // Returns RefNum. // If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter. @@ -46,44 +34,32 @@ namespace MWWorld void unsetRefNum(); /// Does the RefNum have a content file? - bool hasContentFile() const { return mCellRef.mRefNum.hasContentFile(); } + bool hasContentFile() const { return mRefNum.hasContentFile(); } // Id of object being referenced - const ESM::RefId& getRefId() const { return mCellRef.mRefID; } + const ESM::RefId& getRefId() const { return mReferenceType; } // For doors - true if this door teleports to somewhere else, false // if it should open through animation. - bool getTeleport() const { return mCellRef.mTeleport; } + bool getTeleport() const { return mCellRef.isESM4() ? false : mCellRef.getEsm3().mTeleport; } // Teleport location for the door, if this is a teleporting door. - const ESM::Position& getDoorDest() const { return mCellRef.mDoorDest; } + const ESM::Position& getDoorDest() const { return mDoorDest; } // Destination cell for doors (optional) - const std::string& getDestCell() const { return mCellRef.mDestCell; } + const std::string& getDestCell() const { return mDestCell; } // Scale applied to mesh - float getScale() const - { - if (mIsEsm4) - return mCellRef4.mScale; - else - return mCellRef.mScale; - } + float getScale() const { return mScale; } void setScale(float scale); // The *original* position and rotation as it was given in the Construction Set. // Current position and rotation of the object is stored in RefData. - const ESM::Position& getPosition() const - { - if (mIsEsm4) - return mRefrPos; - else - return mCellRef.mPos; - } + const ESM::Position& getPosition() const { return mPos; } void setPosition(const ESM::Position& position); // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). - float getEnchantmentCharge() const { return mCellRef.mEnchantmentCharge; } + float getEnchantmentCharge() const { return mEnchantmentCharge; } // Remaining enchantment charge rescaled to the supplied maximum charge (such as one of the enchantment). float getNormalizedEnchantmentCharge(int maxCharge) const; @@ -93,50 +69,53 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. // If this returns int(-1) it means full health. - int getCharge() const { return mCellRef.mChargeInt; } - float getChargeFloat() const { return mCellRef.mChargeFloat; } // Implemented as union with int charge + int getCharge() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mChargeInt; } + float getChargeFloat() const + { + return mCellRef.isESM4() ? 0.f : mCellRef.getEsm3().mChargeFloat; + } // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 // The NPC that owns this object (and will get angry if you steal it) - const ESM::RefId& getOwner() const { return mCellRef.mOwner; } + const ESM::RefId& getOwner() const { return mOwner; } void setOwner(const ESM::RefId& owner); // Name of a global variable. If the global variable is set to '1', using the object is temporarily allowed // even if it has an Owner field. // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. - const std::string& getGlobalVariable() const { return mCellRef.mGlobalVariable; } + const std::string& getGlobalVariable() const { return mGlobalVariable; } void resetGlobalVariable(); // ID of creature trapped in this soul gem - const ESM::RefId& getSoul() const { return mCellRef.mSoul; } + const ESM::RefId& getSoul() const { return mSoul; } void setSoul(const ESM::RefId& soul); // The faction that owns this object (and will get angry if // you take it and are not a faction member) - const ESM::RefId& getFaction() const { return mCellRef.mFaction; } + const ESM::RefId& getFaction() const { return mFaction; } void setFaction(const ESM::RefId& faction); // PC faction rank required to use the item. Sometimes is -1, which means "any rank". void setFactionRank(int factionRank); - int getFactionRank() const { return mCellRef.mFactionRank; } + int getFactionRank() const { return mFactionRank; } // Lock level for doors and containers // Positive for a locked door. 0 for a door that was never locked. // For an unlocked door, it is set to -(previous locklevel) - int getLockLevel() const { return mCellRef.mLockLevel; } + int getLockLevel() const { return mLockLevel; } void setLockLevel(int lockLevel); void lock(int lockLevel); void unlock(); // Key and trap ID names, if any - const ESM::RefId& getKey() const { return mCellRef.mKey; } - const ESM::RefId& getTrap() const { return mCellRef.mTrap; } + const ESM::RefId& getKey() const { return mKey; } + const ESM::RefId& getTrap() const { return mTrap; } void setTrap(const ESM::RefId& trap); // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int getGoldValue() const { return mCellRef.mGoldValue; } + int getGoldValue() const { return mGoldValue; } void setGoldValue(int value); // Write the content of this CellRef into the given ObjectState @@ -147,10 +126,15 @@ namespace MWWorld private: bool mChanged; - ESM::CellRef mCellRef; - ESM4::Reference mCellRef4; - ESM::Position mRefrPos; - bool mIsEsm4; + ESM::ReferenceVariant mCellRef; + + ESM::RefId mSoul, mFaction, mKey, mTrap, mOwner, mReferenceType; + float Scale; + ESM::Position mPos, mDoorDest; + ESM::RefNum mRefNum; + std::string mGlobalVariable, mDestCell; + int mLockLevel, mGoldValue, mFactionRank, mEnchantmentCharge; + float mScale; }; } diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index b63a89315a..753f0690e0 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include namespace ESM4 { @@ -39,6 +40,31 @@ namespace ESM const ESM::Cell& getEsm3() const; }; + + struct ReferenceVariant + { + protected: + std::variant mVariant; + + public: + explicit ReferenceVariant(const ESM4::Reference& ref) + : mVariant(ref) + { + } + + explicit ReferenceVariant(const ESM::CellRef& ref) + : mVariant(ref) + { + } + + bool isESM4() const { return std::holds_alternative(mVariant); } + + const ESM::CellRef& getEsm3() const { return std::get(mVariant); } + const ESM4::Reference& getEsm4() const { return std::get(mVariant); } + + ESM::CellRef& getEsm3() { return std::get(mVariant); } + ESM4::Reference& getEsm4() { return std::get(mVariant); } + }; } #endif From 216ca71149bdc689696ae6d85b7ad7c92c41826d Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 28 Jan 2023 12:07:47 +0100 Subject: [PATCH 14/25] Applied review comments getEditorName => getNameId restored cosntructor in CoordinateConverter --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwlua/cellbindings.cpp | 4 ++-- apps/openmw/mwlua/localscripts.cpp | 2 +- apps/openmw/mwmechanics/aifollow.cpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/spelleffects.cpp | 2 +- apps/openmw/mwworld/cell.hpp | 5 ++++- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 14 +++++++------- components/detournavigator/navigatorimpl.cpp | 2 +- components/esm/esmbridge.hpp | 2 -- components/esm3/loadcell.hpp | 2 ++ components/misc/coordinateconverter.hpp | 5 +++++ 15 files changed, 31 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c64489bae5..d94ada37e9 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -705,7 +705,7 @@ namespace MWGui ESM::Position markedPosition; MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); if (markedCell && markedCell->isExterior() == !mInterior - && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getEditorName(), mPrefix))) + && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getNameId(), mPrefix))) { MarkerUserData markerPos(mLocalMapRender); MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e22d1302b1..6bd1ea7757 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -958,7 +958,7 @@ namespace MWGui if (cellCommon->isExterior()) { - if (!cellCommon->getEditorName().empty()) + if (!cellCommon->getNameId().empty()) mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY()); mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY()); @@ -967,8 +967,8 @@ namespace MWGui } else { - mMap->setCellPrefix(std::string(cellCommon->getEditorName())); - mHud->setCellPrefix(std::string(cellCommon->getEditorName())); + mMap->setCellPrefix(std::string(cellCommon->getNameId())); + mHud->setCellPrefix(std::string(cellCommon->getNameId())); osg::Vec3f worldPos; if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index c43f8dd21a..dc50a79eef 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -35,11 +35,11 @@ namespace MWLua if (cell->isExterior()) res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")"; else - res << "interior(" << cell->getEditorName() << ")"; + res << "interior(" << cell->getNameId() << ")"; return res.str(); }; - cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getEditorName(); }); + cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); }); cellT["region"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 88c824cc59..883afb5328 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -181,7 +181,7 @@ namespace MWLua ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); else ai.stack(MWMechanics::AiEscort( - refId, esmCell->getEditorName(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false), + refId, esmCell->getNameId(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); }; selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) { diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 6185535a67..55a5e2534c 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -175,7 +175,7 @@ namespace MWMechanics } } else if (Misc::StringUtils::ciEqual( - mCellId, actor.getCell()->getCell()->getEditorName())) // Cell to travel to + mCellId, actor.getCell()->getCell()->getNameId())) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c966f704e9..8e7b38fa2f 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -418,7 +418,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) if (playerCell->isExterior()) { // get actor's distance from origin of center cell - Misc::CoordinateConverter(ESM::CellVariant(*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 a421f7e8cd..f7a7141ecd 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -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(ESM::CellVariant(*cell)); + auto converter = Misc::CoordinateConverter(cell); const osg::Vec3f npcPos = converter.toLocalVec3(mInitialActorPosition); // Find closest pathgrid point diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 66b572f1d3..31b82b4a14 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -489,7 +489,7 @@ namespace MWMechanics { std::string_view dest; if (!markedCell->isExterior()) - dest = markedCell->getCell()->getEditorName(); + dest = markedCell->getCell()->getNameId(); MWWorld::ActionTeleport action(dest, markedPosition, false); action.execute(target); if (!caster.isEmpty()) diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 7507b76993..3a0d063e02 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -1,6 +1,8 @@ #ifndef OPENW_MWORLD_CELL #define OPENW_MWORLD_CELL +#include + #include #include #include @@ -43,7 +45,8 @@ namespace MWWorld 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_view getNameId() const { return mNameID; } + std::string_view getDisplayName() const { return mDisplayname; } std::string getDescription() const; const MoodData& getMood() const { return mMood; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0075289808..d77e729c35 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -747,7 +747,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->getEditorName()) + if (it->mName == (*iter)->getCell()->getNameId()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c7ec164348..39d324a80d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -639,8 +639,8 @@ namespace MWWorld std::string_view World::getCellName(const MWWorld::Cell& cell) const { - if (!cell.isExterior() || !cell.getEditorName().empty()) - return cell.getEditorName(); + if (!cell.isExterior() || !cell.getNameId().empty()) + return cell.getNameId(); if (!cell.isEsm4()) { @@ -1139,7 +1139,7 @@ namespace MWWorld { if (!newCell->isExterior()) { - changeToInteriorCell(newCell->getCell()->getEditorName(), pos, false); + changeToInteriorCell(newCell->getCell()->getNameId(), pos, false); removeContainerScripts(getPlayerPtr()); } else @@ -1400,7 +1400,7 @@ namespace MWWorld esmPos.pos[2] = traced.z(); std::string_view cell; if (!actor.getCell()->isExterior()) - cell = actor.getCell()->getCell()->getEditorName(); + cell = actor.getCell()->getCell()->getNameId(); MWWorld::ActionTeleport(cell, esmPos, false).execute(actor); } } @@ -3270,7 +3270,7 @@ namespace MWWorld std::set checkedCells; std::set currentCells; std::set nextCells; - nextCells.insert(cell->getCell()->getEditorName()); + nextCells.insert(cell->getCell()->getNameId()); while (!nextCells.empty()) { @@ -3325,7 +3325,7 @@ namespace MWWorld std::set nextCells; MWWorld::ConstPtr closestMarker; - nextCells.insert(ptr.getCell()->getCell()->getEditorName()); + nextCells.insert(ptr.getCell()->getCell()->getNameId()); while (!nextCells.empty()) { currentCells = nextCells; @@ -3420,7 +3420,7 @@ namespace MWWorld std::string_view cellName = ""; if (!closestMarker.mCell->isExterior()) - cellName = closestMarker.mCell->getCell()->getEditorName(); + cellName = closestMarker.mCell->getCell()->getNameId(); MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index f064842f6b..0978f69c24 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -134,7 +134,7 @@ namespace DetourNavigator void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) { - Misc::CoordinateConverter converter = Misc::CoordinateConverter(ESM::CellVariant(cell)); + Misc::CoordinateConverter converter(&cell); for (const auto& edge : pathgrid.mEdges) { const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0])); diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index 753f0690e0..e50b73e61b 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -43,10 +43,8 @@ namespace ESM struct ReferenceVariant { - protected: std::variant mVariant; - public: explicit ReferenceVariant(const ESM4::Reference& ref) : mVariant(ref) { diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 8bd707d825..3cf1834dfa 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -156,6 +156,8 @@ namespace ESM int getGridY() const { return mData.mY; } + bool hasWater() const { return ((mData.mFlags & HasWater) != 0) || isExterior(); } + bool hasAmbient() const { return mHasAmbi; } void setHasAmbient(bool hasAmbi) { mHasAmbi = hasAmbi; } diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp index 7865ed9c5f..9c829e91cd 100644 --- a/components/misc/coordinateconverter.hpp +++ b/components/misc/coordinateconverter.hpp @@ -26,6 +26,11 @@ namespace Misc { } + explicit CoordinateConverter(const ESM::Cell* cell) + : CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY()) + { + } + /// in-place conversion from local to world void toWorld(ESM::Pathgrid::Point& point) const { From f9da66e9ee2af7a2d9450e719cae2635b8567ea9 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 28 Jan 2023 18:57:55 +0100 Subject: [PATCH 15/25] Greatly improved how the variant on MWWorld::CellRef works --- apps/openmw/mwworld/cellref.cpp | 250 ++++++++++++++---------------- apps/openmw/mwworld/cellref.hpp | 70 ++++++--- apps/openmw/mwworld/cellstore.cpp | 1 - apps/openmw/mwworld/refdata.cpp | 3 +- components/esm4/loadrefr.cpp | 6 +- components/esm4/loadrefr.hpp | 6 +- 6 files changed, 168 insertions(+), 168 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index ffc98ef208..ce6b49595b 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -7,28 +7,17 @@ namespace MWWorld { + // makes it easier to use std visit with a variant + template + struct RefVisit : Ts... + { + using Ts::operator()...; + }; + CellRef::CellRef(const ESM::CellRef& ref) : mCellRef(ESM::ReferenceVariant(ref)) { mChanged = false; - mSoul = ref.mSoul; - mTrap = ref.mTrap; - mKey = ref.mKey; - mFaction = ref.mFaction; - mOwner = ref.mOwner; - mReferenceType = ref.mRefID; - mPos = ref.mPos; - mDoorDest = ref.mDoorDest; - mRefNum = ref.mRefNum; - mGlobalVariable = ref.mGlobalVariable; - mDestCell = ref.mDestCell; - - mLockLevel = ref.mLockLevel; - mGoldValue = ref.mGoldValue; - mFactionRank = ref.mFactionRank; - mEnchantmentCharge = ref.mEnchantmentCharge; - - mScale = ref.mScale; } CellRef::CellRef(const ESM4::Reference& ref) @@ -36,68 +25,75 @@ namespace MWWorld { mChanged = false; + } - mReferenceType = ref.mBaseObj; - mPos = { { ref.mPlacement.pos.x, ref.mPlacement.pos.y, ref.mPlacement.pos.z }, - { ref.mPlacement.rot.x, ref.mPlacement.rot.y, ref.mPlacement.rot.z } }; - - mRefNum = {}; - mDoorDest = {}; - - mLockLevel = ref.mLockLevel; - mFactionRank = ref.mFactionRank; - mGoldValue = 0; - mEnchantmentCharge = 0; + static const ESM::RefNum emptyRefNum = {}; - mScale = ref.mScale; + const ESM::RefNum& CellRef::getRefNum() const + { + return std::visit(RefVisit{ [&](const ESM4::Reference& ref) -> const ESM::RefNum& { return emptyRefNum; }, + [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; } }, + mCellRef.mVariant); } const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) { - if (!mRefNum.isSet()) - { - // Generated RefNums have negative mContentFile - assert(lastAssignedRefNum.mContentFile < 0); - lastAssignedRefNum.mIndex++; - if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed - { - if (lastAssignedRefNum.mContentFile > std::numeric_limits::min()) - lastAssignedRefNum.mContentFile--; - else - Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; - } - mRefNum = lastAssignedRefNum; - mChanged = true; - } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mRefNum = mRefNum; - return mRefNum; + return std::visit( + RefVisit{ [&](ESM4::Reference& ref) -> const ESM::RefNum& { return emptyRefNum; }, + [&](ESM::CellRef& ref) -> const ESM::RefNum& { + if (!ref.mRefNum.isSet()) + { + // Generated RefNums have negative mContentFile + assert(lastAssignedRefNum.mContentFile < 0); + lastAssignedRefNum.mIndex++; + if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed + { + if (lastAssignedRefNum.mContentFile > std::numeric_limits::min()) + lastAssignedRefNum.mContentFile--; + else + Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; + } + ref.mRefNum = lastAssignedRefNum; + mChanged = true; + } + return ref.mRefNum; + } }, + mCellRef.mVariant); } void CellRef::unsetRefNum() { - mRefNum = ESM::RefNum{}; - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mRefNum = mRefNum; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; } }, + mCellRef.mVariant); + } + + static const std::string emptyString = ""; + + const std::string& CellRef::getDestCell() const + { + return mCellRef.isESM4() ? emptyString : mCellRef.getEsm3().mDestCell; } void CellRef::setScale(float scale) { - if (scale != mScale) + if (scale != getScale()) { mChanged = true; - mScale = scale; + std::visit([scale](auto&& ref) { ref.mScale = scale; }, mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mScale = Scale; } void CellRef::setPosition(const ESM::Position& position) { mChanged = true; - mPos = position; - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mPos = position; + std::visit([&position](auto&& ref) { ref.mPos = position; }, mCellRef.mVariant); + } + + float CellRef::getEnchantmentCharge() const + { + return std::visit(RefVisit{ [&](const ESM4::Reference& ref) { return 0.f; }, + [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; } }, + mCellRef.mVariant); } float CellRef::getNormalizedEnchantmentCharge(int maxCharge) const @@ -106,140 +102,127 @@ namespace MWWorld { return 0; } - else if (mEnchantmentCharge == -1) + else if (getEnchantmentCharge() == -1) { return 1; } else { - return mEnchantmentCharge / static_cast(maxCharge); + return getEnchantmentCharge() / static_cast(maxCharge); } } void CellRef::setEnchantmentCharge(float charge) { - if (charge != mEnchantmentCharge) + if (charge != getEnchantmentCharge()) { mChanged = true; - mEnchantmentCharge = charge; + + std::visit( + RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mEnchantmentCharge = mEnchantmentCharge; } void CellRef::setCharge(int charge) { - if (mCellRef.isESM4()) - return; - - auto& cellRef3 = mCellRef.getEsm3(); - if (charge != cellRef3.mChargeInt) - { - mChanged = true; - cellRef3.mChargeInt = charge; - } + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mChargeInt = charge; } }, + mCellRef.mVariant); } void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) { - if (mCellRef.isESM4()) - return; - - auto& cellRef3 = mCellRef.getEsm3(); - cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); - if (cellRef3.mChargeIntRemainder > 1.0f) - { - float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); - if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) - { - cellRef3.mChargeInt = 0; - } - else - { - cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); - } - cellRef3.mChargeIntRemainder = newChargeRemainder; - } + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, + [&](ESM::CellRef& cellRef3) { + cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); + if (cellRef3.mChargeIntRemainder > 1.0f) + { + float newChargeRemainder + = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); + if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) + { + cellRef3.mChargeInt = 0; + } + else + { + cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); + } + cellRef3.mChargeIntRemainder = newChargeRemainder; + } + } }, + mCellRef.mVariant); } void CellRef::setChargeFloat(float charge) { - if (mCellRef.isESM4()) - return; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; } }, + mCellRef.mVariant); + } - auto& cellRef3 = mCellRef.getEsm3(); - if (charge != cellRef3.mChargeFloat) - { - mChanged = true; - cellRef3.mChargeFloat = charge; - } + const std::string& CellRef::getGlobalVariable() const + { + + return std::visit(RefVisit{ [&](const ESM4::Reference& ref) -> const std::string& { return emptyString; }, + [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; } }, + mCellRef.mVariant); } void CellRef::resetGlobalVariable() { - if (!mGlobalVariable.empty()) + if (!getGlobalVariable().empty()) { mChanged = true; - mGlobalVariable.erase(); + std::visit( + RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); } }, + mCellRef.mVariant); } - - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mGlobalVariable = mGlobalVariable; } void CellRef::setFactionRank(int factionRank) { - if (factionRank != mFactionRank) + if (factionRank != getFactionRank()) { mChanged = true; - mFactionRank = factionRank; + std::visit([&](auto&& ref) { ref.mFactionRank = factionRank; }, mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mFactionRank = mFactionRank; } void CellRef::setOwner(const ESM::RefId& owner) { - if (owner != mOwner) + if (owner != getOwner()) { - mChanged = true; - mOwner = owner; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mOwner = owner; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mOwner = mOwner; } void CellRef::setSoul(const ESM::RefId& soul) { - if (soul != mSoul) + if (soul != getSoul()) { mChanged = true; - mSoul = soul; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mSoul = soul; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mSoul = mSoul; } void CellRef::setFaction(const ESM::RefId& faction) { - if (faction != mFaction) + if (faction != getFaction()) { mChanged = true; - mFaction = faction; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mFaction = faction; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mFaction = mFaction; } void CellRef::setLockLevel(int lockLevel) { - if (lockLevel != mLockLevel) + if (lockLevel != getLockLevel()) { mChanged = true; - mLockLevel = lockLevel; + std::visit([&](auto&& ref) { ref.mLockLevel = lockLevel; }, mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mLockLevel = mLockLevel; } void CellRef::lock(int lockLevel) @@ -252,29 +235,27 @@ namespace MWWorld void CellRef::unlock() { - setLockLevel(-abs(mLockLevel)); // Makes lockLevel negative + setLockLevel(-abs(getLockLevel())); // Makes lockLevel negative } void CellRef::setTrap(const ESM::RefId& trap) { - if (trap != mTrap) + if (trap != getTrap()) { mChanged = true; - mTrap = trap; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mTrap = trap; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mTrap = mTrap; } void CellRef::setGoldValue(int value) { - if (value != mGoldValue) + if (value != getGoldValue()) { mChanged = true; - mGoldValue = value; + std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mGoldValue = value; } }, + mCellRef.mVariant); } - if (!mCellRef.isESM4()) - mCellRef.getEsm3().mGoldValue = mGoldValue; } void CellRef::writeState(ESM::ObjectState& state) const @@ -285,5 +266,4 @@ namespace MWWorld state.mRef = cellRef3; } } - } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index b3f3e84125..116c85b84a 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -18,13 +18,14 @@ namespace MWWorld /// \brief Encapsulated variant of ESM::CellRef with change tracking class CellRef { + protected: public: CellRef(const ESM::CellRef& ref); CellRef(const ESM4::Reference& ref); // Note: Currently unused for items in containers - const ESM::RefNum& getRefNum() const { return mRefNum; } + const ESM::RefNum& getRefNum() const; // Returns RefNum. // If RefNum is not set, assigns a generated one and changes the "lastAssignedRefNum" counter. @@ -34,32 +35,44 @@ namespace MWWorld void unsetRefNum(); /// Does the RefNum have a content file? - bool hasContentFile() const { return mRefNum.hasContentFile(); } + bool hasContentFile() const { return getRefNum().hasContentFile(); } // Id of object being referenced - const ESM::RefId& getRefId() const { return mReferenceType; } + const ESM::RefId& getRefId() const + { + return mCellRef.isESM4() ? mCellRef.getEsm4().mBaseObj : mCellRef.getEsm3().mRefID; + } // For doors - true if this door teleports to somewhere else, false // if it should open through animation. bool getTeleport() const { return mCellRef.isESM4() ? false : mCellRef.getEsm3().mTeleport; } // Teleport location for the door, if this is a teleporting door. - const ESM::Position& getDoorDest() const { return mDoorDest; } + const ESM::Position& getDoorDest() const + { + return mCellRef.isESM4() ? mCellRef.getEsm4().mDoor.destPos : mCellRef.getEsm3().mDoorDest; + } // Destination cell for doors (optional) - const std::string& getDestCell() const { return mDestCell; } + const std::string& getDestCell() const; // Scale applied to mesh - float getScale() const { return mScale; } + float getScale() const + { + return std::visit([&](auto&& ref) { return ref.mScale; }, mCellRef.mVariant); + } void setScale(float scale); // The *original* position and rotation as it was given in the Construction Set. // Current position and rotation of the object is stored in RefData. - const ESM::Position& getPosition() const { return mPos; } + const ESM::Position& getPosition() const + { + return std::visit([](auto&& ref) -> const ESM::Position& { return ref.mPos; }, mCellRef.mVariant); + } void setPosition(const ESM::Position& position); // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). - float getEnchantmentCharge() const { return mEnchantmentCharge; } + float getEnchantmentCharge() const; // Remaining enchantment charge rescaled to the supplied maximum charge (such as one of the enchantment). float getNormalizedEnchantmentCharge(int maxCharge) const; @@ -79,43 +92,58 @@ namespace MWWorld void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 // The NPC that owns this object (and will get angry if you steal it) - const ESM::RefId& getOwner() const { return mOwner; } + const ESM::RefId& getOwner() const + { + return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mOwner; + } void setOwner(const ESM::RefId& owner); // Name of a global variable. If the global variable is set to '1', using the object is temporarily allowed // even if it has an Owner field. // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. - const std::string& getGlobalVariable() const { return mGlobalVariable; } + const std::string& getGlobalVariable() const; void resetGlobalVariable(); // ID of creature trapped in this soul gem - const ESM::RefId& getSoul() const { return mSoul; } + const ESM::RefId& getSoul() const { return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mSoul; } void setSoul(const ESM::RefId& soul); // The faction that owns this object (and will get angry if // you take it and are not a faction member) - const ESM::RefId& getFaction() const { return mFaction; } + const ESM::RefId& getFaction() const + { + return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mFaction; + } void setFaction(const ESM::RefId& faction); // PC faction rank required to use the item. Sometimes is -1, which means "any rank". void setFactionRank(int factionRank); - int getFactionRank() const { return mFactionRank; } + int getFactionRank() const + { + return std::visit([&](auto&& ref) { return ref.mFactionRank; }, mCellRef.mVariant); + } // Lock level for doors and containers // Positive for a locked door. 0 for a door that was never locked. // For an unlocked door, it is set to -(previous locklevel) - int getLockLevel() const { return mLockLevel; } + int getLockLevel() const + { + return std::visit([](auto&& ref) { return static_cast(ref.mLockLevel); }, mCellRef.mVariant); + } void setLockLevel(int lockLevel); void lock(int lockLevel); void unlock(); // Key and trap ID names, if any - const ESM::RefId& getKey() const { return mKey; } - const ESM::RefId& getTrap() const { return mTrap; } + const ESM::RefId& getKey() const + { + return std::visit([](auto&& ref) -> const ESM::RefId& { return ref.mKey; }, mCellRef.mVariant); + } + const ESM::RefId& getTrap() const { return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mTrap; } void setTrap(const ESM::RefId& trap); // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int getGoldValue() const { return mGoldValue; } + int getGoldValue() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mGoldValue; } void setGoldValue(int value); // Write the content of this CellRef into the given ObjectState @@ -127,14 +155,6 @@ namespace MWWorld private: bool mChanged; ESM::ReferenceVariant mCellRef; - - ESM::RefId mSoul, mFaction, mKey, mTrap, mOwner, mReferenceType; - float Scale; - ESM::Position mPos, mDoorDest; - ESM::RefNum mRefNum; - std::string mGlobalVariable, mDestCell; - int mLockLevel, mGoldValue, mFactionRank, mEnchantmentCharge; - float mScale; }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1dd43ed187..9e3fad85df 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -840,7 +840,6 @@ namespace MWWorld void CellStore::loadRefs() { - assert(mCellVariant.isValid()); std::map refNumToID; // used to detect refID modifications std::visit([&refNumToID, this](auto&& cell) { this->loadRefs(*cell, refNumToID); }, mCellVariant.mVariant); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index b1e03a5722..e0d0f63cf6 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -91,8 +91,7 @@ namespace MWWorld , mEnabled(true) , mPhysicsPostponed(false) , mCount(1) - , mPosition{ { cellRef.mPlacement.pos.x, cellRef.mPlacement.pos.y, cellRef.mPlacement.pos.z }, - { cellRef.mPlacement.rot.x, cellRef.mPlacement.rot.y, cellRef.mPlacement.rot.z } } + , mPosition(cellRef.mPos) , mCustomData(nullptr) , mChanged(false) , mFlags(0) diff --git a/components/esm4/loadrefr.cpp b/components/esm4/loadrefr.cpp index b95f24e73a..733d2dd1e9 100644 --- a/components/esm4/loadrefr.cpp +++ b/components/esm4/loadrefr.cpp @@ -76,7 +76,7 @@ void ESM4::Reference::load(ESM4::Reader& reader) break; } case ESM4::SUB_DATA: - reader.get(mPlacement); + reader.get(mPos); break; case ESM4::SUB_XSCL: reader.get(mScale); @@ -235,7 +235,9 @@ void ESM4::Reference::load(ESM4::Reader& reader) reader.get(dummy); reader.get(dummy); reader.get(dummy); - reader.getFormId(mKey); + FormId keyForm; + reader.getFormId(keyForm); + mKey = ESM::RefId::formIdRefId(keyForm); reader.get(dummy); // flag? reader.get(dummy); reader.get(dummy); diff --git a/components/esm4/loadrefr.hpp b/components/esm4/loadrefr.hpp index fb54c35863..aa95121378 100644 --- a/components/esm4/loadrefr.hpp +++ b/components/esm4/loadrefr.hpp @@ -59,7 +59,7 @@ namespace ESM4 struct TeleportDest { FormId destDoor; - Placement destPos; + ESM::Position destPos; std::uint32_t flags; // 0x01 no alarm (only in TES5) }; @@ -84,7 +84,7 @@ namespace ESM4 std::string mFullName; ESM::RefId mBaseObj; - Placement mPlacement; + ESM::Position mPos; float mScale = 1.0f; FormId mOwner; FormId mGlobal; @@ -105,7 +105,7 @@ namespace ESM4 TeleportDest mDoor; bool mIsLocked; std::int8_t mLockLevel; - FormId mKey; + ESM::RefId mKey; FormId mTargetRef; From 9054722f4aa03218dac5e2891a9ff58bc69910ff Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 28 Jan 2023 19:21:13 +0100 Subject: [PATCH 16/25] std::visit everywhere! --- apps/openmw/mwworld/cellref.cpp | 7 +-- apps/openmw/mwworld/cellref.hpp | 85 +++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index ce6b49595b..38f13c8a69 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -260,10 +260,7 @@ namespace MWWorld void CellRef::writeState(ESM::ObjectState& state) const { - if (!mCellRef.isESM4()) - { - auto& cellRef3 = mCellRef.getEsm3(); - state.mRef = cellRef3; - } + std::visit(RefVisit{ [&](const ESM4::Reference& ref) {}, [&](const ESM::CellRef& ref) { state.mRef = ref; } }, + mCellRef.mVariant); } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 116c85b84a..85acc1e548 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -40,17 +40,35 @@ namespace MWWorld // Id of object being referenced const ESM::RefId& getRefId() const { - return mCellRef.isESM4() ? mCellRef.getEsm4().mBaseObj : mCellRef.getEsm3().mRefID; + struct Visitor + { + const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mRefID; } + const ESM::RefId& operator()(const ESM4::Reference& ref) { return ref.mBaseObj; } + }; + return std::visit(Visitor(), mCellRef.mVariant); } // For doors - true if this door teleports to somewhere else, false // if it should open through animation. - bool getTeleport() const { return mCellRef.isESM4() ? false : mCellRef.getEsm3().mTeleport; } + bool getTeleport() const + { + struct Visitor + { + bool operator()(const ESM::CellRef& ref) { return ref.mTeleport; } + bool operator()(const ESM4::Reference& ref) { return 0; } + }; + return std::visit(Visitor(), mCellRef.mVariant); + } // Teleport location for the door, if this is a teleporting door. const ESM::Position& getDoorDest() const { - return mCellRef.isESM4() ? mCellRef.getEsm4().mDoor.destPos : mCellRef.getEsm3().mDoorDest; + struct Visitor + { + const ESM::Position& operator()(const ESM::CellRef& ref) { return ref.mDoorDest; } + const ESM::Position& operator()(const ESM4::Reference& ref) { return ref.mDoor.destPos; } + }; + return std::visit(Visitor(), mCellRef.mVariant); } // Destination cell for doors (optional) @@ -82,10 +100,23 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. // If this returns int(-1) it means full health. - int getCharge() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mChargeInt; } + int getCharge() const + { + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; } + int operator()(const ESM4::Reference& ref) { return 0; } + }; + return std::visit(Visitor(), mCellRef.mVariant); + } float getChargeFloat() const { - return mCellRef.isESM4() ? 0.f : mCellRef.getEsm3().mChargeFloat; + struct Visitor + { + float operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; } + float operator()(const ESM4::Reference& ref) { return 0; } + }; + return std::visit(Visitor(), mCellRef.mVariant); } // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); @@ -94,7 +125,12 @@ namespace MWWorld // The NPC that owns this object (and will get angry if you steal it) const ESM::RefId& getOwner() const { - return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mOwner; + struct Visitor + { + const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mOwner; } + const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + }; + return std::visit(Visitor(), mCellRef.mVariant); } void setOwner(const ESM::RefId& owner); @@ -106,14 +142,27 @@ namespace MWWorld void resetGlobalVariable(); // ID of creature trapped in this soul gem - const ESM::RefId& getSoul() const { return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mSoul; } + const ESM::RefId& getSoul() const + { + struct Visitor + { + const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mSoul; } + const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + }; + return std::visit(Visitor(), mCellRef.mVariant); + } void setSoul(const ESM::RefId& soul); // The faction that owns this object (and will get angry if // you take it and are not a faction member) const ESM::RefId& getFaction() const { - return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mFaction; + struct Visitor + { + const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mFaction; } + const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + }; + return std::visit(Visitor(), mCellRef.mVariant); } void setFaction(const ESM::RefId& faction); @@ -139,11 +188,27 @@ namespace MWWorld { return std::visit([](auto&& ref) -> const ESM::RefId& { return ref.mKey; }, mCellRef.mVariant); } - const ESM::RefId& getTrap() const { return mCellRef.isESM4() ? ESM::RefId::sEmpty : mCellRef.getEsm3().mTrap; } + const ESM::RefId& getTrap() const + { + struct Visitor + { + const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mTrap; } + const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + }; + return std::visit(Visitor(), mCellRef.mVariant); + } void setTrap(const ESM::RefId& trap); // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int getGoldValue() const { return mCellRef.isESM4() ? 0 : mCellRef.getEsm3().mGoldValue; } + int getGoldValue() const + { + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mGoldValue; } + int operator()(const ESM4::Reference& ref) { return 0; } + }; + return std::visit(Visitor(), mCellRef.mVariant); + } void setGoldValue(int value); // Write the content of this CellRef into the given ObjectState From 808c7367c95d37b623a28a38a39a20266e1a3217 Mon Sep 17 00:00:00 2001 From: fteppe Date: Sun, 29 Jan 2023 10:54:21 +0100 Subject: [PATCH 17/25] Fix compile --- apps/openmw/mwworld/cellref.cpp | 3 +++ apps/openmw/mwworld/cellstore.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 38f13c8a69..5229614258 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -14,6 +14,9 @@ namespace MWWorld using Ts::operator()...; }; + template + RefVisit(Ts...) -> RefVisit; + CellRef::CellRef(const ESM::CellRef& ref) : mCellRef(ESM::ReferenceVariant(ref)) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 9e3fad85df..35b6dc98f3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1087,8 +1087,8 @@ namespace MWWorld struct Visitor { - bool operator()(const ESM::Cell* a, const ESM::Cell* b) const { return a->getCellId() == b->getCellId(); }; - bool operator()(const ESM4::Cell* a, const ESM4::Cell* b) const { return a->mId == b->mId; }; + bool operator()(const ESM::Cell* a, const ESM::Cell* b) const { return a->getCellId() == b->getCellId(); } + bool operator()(const ESM4::Cell* a, const ESM4::Cell* b) const { return a->mId == b->mId; } template bool operator()(L, R) const From aa29f86efee572fff8c95aa63b991e66f0f4ee9a Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 28 Jan 2023 19:45:27 +0100 Subject: [PATCH 18/25] fixed struct vs class. --- apps/openmw/mwworld/cell.hpp | 2 +- components/esm/esmbridge.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 3a0d063e02..f8545f40e3 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -22,7 +22,7 @@ namespace MWWorld { class CellStore; - struct Cell : public ESM::CellVariant + class Cell : public ESM::CellVariant { friend MWWorld::CellStore; struct MoodData diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index e50b73e61b..1439f271c1 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -18,7 +18,7 @@ namespace ESM struct CellId; struct RefId; - struct CellVariant + class CellVariant { protected: std::variant mVariant; From 0723c324285aff6ccdd5bcca263ae1fae686d601 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 28 Jan 2023 19:47:04 +0100 Subject: [PATCH 19/25] flags no longer bitfield --- apps/openmw/mwworld/cell.cpp | 10 +++++----- apps/openmw/mwworld/cell.hpp | 9 ++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 372f130fcd..5f43b5bd43 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -17,9 +17,9 @@ namespace MWWorld mRegion = ESM::RefId::sEmpty; // Unimplemented for now - mFlags.hasWater = (cell.mCellFlags & ESM4::CELL_HasWater) != 0; + mFlags.hasWater = cell.mCellFlags & ESM4::CELL_HasWater; mFlags.isExterior = !(cell.mCellFlags & ESM4::CELL_Interior); - mFlags.isQuasiExterior = (cell.mCellFlags & ESM4::CELL_QuasiExt) != 0; + mFlags.isQuasiExterior = cell.mCellFlags & ESM4::CELL_QuasiExt; mFlags.noSleep = false; // No such notion in ESM4 mCellId.mWorldspace = Misc::StringUtils::lowerCase(cell.mEditorId); @@ -44,10 +44,10 @@ namespace MWWorld mRegion = ESM::RefId::sEmpty; // Unimplemented for now - mFlags.hasWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0; + mFlags.hasWater = cell.mData.mFlags & ESM::Cell::HasWater; 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; + mFlags.isQuasiExterior = cell.mData.mFlags & ESM::Cell::QuasiEx; + mFlags.noSleep = cell.mData.mFlags & ESM::Cell::NoSleep; mCellId = cell.getCellId(); diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index f8545f40e3..902f2487e0 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -53,11 +53,10 @@ namespace MWWorld private: struct { - uint8_t isExterior : 1; - uint8_t isQuasiExterior : 1; - uint8_t hasWater : 1; - uint8_t noSleep : 1; - uint8_t _free : 4; + bool isExterior; + bool isQuasiExterior; + bool hasWater; + bool noSleep; } mFlags; osg::Vec2i mGridPos; From ebfee18e354fa89c13e5bc435c95294a3cf4517a Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 29 Jan 2023 11:28:23 +0100 Subject: [PATCH 20/25] implements std::visit for CellVariant, fixes struct vs class forward decl --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/fogmanager.hpp | 2 +- apps/openmw/mwrender/renderingmanager.hpp | 4 +-- apps/openmw/mwworld/cell.hpp | 1 - apps/openmw/mwworld/cellstore.cpp | 4 +-- components/esm/esmbridge.hpp | 36 +++++++++++++++++++++-- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5219ab72cc..fc7bc21d8b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -57,7 +57,7 @@ namespace ESM struct ItemLevList; struct TimeStamp; struct RefId; - struct CellVariant; + class CellVariant; } diff --git a/apps/openmw/mwrender/fogmanager.hpp b/apps/openmw/mwrender/fogmanager.hpp index 258371bc9e..a0a2f71047 100644 --- a/apps/openmw/mwrender/fogmanager.hpp +++ b/apps/openmw/mwrender/fogmanager.hpp @@ -5,7 +5,7 @@ namespace MWWorld { - struct Cell; + class Cell; } namespace MWRender diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 70b40f6f67..62e546bdad 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,7 +43,7 @@ namespace ESM { struct Cell; struct RefNum; - struct CellVariant; + class CellVariant; } namespace Terrain @@ -74,7 +74,7 @@ namespace DetourNavigator namespace MWWorld { class GroundcoverStore; - struct Cell; + class Cell; } namespace Debug diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 902f2487e0..a052222005 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -24,7 +24,6 @@ namespace MWWorld class Cell : public ESM::CellVariant { - friend MWWorld::CellStore; struct MoodData { uint32_t mAmbiantColor; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 35b6dc98f3..767c3c86d0 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -842,7 +842,7 @@ namespace MWWorld { std::map refNumToID; // used to detect refID modifications - std::visit([&refNumToID, this](auto&& cell) { this->loadRefs(*cell, refNumToID); }, mCellVariant.mVariant); + std::visit([&refNumToID, this](auto&& cell) { this->loadRefs(*cell, refNumToID); }, mCellVariant); updateMergedRefs(); } @@ -1099,7 +1099,7 @@ namespace MWWorld bool CellStore::operator==(const CellStore& right) const { - return std::visit(Visitor{}, this->mCellVariant.mVariant, right.mCellVariant.mVariant); + return std::visit(Visitor{}, this->mCellVariant, right.mCellVariant); } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index 1439f271c1..7912e66cbe 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -35,10 +35,24 @@ namespace ESM } bool isEsm4() const { return std::holds_alternative(mVariant); } - const ESM4::Cell& getEsm4() const; - const ESM::Cell& getEsm3() const; + + template + auto visit(F&& f) const + { + return std::visit(f, mVariant); + } + template + auto visit(F&& f) + { + return std::visit(f, mVariant); + } + template + auto visit(F&& f, const CellVariant& v2) const + { + return std::visit(f, mVariant, v2.mVariant); + } }; struct ReferenceVariant @@ -65,4 +79,22 @@ namespace ESM }; } +namespace std +{ + template + auto visit(F&& f, const ESM::CellVariant& v) + { + return v.visit(f); + } + template + auto visit(F&& f, ESM::CellVariant& v) + { + return v.visit(f); + } + template + auto visit(F&& f, const ESM::CellVariant& v1, const ESM::CellVariant& v2) + { + return v1.visit(f, v2); + } +} #endif From 144e0197fb049ddc15993ae1d4fee2a645b3ed1c Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 29 Jan 2023 12:06:05 +0100 Subject: [PATCH 21/25] fix charge int + struct vs class mismatch --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/cellref.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index fc7bc21d8b..0e8af6eae9 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -94,7 +94,7 @@ namespace MWWorld class TimeStamp; class ESMStore; class RefData; - struct Cell; + class Cell; typedef std::vector> PtrMovementList; } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 85acc1e548..25c3e768ef 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -104,7 +104,7 @@ namespace MWWorld { struct Visitor { - int operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; } + int operator()(const ESM::CellRef& ref) { return ref.mChargeInt; } int operator()(const ESM4::Reference& ref) { return 0; } }; return std::visit(Visitor(), mCellRef.mVariant); From 4e7cde5d72865604f4d37fc65b7eadaedbf64195 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 29 Jan 2023 19:18:50 +0100 Subject: [PATCH 22/25] applied some review changes. crashfix tests --- apps/openmw/mwmechanics/aiwander.hpp | 1 - apps/openmw/mwworld/cell.cpp | 17 +++--- apps/openmw/mwworld/cell.hpp | 16 ++--- apps/openmw/mwworld/cellref.cpp | 90 ++++++++++++++++++++-------- apps/openmw/mwworld/cellref.hpp | 20 +++---- apps/openmw/mwworld/cellstore.cpp | 8 --- apps/openmw/mwworld/livecellref.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 5 +- apps/openmw/mwworld/worldimp.cpp | 3 +- components/esm3/cellid.cpp | 2 +- components/esm3/cellid.hpp | 1 - 11 files changed, 96 insertions(+), 69 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index f956367321..b4d59bdbe2 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -160,7 +160,6 @@ namespace MWMechanics }; /// convert point from local (i.e. cell) to world coordinates - void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::CellCommon* cell); void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage, diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 5f43b5bd43..9a345d2ac8 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -17,13 +17,12 @@ namespace MWWorld mRegion = ESM::RefId::sEmpty; // Unimplemented for now - mFlags.hasWater = cell.mCellFlags & ESM4::CELL_HasWater; - mFlags.isExterior = !(cell.mCellFlags & ESM4::CELL_Interior); - mFlags.isQuasiExterior = cell.mCellFlags & ESM4::CELL_QuasiExt; - mFlags.noSleep = false; // No such notion in ESM4 + mFlags.mHasWater = cell.mCellFlags & ESM4::CELL_HasWater; + mFlags.mIsExterior = !(cell.mCellFlags & ESM4::CELL_Interior); + mFlags.mIsQuasiExterior = cell.mCellFlags & ESM4::CELL_QuasiExt; + mFlags.mNoSleep = 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(); @@ -44,10 +43,10 @@ namespace MWWorld mRegion = ESM::RefId::sEmpty; // Unimplemented for now - mFlags.hasWater = cell.mData.mFlags & ESM::Cell::HasWater; - mFlags.isExterior = !(cell.mData.mFlags & ESM::Cell::Interior); - mFlags.isQuasiExterior = cell.mData.mFlags & ESM::Cell::QuasiEx; - mFlags.noSleep = cell.mData.mFlags & ESM::Cell::NoSleep; + mFlags.mHasWater = cell.mData.mFlags & ESM::Cell::HasWater; + mFlags.mIsExterior = !(cell.mData.mFlags & ESM::Cell::Interior); + mFlags.mIsQuasiExterior = cell.mData.mFlags & ESM::Cell::QuasiEx; + mFlags.mNoSleep = cell.mData.mFlags & ESM::Cell::NoSleep; mCellId = cell.getCellId(); diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index a052222005..21a53792da 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -38,10 +38,10 @@ namespace MWWorld 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; } + bool isExterior() const { return mFlags.mIsExterior; } + bool isQuasiExterior() const { return mFlags.mIsQuasiExterior; } + bool hasWater() const { return mFlags.mHasWater; } + bool noSleep() const { return mFlags.mNoSleep; } const ESM::CellId& getCellId() const { return mCellId; } const ESM::RefId& getRegion() const { return mRegion; } std::string_view getNameId() const { return mNameID; } @@ -52,10 +52,10 @@ namespace MWWorld private: struct { - bool isExterior; - bool isQuasiExterior; - bool hasWater; - bool noSleep; + bool mIsExterior; + bool mIsQuasiExterior; + bool mHasWater; + bool mNoSleep; } mFlags; osg::Vec2i mGridPos; diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 5229614258..4eef83e50d 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -20,29 +20,29 @@ namespace MWWorld CellRef::CellRef(const ESM::CellRef& ref) : mCellRef(ESM::ReferenceVariant(ref)) { - mChanged = false; } CellRef::CellRef(const ESM4::Reference& ref) : mCellRef(ESM::ReferenceVariant(ref)) { - - mChanged = false; } static const ESM::RefNum emptyRefNum = {}; const ESM::RefNum& CellRef::getRefNum() const { - return std::visit(RefVisit{ [&](const ESM4::Reference& ref) -> const ESM::RefNum& { return emptyRefNum; }, - [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; } }, + return std::visit(RefVisit{ + [&](const ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, + [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; }, + }, mCellRef.mVariant); } const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) { return std::visit( - RefVisit{ [&](ESM4::Reference& ref) -> const ESM::RefNum& { return emptyRefNum; }, + RefVisit{ + [&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, [&](ESM::CellRef& ref) -> const ESM::RefNum& { if (!ref.mRefNum.isSet()) { @@ -60,13 +60,17 @@ namespace MWWorld mChanged = true; } return ref.mRefNum; - } }, + }, + }, mCellRef.mVariant); } void CellRef::unsetRefNum() { - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; }, + }, mCellRef.mVariant); } @@ -94,8 +98,10 @@ namespace MWWorld float CellRef::getEnchantmentCharge() const { - return std::visit(RefVisit{ [&](const ESM4::Reference& ref) { return 0.f; }, - [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; } }, + return std::visit(RefVisit{ + [&](const ESM4::Reference& /*ref*/) { return 0.f; }, + [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; }, + }, mCellRef.mVariant); } @@ -121,21 +127,27 @@ namespace MWWorld { mChanged = true; - std::visit( - RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; }, + }, mCellRef.mVariant); } } void CellRef::setCharge(int charge) { - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mChargeInt = charge; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mChargeInt = charge; }, + }, mCellRef.mVariant); } void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) { - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, [&](ESM::CellRef& cellRef3) { cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); if (cellRef3.mChargeIntRemainder > 1.0f) @@ -152,21 +164,27 @@ namespace MWWorld } cellRef3.mChargeIntRemainder = newChargeRemainder; } - } }, + }, + }, mCellRef.mVariant); } void CellRef::setChargeFloat(float charge) { - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; }, + }, mCellRef.mVariant); } const std::string& CellRef::getGlobalVariable() const { - return std::visit(RefVisit{ [&](const ESM4::Reference& ref) -> const std::string& { return emptyString; }, - [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; } }, + return std::visit(RefVisit{ + [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, + [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; }, + }, mCellRef.mVariant); } @@ -175,8 +193,10 @@ namespace MWWorld if (!getGlobalVariable().empty()) { mChanged = true; - std::visit( - RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); }, + }, mCellRef.mVariant); } } @@ -194,7 +214,10 @@ namespace MWWorld { if (owner != getOwner()) { - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mOwner = owner; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mOwner = owner; }, + }, mCellRef.mVariant); } } @@ -204,7 +227,10 @@ namespace MWWorld if (soul != getSoul()) { mChanged = true; - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mSoul = soul; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mSoul = soul; }, + }, mCellRef.mVariant); } } @@ -214,7 +240,10 @@ namespace MWWorld if (faction != getFaction()) { mChanged = true; - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mFaction = faction; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mFaction = faction; }, + }, mCellRef.mVariant); } } @@ -246,7 +275,10 @@ namespace MWWorld if (trap != getTrap()) { mChanged = true; - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mTrap = trap; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mTrap = trap; }, + }, mCellRef.mVariant); } } @@ -256,14 +288,20 @@ namespace MWWorld if (value != getGoldValue()) { mChanged = true; - std::visit(RefVisit{ [&](ESM4::Reference& ref) {}, [&](ESM::CellRef& ref) { ref.mGoldValue = value; } }, + std::visit(RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM::CellRef& ref) { ref.mGoldValue = value; }, + }, mCellRef.mVariant); } } void CellRef::writeState(ESM::ObjectState& state) const { - std::visit(RefVisit{ [&](const ESM4::Reference& ref) {}, [&](const ESM::CellRef& ref) { state.mRef = ref; } }, + std::visit(RefVisit{ + [&](const ESM4::Reference& /*ref*/) {}, + [&](const ESM::CellRef& ref) { state.mRef = ref; }, + }, mCellRef.mVariant); } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 25c3e768ef..cab671bd0c 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -20,9 +20,9 @@ namespace MWWorld { protected: public: - CellRef(const ESM::CellRef& ref); + explicit CellRef(const ESM::CellRef& ref); - CellRef(const ESM4::Reference& ref); + explicit CellRef(const ESM4::Reference& ref); // Note: Currently unused for items in containers const ESM::RefNum& getRefNum() const; @@ -105,7 +105,7 @@ namespace MWWorld struct Visitor { int operator()(const ESM::CellRef& ref) { return ref.mChargeInt; } - int operator()(const ESM4::Reference& ref) { return 0; } + int operator()(const ESM4::Reference& /*ref*/) { return 0; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -114,7 +114,7 @@ namespace MWWorld struct Visitor { float operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; } - float operator()(const ESM4::Reference& ref) { return 0; } + float operator()(const ESM4::Reference& /*ref*/) { return 0; } }; return std::visit(Visitor(), mCellRef.mVariant); } // Implemented as union with int charge @@ -128,7 +128,7 @@ namespace MWWorld struct Visitor { const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mOwner; } - const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -147,7 +147,7 @@ namespace MWWorld struct Visitor { const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mSoul; } - const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -160,7 +160,7 @@ namespace MWWorld struct Visitor { const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mFaction; } - const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -193,7 +193,7 @@ namespace MWWorld struct Visitor { const ESM::RefId& operator()(const ESM::CellRef& ref) { return ref.mTrap; } - const ESM::RefId& operator()(const ESM4::Reference& ref) { return ESM::RefId::sEmpty; } + const ESM::RefId& operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId::sEmpty; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -205,7 +205,7 @@ namespace MWWorld struct Visitor { int operator()(const ESM::CellRef& ref) { return ref.mGoldValue; } - int operator()(const ESM4::Reference& ref) { return 0; } + int operator()(const ESM4::Reference& /*ref*/) { return 0; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -218,7 +218,7 @@ namespace MWWorld bool hasChanged() const { return mChanged; } private: - bool mChanged; + bool mChanged = false; ESM::ReferenceVariant mCellRef; }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 767c3c86d0..d322c183cf 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -382,17 +382,9 @@ namespace MWWorld if (const X* ptr = store.search(ref.mBaseObj)) { - // typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.); - LiveRef liveCellRef(ref, ptr); - if (deleted) liveCellRef.mData.setDeletedByContentFile(true); - - /*if (iter != mList.end()) - *iter = liveCellRef; - else - */ mList.push_back(liveCellRef); } else diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 88218429e1..7668f18de1 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -31,7 +31,7 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Referen void MWWorld::LiveCellRefBase::loadImp(const ESM::ObjectState& state) { - mRef = state.mRef; + mRef = MWWorld::CellRef(state.mRef); mData = RefData(state, mData.isDeletedByContentFile()); Ptr ptr(this); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d77e729c35..0e285ee30d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -317,8 +317,7 @@ namespace MWWorld { if (mActiveCells.find(cell) == mActiveCells.end()) return; - std::string description = cell->getCell()->getDescription(); - Log(Debug::Info) << "Unloading cell " << description; + Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription(); ListAndResetObjectsVisitor visitor; @@ -387,7 +386,7 @@ namespace MWWorld const int cellX = cell->getCell()->getGridX(); const int cellY = cell->getCell()->getGridY(); - auto cellVariant = *cell->getCell(); + const MWWorld::Cell& cellVariant = *cell->getCell(); if (cellVariant.isExterior()) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 39d324a80d..641619acf6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -645,7 +645,8 @@ namespace MWWorld if (!cell.isEsm4()) { const ESM::Region* region = mStore.get().search(cell.getEsm3().mRegion); - return region->mName; + if (region) + return region->mName; } return mStore.get().find("sDefaultCellname")->mValue.getString(); diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index f5318cbbd7..a63a1bfad6 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -31,7 +31,7 @@ namespace ESM bool operator==(const CellId& left, const CellId& right) { - return left.mWorld == right.mWorld && left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged + return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged && (!left.mPaged || (left.mIndex.mX == right.mIndex.mX && left.mIndex.mY == right.mIndex.mY)); } diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 8d2418790f..33db9e7432 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -17,7 +17,6 @@ namespace ESM int mY; }; - ESM::RefId mWorld; std::string mWorldspace; CellIndex mIndex; bool mPaged; From 1caed2de2a0dfe94dca7fc89dfa654cecb3a0079 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 31 Jan 2023 19:50:48 +0100 Subject: [PATCH 23/25] Applies some review comments. Proper visit for ESM::CellVariant Fixed MWWorldCell constructor --- apps/openmw/mwbase/world.hpp | 4 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwmechanics/aiwander.hpp | 2 - apps/openmw/mwrender/renderingmanager.hpp | 1 - apps/openmw/mwworld/cell.cpp | 72 ++++++++++------------- apps/openmw/mwworld/cell.hpp | 19 +++--- apps/openmw/mwworld/cellstore.cpp | 14 ++--- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 18 ++++-- apps/openmw/mwworld/worldimp.hpp | 1 + components/esm/esmbridge.hpp | 36 ++---------- components/esm4/loadcell.cpp | 1 - 13 files changed, 71 insertions(+), 102 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 0e8af6eae9..ba1c34545d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -57,8 +57,6 @@ namespace ESM struct ItemLevList; struct TimeStamp; struct RefId; - class CellVariant; - } namespace MWPhysics @@ -184,6 +182,8 @@ namespace MWBase /// generate a name. virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0; + virtual std::string_view getCellName(const ESM::Cell* cell) const = 0; + virtual void removeRefScript(MWWorld::RefData* ref) = 0; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 0d27474428..075b2cffa8 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -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().search(index.x(), index.y()); - dest = world->getCellName(MWWorld::Cell(*cell)); + dest = world->getCellName(cell); } return "#{sCell=" + std::string{ dest } + "}"; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index b4d59bdbe2..9b5a7aed42 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -12,7 +12,6 @@ namespace ESM { struct Cell; - struct CellCommon; namespace AiSequence { struct AiWander; @@ -159,7 +158,6 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; - /// convert point from local (i.e. cell) to world coordinates void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage, diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 62e546bdad..5f2ef350c1 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,7 +43,6 @@ namespace ESM { struct Cell; struct RefNum; - class CellVariant; } namespace Terrain diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 9a345d2ac8..9444e42136 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -8,52 +8,44 @@ namespace MWWorld { Cell::Cell(const ESM4::Cell& cell) : ESM::CellVariant(cell) + , mIsExterior(!(cell.mCellFlags & ESM4::CELL_Interior)) + , mIsQuasiExterior(cell.mCellFlags & ESM4::CELL_QuasiExt) + , mHasWater(cell.mCellFlags & ESM4::CELL_HasWater) + , mNoSleep(false) // No such notion in ESM4 + , mGridPos(cell.mX, cell.mY) + , mDisplayname(cell.mFullName) + , mNameID(cell.mEditorId) + , mRegion(ESM::RefId::sEmpty) // Unimplemented for now + , mCellId{ + .mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) }, + .mIndex{ cell.getGridX(), cell.getGridY() }, + .mPaged = isExterior(),} + ,mMood{ + .mAmbiantColor = cell.mLighting.ambient, + .mDirectionalColor = cell.mLighting.directional, + .mFogColor = cell.mLighting.fogColor, + .mFogDensity = cell.mLighting.fogPower,} { - - mNameID = cell.mEditorId; - mDisplayname = cell.mFullName; - mGridPos.x() = cell.mX; - mGridPos.y() = cell.mY; - - mRegion = ESM::RefId::sEmpty; // Unimplemented for now - - mFlags.mHasWater = cell.mCellFlags & ESM4::CELL_HasWater; - mFlags.mIsExterior = !(cell.mCellFlags & ESM4::CELL_Interior); - mFlags.mIsQuasiExterior = cell.mCellFlags & ESM4::CELL_QuasiExt; - mFlags.mNoSleep = false; // No such notion in ESM4 - - mCellId.mWorldspace = Misc::StringUtils::lowerCase(cell.mEditorId); - 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) + , mIsExterior(!(cell.mData.mFlags & ESM::Cell::Interior)) + , mIsQuasiExterior(cell.mData.mFlags & ESM::Cell::QuasiEx) + , mHasWater(cell.mData.mFlags & ESM::Cell::HasWater) + , mNoSleep(cell.mData.mFlags & ESM::Cell::NoSleep) + , mGridPos(cell.getGridX(), cell.getGridY()) + , mDisplayname(cell.mName) + , mNameID(cell.mName) + , mRegion(ESM::RefId::sEmpty) // Unimplemented for now + , mCellId(cell.getCellId()) + , mMood{ + .mAmbiantColor = cell.mAmbi.mAmbient, + .mDirectionalColor = cell.mAmbi.mSunlight, + .mFogColor = cell.mAmbi.mFog, + .mFogDensity = cell.mAmbi.mFogDensity, + } { - mNameID = cell.mName; - mDisplayname = cell.mName; - mGridPos.x() = cell.getGridX(); - mGridPos.y() = cell.getGridY(); - - mRegion = ESM::RefId::sEmpty; // Unimplemented for now - - mFlags.mHasWater = cell.mData.mFlags & ESM::Cell::HasWater; - mFlags.mIsExterior = !(cell.mData.mFlags & ESM::Cell::Interior); - mFlags.mIsQuasiExterior = cell.mData.mFlags & ESM::Cell::QuasiEx; - mFlags.mNoSleep = cell.mData.mFlags & ESM::Cell::NoSleep; - - 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 diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 21a53792da..b90fed31f8 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -38,10 +38,10 @@ namespace MWWorld int getGridX() const { return mGridPos.x(); } int getGridY() const { return mGridPos.y(); } - bool isExterior() const { return mFlags.mIsExterior; } - bool isQuasiExterior() const { return mFlags.mIsQuasiExterior; } - bool hasWater() const { return mFlags.mHasWater; } - bool noSleep() const { return mFlags.mNoSleep; } + bool isExterior() const { return mIsExterior; } + bool isQuasiExterior() const { return mIsQuasiExterior; } + bool hasWater() const { return mHasWater; } + bool noSleep() const { return mNoSleep; } const ESM::CellId& getCellId() const { return mCellId; } const ESM::RefId& getRegion() const { return mRegion; } std::string_view getNameId() const { return mNameID; } @@ -50,13 +50,10 @@ namespace MWWorld const MoodData& getMood() const { return mMood; } private: - struct - { - bool mIsExterior; - bool mIsQuasiExterior; - bool mHasWater; - bool mNoSleep; - } mFlags; + bool mIsExterior; + bool mIsQuasiExterior; + bool mHasWater; + bool mNoSleep; osg::Vec2i mGridPos; std::string mDisplayname; // How the game displays it diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index d322c183cf..40bd9107a1 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -709,7 +709,7 @@ namespace MWWorld if (mCellVariant.isEsm4()) return; - auto cell3 = mCellVariant.getEsm3(); + const ESM::Cell& cell3 = mCellVariant.getEsm3(); if (cell3.mContextList.empty()) return; // this is a dynamically generated cell -> skipping. @@ -834,7 +834,7 @@ namespace MWWorld { std::map refNumToID; // used to detect refID modifications - std::visit([&refNumToID, this](auto&& cell) { this->loadRefs(*cell, refNumToID); }, mCellVariant); + ESM::visit([&refNumToID, this](auto&& cell) { this->loadRefs(cell, refNumToID); }, mCellVariant); updateMergedRefs(); } @@ -1077,13 +1077,13 @@ namespace MWWorld } } - struct Visitor + struct IsEqualVisitor { - bool operator()(const ESM::Cell* a, const ESM::Cell* b) const { return a->getCellId() == b->getCellId(); } - bool operator()(const ESM4::Cell* a, const ESM4::Cell* b) const { return a->mId == b->mId; } + bool operator()(const ESM::Cell& a, const ESM::Cell& b) const { return a.getCellId() == b.getCellId(); } + bool operator()(const ESM4::Cell& a, const ESM4::Cell& b) const { return a.mId == b.mId; } template - bool operator()(L, R) const + bool operator()(const L&, const R&) const { return false; } @@ -1091,7 +1091,7 @@ namespace MWWorld bool CellStore::operator==(const CellStore& right) const { - return std::visit(Visitor{}, this->mCellVariant, right.mCellVariant); + return ESM::visit(IsEqualVisitor(), this->mCellVariant, right.mCellVariant); } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 528ec2b902..720aa394b5 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "cell.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0e285ee30d..c3b1ec1ec6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -432,7 +432,7 @@ namespace MWWorld if (!cellVariant.isEsm4()) { - auto cell3 = cellVariant.getEsm3(); + const ESM::Cell& cell3 = cellVariant.getEsm3(); if (const auto pathgrid = mWorld.getStore().get().search(cell3)) mNavigator.addPathgrid(cell3, *pathgrid); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 641619acf6..8f213df71f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -644,11 +644,21 @@ namespace MWWorld if (!cell.isEsm4()) { - const ESM::Region* region = mStore.get().search(cell.getEsm3().mRegion); - if (region) - return region->mName; + return getCellName(&cell.getEsm3()); } + return mStore.get().find("sDefaultCellname")->mValue.getString(); + } + + std::string_view World::getCellName(const ESM::Cell* cell) const + { + if (cell) + { + if (!cell->isExterior() || !cell->mName.empty()) + return cell->mName; + if (const ESM::Region* region = mStore.get().search(cell->mRegion)) + return region->mName; + } return mStore.get().find("sDefaultCellname")->mValue.getString(); } @@ -3244,7 +3254,7 @@ namespace MWWorld } else { - auto cellVariant = *cell->getCell(); + const MWWorld::Cell& 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; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0d3a45e656..3cdf144d75 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -270,6 +270,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 MWWorld::Cell& cell) const override; + std::string_view getCellName(const ESM::Cell* cell) const override; void removeRefScript(MWWorld::RefData* ref) override; //< Remove the script attached to ref from mLocalScripts diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index 7912e66cbe..83e858d7b6 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -38,21 +38,8 @@ namespace ESM const ESM4::Cell& getEsm4() const; const ESM::Cell& getEsm3() const; - template - auto visit(F&& f) const - { - return std::visit(f, mVariant); - } - template - auto visit(F&& f) - { - return std::visit(f, mVariant); - } - template - auto visit(F&& f, const CellVariant& v2) const - { - return std::visit(f, mVariant, v2.mVariant); - } + template + friend auto visit(F&& f, T&&... v); }; struct ReferenceVariant @@ -77,24 +64,11 @@ namespace ESM ESM::CellRef& getEsm3() { return std::get(mVariant); } ESM4::Reference& getEsm4() { return std::get(mVariant); } }; -} -namespace std -{ - template - auto visit(F&& f, const ESM::CellVariant& v) - { - return v.visit(f); - } - template - auto visit(F&& f, ESM::CellVariant& v) - { - return v.visit(f); - } - template - auto visit(F&& f, const ESM::CellVariant& v1, const ESM::CellVariant& v2) + template + auto visit(F&& f, T&&... v) { - return v1.visit(f, v2); + return std::visit([&](auto*... ptr) { return std::forward(f)(*ptr...); }, std::forward(v).mVariant...); } } #endif diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 09eef41679..0b829d657f 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -39,7 +39,6 @@ // #include "writer.hpp" #include -#include // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // From f3d5f6345e033ff095bac74b9792529fda621998 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 4 Feb 2023 17:16:42 +0100 Subject: [PATCH 24/25] Fixed large lambdas that affected readability. --- apps/openmw/mwworld/cellref.cpp | 79 +++++++++++++++++---------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 4eef83e50d..34884f8b52 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -40,27 +40,28 @@ namespace MWWorld const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) { + auto esm3Visit = [&](ESM::CellRef& ref) -> const ESM::RefNum& { + if (!ref.mRefNum.isSet()) + { + // Generated RefNums have negative mContentFile + assert(lastAssignedRefNum.mContentFile < 0); + lastAssignedRefNum.mIndex++; + if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed + { + if (lastAssignedRefNum.mContentFile > std::numeric_limits::min()) + lastAssignedRefNum.mContentFile--; + else + Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; + } + ref.mRefNum = lastAssignedRefNum; + mChanged = true; + } + return ref.mRefNum; + }; return std::visit( RefVisit{ [&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, - [&](ESM::CellRef& ref) -> const ESM::RefNum& { - if (!ref.mRefNum.isSet()) - { - // Generated RefNums have negative mContentFile - assert(lastAssignedRefNum.mContentFile < 0); - lastAssignedRefNum.mIndex++; - if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed - { - if (lastAssignedRefNum.mContentFile > std::numeric_limits::min()) - lastAssignedRefNum.mContentFile--; - else - Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum"; - } - ref.mRefNum = lastAssignedRefNum; - mChanged = true; - } - return ref.mRefNum; - }, + esm3Visit, }, mCellRef.mVariant); } @@ -146,26 +147,27 @@ namespace MWWorld void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) { - std::visit(RefVisit{ - [&](ESM4::Reference& /*ref*/) {}, - [&](ESM::CellRef& cellRef3) { - cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); - if (cellRef3.mChargeIntRemainder > 1.0f) - { - float newChargeRemainder - = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); - if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) - { - cellRef3.mChargeInt = 0; - } - else - { - cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); - } - cellRef3.mChargeIntRemainder = newChargeRemainder; - } - }, - }, + auto esm3Visit = [&](ESM::CellRef& cellRef3) { + cellRef3.mChargeIntRemainder += std::abs(chargeRemainder); + if (cellRef3.mChargeIntRemainder > 1.0f) + { + float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder)); + if (cellRef3.mChargeInt <= static_cast(cellRef3.mChargeIntRemainder)) + { + cellRef3.mChargeInt = 0; + } + else + { + cellRef3.mChargeInt -= static_cast(cellRef3.mChargeIntRemainder); + } + cellRef3.mChargeIntRemainder = newChargeRemainder; + } + }; + std::visit( + RefVisit{ + [&](ESM4::Reference& /*ref*/) {}, + esm3Visit, + }, mCellRef.mVariant); } @@ -180,7 +182,6 @@ namespace MWWorld const std::string& CellRef::getGlobalVariable() const { - return std::visit(RefVisit{ [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; }, From 084207af644fa0cba3e0835b53f52b95efadc0aa Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 4 Feb 2023 18:45:53 +0100 Subject: [PATCH 25/25] 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