1 #ifndef CSM_WOLRD_REFIDDATA_H 2 #define CSM_WOLRD_REFIDDATA_H 3 4 #include <vector> 5 #include <map> 6 7 #include <components/esm/loadacti.hpp> 8 #include <components/esm/loadalch.hpp> 9 #include <components/esm/loadappa.hpp> 10 #include <components/esm/loadarmo.hpp> 11 #include <components/esm/loadbook.hpp> 12 #include <components/esm/loadclot.hpp> 13 #include <components/esm/loadcont.hpp> 14 #include <components/esm/loadcrea.hpp> 15 #include <components/esm/loaddoor.hpp> 16 #include <components/esm/loadingr.hpp> 17 #include <components/esm/loadlevlist.hpp> 18 #include <components/esm/loadligh.hpp> 19 #include <components/esm/loadlock.hpp> 20 #include <components/esm/loadprob.hpp> 21 #include <components/esm/loadrepa.hpp> 22 #include <components/esm/loadstat.hpp> 23 #include <components/esm/loadweap.hpp> 24 #include <components/esm/loadnpc.hpp> 25 #include <components/esm/loadmisc.hpp> 26 #include <components/esm/esmwriter.hpp> 27 28 #include <components/misc/stringops.hpp> 29 30 #include "record.hpp" 31 #include "universalid.hpp" 32 33 namespace ESM 34 { 35 class ESMReader; 36 } 37 38 namespace CSMWorld 39 { 40 struct RefIdDataContainerBase 41 { 42 virtual ~RefIdDataContainerBase(); 43 44 virtual int getSize() const = 0; 45 46 virtual const RecordBase& getRecord (int index) const = 0; 47 48 virtual RecordBase& getRecord (int index)= 0; 49 50 virtual void appendRecord (const std::string& id, bool base) = 0; 51 52 virtual void insertRecord (RecordBase& record) = 0; 53 54 virtual int load (ESM::ESMReader& reader, bool base) = 0; 55 ///< \return index of a loaded record or -1 if no record was loaded 56 57 virtual void erase (int index, int count) = 0; 58 59 virtual std::string getId (int index) const = 0; 60 61 virtual void save (int index, ESM::ESMWriter& writer) const = 0; 62 }; 63 64 template<typename RecordT> 65 struct RefIdDataContainer : public RefIdDataContainerBase 66 { 67 std::vector<Record<RecordT> > mContainer; 68 69 int getSize() const override; 70 71 const RecordBase& getRecord (int index) const override; 72 73 RecordBase& getRecord (int index) override; 74 75 void appendRecord (const std::string& id, bool base) override; 76 77 void insertRecord (RecordBase& record) override; 78 79 int load (ESM::ESMReader& reader, bool base) override; 80 ///< \return index of a loaded record or -1 if no record was loaded 81 82 void erase (int index, int count) override; 83 84 std::string getId (int index) const override; 85 86 void save (int index, ESM::ESMWriter& writer) const override; 87 }; 88 89 template<typename RecordT> insertRecord(RecordBase & record)90 void RefIdDataContainer<RecordT>::insertRecord(RecordBase& record) 91 { 92 Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record); 93 mContainer.push_back(newRecord); 94 } 95 96 template<typename RecordT> getSize() const97 int RefIdDataContainer<RecordT>::getSize() const 98 { 99 return static_cast<int> (mContainer.size()); 100 } 101 102 template<typename RecordT> getRecord(int index) const103 const RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) const 104 { 105 return mContainer.at (index); 106 } 107 108 template<typename RecordT> getRecord(int index)109 RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) 110 { 111 return mContainer.at (index); 112 } 113 114 template<typename RecordT> appendRecord(const std::string & id,bool base)115 void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base) 116 { 117 Record<RecordT> record; 118 119 record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; 120 121 record.mBase.mId = id; 122 record.mModified.mId = id; 123 (base ? record.mBase : record.mModified).blank(); 124 125 mContainer.push_back (record); 126 } 127 128 template<typename RecordT> load(ESM::ESMReader & reader,bool base)129 int RefIdDataContainer<RecordT>::load (ESM::ESMReader& reader, bool base) 130 { 131 RecordT record; 132 bool isDeleted = false; 133 134 record.load(reader, isDeleted); 135 136 int index = 0; 137 int numRecords = static_cast<int>(mContainer.size()); 138 for (; index < numRecords; ++index) 139 { 140 if (Misc::StringUtils::ciEqual(mContainer[index].get().mId, record.mId)) 141 { 142 break; 143 } 144 } 145 146 if (isDeleted) 147 { 148 if (index == numRecords) 149 { 150 // deleting a record that does not exist 151 // ignore it for now 152 /// \todo report the problem to the user 153 return -1; 154 } 155 156 // Flag the record as Deleted even for a base content file. 157 // RefIdData is responsible for its erasure. 158 mContainer[index].mState = RecordBase::State_Deleted; 159 } 160 else 161 { 162 if (index == numRecords) 163 { 164 appendRecord(record.mId, base); 165 if (base) 166 { 167 mContainer.back().mBase = record; 168 } 169 else 170 { 171 mContainer.back().mModified = record; 172 } 173 } 174 else if (!base) 175 { 176 mContainer[index].setModified(record); 177 } 178 else 179 { 180 // Overwrite 181 mContainer[index].setModified(record); 182 mContainer[index].merge(); 183 } 184 } 185 186 return index; 187 } 188 189 template<typename RecordT> erase(int index,int count)190 void RefIdDataContainer<RecordT>::erase (int index, int count) 191 { 192 if (index<0 || index+count>getSize()) 193 throw std::runtime_error ("invalid RefIdDataContainer index"); 194 195 mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count); 196 } 197 198 template<typename RecordT> getId(int index) const199 std::string RefIdDataContainer<RecordT>::getId (int index) const 200 { 201 return mContainer.at (index).get().mId; 202 } 203 204 template<typename RecordT> save(int index,ESM::ESMWriter & writer) const205 void RefIdDataContainer<RecordT>::save (int index, ESM::ESMWriter& writer) const 206 { 207 Record<RecordT> record = mContainer.at(index); 208 209 if (record.isModified() || record.mState == RecordBase::State_Deleted) 210 { 211 RecordT esmRecord = record.get(); 212 writer.startRecord(esmRecord.sRecordId); 213 esmRecord.save(writer, record.mState == RecordBase::State_Deleted); 214 writer.endRecord(esmRecord.sRecordId); 215 } 216 } 217 218 219 class RefIdData 220 { 221 public: 222 223 typedef std::pair<int, UniversalId::Type> LocalIndex; 224 225 private: 226 227 RefIdDataContainer<ESM::Activator> mActivators; 228 RefIdDataContainer<ESM::Potion> mPotions; 229 RefIdDataContainer<ESM::Apparatus> mApparati; 230 RefIdDataContainer<ESM::Armor> mArmors; 231 RefIdDataContainer<ESM::Book> mBooks; 232 RefIdDataContainer<ESM::Clothing> mClothing; 233 RefIdDataContainer<ESM::Container> mContainers; 234 RefIdDataContainer<ESM::Creature> mCreatures; 235 RefIdDataContainer<ESM::Door> mDoors; 236 RefIdDataContainer<ESM::Ingredient> mIngredients; 237 RefIdDataContainer<ESM::CreatureLevList> mCreatureLevelledLists; 238 RefIdDataContainer<ESM::ItemLevList> mItemLevelledLists; 239 RefIdDataContainer<ESM::Light> mLights; 240 RefIdDataContainer<ESM::Lockpick> mLockpicks; 241 RefIdDataContainer<ESM::Miscellaneous> mMiscellaneous; 242 RefIdDataContainer<ESM::NPC> mNpcs; 243 RefIdDataContainer<ESM::Probe> mProbes; 244 RefIdDataContainer<ESM::Repair> mRepairs; 245 RefIdDataContainer<ESM::Static> mStatics; 246 RefIdDataContainer<ESM::Weapon> mWeapons; 247 248 std::map<std::string, LocalIndex> mIndex; 249 250 std::map<UniversalId::Type, RefIdDataContainerBase *> mRecordContainers; 251 252 void erase (const LocalIndex& index, int count); 253 ///< Must not spill over into another type. 254 255 std::string getRecordId(const LocalIndex &index) const; 256 257 public: 258 259 RefIdData(); 260 261 LocalIndex globalToLocalIndex (int index) const; 262 263 int localToGlobalIndex (const LocalIndex& index) const; 264 265 LocalIndex searchId (const std::string& id) const; 266 267 void erase (int index, int count); 268 269 void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, 270 const std::string& id); 271 272 const RecordBase& getRecord (const LocalIndex& index) const; 273 274 RecordBase& getRecord (const LocalIndex& index); 275 276 void appendRecord (UniversalId::Type type, const std::string& id, bool base); 277 278 int getAppendIndex (UniversalId::Type type) const; 279 280 void load (ESM::ESMReader& reader, bool base, UniversalId::Type type); 281 282 int getSize() const; 283 284 std::vector<std::string> getIds (bool listDeleted = true) const; 285 ///< Return a sorted collection of all IDs 286 /// 287 /// \param listDeleted include deleted record in the list 288 289 void save (int index, ESM::ESMWriter& writer) const; 290 291 //RECORD CONTAINERS ACCESS METHODS 292 const RefIdDataContainer<ESM::Book>& getBooks() const; 293 const RefIdDataContainer<ESM::Activator>& getActivators() const; 294 const RefIdDataContainer<ESM::Potion>& getPotions() const; 295 const RefIdDataContainer<ESM::Apparatus>& getApparati() const; 296 const RefIdDataContainer<ESM::Armor>& getArmors() const; 297 const RefIdDataContainer<ESM::Clothing>& getClothing() const; 298 const RefIdDataContainer<ESM::Container>& getContainers() const; 299 const RefIdDataContainer<ESM::Creature>& getCreatures() const; 300 const RefIdDataContainer<ESM::Door>& getDoors() const; 301 const RefIdDataContainer<ESM::Ingredient>& getIngredients() const; 302 const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const; 303 const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const; 304 const RefIdDataContainer<ESM::Light>& getLights() const; 305 const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const; 306 const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const; 307 const RefIdDataContainer<ESM::NPC>& getNPCs() const; 308 const RefIdDataContainer<ESM::Weapon >& getWeapons() const; 309 const RefIdDataContainer<ESM::Probe >& getProbes() const; 310 const RefIdDataContainer<ESM::Repair>& getRepairs() const; 311 const RefIdDataContainer<ESM::Static>& getStatics() const; 312 313 void copyTo (int index, RefIdData& target) const; 314 }; 315 } 316 317 #endif 318