diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 1e92df85ec..b0684b1ab4 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -630,6 +630,12 @@ namespace MWWorld } void Store::clearDynamic() { + for (const auto& [_, cell] : mDynamicExt) + mCells.erase(cell->mId); + mDynamicExt.clear(); + for (const auto& [_, cell] : mDynamicInt) + mCells.erase(cell->mId); + mDynamicInt.clear(); setUp(); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77bf039276..0bd686ce7f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -473,8 +473,8 @@ namespace MWWorld mStore.write(writer, progress); // dynamic Store must be written (and read) before Cells, so that // references to custom made records will be recognized + mWorldModel.write(writer, progress); // the player's cell needs to be loaded before the player mPlayer->write(writer, progress); - mWorldModel.write(writer, progress); mGlobalVariables.write(writer, progress); mWeatherManager->write(writer, progress); mProjectileManager->write(writer, progress); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index b9187f59c4..3a1c486f0e 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -101,6 +101,24 @@ namespace MWWorld return Cell(*cell); return std::nullopt; } + + CellStore* getOrCreateExterior(const ESM::ExteriorCellLocation& location, + std::map& exteriors, ESMStore& store, + ESM::ReadersCache& readers, std::unordered_map& cells, bool triggerEvent) + { + if (const auto it = exteriors.find(location); it != exteriors.end()) + { + assert(it->second != nullptr); + return it->second; + } + auto [cell, created] = createExteriorCell(location, store); + const ESM::RefId id = cell.getId(); + CellStore* const cellStore = &emplaceCellStore(id, std::move(cell), store, readers, cells); + exteriors.emplace(location, cellStore); + if (created && triggerEvent) + MWBase::Environment::get().getLuaManager()->exteriorCreated(*cellStore); + return cellStore; + } } } @@ -178,23 +196,7 @@ namespace MWWorld { CellStore& WorldModel::getExterior(ESM::ExteriorCellLocation location, bool forceLoad) const { - const auto it = mExteriors.find(location); - CellStore* cellStore = nullptr; - - if (it == mExteriors.end()) - { - auto [cell, created] = createExteriorCell(location, mStore); - const ESM::RefId id = cell.getId(); - cellStore = &emplaceCellStore(id, std::move(cell), mStore, mReaders, mCells); - mExteriors.emplace(location, cellStore); - if (created) - MWBase::Environment::get().getLuaManager()->exteriorCreated(*cellStore); - } - else - { - assert(it->second != nullptr); - cellStore = it->second; - } + CellStore* cellStore = getOrCreateExterior(location, mExteriors, mStore, mReaders, mCells, true); if (forceLoad && cellStore->getState() != CellStore::State_Loaded) cellStore->load(); @@ -447,17 +449,26 @@ void MWWorld::WorldModel::write(ESM::ESMWriter& writer, Loading::Listener& progr } } -struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback +struct MWWorld::WorldModel::GetCellStoreCallback : public CellStore::GetCellStoreCallback { public: - GetCellStoreCallback(MWWorld::WorldModel& worldModel) + GetCellStoreCallback(WorldModel& worldModel) : mWorldModel(worldModel) { } - MWWorld::WorldModel& mWorldModel; + WorldModel& mWorldModel; - MWWorld::CellStore* getCellStore(const ESM::RefId& cellId) override { return mWorldModel.findCell(cellId); } + CellStore* getCellStore(const ESM::RefId& cellId) override + { + if (const auto* exteriorId = cellId.getIf()) + { + ESM::ExteriorCellLocation location(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId); + return getOrCreateExterior( + location, mWorldModel.mExteriors, mWorldModel.mStore, mWorldModel.mReaders, mWorldModel.mCells, false); + } + return mWorldModel.findCell(cellId); + } }; bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type) @@ -467,7 +478,10 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type) ESM::CellState state; state.mId = reader.getCellId(); - CellStore* const cellStore = findCell(state.mId); + GetCellStoreCallback callback(*this); + + CellStore* const cellStore = callback.getCellStore(state.mId); + if (cellStore == nullptr) { Log(Debug::Warning) << "Dropping state for cell " << state.mId << " (cell no longer exists)"; @@ -484,8 +498,6 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type) if (cellStore->getState() != CellStore::State_Loaded) cellStore->load(); - GetCellStoreCallback callback(*this); - cellStore->readReferences(reader, &callback); return true; diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 904dd27411..4c39d866de 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -104,6 +104,8 @@ namespace MWWorld bool readRecord(ESM::ESMReader& reader, uint32_t type); private: + struct GetCellStoreCallback; + PtrRegistry mPtrRegistry; // defined before mCells because during destruction it should be the last MWWorld::ESMStore& mStore;