From 5037dcf9bc16ded70473a27aa82668b6aab0a49d Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 27 Jan 2023 15:29:05 +0100 Subject: [PATCH] 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: