mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
refactors MWWorld::Store maps (#3197)
With this PR we clean up `MWWorld::Store` maps according to the approach of PR #3184.
This commit is contained in:
parent
7d34149adc
commit
1329f22186
@ -61,7 +61,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ESM::NPC> getNPCsToReplace(const MWWorld::Store<ESM::Faction>& factions, const MWWorld::Store<ESM::Class>& classes, const std::map<std::string, ESM::NPC>& npcs)
|
||||
std::vector<ESM::NPC> getNPCsToReplace(const MWWorld::Store<ESM::Faction>& factions, const MWWorld::Store<ESM::Class>& classes, const std::unordered_map<std::string, ESM::NPC, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>& npcs)
|
||||
{
|
||||
// Cache first class from store - we will use it if current class is not found
|
||||
std::string defaultCls;
|
||||
@ -114,8 +114,8 @@ namespace
|
||||
|
||||
// Custom enchanted items can reference scripts that no longer exist, this doesn't necessarily mean the base item no longer exists however.
|
||||
// So instead of removing the item altogether, we're only removing the script.
|
||||
template<class T>
|
||||
void removeMissingScripts(const MWWorld::Store<ESM::Script>& scripts, std::map<std::string, T>& items)
|
||||
template<class MapT>
|
||||
void removeMissingScripts(const MWWorld::Store<ESM::Script>& scripts, MapT& items)
|
||||
{
|
||||
for(auto& [id, item] : items)
|
||||
{
|
||||
@ -324,7 +324,6 @@ void ESMStore::countRecords()
|
||||
if (value.mRefID != deletedRefID)
|
||||
{
|
||||
std::string& refId = refIDs[value.mRefID];
|
||||
Misc::StringUtils::lowerCaseInPlace(refId);
|
||||
++mRefCount[std::move(refId)];
|
||||
}
|
||||
};
|
||||
@ -333,8 +332,7 @@ void ESMStore::countRecords()
|
||||
|
||||
int ESMStore::getRefCount(const std::string& id) const
|
||||
{
|
||||
const std::string lowerId = Misc::StringUtils::lowerCase(id);
|
||||
auto it = mRefCount.find(lowerId);
|
||||
auto it = mRefCount.find(id);
|
||||
if(it == mRefCount.end())
|
||||
return 0;
|
||||
return it->second;
|
||||
@ -533,9 +531,8 @@ void ESMStore::removeMissingObjects(Store<T>& store)
|
||||
throw std::runtime_error ("Invalid player record (race or class unavailable");
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<MWMechanics::SpellList>, bool> ESMStore::getSpellList(const std::string& originalId) const
|
||||
std::pair<std::shared_ptr<MWMechanics::SpellList>, bool> ESMStore::getSpellList(const std::string& id) const
|
||||
{
|
||||
const std::string id = Misc::StringUtils::lowerCase(originalId);
|
||||
auto result = mSpellListCache.find(id);
|
||||
std::shared_ptr<MWMechanics::SpellList> ptr;
|
||||
if (result != mSpellListCache.end())
|
||||
|
@ -75,16 +75,17 @@ namespace MWWorld
|
||||
|
||||
// Lookup of all IDs. Makes looking up references faster. Just
|
||||
// maps the id name to the record type.
|
||||
std::map<std::string, int> mIds;
|
||||
std::map<std::string, int> mStaticIds;
|
||||
using IDMap = std::unordered_map<std::string, int, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>;
|
||||
IDMap mIds;
|
||||
IDMap mStaticIds;
|
||||
|
||||
std::unordered_map<std::string, int> mRefCount;
|
||||
IDMap mRefCount;
|
||||
|
||||
std::map<int, StoreBase *> mStores;
|
||||
|
||||
unsigned int mDynamicCount;
|
||||
|
||||
mutable std::map<std::string, std::weak_ptr<MWMechanics::SpellList> > mSpellListCache;
|
||||
mutable std::unordered_map<std::string, std::weak_ptr<MWMechanics::SpellList>, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mSpellListCache;
|
||||
|
||||
/// Validate entries in store after setup
|
||||
void validate();
|
||||
@ -115,10 +116,9 @@ namespace MWWorld
|
||||
}
|
||||
|
||||
/// Look up the given ID in 'all'. Returns 0 if not found.
|
||||
/// \note id must be in lower case.
|
||||
int find(const std::string &id) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator it = mIds.find(id);
|
||||
IDMap::const_iterator it = mIds.find(id);
|
||||
if (it == mIds.end()) {
|
||||
return 0;
|
||||
}
|
||||
@ -126,7 +126,7 @@ namespace MWWorld
|
||||
}
|
||||
int findStatic(const std::string &id) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator it = mStaticIds.find(id);
|
||||
IDMap::const_iterator it = mStaticIds.find(id);
|
||||
if (it == mStaticIds.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ namespace MWWorld
|
||||
bool isDeleted = false;
|
||||
|
||||
record.load(esm, isDeleted);
|
||||
|
||||
mStatic.insert_or_assign(record.mIndex, record);
|
||||
auto idx = record.mIndex;
|
||||
mStatic.insert_or_assign(idx, std::move(record));
|
||||
}
|
||||
template<typename T>
|
||||
int IndexedStore<T>::getSize() const
|
||||
@ -98,13 +98,11 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
const T *Store<T>::search(const std::string &id) const
|
||||
{
|
||||
std::string idLower = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(idLower);
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(id);
|
||||
if (dit != mDynamic.end())
|
||||
return &dit->second;
|
||||
|
||||
typename std::map<std::string, T>::const_iterator it = mStatic.find(idLower);
|
||||
typename Static::const_iterator it = mStatic.find(id);
|
||||
if (it != mStatic.end())
|
||||
return &(it->second);
|
||||
|
||||
@ -113,8 +111,7 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
const T *Store<T>::searchStatic(const std::string &id) const
|
||||
{
|
||||
std::string idLower = Misc::StringUtils::lowerCase(id);
|
||||
typename std::map<std::string, T>::const_iterator it = mStatic.find(idLower);
|
||||
typename Static::const_iterator it = mStatic.find(id);
|
||||
if (it != mStatic.end())
|
||||
return &(it->second);
|
||||
|
||||
@ -159,7 +156,7 @@ namespace MWWorld
|
||||
bool isDeleted = false;
|
||||
|
||||
record.load(esm, isDeleted);
|
||||
Misc::StringUtils::lowerCaseInPlace(record.mId);
|
||||
Misc::StringUtils::lowerCaseInPlace(record.mId); // TODO: remove this line once we have ported our remaining code base to lowercase on lookup
|
||||
|
||||
std::pair<typename Static::iterator, bool> inserted = mStatic.insert_or_assign(record.mId, record);
|
||||
if (inserted.second)
|
||||
@ -206,14 +203,13 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
T *Store<T>::insert(const T &item, bool overrideOnly)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase(item.mId);
|
||||
if(overrideOnly)
|
||||
{
|
||||
auto it = mStatic.find(id);
|
||||
auto it = mStatic.find(item.mId);
|
||||
if(it == mStatic.end())
|
||||
return nullptr;
|
||||
}
|
||||
std::pair<typename Dynamic::iterator, bool> result = mDynamic.insert_or_assign(id, item);
|
||||
std::pair<typename Dynamic::iterator, bool> result = mDynamic.insert_or_assign(item.mId, item);
|
||||
T *ptr = &result.first->second;
|
||||
if (result.second)
|
||||
mShared.push_back(ptr);
|
||||
@ -222,8 +218,7 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
T *Store<T>::insertStatic(const T &item)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase(item.mId);
|
||||
std::pair<typename Static::iterator, bool> result = mStatic.insert_or_assign(id, item);
|
||||
std::pair<typename Static::iterator, bool> result = mStatic.insert_or_assign(item.mId, item);
|
||||
T *ptr = &result.first->second;
|
||||
if (result.second)
|
||||
mShared.push_back(ptr);
|
||||
@ -232,9 +227,7 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
bool Store<T>::eraseStatic(const std::string &id)
|
||||
{
|
||||
std::string idLower = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
typename std::map<std::string, T>::iterator it = mStatic.find(idLower);
|
||||
typename Static::iterator it = mStatic.find(id);
|
||||
|
||||
if (it != mStatic.end()) {
|
||||
// delete from the static part of mShared
|
||||
@ -242,7 +235,7 @@ namespace MWWorld
|
||||
typename std::vector<T *>::iterator end = sharedIter + mStatic.size();
|
||||
|
||||
while (sharedIter != mShared.end() && sharedIter != end) {
|
||||
if((*sharedIter)->mId == idLower) {
|
||||
if(Misc::StringUtils::ciEqual((*sharedIter)->mId, id)) {
|
||||
mShared.erase(sharedIter);
|
||||
break;
|
||||
}
|
||||
@ -257,17 +250,13 @@ namespace MWWorld
|
||||
template<typename T>
|
||||
bool Store<T>::erase(const std::string &id)
|
||||
{
|
||||
std::string key = Misc::StringUtils::lowerCase(id);
|
||||
typename Dynamic::iterator it = mDynamic.find(key);
|
||||
if (it == mDynamic.end()) {
|
||||
if (!mDynamic.erase(id))
|
||||
return false;
|
||||
}
|
||||
mDynamic.erase(it);
|
||||
|
||||
// have to reinit the whole shared part
|
||||
assert(mShared.size() >= mStatic.size());
|
||||
mShared.erase(mShared.begin() + mStatic.size(), mShared.end());
|
||||
for (it = mDynamic.begin(); it != mDynamic.end(); ++it) {
|
||||
for (auto it = mDynamic.begin(); it != mDynamic.end(); ++it) {
|
||||
mShared.push_back(&it->second);
|
||||
}
|
||||
return true;
|
||||
@ -353,12 +342,8 @@ namespace MWWorld
|
||||
ESM::LandTexture* tex = const_cast<ESM::LandTexture*>(search(lt.mIndex, i));
|
||||
if (tex)
|
||||
{
|
||||
const std::string texId = Misc::StringUtils::lowerCase(tex->mId);
|
||||
const std::string ltId = Misc::StringUtils::lowerCase(lt.mId);
|
||||
if (texId == ltId)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(tex->mId, lt.mId))
|
||||
tex->mTexture = lt.mTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,9 +352,10 @@ namespace MWWorld
|
||||
ltexl.resize(lt.mIndex+1);
|
||||
|
||||
// Store it
|
||||
ltexl[lt.mIndex] = lt;
|
||||
auto idx = lt.mIndex;
|
||||
ltexl[idx] = std::move(lt);
|
||||
|
||||
return RecordId(lt.mId, isDeleted);
|
||||
return RecordId(ltexl[idx].mId, isDeleted);
|
||||
}
|
||||
RecordId Store<ESM::LandTexture>::load(ESM::ESMReader &esm)
|
||||
{
|
||||
@ -503,16 +489,12 @@ namespace MWWorld
|
||||
}
|
||||
const ESM::Cell *Store<ESM::Cell>::search(const std::string &id) const
|
||||
{
|
||||
ESM::Cell cell;
|
||||
cell.mName = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
std::map<std::string, ESM::Cell>::const_iterator it = mInt.find(cell.mName);
|
||||
|
||||
DynamicInt::const_iterator it = mInt.find(id);
|
||||
if (it != mInt.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName);
|
||||
DynamicInt::const_iterator dit = mDynamicInt.find(id);
|
||||
if (dit != mDynamicInt.end()) {
|
||||
return &dit->second;
|
||||
}
|
||||
@ -521,48 +503,34 @@ namespace MWWorld
|
||||
}
|
||||
const ESM::Cell *Store<ESM::Cell>::search(int x, int y) const
|
||||
{
|
||||
ESM::Cell cell;
|
||||
cell.mData.mX = x;
|
||||
cell.mData.mY = y;
|
||||
|
||||
std::pair<int, int> key(x, y);
|
||||
DynamicExt::const_iterator it = mExt.find(key);
|
||||
if (it != mExt.end()) {
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
DynamicExt::const_iterator dit = mDynamicExt.find(key);
|
||||
if (dit != mDynamicExt.end()) {
|
||||
if (dit != mDynamicExt.end())
|
||||
return &dit->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
const ESM::Cell *Store<ESM::Cell>::searchStatic(int x, int y) const
|
||||
{
|
||||
ESM::Cell cell;
|
||||
cell.mData.mX = x;
|
||||
cell.mData.mY = y;
|
||||
|
||||
std::pair<int, int> key(x, y);
|
||||
DynamicExt::const_iterator it = mExt.find(key);
|
||||
if (it != mExt.end()) {
|
||||
DynamicExt::const_iterator it = mExt.find(std::make_pair(x,y));
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const ESM::Cell *Store<ESM::Cell>::searchOrCreate(int x, int y)
|
||||
{
|
||||
std::pair<int, int> key(x, y);
|
||||
DynamicExt::const_iterator it = mExt.find(key);
|
||||
if (it != mExt.end()) {
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
DynamicExt::const_iterator dit = mDynamicExt.find(key);
|
||||
if (dit != mDynamicExt.end()) {
|
||||
if (dit != mDynamicExt.end())
|
||||
return &dit->second;
|
||||
}
|
||||
|
||||
ESM::Cell newCell;
|
||||
newCell.mData.mX = x;
|
||||
@ -625,12 +593,11 @@ namespace MWWorld
|
||||
// Load the (x,y) coordinates of the cell, if it is an exterior cell,
|
||||
// so we can find the cell we need to merge with
|
||||
cell.loadNameAndData(esm, isDeleted);
|
||||
std::string idLower = Misc::StringUtils::lowerCase(cell.mName);
|
||||
|
||||
if(cell.mData.mFlags & ESM::Cell::Interior)
|
||||
{
|
||||
// Store interior cell by name, try to merge with existing parent data.
|
||||
ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(idLower));
|
||||
ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(cell.mName));
|
||||
if (oldcell) {
|
||||
// merge new cell into old cell
|
||||
// push the new references on the list of references to manage (saveContext = true)
|
||||
@ -642,7 +609,7 @@ namespace MWWorld
|
||||
// spawn a new cell
|
||||
cell.loadCell(esm, true);
|
||||
|
||||
mInt[idLower] = cell;
|
||||
mInt[cell.mName] = cell;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -780,27 +747,19 @@ namespace MWWorld
|
||||
const std::string cellType = (cell.isExterior()) ? "exterior" : "interior";
|
||||
throw std::runtime_error("Failed to create " + cellType + " cell");
|
||||
}
|
||||
ESM::Cell *ptr;
|
||||
if (cell.isExterior()) {
|
||||
std::pair<int, int> key(cell.getGridX(), cell.getGridY());
|
||||
|
||||
// duplicate insertions are avoided by search(ESM::Cell &)
|
||||
std::pair<DynamicExt::iterator, bool> result =
|
||||
mDynamicExt.insert(std::make_pair(key, cell));
|
||||
|
||||
ptr = &result.first->second;
|
||||
mSharedExt.push_back(ptr);
|
||||
DynamicExt::iterator result = mDynamicExt.emplace(key, cell).first;
|
||||
mSharedExt.push_back(&result->second);
|
||||
return &result->second;
|
||||
} else {
|
||||
std::string key = Misc::StringUtils::lowerCase(cell.mName);
|
||||
|
||||
// duplicate insertions are avoided by search(ESM::Cell &)
|
||||
std::pair<DynamicInt::iterator, bool> result =
|
||||
mDynamicInt.insert(std::make_pair(key, cell));
|
||||
|
||||
ptr = &result.first->second;
|
||||
mSharedInt.push_back(ptr);
|
||||
DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, cell).first;
|
||||
mSharedInt.push_back(&result->second);
|
||||
return &result->second;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
bool Store<ESM::Cell>::erase(const ESM::Cell &cell)
|
||||
{
|
||||
@ -811,8 +770,7 @@ namespace MWWorld
|
||||
}
|
||||
bool Store<ESM::Cell>::erase(const std::string &id)
|
||||
{
|
||||
std::string key = Misc::StringUtils::lowerCase(id);
|
||||
DynamicInt::iterator it = mDynamicInt.find(key);
|
||||
DynamicInt::iterator it = mDynamicInt.find(id);
|
||||
|
||||
if (it == mDynamicInt.end()) {
|
||||
return false;
|
||||
@ -1062,12 +1020,11 @@ namespace MWWorld
|
||||
|
||||
dialogue.loadId(esm);
|
||||
|
||||
std::string idLower = Misc::StringUtils::lowerCase(dialogue.mId);
|
||||
std::map<std::string, ESM::Dialogue>::iterator found = mStatic.find(idLower);
|
||||
Static::iterator found = mStatic.find(dialogue.mId);
|
||||
if (found == mStatic.end())
|
||||
{
|
||||
dialogue.loadData(esm, isDeleted);
|
||||
mStatic.insert(std::make_pair(idLower, dialogue));
|
||||
mStatic.emplace(dialogue.mId, dialogue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1081,11 +1038,7 @@ namespace MWWorld
|
||||
template<>
|
||||
bool Store<ESM::Dialogue>::eraseStatic(const std::string &id)
|
||||
{
|
||||
auto it = mStatic.find(Misc::StringUtils::lowerCase(id));
|
||||
|
||||
if (it != mStatic.end())
|
||||
mStatic.erase(it);
|
||||
|
||||
mStatic.erase(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include "recordcmp.hpp"
|
||||
@ -147,14 +148,13 @@ namespace MWWorld
|
||||
template <class T>
|
||||
class Store : public StoreBase
|
||||
{
|
||||
std::map<std::string, T> mStatic;
|
||||
std::vector<T *> mShared; // Preserves the record order as it came from the content files (this
|
||||
typedef std::unordered_map<std::string, T, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Static;
|
||||
Static mStatic;
|
||||
std::vector<T*> 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<std::string, T> mDynamic;
|
||||
|
||||
typedef std::map<std::string, T> Dynamic;
|
||||
typedef std::map<std::string, T> Static;
|
||||
typedef std::unordered_map<std::string, T, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Dynamic;
|
||||
Dynamic mDynamic;
|
||||
|
||||
friend class ESMStore;
|
||||
|
||||
@ -294,7 +294,7 @@ namespace MWWorld
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<std::string, ESM::Cell> DynamicInt;
|
||||
typedef std::unordered_map<std::string, ESM::Cell, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> DynamicInt;
|
||||
typedef std::map<std::pair<int, int>, ESM::Cell, DynamicExtCmp> DynamicExt;
|
||||
|
||||
DynamicInt mInt;
|
||||
@ -354,7 +354,7 @@ namespace MWWorld
|
||||
class Store<ESM::Pathgrid> : public StoreBase
|
||||
{
|
||||
private:
|
||||
typedef std::map<std::string, ESM::Pathgrid> Interior;
|
||||
typedef std::unordered_map<std::string, ESM::Pathgrid, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> Interior;
|
||||
typedef std::map<std::pair<int, int>, ESM::Pathgrid> Exterior;
|
||||
|
||||
Interior mInt;
|
||||
|
Loading…
x
Reference in New Issue
Block a user