From 1ed22442980e2cc62b3c2d10c744446c6226d3d5 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 3 Jul 2022 18:11:20 +0200 Subject: [PATCH] Store refactor: Now way easier to create new stores, a good chunk of it is automated, only simple macros are used now The case of indexedStores remains an issue, because they can't be stored with the rest because they don't inherit of store base --- apps/openmw/mwworld/esmstore.cpp | 622 ++++++++++++------------------- apps/openmw/mwworld/esmstore.hpp | 7 +- 2 files changed, 247 insertions(+), 382 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index a38907ce1b..3176a28d5e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -188,59 +188,19 @@ AddStoreType(ESM::Attribute); static const int sRecordTypeCount = sRecordTypeCounter; + + namespace MWWorld { - struct ESMStoreImp { - Store mActivators; - Store mPotions; - Store mAppas; - Store mArmors; - Store mBodyParts; - Store mBooks; - Store mBirthSigns; - Store mClasses; - Store mClothes; - Store mContainers; - Store mCreatures; - Store mDialogs; - Store mDoors; - Store mEnchants; - Store mFactions; - Store mGlobals; - Store mIngreds; - Store mCreatureLists; - Store mItemLists; - Store mLights; - Store mLockpicks; - Store mMiscItems; - Store mNpcs; - Store mProbes; - Store mRaces; - Store mRegions; - Store mRepairs; - Store mSoundGens; - Store mSounds; - Store mSpells; - Store mStartScripts; - Store mStatics; - Store mWeapons; + //These 3 don't inherit from store base + Store mMagicEffect; + Store mSkills; + Store mAttributes; - Store mGameSettings; - Store mScripts; + std::map mESM3RecordToRecordId; - // Lists that need special rules - Store mCells; - Store mLands; - Store mLandTextures; - Store mPathgrids; - - Store mMagicEffects; - Store mSkills; - - // Special entry which is hardcoded and not loaded from an ESM - Store mAttributes; template static const T* ESM3StoreInsert(ESMStore& stores, const T &toInsert) @@ -258,10 +218,11 @@ namespace MWWorld record.mId = id; T *ptr = store.insert(record); - for (ESMStore::iterator it = stores.mStores.begin(); it != stores.mStores.end(); ++it) { - if (it->second == &store) { - stores.mIds[ptr->mId] = it->first; - } + auto esm3RecordType_find = stores.mStoreImp->mESM3RecordToRecordId.find(GetRecordTypeId(T)); + + if (esm3RecordType_find != stores.mStoreImp->mESM3RecordToRecordId.end()) + { + stores.mIds[ptr->mId] = esm3RecordType_find->first; } return ptr; } @@ -271,10 +232,10 @@ namespace MWWorld Store &store = const_cast &>( stores.get()); T *ptr = store.insert(x); - for (ESMStore::iterator it = stores.mStores.begin(); it != stores.mStores.end(); ++it) { - if (it->second == &store) { - stores.mIds[ptr->mId] = it->first; - } + auto esm3RecordType_find = stores.mStoreImp->mESM3RecordToRecordId.find(GetRecordTypeId(T)); + if (esm3RecordType_find != stores.mStoreImp->mESM3RecordToRecordId.end()) + { + stores.mIds[ptr->mId] = esm3RecordType_find->first; } return ptr; } @@ -293,60 +254,161 @@ namespace MWWorld T record = x; T *ptr = store.insertStatic(record); - for (ESMStore::iterator it = stores.mStores.begin(); it != stores.mStores.end(); ++it) { - if (it->second == &store) { - stores.mIds[ptr->mId] = it->first; - } + auto esm3RecordType_find = stores.mStoreImp->mESM3RecordToRecordId.find(GetRecordTypeId(T)); + if (esm3RecordType_find != stores.mStoreImp->mESM3RecordToRecordId.end()) + { + stores.mIds[ptr->mId] = esm3RecordType_find->first; } return ptr; } + + ESMStoreImp() + { + mESM3RecordToRecordId[ESM::REC_ACTI] = GetRecordTypeId(ESM::Activator); + mESM3RecordToRecordId[ESM::REC_ALCH] = GetRecordTypeId(ESM::Potion); + mESM3RecordToRecordId[ESM::REC_APPA] = GetRecordTypeId(ESM::Apparatus); + mESM3RecordToRecordId[ESM::REC_ARMO] = GetRecordTypeId(ESM::Armor); + mESM3RecordToRecordId[ESM::REC_BODY] = GetRecordTypeId(ESM::BodyPart); + mESM3RecordToRecordId[ESM::REC_BOOK] = GetRecordTypeId(ESM::Book); + mESM3RecordToRecordId[ESM::REC_BSGN] = GetRecordTypeId(ESM::BirthSign); + mESM3RecordToRecordId[ESM::REC_CELL] = GetRecordTypeId(ESM::Cell); + mESM3RecordToRecordId[ESM::REC_CLAS] = GetRecordTypeId(ESM::Class); + mESM3RecordToRecordId[ESM::REC_CLOT] = GetRecordTypeId(ESM::Clothing); + mESM3RecordToRecordId[ESM::REC_CONT] = GetRecordTypeId(ESM::Container); + mESM3RecordToRecordId[ESM::REC_CREA] = GetRecordTypeId(ESM::Creature); + mESM3RecordToRecordId[ESM::REC_DIAL] = GetRecordTypeId(ESM::Dialogue); + mESM3RecordToRecordId[ESM::REC_DOOR] = GetRecordTypeId(ESM::Door); + mESM3RecordToRecordId[ESM::REC_ENCH] = GetRecordTypeId(ESM::Enchantment); + mESM3RecordToRecordId[ESM::REC_FACT] = GetRecordTypeId(ESM::Faction); + mESM3RecordToRecordId[ESM::REC_GLOB] = GetRecordTypeId(ESM::Global); + mESM3RecordToRecordId[ESM::REC_GMST] = GetRecordTypeId(ESM::GameSetting); + mESM3RecordToRecordId[ESM::REC_INGR] = GetRecordTypeId(ESM::Ingredient); + mESM3RecordToRecordId[ESM::REC_LAND] = GetRecordTypeId(ESM::Land); + mESM3RecordToRecordId[ESM::REC_LEVC] = GetRecordTypeId(ESM::CreatureLevList); + mESM3RecordToRecordId[ESM::REC_LEVI] = GetRecordTypeId(ESM::ItemLevList); + mESM3RecordToRecordId[ESM::REC_LIGH] = GetRecordTypeId(ESM::Light); + mESM3RecordToRecordId[ESM::REC_LOCK] = GetRecordTypeId(ESM::Lockpick); + mESM3RecordToRecordId[ESM::REC_LTEX] = GetRecordTypeId(ESM::LandTexture); + mESM3RecordToRecordId[ESM::REC_MISC] = GetRecordTypeId(ESM::Miscellaneous); + mESM3RecordToRecordId[ESM::REC_NPC_] = GetRecordTypeId(ESM::NPC); + mESM3RecordToRecordId[ESM::REC_PGRD] = GetRecordTypeId(ESM::Pathgrid); + mESM3RecordToRecordId[ESM::REC_PROB] = GetRecordTypeId(ESM::Probe); + mESM3RecordToRecordId[ESM::REC_RACE] = GetRecordTypeId(ESM::Race); + mESM3RecordToRecordId[ESM::REC_REGN] = GetRecordTypeId(ESM::Region); + mESM3RecordToRecordId[ESM::REC_REPA] = GetRecordTypeId(ESM::Repair); + mESM3RecordToRecordId[ESM::REC_SCPT] = GetRecordTypeId(ESM::Script); + mESM3RecordToRecordId[ESM::REC_SNDG] = GetRecordTypeId(ESM::SoundGenerator); + mESM3RecordToRecordId[ESM::REC_SOUN] = GetRecordTypeId(ESM::Sound); + mESM3RecordToRecordId[ESM::REC_SPEL] = GetRecordTypeId(ESM::Spell); + mESM3RecordToRecordId[ESM::REC_SSCR] = GetRecordTypeId(ESM::StartScript); + mESM3RecordToRecordId[ESM::REC_STAT] = GetRecordTypeId(ESM::Static); + mESM3RecordToRecordId[ESM::REC_WEAP] = GetRecordTypeId(ESM::Weapon); + } }; + +#define defineGetters(__Type) template <> const Store<__Type>& ESMStore::get<__Type>() const { return static_cast&>(*mStores[GetRecordTypeId(__Type)]); } \ + template <> Store<__Type>& ESMStore::getWritable<__Type>() { return static_cast&>(*mStores[GetRecordTypeId(__Type)]); } + + defineGetters(ESM::Activator); + defineGetters(ESM::Potion); + defineGetters(ESM::Apparatus); + defineGetters(ESM::Armor); + defineGetters(ESM::BodyPart); + defineGetters(ESM::Book); + defineGetters(ESM::BirthSign); + defineGetters(ESM::Class); + defineGetters(ESM::Clothing); + defineGetters(ESM::Container); + defineGetters(ESM::Creature); + defineGetters(ESM::Dialogue); + defineGetters(ESM::Door); + defineGetters(ESM::Enchantment); + defineGetters(ESM::Faction); + defineGetters(ESM::Global); + defineGetters(ESM::Ingredient); + defineGetters(ESM::CreatureLevList); + defineGetters(ESM::ItemLevList); + defineGetters(ESM::Light); + defineGetters(ESM::Lockpick); + defineGetters(ESM::Miscellaneous); + defineGetters(ESM::NPC); + defineGetters(ESM::Probe); + defineGetters(ESM::Race); + defineGetters(ESM::Region); + defineGetters(ESM::Repair); + defineGetters(ESM::SoundGenerator); + defineGetters(ESM::Sound); + defineGetters(ESM::Spell); + defineGetters(ESM::StartScript); + defineGetters(ESM::Static); + defineGetters(ESM::Weapon); + defineGetters(ESM::GameSetting); + defineGetters(ESM::Script); + defineGetters(ESM::Cell); + defineGetters(ESM::Land); + defineGetters(ESM::LandTexture); + defineGetters(ESM::Pathgrid); +#undef defineGetters + template <> const Store& ESMStore::get() const { return mStoreImp->mMagicEffect; } + template <> Store& ESMStore::getWritable() { return mStoreImp->mMagicEffect; } + + template <> const Store& ESMStore::get() const { return mStoreImp->mSkills; } + template <> Store& ESMStore::getWritable() { return mStoreImp->mSkills; } + + template <> const Store& ESMStore::get() const { return mStoreImp->mAttributes; } + template <> Store& ESMStore::getWritable() { return mStoreImp->mAttributes; } + ESMStore::ESMStore() { + mStores.resize(sRecordTypeCount); +#define createStore(__Type) mStores[GetRecordTypeId(__Type)] = std::make_unique>(); + + createStore(ESM::Activator); + createStore(ESM::Potion); + createStore(ESM::Apparatus); + createStore(ESM::Armor); + createStore(ESM::BodyPart); + createStore(ESM::Book); + createStore(ESM::BirthSign); + createStore(ESM::Class); + createStore(ESM::Clothing); + createStore(ESM::Container); + createStore(ESM::Creature); + createStore(ESM::Dialogue); + createStore(ESM::Door); + createStore(ESM::Enchantment); + createStore(ESM::Faction); + createStore(ESM::Global); + createStore(ESM::Ingredient); + createStore(ESM::CreatureLevList); + createStore(ESM::ItemLevList); + createStore(ESM::Light); + createStore(ESM::Lockpick); + createStore(ESM::Miscellaneous); + createStore(ESM::NPC); + createStore(ESM::Probe); + createStore(ESM::Race); + createStore(ESM::Region); + createStore(ESM::Repair); + createStore(ESM::SoundGenerator); + createStore(ESM::Sound); + createStore(ESM::Spell); + createStore(ESM::StartScript); + createStore(ESM::Static); + createStore(ESM::Weapon); + createStore(ESM::GameSetting); + createStore(ESM::Script); + createStore(ESM::Cell); + createStore(ESM::Land); + createStore(ESM::LandTexture); + createStore(ESM::Pathgrid); +#undef createStore + mStoreImp = std::make_unique(); mDynamicCount = 0; - mStores[ESM::REC_ACTI] = &mStoreImp->mActivators; - mStores[ESM::REC_ALCH] = &mStoreImp->mPotions; - mStores[ESM::REC_APPA] = &mStoreImp->mAppas; - mStores[ESM::REC_ARMO] = &mStoreImp->mArmors; - mStores[ESM::REC_BODY] = &mStoreImp->mBodyParts; - mStores[ESM::REC_BOOK] = &mStoreImp->mBooks; - mStores[ESM::REC_BSGN] = &mStoreImp->mBirthSigns; - mStores[ESM::REC_CELL] = &mStoreImp->mCells; - mStores[ESM::REC_CLAS] = &mStoreImp->mClasses; - mStores[ESM::REC_CLOT] = &mStoreImp->mClothes; - mStores[ESM::REC_CONT] = &mStoreImp->mContainers; - mStores[ESM::REC_CREA] = &mStoreImp->mCreatures; - mStores[ESM::REC_DIAL] = &mStoreImp->mDialogs; - mStores[ESM::REC_DOOR] = &mStoreImp->mDoors; - mStores[ESM::REC_ENCH] = &mStoreImp->mEnchants; - mStores[ESM::REC_FACT] = &mStoreImp->mFactions; - mStores[ESM::REC_GLOB] = &mStoreImp->mGlobals; - mStores[ESM::REC_GMST] = &mStoreImp->mGameSettings; - mStores[ESM::REC_INGR] = &mStoreImp->mIngreds; - mStores[ESM::REC_LAND] = &mStoreImp->mLands; - mStores[ESM::REC_LEVC] = &mStoreImp->mCreatureLists; - mStores[ESM::REC_LEVI] = &mStoreImp->mItemLists; - mStores[ESM::REC_LIGH] = &mStoreImp->mLights; - mStores[ESM::REC_LOCK] = &mStoreImp->mLockpicks; - mStores[ESM::REC_LTEX] = &mStoreImp->mLandTextures; - mStores[ESM::REC_MISC] = &mStoreImp->mMiscItems; - mStores[ESM::REC_NPC_] = &mStoreImp->mNpcs; - mStores[ESM::REC_PGRD] = &mStoreImp->mPathgrids; - mStores[ESM::REC_PROB] = &mStoreImp->mProbes; - mStores[ESM::REC_RACE] = &mStoreImp->mRaces; - mStores[ESM::REC_REGN] = &mStoreImp->mRegions; - mStores[ESM::REC_REPA] = &mStoreImp->mRepairs; - mStores[ESM::REC_SCPT] = &mStoreImp->mScripts; - mStores[ESM::REC_SNDG] = &mStoreImp->mSoundGens; - mStores[ESM::REC_SOUN] = &mStoreImp->mSounds; - mStores[ESM::REC_SPEL] = &mStoreImp->mSpells; - mStores[ESM::REC_SSCR] = &mStoreImp->mStartScripts; - mStores[ESM::REC_STAT] = &mStoreImp->mStatics; - mStores[ESM::REC_WEAP] = &mStoreImp->mWeapons; - mStoreImp->mPathgrids.setCells(mStoreImp->mCells); + getWritable().setCells(getWritable()); } ESMStore::~ESMStore() @@ -355,8 +417,8 @@ namespace MWWorld void ESMStore::clearDynamic() { - for (std::map::iterator it = mStores.begin(); it != mStores.end(); ++it) - it->second->clearDynamic(); + for (std::vector>::iterator it = mStores.begin(); it != mStores.end(); ++it) + (*it)->clearDynamic(); movePlayerRecord(); } @@ -383,7 +445,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialo // Land texture loading needs to use a separate internal store for each plugin. // We set the number of plugins here so we can properly verify if valid plugin // indices are being passed to the LandTexture Store retrieval methods. - mStoreImp->mLandTextures.resize(esm.getIndex()+1); + getWritable().resize(esm.getIndex()+1); // Loop through all records while(esm.hasMoreRecs()) @@ -397,9 +459,9 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialo } // Look up the record type. - std::map::iterator it = mStores.find(n.toInt()); + std::map::iterator it = mStoreImp->mESM3RecordToRecordId.find(n.toInt()); - if (it == mStores.end()) { + if (it == mStoreImp->mESM3RecordToRecordId.end()) { if (n.toInt() == ESM::REC_INFO) { if (dialogue) { @@ -411,9 +473,9 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialo esm.skipRecord(); } } else if (n.toInt() == ESM::REC_MGEF) { - mStoreImp->mMagicEffects.load (esm); + getWritable().load (esm); } else if (n.toInt() == ESM::REC_SKIL) { - mStoreImp->mSkills.load (esm); + getWritable().load (esm); } else if (n.toInt() == ESM::REC_FILT || n.toInt() == ESM::REC_DBGP) { @@ -431,15 +493,15 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialo throw std::runtime_error("Unknown record: " + n.toString()); } } else { - RecordId id = it->second->load(esm); + RecordId id = mStores[ it->second]->load(esm); if (id.mIsDeleted) { - it->second->eraseStatic(id.mId); + mStores[ it->second]->eraseStatic(id.mId); continue; } if (n.toInt() == ESM::REC_DIAL) { - dialogue = const_cast(mStoreImp->mDialogs.find(id.mId)); + dialogue = const_cast(getWritable().find(id.mId)); } else { dialogue = nullptr; } @@ -479,14 +541,14 @@ void ESMStore::setUp() { mIds.clear(); - std::map::iterator storeIt = mStores.begin(); - for (; storeIt != mStores.end(); ++storeIt) { - storeIt->second->setUp(); + std::map::iterator storeIt = mStoreImp->mESM3RecordToRecordId.begin(); + for (; storeIt != mStoreImp->mESM3RecordToRecordId.end(); ++storeIt) { + mStores[storeIt->second]->setUp(); if (isCacheableRecord(storeIt->first)) { std::vector identifiers; - storeIt->second->listIdentifier(identifiers); + mStores[storeIt->second]->listIdentifier(identifiers); for (std::vector::const_iterator record = identifiers.begin(); record != identifiers.end(); ++record) mIds[*record] = storeIt->first; @@ -497,10 +559,10 @@ void ESMStore::setUp() for (const auto& [k, v] : mIds) mStaticIds.emplace(Misc::StringUtils::lowerCase(k), v); - mStoreImp->mSkills.setUp(); - mStoreImp->mMagicEffects.setUp(); - mStoreImp->mAttributes.setUp(); - mStoreImp->mDialogs.setUp(); + getWritable().setUp(); + getWritable().setUp();; + getWritable().setUp(); + getWritable().setUp(); } void ESMStore::validateRecords(ESM::ReadersCache& readers) @@ -517,9 +579,10 @@ void ESMStore::countAllCellRefs(ESM::ReadersCache& readers) return; std::vector refs; std::vector refIDs; - for(auto it = mStoreImp->mCells.intBegin(); it != mStoreImp->mCells.intEnd(); ++it) + Store Cells = getWritable < ESM::Cell>(); + for(auto it = Cells.intBegin(); it != Cells.intEnd(); ++it) readRefs(*it, refs, refIDs, readers); - for(auto it = mStoreImp->mCells.extBegin(); it != mStoreImp->mCells.extEnd(); ++it) + for(auto it = Cells.extBegin(); it != Cells.extEnd(); ++it) readRefs(*it, refs, refIDs, readers); const auto lessByRefNum = [] (const Ref& l, const Ref& r) { return l.mRefNum < r.mRefNum; }; std::stable_sort(refs.begin(), refs.end(), lessByRefNum); @@ -548,17 +611,19 @@ int ESMStore::getRefCount(std::string_view id) const void ESMStore::validate() { - std::vector npcsToReplace = getNPCsToReplace(mStoreImp->mFactions, mStoreImp->mClasses, mStoreImp->mNpcs.mStatic); + auto& NPCs = getWritable(); + std::vector npcsToReplace = getNPCsToReplace(getWritable(), getWritable(), NPCs.mStatic); for (const ESM::NPC &npc : npcsToReplace) { - mStoreImp->mNpcs.eraseStatic(npc.mId); - mStoreImp->mNpcs.insertStatic(npc); + NPCs.eraseStatic(npc.mId); + NPCs.insertStatic(npc); } // Validate spell effects for invalid arguments std::vector spellsToReplace; - for (ESM::Spell spell : mStoreImp->mSpells) + auto& Spells = getWritable(); + for (ESM::Spell spell : Spells) { if (spell.mEffects.mList.empty()) continue; @@ -567,7 +632,7 @@ void ESMStore::validate() auto iter = spell.mEffects.mList.begin(); while (iter != spell.mEffects.mList.end()) { - const ESM::MagicEffect* mgef = mStoreImp->mMagicEffects.search(iter->mEffectID); + const ESM::MagicEffect* mgef = getWritable().search(iter->mEffectID); if (!mgef) { Log(Debug::Verbose) << "Spell '" << spell.mId << "' has an invalid effect (index " << iter->mEffectID << ") present. Dropping the effect."; @@ -614,31 +679,35 @@ void ESMStore::validate() for (const ESM::Spell &spell : spellsToReplace) { - mStoreImp->mSpells.eraseStatic(spell.mId); - mStoreImp->mSpells.insertStatic(spell); + Spells.eraseStatic(spell.mId); + Spells.insertStatic(spell); } } void ESMStore::movePlayerRecord() { - auto player = mStoreImp->mNpcs.find("player"); - mStoreImp->mNpcs.insert(*player); + auto& NPCs = getWritable(); + auto player = NPCs.find("player"); + NPCs.insert(*player); } void ESMStore::validateDynamic() { - std::vector npcsToReplace = getNPCsToReplace(mStoreImp->mFactions, mStoreImp->mClasses, mStoreImp->mNpcs.mDynamic); + auto& NPCs = getWritable(); + auto& scripts = getWritable(); + + std::vector npcsToReplace = getNPCsToReplace(getWritable(), getWritable(), NPCs.mDynamic); for (const ESM::NPC &npc : npcsToReplace) - mStoreImp->mNpcs.insert(npc); + NPCs.insert(npc); - removeMissingScripts(mStoreImp->mScripts, mStoreImp->mArmors.mDynamic); - removeMissingScripts(mStoreImp->mScripts, mStoreImp->mBooks.mDynamic); - removeMissingScripts(mStoreImp->mScripts, mStoreImp->mClothes.mDynamic); - removeMissingScripts(mStoreImp->mScripts, mStoreImp->mWeapons.mDynamic); + removeMissingScripts(scripts, getWritable().mDynamic); + removeMissingScripts(scripts, getWritable().mDynamic); + removeMissingScripts(scripts, getWritable().mDynamic); + removeMissingScripts(scripts, getWritable().mDynamic); - removeMissingObjects(mStoreImp->mCreatureLists); - removeMissingObjects(mStoreImp->mItemLists); + removeMissingObjects(getWritable()); + removeMissingObjects(getWritable()); } // Leveled lists can be modified by scripts. This removes items that no longer exist (presumably because the plugin was removed) from modified lists @@ -663,19 +732,20 @@ void ESMStore::removeMissingObjects(Store& store) int ESMStore::countSavedGameRecords() const { return 1 // DYNA (dynamic name counter) - +mStoreImp->mPotions.getDynamicSize() - +mStoreImp->mArmors.getDynamicSize() - +mStoreImp->mBooks.getDynamicSize() - +mStoreImp->mClasses.getDynamicSize() - +mStoreImp->mClothes.getDynamicSize() - +mStoreImp->mEnchants.getDynamicSize() - +mStoreImp->mNpcs.getDynamicSize() - +mStoreImp->mSpells.getDynamicSize() - +mStoreImp->mWeapons.getDynamicSize() - +mStoreImp->mCreatureLists.getDynamicSize() - +mStoreImp->mItemLists.getDynamicSize() - +mStoreImp->mCreatures.getDynamicSize() - +mStoreImp->mContainers.getDynamicSize(); + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize() + + get().getDynamicSize(); + } void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const @@ -686,19 +756,19 @@ void ESMStore::removeMissingObjects(Store& store) writer.endRecord("COUN"); writer.endRecord(ESM::REC_DYNA); - mStoreImp->mPotions.write (writer, progress); - mStoreImp->mArmors.write (writer, progress); - mStoreImp->mBooks.write (writer, progress); - mStoreImp->mClasses.write (writer, progress); - mStoreImp->mClothes.write (writer, progress); - mStoreImp->mEnchants.write (writer, progress); - mStoreImp->mSpells.write (writer, progress); - mStoreImp->mWeapons.write (writer, progress); - mStoreImp->mNpcs.write (writer, progress); - mStoreImp->mItemLists.write (writer, progress); - mStoreImp->mCreatureLists.write (writer, progress); - mStoreImp->mCreatures.write (writer, progress); - mStoreImp->mContainers.write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); + get().write (writer, progress); } bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) @@ -715,12 +785,12 @@ void ESMStore::removeMissingObjects(Store& store) case ESM::REC_WEAP: case ESM::REC_LEVI: case ESM::REC_LEVC: - mStores[type]->read (reader); + mStores[mStoreImp->mESM3RecordToRecordId[type] ]->read (reader); return true; case ESM::REC_NPC_: case ESM::REC_CREA: case ESM::REC_CONT: - mStores[type]->read (reader, true); + mStores[mStoreImp->mESM3RecordToRecordId[type]]->read (reader, true); return true; case ESM::REC_DYNA: @@ -738,10 +808,10 @@ void ESMStore::removeMissingObjects(Store& store) { setUp(); - const ESM::NPC *player = mStoreImp->mNpcs.find ("player"); + const ESM::NPC *player = get().find ("player"); - if (!mStoreImp->mRaces.find (player->mRace) || - !mStoreImp->mClasses.find (player->mClass)) + if (!get().find (player->mRace) || + !get().find (player->mClass)) throw std::runtime_error ("Invalid player record (race or class unavailable"); } @@ -766,19 +836,19 @@ void ESMStore::removeMissingObjects(Store& store) template <> const ESM::Cell *ESMStore::insert(const ESM::Cell &cell) { - return mStoreImp->mCells.insert(cell); + return getWritable().insert(cell); } template <> const ESM::NPC *ESMStore::insert(const ESM::NPC &npc) { const std::string id = "$dynamic" + std::to_string(mDynamicCount++); - + auto& NPCs = getWritable(); if (Misc::StringUtils::ciEqual(npc.mId, "player")) { - return mStoreImp->mNpcs.insert(npc); + return NPCs.insert(npc); } - else if (mStoreImp->mNpcs.search(id) != nullptr) + else if (NPCs.search(id) != nullptr) { const std::string msg = "Try to override existing record '" + id + "'"; throw std::runtime_error(msg); @@ -787,7 +857,7 @@ void ESMStore::removeMissingObjects(Store& store) record.mId = id; - ESM::NPC *ptr = mStoreImp->mNpcs.insert(record); + ESM::NPC *ptr = NPCs.insert(record); mIds[ptr->mId] = ESM::REC_NPC_; return ptr; } @@ -821,213 +891,5 @@ void ESMStore::removeMissingObjects(Store& store) ESM3overrideRecord(ESM::NPC); #undef ESM3overrideRecord - template <> - const Store &ESMStore::get() const { - return mStoreImp->mActivators; - } - template <> - const Store &ESMStore::get() const { - return mStoreImp->mPotions; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mAppas; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mArmors; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mBodyParts; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mBooks; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mBirthSigns; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mClasses; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mClothes; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mContainers; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mCreatures; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mDialogs; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mDoors; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mEnchants; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mFactions; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mGlobals; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mIngreds; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mCreatureLists; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mItemLists; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mLights; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mLockpicks; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mMiscItems; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mNpcs; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mProbes; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mRaces; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mRegions; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mRepairs; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mSoundGens; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mSounds; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mSpells; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mStartScripts; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mStatics; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mWeapons; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mGameSettings; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mScripts; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mCells; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mLands; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mLandTextures; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mPathgrids; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mMagicEffects; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mSkills; - } - - template <> - const Store &ESMStore::get() const { - return mStoreImp->mAttributes; - } } // end namespace diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index b2f99bbfa8..e4af64a285 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -43,12 +43,15 @@ namespace MWWorld std::unordered_map mRefCount; - std::map mStores; + std::vector> mStores; unsigned int mDynamicCount; mutable std::unordered_map, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mSpellListCache; + template + Store& getWritable(); + /// Validate entries in store after setup void validate(); @@ -67,7 +70,7 @@ namespace MWWorld ESM::LuaScriptsCfg getLuaScriptsCfg() const; /// \todo replace with SharedIterator - typedef std::map::const_iterator iterator; + typedef std::vector>::const_iterator iterator; iterator begin() const { return mStores.begin();