diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c41fc844f9..acb1ac7463 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -2,6 +2,7 @@ #include "magiceffects.hpp" #include +#include #include @@ -42,7 +43,10 @@ #include #include #include +#include +#include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/luamanager.hpp" @@ -756,17 +760,45 @@ namespace MWWorld } } + template + static void visitCell4References(const ESM4::Cell& cell, ESM::ReadersCache& readers, ReferenceInvocable&& invocable) + { + auto stream = Files::openBinaryInputFileStream(cell.mReaderContext.filename); + ESM4::Reader readerESM4( + std::move(stream), cell.mReaderContext.filename, MWBase::Environment::get().getResourceSystem()->getVFS()); + + readerESM4.setEncoder(readers.getStatelessEncoder()); + readerESM4.restoreContext(cell.mReaderContext); + bool continueRead = true; + while (ESM::RefId::formIdRefId(readerESM4.getContext().currCell) == cell.mId && readerESM4.hasMoreRecs() + && continueRead) + { + continueRead = ESM4::ReaderUtils::readItem( + readerESM4, + [&](ESM4::Reader& reader) { + auto recordType = static_cast(reader.hdr().record.typeId); + ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); + if (esm4RecName == ESM::RecNameInts::REC_REFR4) + { + ESM4::Reference ref; + ref.load(reader); + invocable(ref); + return true; + } + else if (esm4RecName == ESM::RecNameInts::REC_CELL4) + { + ESM4::Cell cellToLoad; + cellToLoad.load(reader); // This is necessary to exit + } + return false; + }, + [&](ESM4::Reader& reader) {}); + } + } + 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); - } - } + visitCell4References(cell, mReaders, [&](ESM4::Reference& ref) { mIds.push_back(ref.mBaseObj); }); } void CellStore::listRefs() @@ -830,15 +862,7 @@ namespace MWWorld 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); - } - } + visitCell4References(cell, mReaders, [&](ESM4::Reference& ref) { loadRef(ref, false); }); } void CellStore::loadRefs() diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 7cb2925232..24f63eafc4 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -65,8 +65,7 @@ namespace MWWorld { ESM4::Reader readerESM4( std::move(stream), filepath, MWBase::Environment::get().getResourceSystem()->getVFS()); - auto statelessEncoder = mEncoder->getStatelessEncoder(); - readerESM4.setEncoder(&statelessEncoder); + readerESM4.setEncoder(mReaders.getStatelessEncoder()); mStore.loadESM4(readerESM4); break; } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 3f153d45c0..ea72f6bd9e 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -29,7 +29,6 @@ namespace ESM4 class Reader; struct Static; struct Cell; - struct Reference; struct Light; } @@ -106,7 +105,7 @@ namespace MWWorld // Special entry which is hardcoded and not loaded from an ESM Store, - Store, Store, Store, Store>; + Store, Store, Store>; private: template diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c3b8427ecf..7509ff7286 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -270,6 +270,8 @@ namespace MWWorld , mPlayerInJail(false) , mSpellPreloadTimer(0.f) { + if (encoder) + mReaders.setStatelessEncoder(encoder->getStatelessEncoder()); mESMVersions.resize(mContentFiles.size(), -1); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); diff --git a/components/esm3/readerscache.hpp b/components/esm3/readerscache.hpp index 5d8c2afcbd..94bee206ec 100644 --- a/components/esm3/readerscache.hpp +++ b/components/esm3/readerscache.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace ESM { class ReadersCache @@ -55,13 +57,23 @@ namespace ESM BusyItem get(std::size_t index); + void setStatelessEncoder(const ToUTF8::StatelessUtf8Encoder& statelessEncoderPtr) + { + mStatelessEncoder.emplace(statelessEncoderPtr); + } + + const ToUTF8::StatelessUtf8Encoder* getStatelessEncoder() + { + return mStatelessEncoder.has_value() ? &mStatelessEncoder.value() : nullptr; + } + private: const std::size_t mCapacity; std::map::iterator> mIndex; std::list mBusyItems; std::list mFreeItems; std::list mClosedItems; - + std::optional mStatelessEncoder; inline void closeExtraReaders(); inline void releaseItem(std::list::iterator it) noexcept; diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 1b61b746cf..fc199be6fc 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -240,6 +240,8 @@ void ESM4::Cell::load(ESM4::Reader& reader) throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); } } + + mReaderContext = reader.getContext(); } // void ESM4::Cell::save(ESM4::Writer& writer) const diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index da7a3fea63..264746a1c6 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -37,6 +37,7 @@ #include #include #include +#include namespace ESM4 { @@ -96,6 +97,8 @@ namespace ESM4 CellGroup* mCellGroup; + ESM4::ReaderContext mReaderContext; + void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const;