#ifndef OPENMW_MWWORLD_STORE_H #define OPENMW_MWWORLD_STORE_H #include #include #include #include "recordcmp.hpp" namespace ESM { struct Land; } namespace Loading { class Listener; } namespace MWWorld { struct RecordId { std::string mId; bool mIsDeleted; RecordId(const std::string &id = "", bool isDeleted = false); }; class StoreBase { public: virtual ~StoreBase() {} virtual void setUp() {} /// List identifiers of records contained in this Store (case-smashed). No-op for Stores that don't use string IDs. virtual void listIdentifier(std::vector &list) const {} virtual size_t getSize() const = 0; virtual int getDynamicSize() const { return 0; } virtual RecordId load(ESM::ESMReader &esm) = 0; virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} virtual RecordId read (ESM::ESMReader& reader) { return RecordId(); } ///< Read into dynamic storage }; template class IndexedStore { protected: typedef typename std::map Static; Static mStatic; public: typedef typename std::map::const_iterator iterator; IndexedStore(); iterator begin() const; iterator end() const; void load(ESM::ESMReader &esm); int getSize() const; void setUp(); const T *search(int index) const; const T *find(int index) const; }; template class SharedIterator { typedef typename std::vector::const_iterator Iter; Iter mIter; public: SharedIterator() {} SharedIterator(const SharedIterator &orig) : mIter(orig.mIter) {} SharedIterator(const Iter &iter) : mIter(iter) {} SharedIterator &operator++() { ++mIter; return *this; } SharedIterator operator++(int) { SharedIterator iter = *this; ++mIter; return iter; } SharedIterator &operator--() { --mIter; return *this; } SharedIterator operator--(int) { SharedIterator iter = *this; --mIter; return iter; } bool operator==(const SharedIterator &x) const { return mIter == x.mIter; } bool operator!=(const SharedIterator &x) const { return !(*this == x); } const T &operator*() const { return **mIter; } const T *operator->() const { return &(**mIter); } }; class ESMStore; template class Store : public StoreBase { std::map mStatic; 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; typedef std::map Static; friend class ESMStore; public: Store(); Store(const Store &orig); typedef SharedIterator iterator; // setUp needs to be called again after virtual void clearDynamic(); void setUp(); const T *search(const std::string &id) const; /** * Does the record with this ID come from the dynamic store? */ bool isDynamic(const std::string &id) const; /** Returns a random record that starts with the named ID, or NULL if not found. */ const T *searchRandom(const std::string &id) const; const T *find(const std::string &id) const; /** Returns a random record that starts with the named ID. An exception is thrown if none * are found. */ const T *findRandom(const std::string &id) const; iterator begin() const; iterator end() const; size_t getSize() const; int getDynamicSize() const; /// @note The record identifiers are listed in the order that the records were defined by the content files. void listIdentifier(std::vector &list) const; T *insert(const T &item); T *insertStatic(const T &item); bool eraseStatic(const std::string &id); bool erase(const std::string &id); bool erase(const T &item); RecordId load(ESM::ESMReader &esm); void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; RecordId read(ESM::ESMReader& reader); }; 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; /// Resize the internal store to hold at least \a num plugins. void resize(size_t num); size_t getSize() const; size_t getSize(size_t plugin) const; RecordId load(ESM::ESMReader &esm, size_t plugin); RecordId load(ESM::ESMReader &esm); iterator begin(size_t plugin) const; iterator end(size_t plugin) const; }; template <> class Store : public StoreBase { std::vector mStatic; public: typedef SharedIterator iterator; virtual ~Store(); size_t getSize() const; 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); void setUp(); }; 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::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 *searchOrCreate(int x, int y); const ESM::Cell *find(const std::string &id) const; const ESM::Cell *find(int x, int y) const; void setUp(); RecordId load(ESM::ESMReader &esm); 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; void listIdentifier(std::vector &list) const; 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::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); size_t getSize() const; void setUp(); 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; const ESM::Attribute *find(size_t index) const; void setUp(); size_t getSize() const; iterator begin() const; iterator end() const; }; } //end namespace #endif