diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index c9738be46a..00e59c46fc 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -248,6 +248,7 @@ namespace MWWorld { for (const auto& store : mDynamicStores) store->clearDynamic(); + mStoreImp->mIds = mStoreImp->mStaticIds; movePlayerRecord(); } @@ -426,32 +427,36 @@ namespace MWWorld void ESMStore::setUp() { - mStoreImp->mIds.clear(); + if (mIsSetUpDone) + throw std::logic_error("ESMStore::setUp() is called twice"); + mIsSetUpDone = true; - std::map::iterator storeIt = mStoreImp->mRecNameToStore.begin(); - for (; storeIt != mStoreImp->mRecNameToStore.end(); ++storeIt) - { - storeIt->second->setUp(); - - if (isCacheableRecord(storeIt->first)) - { - std::vector identifiers; - storeIt->second->listIdentifier(identifiers); - - for (auto& record : identifiers) - mStoreImp->mIds[record] = storeIt->first; - } - } - - if (mStoreImp->mStaticIds.empty()) - for (const auto& [k, v] : mStoreImp->mIds) - mStoreImp->mStaticIds.emplace(k, v); + for (const auto& [_, store] : mStoreImp->mRecNameToStore) + store->setUp(); getWritable().setUp(get()); getWritable().setUp(); getWritable().setUp(get()); getWritable().updateLandPositions(get()); getWritable().preprocessReferences(get()); + + rebuildIdsIndex(); + mStoreImp->mStaticIds = mStoreImp->mIds; + } + + void ESMStore::rebuildIdsIndex() + { + mStoreImp->mIds.clear(); + for (const auto& [recordType, store] : mStoreImp->mRecNameToStore) + { + if (isCacheableRecord(recordType)) + { + std::vector identifiers; + store->listIdentifier(identifiers); + for (auto& record : identifiers) + mStoreImp->mIds[record] = recordType; + } + } } void ESMStore::validateRecords(ESM::ReadersCache& readers) @@ -704,8 +709,6 @@ namespace MWWorld void ESMStore::checkPlayer() { - setUp(); - const ESM::NPC* player = get().find(ESM::RefId::stringRefId("Player")); if (!get().find(player->mRace) || !get().find(player->mClass)) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 535f5fb430..7d0447c494 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -165,6 +165,8 @@ namespace MWWorld std::filesystem::path>; // path to an omwscripts file std::vector mLuaContent; + bool mIsSetUpDone = false; + public: void addOMWScripts(std::filesystem::path filePath) { mLuaContent.push_back(std::move(filePath)); } ESM::LuaScriptsCfg getLuaScriptsCfg() const; @@ -185,6 +187,7 @@ namespace MWWorld ~ESMStore(); void clearDynamic(); + void rebuildIdsIndex(); void movePlayerRecord(); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index e33ab23cf4..e19e099580 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -488,7 +488,7 @@ namespace MWWorld { // The land is static for given game session, there is no need to refresh it every load. if (mBuilt) - return; + throw std::logic_error("Store::setUp() is called twice"); mBuilt = true; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5338980299..5d07242d0a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2284,6 +2284,7 @@ namespace MWWorld void World::saveLoaded() { + mStore.rebuildIdsIndex(); mStore.validateDynamic(); mCurrentDate->setup(mGlobalVariables); } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 432dea172c..ba54e4a5e0 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -325,29 +325,39 @@ TYPED_TEST_P(StoreTest, delete_test) ESM::ESMReader reader; ESM::Dialogue* dialogue = nullptr; - MWWorld::ESMStore esmStore; - // master file inserts a record - reader.open(getEsmFile(record, false, formatVersion), "filename"); - esmStore.load(reader, &dummyListener, dialogue); - esmStore.setUp(); + { + MWWorld::ESMStore esmStore; + reader.open(getEsmFile(record, false, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); // master file inserts a record + esmStore.setUp(); - EXPECT_EQ(esmStore.get().getSize(), 1); + EXPECT_EQ(esmStore.get().getSize(), 1); + } + { + MWWorld::ESMStore esmStore; + reader.open(getEsmFile(record, false, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); // master file inserts a record + reader.open(getEsmFile(record, true, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); // now a plugin deletes it + esmStore.setUp(); - // now a plugin deletes it - reader.open(getEsmFile(record, true, formatVersion), "filename"); - esmStore.load(reader, &dummyListener, dialogue); - esmStore.setUp(); + EXPECT_EQ(esmStore.get().getSize(), 0); + } + { + MWWorld::ESMStore esmStore; + reader.open(getEsmFile(record, false, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); // master file inserts a record + reader.open(getEsmFile(record, true, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); // now a plugin deletes it + // now another plugin inserts it again + // expected behaviour is the record to reappear rather than staying deleted + reader.open(getEsmFile(record, false, formatVersion), "filename"); + esmStore.load(reader, &dummyListener, dialogue); + esmStore.setUp(); - EXPECT_EQ(esmStore.get().getSize(), 0); - - // now another plugin inserts it again - // expected behaviour is the record to reappear rather than staying deleted - reader.open(getEsmFile(record, false, formatVersion), "filename"); - esmStore.load(reader, &dummyListener, dialogue); - esmStore.setUp(); - - EXPECT_EQ(esmStore.get().getSize(), 1); + EXPECT_EQ(esmStore.get().getSize(), 1); + } } } @@ -410,13 +420,13 @@ TYPED_TEST_P(StoreTest, overwrite_test) // master file inserts a record reader.open(getEsmFile(record, false, formatVersion), "filename"); esmStore.load(reader, &dummyListener, dialogue); - esmStore.setUp(); // now a plugin overwrites it with changed data record.mId = recordIdUpper; // change id to uppercase, to test case smashing while we're at it record.mModel = "the_new_model"; reader.open(getEsmFile(record, false, formatVersion), "filename"); esmStore.load(reader, &dummyListener, dialogue); + esmStore.setUp(); // verify that changes were actually applied