From e032214fcb293d555580802f485c596e2ab7c5e9 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 12 Mar 2023 15:11:10 +0100 Subject: [PATCH] Use common info ordering implementation for engine and editor --- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/store.cpp | 2 +- apps/openmw_test_suite/mwworld/test_store.cpp | 4 +- components/esm3/infoorder.cpp | 87 ------------------- components/esm3/loaddial.cpp | 55 ++---------- components/esm3/loaddial.hpp | 17 ++-- 6 files changed, 16 insertions(+), 151 deletions(-) delete mode 100644 components/esm3/infoorder.cpp diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index cc3d1e47f9..8ccf643e56 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -318,7 +318,7 @@ namespace MWWorld { if (dialogue) { - dialogue->readInfo(esm, esm.getIndex() != 0); + dialogue->readInfo(esm); } else { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 866fa66440..7971d05094 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1070,7 +1070,7 @@ namespace MWWorld // DialInfos marked as deleted are kept during the loading phase, so that the linked list // structure is kept intact for inserting further INFOs. Delete them now that loading is done. for (auto& [_, dial] : mStatic) - dial.clearDeletedInfos(); + dial.setUp(); mShared.clear(); mShared.reserve(mStatic.size()); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 32453517aa..ff0365ca37 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -671,7 +671,7 @@ namespace EXPECT_THAT(dialogue->mInfo, ElementsAre(HasIdEqualTo("info0"), HasIdEqualTo("info1"), HasIdEqualTo("info2"))); } - TEST(MWWorldStoreTest, shouldLoadDialogueWithInfosAsIsWhenReversed) + TEST(MWWorldStoreTest, shouldLoadDialogueWithInfosAndOrderWhenReversed) { DialogueData data = generateDialogueWithInfos(3); @@ -683,7 +683,7 @@ namespace const ESM::Dialogue* dialogue = esmStore.get().search(ESM::RefId::stringRefId("dialogue")); ASSERT_NE(dialogue, nullptr); - EXPECT_THAT(dialogue->mInfo, ElementsAre(HasIdEqualTo("info2"), HasIdEqualTo("info1"), HasIdEqualTo("info0"))); + EXPECT_THAT(dialogue->mInfo, ElementsAre(HasIdEqualTo("info0"), HasIdEqualTo("info1"), HasIdEqualTo("info2"))); } TEST(MWWorldStoreTest, shouldLoadDialogueWithInfosInsertingNewRecordBasedOnPrev) diff --git a/components/esm3/infoorder.cpp b/components/esm3/infoorder.cpp deleted file mode 100644 index c77913e017..0000000000 --- a/components/esm3/infoorder.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "infoorder.hpp" - -namespace ESM -{ - const std::list* InfoOrder::findInfosByTopic(const ESM::RefId& refId) const - { - const auto it = mOrderByTopic.find(refId); - if (it == mOrderByTopic.end()) - return nullptr; - return &it->second; - } - - void InfoOrder::insertInfo(const OrderedInfo& info) - { - auto it = mInfoPositions.find(info.mId); - - if (it != mInfoPositions.end() && it->second->mPrev == info.mPrev) - { - it->second->mNext = info.mNext; - return; - } - - auto& infos = mOrderByTopic[info.mTopicId]; - - if (it == mInfoPositions.end()) - it = mInfoPositions.emplace(info.mId, infos.end()).first; - - std::list::iterator& position = it->second; - - const auto insertOrSplice = [&](std::list::const_iterator before) { - if (position == infos.end()) - position = infos.insert(before, info); - else - infos.splice(before, infos, position); - }; - - if (info.mPrev.empty()) - { - insertOrSplice(infos.begin()); - return; - } - - const auto prevIt = mInfoPositions.find(info.mPrev); - if (prevIt != mInfoPositions.end()) - { - insertOrSplice(std::next(prevIt->second)); - return; - } - - const auto nextIt = mInfoPositions.find(info.mNext); - if (nextIt != mInfoPositions.end()) - { - insertOrSplice(nextIt->second); - return; - } - - insertOrSplice(infos.end()); - } - - void InfoOrder::removeInfo(const ESM::RefId& infoRefId) - { - const auto it = mInfoPositions.find(infoRefId); - - if (it == mInfoPositions.end()) - return; - - const auto topicIt = mOrderByTopic.find(it->second->mTopicId); - - if (topicIt != mOrderByTopic.end()) - topicIt->second.erase(it->second); - - mInfoPositions.erase(it); - } - - void InfoOrder::removeTopic(const ESM::RefId& topicRefId) - { - const auto it = mOrderByTopic.find(topicRefId); - - if (it == mOrderByTopic.end()) - return; - - for (const OrderedInfo& info : it->second) - mInfoPositions.erase(info.mId); - - mOrderByTopic.erase(it); - } -} diff --git a/components/esm3/loaddial.cpp b/components/esm3/loaddial.cpp index 87bed4db81..7681b42db7 100644 --- a/components/esm3/loaddial.cpp +++ b/components/esm3/loaddial.cpp @@ -70,62 +70,17 @@ namespace ESM mInfo.clear(); } - void Dialogue::readInfo(ESMReader& esm, bool merge) + void Dialogue::readInfo(ESMReader& esm) { DialInfo info; bool isDeleted = false; info.load(esm, isDeleted); - - if (!merge || mInfo.empty()) - { - mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); - return; - } - - LookupMap::iterator lookup = mLookup.find(info.mId); - - if (lookup != mLookup.end()) - { - auto it = lookup->second.first; - if (it->mPrev == info.mPrev) - { - *it = info; - lookup->second.second = isDeleted; - return; - } - // Since the new version of this record has a different prev linked list connection, we need to re-insert - // the record - mInfo.erase(it); - mLookup.erase(lookup); - } - - if (!info.mPrev.empty()) - { - lookup = mLookup.find(info.mPrev); - if (lookup != mLookup.end()) - { - auto it = lookup->second.first; - - mLookup[info.mId] = std::make_pair(mInfo.insert(++it, info), isDeleted); - } - else - mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.end(), info), isDeleted); - } - else - mLookup[info.mId] = std::make_pair(mInfo.insert(mInfo.begin(), info), isDeleted); + mInfoOrder.insertInfo(std::move(info), isDeleted); } - void Dialogue::clearDeletedInfos() + void Dialogue::setUp() { - LookupMap::const_iterator current = mLookup.begin(); - LookupMap::const_iterator end = mLookup.end(); - for (; current != end; ++current) - { - if (current->second.second) - { - mInfo.erase(current->second.first); - } - } - mLookup.clear(); + mInfoOrder.removeDeleted(); + mInfoOrder.extractOrderedInfo(mInfo); } } diff --git a/components/esm3/loaddial.hpp b/components/esm3/loaddial.hpp index 3983f483c9..6c3ec16e71 100644 --- a/components/esm3/loaddial.hpp +++ b/components/esm3/loaddial.hpp @@ -7,6 +7,7 @@ #include "components/esm/defs.hpp" #include "components/esm/refid.hpp" +#include "components/esm3/infoorder.hpp" #include "loadinfo.hpp" @@ -23,6 +24,8 @@ namespace ESM struct Dialogue { + using InfoContainer = std::list; + constexpr static RecNameInts sRecordId = REC_DIAL; /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string_view getRecordType() { return "Dialogue"; } @@ -39,17 +42,12 @@ namespace ESM RefId mId; signed char mType; - - typedef std::list InfoContainer; + InfoContainer mInfo; + InfoOrder mInfoOrder; // Parameters: Info ID, (Info iterator, Deleted flag) typedef std::map> LookupMap; - InfoContainer mInfo; - - // This is only used during the loading phase to speed up DialInfo merging. - LookupMap mLookup; - void load(ESMReader& esm, bool& isDeleted); ///< Loads all sub-records of Dialogue record void loadId(ESMReader& esm); @@ -60,11 +58,10 @@ namespace ESM void save(ESMWriter& esm, bool isDeleted = false) const; /// Remove all INFOs that are deleted - void clearDeletedInfos(); + void setUp(); /// Read the next info record - /// @param merge Merge with existing list, or just push each record to the end of the list? - void readInfo(ESMReader& esm, bool merge); + void readInfo(ESMReader& esm); void blank(); ///< Set record to default state (does not touch the ID and does not change the type).