diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index b756a9dc19..73278ba975 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -58,12 +58,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getSpells(), mState)); - /// \todo deal with info records for topcis and journals - appendStage (new WriteCollectionStage > - (mDocument.getData().getTopics(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); - appendStage (new WriteCollectionStage > - (mDocument.getData().getJournals(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); appendStage (new WriteRefIdCollectionStage (mDocument, mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index d68c723179..8e9bcfc0de 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -7,6 +7,10 @@ #include +#include + +#include "../world/infocollection.hpp" + #include "document.hpp" #include "savingstate.hpp" @@ -80,6 +84,115 @@ void CSMDoc::WriteHeaderStage::perform (int stage, std::vector& mes } +CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document, + SavingState& state, bool journal) +: mDocument (document), mState (state), + mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()), + mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos()) +{} + +int CSMDoc::WriteDialogueCollectionStage::setup() +{ + return mTopics.getSize(); +} + +void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector& messages) +{ + const CSMWorld::Record& topic = mTopics.getRecord (stage); + + CSMWorld::RecordBase::State state = topic.mState; + + if (state==CSMWorld::RecordBase::State_Deleted) + { + // if the topic is deleted, we do not need to bother with INFO records. + + /// \todo wrote record with delete flag + + return; + } + + // Test, if we need to save anything associated info records. + bool infoModified = false; + + CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId); + + for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter) + { + CSMWorld::RecordBase::State state = iter->mState; + + if (state==CSMWorld::RecordBase::State_Modified || + state==CSMWorld::RecordBase::State_ModifiedOnly || + state==CSMWorld::RecordBase::State_Deleted) + { + infoModified = true; + break; + } + } + + if (state==CSMWorld::RecordBase::State_Modified || + state==CSMWorld::RecordBase::State_ModifiedOnly || + infoModified) + { + // always write the topic record + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic (change ESMWriter interface?) + type += reinterpret_cast (&topic.mModified.sRecordId)[i]; + + mState.getWriter().startRecord (type); + mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); + topic.mModified.save (mState.getWriter()); + mState.getWriter().endRecord (type); + + // write modified selected info records + for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; + ++iter) + { + CSMWorld::RecordBase::State state = iter->mState; + + if (state==CSMWorld::RecordBase::State_Deleted) + { + /// \todo wrote record with delete flag + } + else if (state==CSMWorld::RecordBase::State_Modified || + state==CSMWorld::RecordBase::State_ModifiedOnly) + { + ESM::DialInfo info = iter->get(); + info.mId = info.mId.substr (info.mId.find_last_of ('#')+1); + + if (iter!=range.first) + { + CSMWorld::InfoCollection::RecordConstIterator prev = iter; + --prev; + + info.mPrev = + prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1); + } + + CSMWorld::InfoCollection::RecordConstIterator next = iter; + ++next; + + if (next!=range.second) + { + info.mNext = + next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1); + } + + std::string type; + for (int i=0; i<4; ++i) + /// \todo make endianess agnostic (change ESMWriter interface?) + type += reinterpret_cast (&info.sRecordId)[i]; + + mState.getWriter().startRecord (type); + mState.getWriter().writeHNCString ("INAM", info.mId); + info.save (mState.getWriter()); + mState.getWriter().endRecord (type); + } + } + } +} + + CSMDoc::WriteRefIdCollectionStage::WriteRefIdCollectionStage (Document& document, SavingState& state) : mDocument (document), mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index ff94116fdb..ca5586511d 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -3,13 +3,23 @@ #include "stage.hpp" -#include "savingstate.hpp" - #include "../world/record.hpp" #include "../world/idcollection.hpp" #include "../filter/filter.hpp" +#include "savingstate.hpp" + +namespace ESM +{ + struct Dialogue; +} + +namespace CSMWorld +{ + class InfoCollection; +} + namespace CSMDoc { class Document; @@ -106,6 +116,25 @@ namespace CSMDoc } + class WriteDialogueCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + const CSMWorld::IdCollection& mTopics; + CSMWorld::InfoCollection& mInfos; + + public: + + WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + class WriteRefIdCollectionStage : public Stage { Document& mDocument; diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 5120a0043c..f86ad3b51b 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -123,7 +123,6 @@ void DialInfo::load(ESMReader &esm) void DialInfo::save(ESMWriter &esm) const { - esm.writeHNCString("INAM", mId); esm.writeHNCString("PNAM", mPrev); esm.writeHNCString("NNAM", mNext); esm.writeHNT("DATA", mData, 12);