From b8fa73dfa9c27733238f0f71800a018ac7c53cff Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Dec 2014 15:28:02 +0100 Subject: [PATCH] Preserve record ordering in Store This fixes the default head/hair used for some races in the chargen UI. --- apps/openmw/mwgui/race.cpp | 13 +++++-- apps/openmw/mwworld/store.hpp | 69 ++++++++++++----------------------- 2 files changed, 32 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index bcb766f8f3..925480334d 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -345,8 +345,7 @@ namespace MWGui const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - - int index = 0; + std::map items; // ID, name MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) { @@ -354,8 +353,14 @@ namespace MWGui if (!playable) // Only display playable races continue; - mRaceList->addItem(it->mName, it->mId); - if (Misc::StringUtils::ciEqual(it->mId, mCurrentRaceId)) + items[it->mId] = it->mName; + } + + int index = 0; + for (std::map::const_iterator it = items.begin(); it != items.end(); ++it) + { + mRaceList->addItem(it->second, it->first); + if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 4fa8b7f543..dcfbb4eb17 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -99,7 +99,9 @@ namespace MWWorld class Store : public StoreBase { std::map mStatic; - std::vector mShared; + std::vector mShared; // 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) std::map mDynamic; typedef std::map Dynamic; @@ -137,8 +139,9 @@ namespace MWWorld // setUp needs to be called again after virtual void clearDynamic() { + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); mDynamic.clear(); - mShared.clear(); } const T *search(const std::string &id) const { @@ -203,18 +206,18 @@ namespace MWWorld void load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); - mStatic[idLower] = T(); - mStatic[idLower].mId = idLower; - mStatic[idLower].load(esm); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); } void setUp() { - mShared.clear(); - mShared.reserve(mStatic.size()); - typename std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } + // remove the dynamic part of mShared + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } iterator begin() const { @@ -356,10 +359,9 @@ namespace MWWorld std::map::iterator it = mStatic.find(idLower); if (it == mStatic.end()) { it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed... I think + it->second.mId = id; // don't smash case here, as this line is printed } - //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins it->second.load(esm); } @@ -368,7 +370,10 @@ namespace MWWorld ESM::Script scpt; scpt.load(esm); Misc::StringUtils::toLower(scpt.mId); - mStatic[scpt.mId] = scpt; + + std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + if (inserted.second) + mShared.push_back(&inserted.first->second); } template <> @@ -376,7 +381,10 @@ namespace MWWorld ESM::StartScript s; s.load(esm); s.mId = Misc::StringUtils::toLower(s.mScript); - mStatic[s.mId] = s; + + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); } template <> @@ -1067,37 +1075,6 @@ namespace MWWorld } }; - - // Specialisation for ESM::Spell to preserve record order as it was in the content files. - // The NPC spell autocalc code heavily depends on this order. - // We could also do this in the base class, but it's usually not a good idea to depend on record order. - template<> - inline void Store::clearDynamic() - { - // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - mDynamic.clear(); - } - - template<> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); - - std::pair inserted = mStatic.insert(std::make_pair(idLower, ESM::Spell())); - if (inserted.second) - mShared.push_back(&mStatic[idLower]); - - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); - } - - template<> - inline void Store::setUp() - { - // remove the dynamic part of mShared - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - } - template<> inline void Store::setUp() {