#ifndef CSM_WOLRD_IDCOLLECTION_H #define CSM_WOLRD_IDCOLLECTION_H #include #include #include #include #include #include #include "collection.hpp" #include "land.hpp" #include "pathgrid.hpp" namespace ESM { class ESMReader; } namespace CSMWorld { struct Pathgrid; /// \brief Single type collection of top level records template > class IdCollection : public Collection { virtual void loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted); public: /// \return Index of loaded record (-1 if no record was loaded) int load(ESM::ESMReader& reader, bool base); /// \param index Index at which the record can be found. /// Special values: -2 index unknown, -1 record does not exist yet and therefore /// does not have an index /// /// \return index int load(const ESXRecordT& record, bool base, int index = -2); bool tryDelete(const std::string& id); ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored. /// /// \return Has the ID been deleted? }; template void IdCollection::loadRecord(ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted) { record.load(reader, isDeleted); } template <> inline void IdCollection>::loadRecord(Land& record, ESM::ESMReader& reader, bool& isDeleted) { record.load(reader, isDeleted); // Load all land data for now. A future optimisation may only load non-base data // if a suitable mechanism for avoiding race conditions can be established. int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; record.loadData(flags); // Prevent data from being reloaded. record.mContext.filename.clear(); } template int IdCollection::load(ESM::ESMReader& reader, bool base) { ESXRecordT record; bool isDeleted = false; loadRecord(record, reader, isDeleted); ESM::RefId id = IdAccessorT().getId(record); int index = this->searchId(id); if (isDeleted) { if (index == -1) { // deleting a record that does not exist // ignore it for now /// \todo report the problem to the user return -1; } if (base) { this->removeRows(index, 1); return -1; } auto baseRecord = std::make_unique>(this->getRecord(index)); baseRecord->mState = RecordBase::State_Deleted; this->setRecord(index, std::move(baseRecord)); return index; } return load(record, base, index); } template int IdCollection::load(const ESXRecordT& record, bool base, int index) { if (index == -2) // index unknown index = this->searchId(IdAccessorT().getId(record)); if (index == -1) { // new record auto record2 = std::make_unique>(); record2->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; (base ? record2->mBase : record2->mModified) = record; index = this->getSize(); this->appendRecord(std::move(record2)); } else { // old record auto record2 = std::make_unique>(Collection::getRecord(index)); if (base) record2->mBase = record; else record2->setModified(record); this->setRecord(index, std::move(record2)); } return index; } template bool IdCollection::tryDelete(const std::string& id) { int index = this->searchId(id); if (index == -1) return false; const Record& record = Collection::getRecord(index); if (record.isDeleted()) return false; if (record.mState == RecordBase::State_ModifiedOnly) { Collection::removeRows(index, 1); } else { auto record2 = std::make_unique>(Collection::getRecord(index)); record2->mState = RecordBase::State_Deleted; this->setRecord(index, std::move(record2)); } return true; } template <> int IdCollection>::load(ESM::ESMReader& reader, bool base); } #endif