From d8440e1fdc84baee8e781333da6a26b53f45119b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 20 May 2014 09:02:22 +0200 Subject: [PATCH 1/5] implemented reference record merging --- apps/opencs/model/world/cell.cpp | 5 --- apps/opencs/model/world/cell.hpp | 3 -- apps/opencs/model/world/data.cpp | 7 ++- apps/opencs/model/world/data.hpp | 1 + apps/opencs/model/world/ref.cpp | 10 ----- apps/opencs/model/world/ref.hpp | 8 ---- apps/opencs/model/world/refcollection.cpp | 52 ++++++++++++++++++----- apps/opencs/model/world/refcollection.hpp | 5 ++- components/esm/cellref.cpp | 11 +++++ components/esm/cellref.hpp | 1 + 10 files changed, 65 insertions(+), 38 deletions(-) diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index cd58fca1e4..40520a9ba7 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -18,8 +18,3 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm) mId = stream.str(); } } - -void CSMWorld::Cell::addRef (const std::string& id) -{ - mRefs.push_back (std::make_pair (id, false)); -} \ No newline at end of file diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index e6f3c8c355..a47dbf45df 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -15,12 +15,9 @@ namespace CSMWorld struct Cell : public ESM::Cell { std::string mId; - std::vector > mRefs; // ID, modified - std::vector mDeletedRefs; void load (ESM::ESMReader &esm); - void addRef (const std::string& id); }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ff33b46655..8b9d9f6dfb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -489,6 +489,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base delete mReader; mReader = 0; mDialogue = 0; + mRefLoadCache.clear(); mReader = new ESM::ESMReader; mReader->setEncoder (&mEncoder); @@ -513,6 +514,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) delete mReader; mReader = 0; mDialogue = 0; + mRefLoadCache.clear(); return true; } @@ -534,9 +536,12 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break; case ESM::REC_CELL: + { mCells.load (*mReader, mBase); - mRefs.load (*mReader, mCells.getSize()-1, mBase); + std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); + mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId]); break; + } case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); break; case ESM::REC_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index ab247b6a34..2b521c5487 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -77,6 +77,7 @@ namespace CSMWorld const ESM::Dialogue *mDialogue; // last loaded dialogue bool mBase; bool mProject; + std::map > mRefLoadCache; // not implemented Data (const Data&); diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index cf9e496ee6..44ffa92b94 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,12 +1,2 @@ #include "ref.hpp" - -#include "cell.hpp" - -void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id) -{ - mId = id; - mCell = cell.mId; - - cell.addRef (mId); -} \ No newline at end of file diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index fcf016ee24..b60cbd7e41 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -3,11 +3,6 @@ #include -namespace ESM -{ - class ESMReader; -} - namespace CSMWorld { class Cell; @@ -17,9 +12,6 @@ namespace CSMWorld { std::string mId; std::string mCell; - - void load (ESM::ESMReader &esm, Cell& cell, const std::string& id); - ///< Load cell ref and register it with \a cell. }; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 4fdd979097..db6e294fa5 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -3,12 +3,15 @@ #include +#include + #include "ref.hpp" #include "cell.hpp" #include "universalid.hpp" #include "record.hpp" -void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) +void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, + std::map& cache) { Record cell = mCells.getRecord (cellIndex); @@ -17,19 +20,48 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CellRef ref; bool deleted = false; - while (cell2.getNextRef (reader, ref, deleted)) + + while (ESM::Cell::getNextRef (reader, ref, deleted)) { - /// \todo handle deleted and moved references - ref.load (reader, cell2, getNewId()); + ref.mCell = cell2.mId; - Record record2; - record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - (base ? record2.mBase : record2.mModified) = ref; + /// \todo handle moved references - appendRecord (record2); + if (deleted) + { + /// \todo handle deleted references + continue; + } + + std::map::iterator iter = cache.find (ref.mRefNum); + + if (iter==cache.end()) + { + // new reference + ref.mId = getNewId(); + + Record record; + record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record.mBase : record.mModified) = ref; + + appendRecord (record); + + cache.insert (std::make_pair (ref.mRefNum, ref.mId)); + } + else + { + // old reference -> merge + ref.mId = iter->second; + + int index = getIndex (ref.mId); + + Record record = getRecord (index); + record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified; + (base ? record.mBase : record.mModified) = ref; + + setRecord (index, record); + } } - - mCells.setRecord (cellIndex, cell); } std::string CSMWorld::RefCollection::getNewId() diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 173efba05b..45aa5758be 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_REFCOLLECTION_H #define CSM_WOLRD_REFCOLLECTION_H +#include + #include "collection.hpp" #include "ref.hpp" #include "record.hpp" @@ -22,7 +24,8 @@ namespace CSMWorld : mCells (cells), mNextId (0) {} - void load (ESM::ESMReader& reader, int cellIndex, bool base); + void load (ESM::ESMReader& reader, int cellIndex, bool base, + std::map& cache); ///< Load a sequence of references. std::string getNewId(); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f04e819c88..00d7dfc19e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -172,3 +172,14 @@ bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) { return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; } + +bool ESM::operator< (const CellRef::RefNum& left, const CellRef::RefNum& right) +{ + if (left.mIndexright.mIndex) + return false; + + return left.mContentFile Date: Tue, 20 May 2014 09:28:18 +0200 Subject: [PATCH 2/5] implemented reference record deleting --- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/refcollection.cpp | 33 ++++++++++++++++++++--- apps/opencs/model/world/refcollection.hpp | 5 +++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8b9d9f6dfb..442e73e511 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -539,7 +539,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) { mCells.load (*mReader, mBase); std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); - mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId]); + mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages); break; } diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index db6e294fa5..3a60c49341 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -11,7 +11,7 @@ #include "record.hpp" void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache) + std::map& cache, CSMDoc::Stage::Messages& messages) { Record cell = mCells.getRecord (cellIndex); @@ -27,14 +27,39 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool /// \todo handle moved references + std::map::iterator iter = cache.find (ref.mRefNum); + if (deleted) { - /// \todo handle deleted references + if (iter==cache.end()) + { + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, + mCells.getId (cellIndex)); + + messages.push_back (std::make_pair (id, + "Attempt to delete a non-existing reference")); + + continue; + } + + int index = getIndex (iter->second); + + Record record = getRecord (index); + + if (record.mState==RecordBase::State_BaseOnly) + { + removeRows (index, 1); + cache.erase (iter); + } + else + { + record.mState = RecordBase::State_Deleted; + setRecord (index, record); + } + continue; } - std::map::iterator iter = cache.find (ref.mRefNum); - if (iter==cache.end()) { // new reference diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 45aa5758be..d80ea24694 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -3,6 +3,8 @@ #include +#include "../doc/stage.hpp" + #include "collection.hpp" #include "ref.hpp" #include "record.hpp" @@ -25,7 +27,8 @@ namespace CSMWorld {} void load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache); + std::map& cache, + CSMDoc::Stage::Messages& messages); ///< Load a sequence of references. std::string getNewId(); From f4334da42ec0076c073aed1a3aec6a4a17f1ba5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 May 2014 09:32:34 +0200 Subject: [PATCH 3/5] added changed reference tracking for cells --- apps/opencs/model/world/cell.hpp | 7 ++-- apps/opencs/model/world/columnimp.hpp | 40 +++++++++++++++++++++++ apps/opencs/model/world/refcollection.cpp | 6 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index a47dbf45df..8a2781590d 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -1,7 +1,7 @@ #ifndef CSM_WOLRD_CELL_H #define CSM_WOLRD_CELL_H -#include +#include #include #include @@ -16,8 +16,11 @@ namespace CSMWorld { std::string mId; - void load (ESM::ESMReader &esm); + /// These are the references modified by the edited content file. These are stored in + /// mModified only. + std::set mTouchedRefs; + void load (ESM::ESMReader &esm); }; } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6976b454d9..6b276d1517 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,6 +10,7 @@ #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" +#include "cell.hpp" namespace CSMWorld { @@ -87,6 +88,45 @@ namespace CSMWorld } }; + /// \brief Specialisation that takes care of the modified reference tracking + template<> + struct RecordStateColumn : public Column + { + RecordStateColumn() + : Column (Columns::ColumnId_Modification, ColumnBase::Display_RecordState) + {} + + virtual QVariant get (const Record& record) const + { + if (record.mState==Record::State_Erased) + return static_cast (Record::State_Deleted); + + if (!record.mModified.mTouchedRefs.empty() && + !record.mState==Record::State_Deleted && + !record.mState==Record::State_ModifiedOnly) + { + static_cast (Record::State_Modified); + } + + return static_cast (record.mState); + } + + virtual void set (Record& record, const QVariant& data) + { + record.mState = static_cast (data.toInt()); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; + template struct FixedRecordTypeColumn : public Column { diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 3a60c49341..1cfa4df766 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -53,6 +53,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool } else { + cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( + mCells.getId (cellIndex))); record.mState = RecordBase::State_Deleted; setRecord (index, record); } @@ -60,6 +62,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool continue; } + if (!base) + cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase ( + mCells.getId (cellIndex))); + if (iter==cache.end()) { // new reference From e0ba9a4bf2fec0f8b6f9fa1863ece0c5710d6dce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 May 2014 12:39:26 +0200 Subject: [PATCH 4/5] added reference collection stage to saving operation (preparation for cell saving) --- apps/opencs/model/doc/saving.cpp | 3 ++ apps/opencs/model/doc/savingstages.cpp | 38 ++++++++++++++++++++++++++ apps/opencs/model/doc/savingstages.hpp | 16 +++++++++++ apps/opencs/model/doc/savingstate.cpp | 7 +++++ apps/opencs/model/doc/savingstate.hpp | 4 +++ apps/opencs/model/world/ref.cpp | 8 ++++++ apps/opencs/model/world/ref.hpp | 2 ++ 7 files changed, 78 insertions(+) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 27d21635eb..337784765c 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -65,7 +65,10 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteRefIdCollectionStage (mDocument, mState)); + appendStage (new CollectionReferencesStage (mDocument, mState)); + + // close file and clean up appendStage (new CloseSaveStage (mState)); appendStage (new FinalSavingStage (mDocument, mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index eb93d90475..fc35e21cd1 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -9,6 +9,8 @@ #include +#include + #include "../world/infocollection.hpp" #include "document.hpp" @@ -214,6 +216,42 @@ void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages) } +CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::CollectionReferencesStage::setup() +{ + mState.getSubRecords().clear(); + + int size = mDocument.getData().getReferences().getSize(); + + int steps = size/100; + if (size%100) ++steps; + + return steps; +} + +void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) +{ + int size = mDocument.getData().getReferences().getSize(); + + for (int i=stage*100; i& record = + mDocument.getData().getReferences().getRecord (i); + + if (record.mState==CSMWorld::RecordBase::State_Deleted || + record.mState==CSMWorld::RecordBase::State_Modified || + record.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mId)].push_back (i); + } + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index c2f0a150a9..653f3a9570 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -163,8 +163,24 @@ namespace CSMDoc virtual void perform (int stage, Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. + }; + class CollectionReferencesStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + CollectionReferencesStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; class CloseSaveStage : public Stage { diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 8742148226..294f830496 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -25,6 +25,8 @@ void CSMDoc::SavingState::start (Document& document, bool project) mStream.clear(); + mSubRecords.clear(); + if (project) mPath = mProjectPath; else @@ -60,4 +62,9 @@ ESM::ESMWriter& CSMDoc::SavingState::getWriter() bool CSMDoc::SavingState::isProjectFile() const { return mProjectFile; +} + +std::map > CSMDoc::SavingState::getSubRecords() +{ + return mSubRecords; } \ No newline at end of file diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 6b45655846..64085bf0d5 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -2,6 +2,7 @@ #define CSM_DOC_SAVINGSTATE_H #include +#include #include @@ -24,6 +25,7 @@ namespace CSMDoc ESM::ESMWriter mWriter; boost::filesystem::path mProjectPath; bool mProjectFile; + std::map > mSubRecords; // record ID, list of subrecords public: @@ -45,6 +47,8 @@ namespace CSMDoc bool isProjectFile() const; ///< Currently saving project file? (instead of content file) + + std::map > getSubRecords(); }; diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 44ffa92b94..d1bd771f80 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,2 +1,10 @@ #include "ref.hpp" + +CSMWorld::CellRef::CellRef() +{ + mRefNum.mIndex = 0; + + // special marker: This reference does not have a RefNum assign to it yet. + mRefNum.mContentFile = -2; +} \ No newline at end of file diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index b60cbd7e41..eb62434cf2 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -12,6 +12,8 @@ namespace CSMWorld { std::string mId; std::string mCell; + + CellRef(); }; } From ae5063277401901eedf12d8026ae6e90ed2118bd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 May 2014 18:08:40 +0200 Subject: [PATCH 5/5] implemented cell and reference saving int OpenCS --- apps/opencs/model/doc/saving.cpp | 1 + apps/opencs/model/doc/savingstages.cpp | 103 ++++++++++++++++++++++++- apps/opencs/model/doc/savingstages.hpp | 16 ++++ apps/opencs/model/doc/savingstate.cpp | 2 +- apps/opencs/model/doc/savingstate.hpp | 2 +- 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 337784765c..45b53f4fe8 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -67,6 +67,7 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new CollectionReferencesStage (mDocument, mState)); + appendStage (new WriteCellCollectionStage (mDocument, mState)); // close file and clean up appendStage (new CloseSaveStage (mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index fc35e21cd1..4846d6c732 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -246,12 +246,113 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages) record.mState==CSMWorld::RecordBase::State_Modified || record.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mId)].push_back (i); + mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)] + .push_back (i); } } } +CSMDoc::WriteCellCollectionStage::WriteCellCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteCellCollectionStage::setup() +{ + return mDocument.getData().getCells().getSize(); +} + +void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& cell = + mDocument.getData().getCells().getRecord (stage); + + std::map >::const_iterator references = + mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId)); + + if (cell.mState==CSMWorld::RecordBase::State_Modified || + cell.mState==CSMWorld::RecordBase::State_ModifiedOnly || + references!=mState.getSubRecords().end()) + { + bool interior = cell.get().mId.substr (0, 1)!="#"; + + // write cell data + mState.getWriter().startRecord (cell.mModified.sRecordId); + + mState.getWriter().writeHNOCString ("NAME", cell.get().mName); + + ESM::Cell cell2 = cell.get(); + + if (interior) + cell2.mData.mFlags |= ESM::Cell::Interior; + else + { + cell2.mData.mFlags &= ~ESM::Cell::Interior; + + std::istringstream stream (cell.get().mId.c_str()); + char ignore; + stream >> ignore >> cell2.mData.mX >> cell2.mData.mY; + } + cell2.save (mState.getWriter()); + + // write references + if (references!=mState.getSubRecords().end()) + { + // first pass: find highest RefNum + int lastRefNum = -1; + + for (std::vector::const_iterator iter (references->second.begin()); + iter!=references->second.end(); ++iter) + { + const CSMWorld::Record& ref = + mDocument.getData().getReferences().getRecord (*iter); + + if (ref.get().mRefNum.mContentFile==0 && ref.get().mRefNum.mIndex>lastRefNum) + lastRefNum = ref.get().mRefNum.mIndex; + } + + // second pass: write + for (std::vector::const_iterator iter (references->second.begin()); + iter!=references->second.end(); ++iter) + { + const CSMWorld::Record& ref = + mDocument.getData().getReferences().getRecord (*iter); + + if (ref.mState==CSMWorld::RecordBase::State_Modified || + ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + if (ref.get().mRefNum.mContentFile==-2) + { + if (lastRefNum>=0xffffff) + throw std::runtime_error ( + "RefNums exhausted in cell: " + cell.get().mId); + + ESM::CellRef ref2 = ref.get(); + ref2.mRefNum.mContentFile = 0; + ref2.mRefNum.mIndex = ++lastRefNum; + + ref2.save (mState.getWriter()); + } + else + ref.get().save (mState.getWriter()); + } + else if (ref.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } + } + } + + mState.getWriter().endRecord (cell.mModified.sRecordId); + } + else if (cell.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 653f3a9570..dcb1a86500 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -182,6 +182,22 @@ namespace CSMDoc ///< Messages resulting from this stage will be appended to \a messages. }; + class WriteCellCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteCellCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class CloseSaveStage : public Stage { SavingState& mState; diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 294f830496..1d93a95f59 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -64,7 +64,7 @@ bool CSMDoc::SavingState::isProjectFile() const return mProjectFile; } -std::map > CSMDoc::SavingState::getSubRecords() +std::map >& CSMDoc::SavingState::getSubRecords() { return mSubRecords; } \ No newline at end of file diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 64085bf0d5..3abb724dea 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -48,7 +48,7 @@ namespace CSMDoc bool isProjectFile() const; ///< Currently saving project file? (instead of content file) - std::map > getSubRecords(); + std::map >& getSubRecords(); };