1 #ifndef CSM_WOLRD_IDCOLLECTION_H 2 #define CSM_WOLRD_IDCOLLECTION_H 3 4 #include <components/esm/esmreader.hpp> 5 6 #include "collection.hpp" 7 #include "land.hpp" 8 9 namespace CSMWorld 10 { 11 /// \brief Single type collection of top level records 12 template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> > 13 class IdCollection : public Collection<ESXRecordT, IdAccessorT> 14 { 15 virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); 16 17 public: 18 19 /// \return Index of loaded record (-1 if no record was loaded) 20 int load (ESM::ESMReader& reader, bool base); 21 22 /// \param index Index at which the record can be found. 23 /// Special values: -2 index unknown, -1 record does not exist yet and therefore 24 /// does not have an index 25 /// 26 /// \return index 27 int load (const ESXRecordT& record, bool base, int index = -2); 28 29 bool tryDelete (const std::string& id); 30 ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored. 31 /// 32 /// \return Has the ID been deleted? 33 }; 34 35 template<typename ESXRecordT, typename IdAccessorT> loadRecord(ESXRecordT & record,ESM::ESMReader & reader,bool & isDeleted)36 void IdCollection<ESXRecordT, IdAccessorT>::loadRecord (ESXRecordT& record, 37 ESM::ESMReader& reader, 38 bool& isDeleted) 39 { 40 record.load (reader, isDeleted); 41 } 42 43 template<> loadRecord(Land & record,ESM::ESMReader & reader,bool & isDeleted)44 inline void IdCollection<Land, IdAccessor<Land> >::loadRecord (Land& record, 45 ESM::ESMReader& reader, bool& isDeleted) 46 { 47 record.load (reader, isDeleted); 48 49 // Load all land data for now. A future optimisation may only load non-base data 50 // if a suitable mechanism for avoiding race conditions can be established. 51 int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | 52 ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; 53 record.loadData (flags); 54 55 // Prevent data from being reloaded. 56 record.mContext.filename.clear(); 57 } 58 59 template<typename ESXRecordT, typename IdAccessorT> load(ESM::ESMReader & reader,bool base)60 int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base) 61 { 62 ESXRecordT record; 63 bool isDeleted = false; 64 65 loadRecord (record, reader, isDeleted); 66 67 std::string id = IdAccessorT().getId (record); 68 int index = this->searchId (id); 69 70 if (isDeleted) 71 { 72 if (index==-1) 73 { 74 // deleting a record that does not exist 75 // ignore it for now 76 /// \todo report the problem to the user 77 return -1; 78 } 79 80 if (base) 81 { 82 this->removeRows (index, 1); 83 return -1; 84 } 85 86 Record<ESXRecordT> baseRecord = this->getRecord (index); 87 baseRecord.mState = RecordBase::State_Deleted; 88 this->setRecord (index, baseRecord); 89 return index; 90 } 91 92 return load (record, base, index); 93 } 94 95 template<typename ESXRecordT, typename IdAccessorT> load(const ESXRecordT & record,bool base,int index)96 int IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base, 97 int index) 98 { 99 if (index==-2) 100 index = this->searchId (IdAccessorT().getId (record)); 101 102 if (index==-1) 103 { 104 // new record 105 Record<ESXRecordT> record2; 106 record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; 107 (base ? record2.mBase : record2.mModified) = record; 108 109 index = this->getSize(); 110 this->appendRecord (record2); 111 } 112 else 113 { 114 // old record 115 Record<ESXRecordT> record2 = Collection<ESXRecordT, IdAccessorT>::getRecord (index); 116 117 if (base) 118 record2.mBase = record; 119 else 120 record2.setModified (record); 121 122 this->setRecord (index, record2); 123 } 124 125 return index; 126 } 127 128 template<typename ESXRecordT, typename IdAccessorT> tryDelete(const std::string & id)129 bool IdCollection<ESXRecordT, IdAccessorT>::tryDelete (const std::string& id) 130 { 131 int index = this->searchId (id); 132 133 if (index==-1) 134 return false; 135 136 Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index); 137 138 if (record.isDeleted()) 139 return false; 140 141 if (record.mState==RecordBase::State_ModifiedOnly) 142 { 143 Collection<ESXRecordT, IdAccessorT>::removeRows (index, 1); 144 } 145 else 146 { 147 record.mState = RecordBase::State_Deleted; 148 this->setRecord (index, record); 149 } 150 151 return true; 152 } 153 } 154 155 #endif 156