mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-28 07:41:34 +00:00
Merge branch 'issue_6501' into 'master'
Fix Stuttering in the dialogue menu #6501 See merge request OpenMW/openmw!1492
This commit is contained in:
commit
5c67c5316d
4 changed files with 112 additions and 24 deletions
|
@ -47,19 +47,8 @@ namespace MWDialogue
|
||||||
|
|
||||||
void tokenizeKeywords(const std::string & text, std::vector<Token> & tokens)
|
void tokenizeKeywords(const std::string & text, std::vector<Token> & tokens)
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::Dialogue> & dialogs =
|
const auto& keywordSearch =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().getDialogIdKeywordSearch();
|
||||||
|
|
||||||
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*/);
|
|
||||||
|
|
||||||
std::vector<KeywordSearch<std::string, int /*unused*/>::Match> matches;
|
std::vector<KeywordSearch<std::string, int /*unused*/>::Match> matches;
|
||||||
keywordSearch.highlightKeywords(text.begin(), text.end(), matches);
|
keywordSearch.highlightKeywords(text.begin(), text.end(), matches);
|
||||||
|
|
|
@ -74,13 +74,13 @@ public:
|
||||||
return left.mBeg < right.mBeg;
|
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;
|
std::vector<Match> matches;
|
||||||
for (Point i = beg; i != end; ++i)
|
for (Point i = beg; i != end; ++i)
|
||||||
{
|
{
|
||||||
// check first character
|
// 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
|
// no match, on to next character
|
||||||
if (candidate == mRoot.mChildren.end ())
|
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
|
// 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
|
// 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)
|
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 ())
|
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
|
// shorter candidates will be added to the vector first. however, we want to check against longer candidates first
|
||||||
std::reverse(candidates.begin(), candidates.end());
|
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)
|
it != candidates.end(); ++it)
|
||||||
{
|
{
|
||||||
candidate = it->second;
|
candidate = it->second;
|
||||||
|
|
|
@ -981,8 +981,11 @@ namespace MWWorld
|
||||||
// Dialogue
|
// Dialogue
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
Store<ESM::Dialogue>::Store()
|
||||||
|
: mKeywordSearchModFlag(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
void Store<ESM::Dialogue>::setUp()
|
void Store<ESM::Dialogue>::setUp()
|
||||||
{
|
{
|
||||||
// DialInfos marked as deleted are kept during the loading phase, so that the linked list
|
// 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: verify and document this inconsistent behaviour
|
||||||
// TODO: if we require this behaviour, maybe we should move it to the place that requires it
|
// 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; });
|
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) {
|
inline RecordId Store<ESM::Dialogue>::load(ESM::ESMReader &esm) {
|
||||||
// The original letter case of a dialogue ID is saved, because it's printed
|
// The original letter case of a dialogue ID is saved, because it's printed
|
||||||
ESM::Dialogue dialogue;
|
ESM::Dialogue dialogue;
|
||||||
|
@ -1018,17 +1058,40 @@ namespace MWWorld
|
||||||
found->second.loadData(esm, isDeleted);
|
found->second.loadData(esm, isDeleted);
|
||||||
dialogue.mId = found->second.mId;
|
dialogue.mId = found->second.mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mKeywordSearchModFlag = true;
|
||||||
|
|
||||||
return RecordId(dialogue.mId, isDeleted);
|
return RecordId(dialogue.mId, isDeleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
bool Store<ESM::Dialogue>::eraseStatic(const std::string &id)
|
bool Store<ESM::Dialogue>::eraseStatic(const std::string &id)
|
||||||
{
|
{
|
||||||
mStatic.erase(id);
|
if (mStatic.erase(id))
|
||||||
|
mKeywordSearchModFlag = true;
|
||||||
|
|
||||||
return 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>;
|
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::Container>;
|
||||||
template class MWWorld::Store<ESM::Creature>;
|
template class MWWorld::Store<ESM::Creature>;
|
||||||
template class MWWorld::Store<ESM::CreatureLevList>;
|
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::Door>;
|
||||||
template class MWWorld::Store<ESM::Enchantment>;
|
template class MWWorld::Store<ESM::Enchantment>;
|
||||||
template class MWWorld::Store<ESM::Faction>;
|
template class MWWorld::Store<ESM::Faction>;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <components/esm/records.hpp>
|
#include <components/esm/records.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
#include "../mwdialogue/keywordsearch.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Land;
|
struct Land;
|
||||||
|
@ -154,7 +156,6 @@ namespace MWWorld
|
||||||
/// @par mShared usually preserves the record order as it came from the content files (this
|
/// @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
|
/// is relevant for the spell autocalc code and selection order
|
||||||
/// for heads/hairs in the character creation)
|
/// for heads/hairs in the character creation)
|
||||||
/// @warning ESM::Dialogue Store currently implements a sorted order for unknown reasons.
|
|
||||||
std::vector<T*> mShared;
|
std::vector<T*> mShared;
|
||||||
typedef std::unordered_map<std::string, T, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Dynamic;
|
typedef std::unordered_map<std::string, T, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Dynamic;
|
||||||
Dynamic mDynamic;
|
Dynamic mDynamic;
|
||||||
|
@ -440,6 +441,41 @@ namespace MWWorld
|
||||||
iterator end() const;
|
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
|
} //end namespace
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue