diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1be89c0c09..bd5c5da710 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -35,6 +35,7 @@ #include "../mwworld/localscripts.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwrender/objects.hpp" diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0169e63950..b42669c533 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/localscripts.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp index 732cdb1f8f..5b4b56a3ea 100644 --- a/apps/openmw/mwdialogue/hypertextparser.cpp +++ b/apps/openmw/mwdialogue/hypertextparser.cpp @@ -5,6 +5,7 @@ #include "../mwworld/store.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "keywordsearch.hpp" diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 040214848c..da6a1d4fab 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -27,6 +27,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/StoreSpecialization.hpp" namespace { diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2be388568b..11d50cb11c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -14,6 +14,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 2def2696bb..9afcec0893 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -12,6 +12,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "actorutil.hpp" #include "npcstats.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 05eff857e0..1c5ef4ec9f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwphysics/collisiontype.hpp" diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index d60eac15de..c6f619e3b5 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -21,6 +21,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "magiceffects.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index d82b8505f1..a2dc38ec0d 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -3,6 +3,7 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 256e1bd871..3115b90d87 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -7,6 +7,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bde5ad0225..efdc9db5fa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -14,6 +14,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" #include "../mwworld/ptr.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index a89e01259c..95edbb5af6 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -11,6 +11,7 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index ee1de3b5ad..44ddc481d9 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -5,6 +5,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 06d504ef6c..5f052531e8 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -18,6 +18,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwrender/animation.hpp" diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 4a9cf49263..2b46ac0956 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -29,6 +29,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/StoreSpecialization.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index e22a8c4f75..1ccd53cc91 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -13,6 +13,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "creaturestats.hpp" #include "spellresistance.hpp" diff --git a/apps/openmw/mwmechanics/spellresistance.cpp b/apps/openmw/mwmechanics/spellresistance.cpp index bb39255b43..a1830609cd 100644 --- a/apps/openmw/mwmechanics/spellresistance.cpp +++ b/apps/openmw/mwmechanics/spellresistance.cpp @@ -7,6 +7,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "creaturestats.hpp" #include "spellutil.hpp" diff --git a/apps/openmw/mwmechanics/spellutil.cpp b/apps/openmw/mwmechanics/spellutil.cpp index 7fa9687189..7b5a4f3b83 100644 --- a/apps/openmw/mwmechanics/spellutil.cpp +++ b/apps/openmw/mwmechanics/spellutil.cpp @@ -7,6 +7,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" + #include "actorutil.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index ec7d2c15e0..8eec0163df 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -19,6 +19,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "vismask.hpp" diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 879a2ef68b..e4d94943a9 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -3,6 +3,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "landmanager.hpp" diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 36669f34ac..6afdc551ed 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -7,6 +7,7 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwworld/StoreSpecialization.hpp b/apps/openmw/mwworld/StoreSpecialization.hpp new file mode 100644 index 0000000000..f4a2ccff20 --- /dev/null +++ b/apps/openmw/mwworld/StoreSpecialization.hpp @@ -0,0 +1,285 @@ +#pragma once +namespace MWWorld +{ + + class StoreBase; + template class Store; + template class IndexedStore; + +template <> + class Store : public StoreBase + { + // For multiple ESM/ESP files we need one list per file. + typedef std::vector LandTextureList; + std::vector mStatic; + + public: + Store(); + + typedef std::vector::const_iterator iterator; + + // Must be threadsafe! Called from terrain background loading threads. + // Not a big deal here, since ESM::LandTexture can never be modified or inserted/erased + const ESM::LandTexture *search(size_t index, size_t plugin) const; + const ESM::LandTexture *find(size_t index, size_t plugin) const; + + void resize(size_t num) { mStatic.resize(num); } + + size_t getSize() const override; + size_t getSize(size_t plugin) const; + + RecordId load(ESM::ESMReader &esm) override; + + iterator begin(size_t plugin) const; + iterator end(size_t plugin) const; + }; + + template <> + class Store : public StoreBase + { + struct SpatialComparator + { + using is_transparent = void; + + bool operator()(const ESM::Land& x, const ESM::Land& y) const + { + return std::tie(x.mX, x.mY) < std::tie(y.mX, y.mY); + } + bool operator()(const ESM::Land& x, const std::pair& y) const + { + return std::tie(x.mX, x.mY) < std::tie(y.first, y.second); + } + bool operator()(const std::pair& x, const ESM::Land& y) const + { + return std::tie(x.first, x.second) < std::tie(y.mX, y.mY); + } + }; + using Statics = std::set; + Statics mStatic; + + public: + typedef typename Statics::iterator iterator; + + virtual ~Store(); + + size_t getSize() const override; + iterator begin() const; + iterator end() const; + + // Must be threadsafe! Called from terrain background loading threads. + // Not a big deal here, since ESM::Land can never be modified or inserted/erased + const ESM::Land *search(int x, int y) const; + const ESM::Land *find(int x, int y) const; + + RecordId load(ESM::ESMReader &esm) override; + void setUp() override; + private: + bool mBuilt = false; + }; + + template <> + class Store : public StoreBase + { + struct DynamicExtCmp + { + bool operator()(const std::pair &left, const std::pair &right) const { + if (left.first == right.first && left.second == right.second) + return false; + + if (left.first == right.first) + return left.second > right.second; + + // Exterior cells are listed in descending, row-major order, + // this is a workaround for an ambiguous chargen_plank reference in the vanilla game. + // there is one at -22,16 and one at -2,-9, the latter should be used. + return left.first > right.first; + } + }; + + typedef std::unordered_map DynamicInt; + typedef std::map, ESM::Cell, DynamicExtCmp> DynamicExt; + + DynamicInt mInt; + DynamicExt mExt; + + std::vector mSharedInt; + std::vector mSharedExt; + + DynamicInt mDynamicInt; + DynamicExt mDynamicExt; + + const ESM::Cell *search(const ESM::Cell &cell) const; + void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); + + public: + typedef SharedIterator iterator; + + const ESM::Cell *search(const std::string &id) const; + const ESM::Cell *search(int x, int y) const; + const ESM::Cell *searchStatic(int x, int y) const; + const ESM::Cell *searchOrCreate(int x, int y); + + const ESM::Cell *find(const std::string &id) const; + const ESM::Cell *find(int x, int y) const; + + void clearDynamic() override; + void setUp() override; + + RecordId load(ESM::ESMReader &esm) override; + + iterator intBegin() const; + iterator intEnd() const; + iterator extBegin() const; + iterator extEnd() const; + + // Return the northernmost cell in the easternmost column. + const ESM::Cell *searchExtByName(const std::string &id) const; + + // Return the northernmost cell in the easternmost column. + const ESM::Cell *searchExtByRegion(const std::string &id) const; + + size_t getSize() const override; + size_t getExtSize() const; + size_t getIntSize() const; + + void listIdentifier(std::vector &list) const override; + + ESM::Cell *insert(const ESM::Cell &cell); + + bool erase(const ESM::Cell &cell); + bool erase(const std::string &id); + + bool erase(int x, int y); + }; + + template <> + class Store : public StoreBase + { + private: + typedef std::unordered_map Interior; + typedef std::map, ESM::Pathgrid> Exterior; + + Interior mInt; + Exterior mExt; + + Store* mCells; + + public: + + Store(); + + void setCells(Store& cells); + RecordId load(ESM::ESMReader &esm) override; + size_t getSize() const override; + + void setUp() override; + + const ESM::Pathgrid *search(int x, int y) const; + const ESM::Pathgrid *search(const std::string& name) const; + const ESM::Pathgrid *find(int x, int y) const; + const ESM::Pathgrid* find(const std::string& name) const; + const ESM::Pathgrid *search(const ESM::Cell &cell) const; + const ESM::Pathgrid *find(const ESM::Cell &cell) const; + }; + + + template <> + class Store : public IndexedStore + { + public: + Store(); + }; + + template <> + class Store : public IndexedStore + { + public: + Store(); + }; + + template <> + class Store : public IndexedStore + { + std::vector mStatic; + + public: + typedef std::vector::const_iterator iterator; + + Store(); + + const ESM::Attribute *search(size_t index) const; + + // calls `search` and throws an exception if not found + const ESM::Attribute *find(size_t index) const; + + void setUp(); + + size_t getSize() const; + iterator begin() const; + iterator end() const; + }; + + template <> + class Store : public StoreBase + { + std::map mStatic; + + public: + typedef std::map::const_iterator iterator; + + Store(); + + const ESM::WeaponType *search(const int id) const; + + // calls `search` and throws an exception if not found + const ESM::WeaponType *find(const int id) const; + + RecordId load(ESM::ESMReader &esm) override { return RecordId({}, false); } + + ESM::WeaponType* insert(const ESM::WeaponType &weaponType); + + void setUp() override; + + size_t getSize() const override; + iterator begin() const; + iterator end() const; + }; + + template <> + class Store : public StoreBase + { + typedef std::unordered_map 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 mShared; + + mutable bool mKeywordSearchModFlag; + mutable MWDialogue::KeywordSearch mKeywordSearch; + + public: + Store(); + + typedef SharedIterator 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; + + void listIdentifier(std::vector &list) const override; + + const MWDialogue::KeywordSearch& getDialogIdKeywordSearch() const; + }; +} diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 3ad8a1ee38..26a0552897 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -15,6 +15,7 @@ #include "esmstore.hpp" #include "containerstore.hpp" #include "cellstore.hpp" +#include "StoreSpecialization.hpp" namespace { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 93009c26cb..ce98a20d3c 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -8,6 +8,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "ptr.hpp" #include "nullaction.hpp" diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 0993bc181f..9b8c0b2129 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -13,6 +13,7 @@ #include #include "../mwmechanics/spelllist.hpp" +#include "StoreSpecialization.hpp" namespace { @@ -292,6 +293,14 @@ namespace MWWorld { } + void ESMStore::clearDynamic() + { + for (std::map::iterator it = mStores.begin(); it != mStores.end(); ++it) + it->second->clearDynamic(); + + movePlayerRecord(); + } + static bool isCacheableRecord(int id) { if (id == ESM::REC_ACTI || id == ESM::REC_ALCH || id == ESM::REC_APPA || id == ESM::REC_ARMO || diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 1eba766e05..b2f99bbfa8 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -4,7 +4,9 @@ #include #include #include +#include +#include #include #include "store.hpp" @@ -21,6 +23,7 @@ namespace MWMechanics namespace ESM { class ReadersCache; + struct Dialogue; } namespace MWWorld @@ -95,13 +98,7 @@ namespace MWWorld ESMStore(); ~ESMStore(); - void clearDynamic () - { - for (std::map::iterator it = mStores.begin(); it != mStores.end(); ++it) - it->second->clearDynamic(); - - movePlayerRecord(); - } + void clearDynamic(); void movePlayerRecord(); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index b25d867542..43a90d2f30 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -30,6 +30,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/StoreSpecialization.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 489f80ed20..3d39bc4bb8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -43,6 +43,7 @@ #include "cellpreloader.hpp" #include "worldimp.hpp" #include "cellutils.hpp" +#include "StoreSpecialization.hpp" namespace { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index a84f4d9de5..46b4755346 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -8,6 +8,7 @@ #include #include +#include "StoreSpecialization.hpp" #include #include diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 163df76106..6aac8b0ba1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -86,6 +86,7 @@ #include "contentloader.hpp" #include "esmloader.hpp" #include "cellutils.hpp" +#include "StoreSpecialization.hpp" namespace MWWorld {