From 74b98f7178584a04d32f9e1b1bc7cd3ab1b1b1ba Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Apr 2015 11:35:46 +1000 Subject: [PATCH] Fixed initial loading of moved refs. --- apps/opencs/model/world/data.cpp | 13 ++++-- apps/opencs/model/world/idcollection.hpp | 9 ++++ apps/opencs/model/world/refcollection.cpp | 55 ++++++++++++++++------- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b25d84829..91fa556ab 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -861,9 +862,15 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_CELL: { - mCells.load (*mReader, mBase); - std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); - mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages); + int index = mCells.load (*mReader, mBase); + if (index < 0 || index >= mCells.getSize()) + { + // log an error and continue loading the refs to the last loaded cell + std::cerr << "Logic error: cell index out of bounds" << std::endl; + index = mCells.getSize()-1; + } + std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); + mRefs.load (*mReader, index, mBase, mRefLoadCache[cellId], messages); break; } diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index f00ea447a..4eafc59bd 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -74,6 +74,15 @@ namespace CSMWorld { ESXRecordT record; + // Sometimes id (i.e. NAME of the cell) may be different to the id we stored + // earlier. e.g. NAME == "Vivec, Arena" but id == "#-4 11". Sometime NAME is + // missing altogether for scripts or cells. + // + // In such cases the returned index will be -1. We then try updating the + // IdAccessor's id manually (e.g. set mId of the record to "Vivec, Arena") + // and try getting the index once more after loading the record. The mId of the + // record would have changed to "#-4 11" after the load, and searchId() should find + // it (if this is a modify) int index = this->searchId (id); if (index==-1) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 14d4a1db5..bd4cf918c 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -2,7 +2,6 @@ #include "refcollection.hpp" #include -#include // FIXME: debug only #include #include @@ -25,36 +24,58 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool ESM::MovedCellRef mref; // hack to initialise mindex - while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef (reader, ref, deleted, true, &mref)) + while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, deleted, true, &mref)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). ref.mOriginalCell = base ? cell2.mId : ""; -#if 0 - if (mref.mRefNum.mIndex != 0 && - ((int)std::floor(ref.mPos.pos[0]/8192) != mref.mTarget[0] || - (int)std::floor(ref.mPos.pos[1]/8192) != mref.mTarget[1])) - { - std::cout <<"refcollection #" << mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; - } -#endif - if (cell.get().isExterior()) { // ignoring moved references sub-record; instead calculate cell from coordinates std::pair index = ref.getCellIndex(); std::ostringstream stream; - if (mref.mRefNum.mIndex) + stream << "#" << index.first << " " << index.second; + + ref.mCell = stream.str(); + + // It is not always possibe to ignore moved references sub-record and calculate from + // coordinates. Some mods may place the ref in positions outside normal bounds, + // resulting in non sensical cell id's. + // + // Use the target cell from the MVRF tag but if different output an error message + if (!base && // don't try to update base records + mref.mRefNum.mIndex != 0) // MVRF tag found { + std::ostringstream stream; stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; - //std::cout <<"refcollection " + stream.str() << std::endl; + ref.mCell = stream.str(); // overwrite + + ref.mOriginalCell = cell2.mId; + + if (deleted) + { + // FIXME: how to mark the record deleted? + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, + mCells.getId (cellIndex)); + + messages.add (id, "Moved reference "+ref.mRefID+" is in DELE state"); + + continue; + } + else + { + if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) + { + std::cerr << "The Position of moved ref " + << ref.mRefID << " does not match the target cell" << std::endl; + std::cerr << "Position: #" << index.first << " " << index.second + <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; + } + // FIXME: need to transfer the ref to the new cell + } } - else - stream << "#" << index.first << " " << index.second; - - ref.mCell = stream.str(); } else ref.mCell = cell2.mId;