diff options
author | psi29a <psi29a@gmail.com> | 2021-12-25 16:00:15 +0000 |
---|---|---|
committer | psi29a <psi29a@gmail.com> | 2021-12-25 16:00:15 +0000 |
commit | 5c67c5316da08e72de9ef726313103faf9d7d26a (patch) | |
tree | 54c986682a30dff8d13b523cc15299ef9c6a4153 | |
parent | 04346b43b0a1efaf0bf79ddaf4ad0244f8cc6868 (diff) | |
parent | 88fc038cebcc25106ef24026c0b29346e0298f3c (diff) |
Merge branch 'issue_6501' into 'master'
Fix Stuttering in the dialogue menu #6501
See merge request OpenMW/openmw!1492
-rw-r--r-- | apps/openmw/mwdialogue/hypertextparser.cpp | 15 | ||||
-rw-r--r-- | apps/openmw/mwdialogue/keywordsearch.hpp | 10 | ||||
-rw-r--r-- | apps/openmw/mwworld/store.cpp | 73 | ||||
-rw-r--r-- | apps/openmw/mwworld/store.hpp | 38 |
4 files changed, 112 insertions, 24 deletions
diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp index caafa5f324..89a42bf2ea 100644 --- a/apps/openmw/mwdialogue/hypertextparser.cpp +++ b/apps/openmw/mwdialogue/hypertextparser.cpp @@ -47,19 +47,8 @@ namespace MWDialogue void tokenizeKeywords(const std::string & text, std::vector<Token> & tokens) { - const MWWorld::Store<ESM::Dialogue> & dialogs = - MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); - - std::vector<std::string> keywordList; - keywordList.reserve(dialogs.getSize()); - for (const auto& it : dialogs) - keywordList.push_back(Misc::StringUtils::lowerCase(it.mId)); - sort(keywordList.begin(), keywordList.end()); - - KeywordSearch<std::string, int /*unused*/> keywordSearch; - - for (const auto& it : keywordList) - keywordSearch.seed(it, 0 /*unused*/); + const auto& keywordSearch = + MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().getDialogIdKeywordSearch(); std::vector<KeywordSearch<std::string, int /*unused*/>::Match> matches; keywordSearch.highlightKeywords(text.begin(), text.end(), matches); diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 39599457ef..3f932084fe 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -74,13 +74,13 @@ public: return left.mBeg < right.mBeg; } - void highlightKeywords (Point beg, Point end, std::vector<Match>& out) + void highlightKeywords (Point beg, Point end, std::vector<Match>& out) const { std::vector<Match> matches; for (Point i = beg; i != end; ++i) { // check first character - typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (Misc::StringUtils::toLower (*i)); + typename Entry::childen_t::const_iterator candidate = mRoot.mChildren.find (Misc::StringUtils::toLower (*i)); // no match, on to next character if (candidate == mRoot.mChildren.end ()) @@ -91,11 +91,11 @@ public: // some keywords might be longer variations of other keywords, so we definitely need a list of candidates // the first element in the pair is length of the match, i.e. depth from the first character on - std::vector< typename std::pair<int, typename Entry::childen_t::iterator> > candidates; + std::vector< typename std::pair<int, typename Entry::childen_t::const_iterator> > candidates; while ((j + 1) != end) { - typename Entry::childen_t::iterator next = candidate->second.mChildren.find (Misc::StringUtils::toLower (*++j)); + typename Entry::childen_t::const_iterator next = candidate->second.mChildren.find (Misc::StringUtils::toLower (*++j)); if (next == candidate->second.mChildren.end ()) { @@ -116,7 +116,7 @@ public: // shorter candidates will be added to the vector first. however, we want to check against longer candidates first std::reverse(candidates.begin(), candidates.end()); - for (typename std::vector< std::pair<int, typename Entry::childen_t::iterator> >::iterator it = candidates.begin(); + for (typename std::vector< std::pair<int, typename Entry::childen_t::const_iterator> >::iterator it = candidates.begin(); it != candidates.end(); ++it) { candidate = it->second; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 4d720a11a7..c767bd669a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -981,8 +981,11 @@ namespace MWWorld // Dialogue //========================================================================= + Store<ESM::Dialogue>::Store() + : mKeywordSearchModFlag(true) + { + } - template<> void Store<ESM::Dialogue>::setUp() { // DialInfos marked as deleted are kept during the loading phase, so that the linked list @@ -997,9 +1000,46 @@ namespace MWWorld // TODO: verify and document this inconsistent behaviour // TODO: if we require this behaviour, maybe we should move it to the place that requires it std::sort(mShared.begin(), mShared.end(), [](const ESM::Dialogue* l, const ESM::Dialogue* r) -> bool { return l->mId < r->mId; }); + + mKeywordSearchModFlag = true; + } + + const ESM::Dialogue *Store<ESM::Dialogue>::search(const std::string &id) const + { + typename Static::const_iterator it = mStatic.find(id); + if (it != mStatic.end()) + return &(it->second); + + return nullptr; + } + + const ESM::Dialogue *Store<ESM::Dialogue>::find(const std::string &id) const + { + const ESM::Dialogue *ptr = search(id); + if (ptr == nullptr) + { + std::stringstream msg; + msg << ESM::Dialogue::getRecordType() << " '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + typename Store<ESM::Dialogue>::iterator Store<ESM::Dialogue>::begin() const + { + return mShared.begin(); + } + + typename Store<ESM::Dialogue>::iterator Store<ESM::Dialogue>::end() const + { + return mShared.end(); + } + + size_t Store<ESM::Dialogue>::getSize() const + { + return mShared.size(); } - template <> inline RecordId Store<ESM::Dialogue>::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed ESM::Dialogue dialogue; @@ -1018,17 +1058,40 @@ namespace MWWorld found->second.loadData(esm, isDeleted); dialogue.mId = found->second.mId; } + + mKeywordSearchModFlag = true; return RecordId(dialogue.mId, isDeleted); } - template<> bool Store<ESM::Dialogue>::eraseStatic(const std::string &id) { - mStatic.erase(id); + if (mStatic.erase(id)) + mKeywordSearchModFlag = true; + return true; } + const MWDialogue::KeywordSearch<std::string, int>& Store<ESM::Dialogue>::getDialogIdKeywordSearch() const + { + if (mKeywordSearchModFlag) + { + mKeywordSearch.clear(); + + std::vector<std::string> keywordList; + keywordList.reserve(getSize()); + for (const auto& it : *this) + keywordList.push_back(Misc::StringUtils::lowerCase(it.mId)); + sort(keywordList.begin(), keywordList.end()); + + for (const auto& it : keywordList) + mKeywordSearch.seed(it, 0 /*unused*/); + + mKeywordSearchModFlag = false; + } + + return mKeywordSearch; + } } template class MWWorld::Store<ESM::Activator>; @@ -1044,7 +1107,7 @@ template class MWWorld::Store<ESM::Clothing>; template class MWWorld::Store<ESM::Container>; template class MWWorld::Store<ESM::Creature>; template class MWWorld::Store<ESM::CreatureLevList>; -template class MWWorld::Store<ESM::Dialogue>; +//template class MWWorld::Store<ESM::Dialogue>; template class MWWorld::Store<ESM::Door>; template class MWWorld::Store<ESM::Enchantment>; template class MWWorld::Store<ESM::Faction>; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 22f36da690..1ec51ad5fd 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -11,6 +11,8 @@ #include <components/esm/records.hpp> #include <components/misc/stringops.hpp> +#include "../mwdialogue/keywordsearch.hpp" + namespace ESM { struct Land; @@ -154,7 +156,6 @@ namespace MWWorld /// @par mShared usually preserves the record order as it came from the content files (this /// is relevant for the spell autocalc code and selection order /// for heads/hairs in the character creation) - /// @warning ESM::Dialogue Store currently implements a sorted order for unknown reasons. std::vector<T*> mShared; typedef std::unordered_map<std::string, T, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Dynamic; Dynamic mDynamic; @@ -440,6 +441,41 @@ namespace MWWorld iterator end() const; }; + template <> + class Store<ESM::Dialogue> : public StoreBase + { + typedef std::unordered_map<std::string, ESM::Dialogue, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Static; + Static mStatic; + /// @par mShared usually preserves the record order as it came from the content files (this + /// is relevant for the spell autocalc code and selection order + /// for heads/hairs in the character creation) + /// @warning ESM::Dialogue Store currently implements a sorted order for unknown reasons. + std::vector<ESM::Dialogue*> mShared; + + mutable bool mKeywordSearchModFlag; + mutable MWDialogue::KeywordSearch<std::string, int /*unused*/> mKeywordSearch; + + public: + Store(); + + typedef SharedIterator<ESM::Dialogue> iterator; + + void setUp() override; + + const ESM::Dialogue *search(const std::string &id) const; + const ESM::Dialogue *find(const std::string &id) const; + + iterator begin() const; + iterator end() const; + + size_t getSize() const override; + + bool eraseStatic(const std::string &id) override; + + RecordId load(ESM::ESMReader &esm) override; + + const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const; + }; } //end namespace |