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();