From cfdbd0d471c6bac72f904f86a1bec486ca2a3822 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 12 Jul 2021 17:30:39 +0200 Subject: [PATCH] Indicate moved cell refs explicitly This is less error prone approach than use of MovedCellRef fields. Also make separate functions for skipping and reading moved cell refs to avoid passing special flags logic and null pointers for unused arguments. --- apps/opencs/model/world/refcollection.cpp | 7 ++-- apps/openmw/mwrender/objectpaging.cpp | 10 +++--- apps/openmw/mwworld/cellstore.cpp | 21 ++++-------- apps/openmw/mwworld/store.cpp | 8 ++--- components/esm/loadcell.cpp | 40 +++++++++++++++-------- components/esm/loadcell.hpp | 9 ++--- 6 files changed, 48 insertions(+), 47 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index dfdb8e73bf..003a300c06 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -19,8 +19,9 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool ESM::MovedCellRef mref; mref.mRefNum.mIndex = 0; bool isDeleted = false; + bool isMoved = false; - while (ESM::Cell::getNextRef(reader, ref, isDeleted, true, &mref)) + while (ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved)) { // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). @@ -34,7 +35,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool ref.mCell = "#" + std::to_string(index.first) + " " + std::to_string(index.second); // Handle non-base moved references - if (!base && mref.mRefNum.mIndex != 0) + if (!base && !isMoved) { // Moved references must have a link back to their original cell // See discussion: https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30 @@ -59,8 +60,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool else ref.mCell = cell2.mId; - mref.mRefNum.mIndex = 0; - // ignore content file number std::map::iterator iter = cache.begin(); unsigned int thisIndex = ref.mRefNum.mIndex & 0x00ffffff; diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index d91f4efaaa..2cbffbc6eb 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -427,13 +427,11 @@ namespace MWRender ESM::MovedCellRef cMRef; cMRef.mRefNum.mIndex = 0; bool deleted = false; - while(cell->getNextRef(esm[index], ref, deleted, /*ignoreMoves*/true, &cMRef)) + bool moved = false; + while(cell->getNextRef(esm[index], ref, deleted, cMRef, moved)) { - if (cMRef.mRefNum.mIndex) - { - cMRef.mRefNum.mIndex = 0; - continue; // ignore refs that are moved - } + if (moved) + continue; if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum) != cell->mMovedRefs.end()) continue; Misc::StringUtils::lowerCaseInPlace(ref.mRefID); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 53245be247..2b73a3362b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -553,17 +553,12 @@ namespace MWWorld ESM::MovedCellRef cMRef; cMRef.mRefNum.mIndex = 0; bool deleted = false; - while(mCell->getNextRef(esm[index], ref, deleted, /*ignoreMoves*/true, &cMRef)) + bool moved = false; + while(mCell->getNextRef(esm[index], ref, deleted, cMRef, moved)) { - if (deleted) + if (deleted || moved) continue; - if (cMRef.mRefNum.mIndex) - { - cMRef.mRefNum.mIndex = 0; - continue; // ignore refs that are moved - } - // Don't list reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum); @@ -618,13 +613,11 @@ namespace MWWorld ESM::MovedCellRef cMRef; cMRef.mRefNum.mIndex = 0; bool deleted = false; - while(mCell->getNextRef(esm[index], ref, deleted, /*ignoreMoves*/true, &cMRef)) + bool moved = false; + while(mCell->getNextRef(esm[index], ref, deleted, cMRef, moved)) { - if (cMRef.mRefNum.mIndex) - { - cMRef.mRefNum.mIndex = 0; - continue; // ignore refs that are moved - } + if (moved) + continue; // Don't load reference if it was moved to a different cell. ESM::MovedCellRefTracker::const_iterator iter = diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2ed051a141..1614e07461 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -502,8 +502,8 @@ namespace MWWorld { ESM::CellRef ref; ESM::MovedCellRef cMRef; - cMRef.mRefNum.mIndex = 0; bool deleted = false; + bool moved = false; ESM::ESM_Context ctx = esm.getContext(); @@ -512,10 +512,10 @@ namespace MWWorld // // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. - while (cell->getNextRef(esm, ref, deleted, /*ignoreMoves*/true, &cMRef)) + while (cell->getNextRef(esm, ref, deleted, cMRef, moved)) { - if (!cMRef.mRefNum.mIndex) - continue; // ignore refs that are not moved + if (!moved) + continue; ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index d43911135a..e90af7b2f6 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -224,7 +224,7 @@ namespace ESM return region + ' ' + cellGrid; } - bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref) + bool Cell::getNextRef(ESMReader& esm, CellRef& ref, bool& isDeleted) { isDeleted = false; @@ -236,18 +236,9 @@ namespace ESM // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { - if (ignoreMoves) - { - esm.getHT (mref->mRefNum.mIndex); - esm.getHNOT (mref->mTarget, "CNDT"); - adjustRefNum (mref->mRefNum, esm); - } - else - { - // skip rest of cell record (moved references), they are handled elsewhere - esm.skipRecord(); // skip MVRF, CNDT - return false; - } + // skip rest of cell record (moved references), they are handled elsewhere + esm.skipRecord(); // skip MVRF, CNDT + return false; } if (esm.peekNextSub("FRMR")) @@ -263,6 +254,29 @@ namespace ESM return false; } + bool Cell::getNextRef(ESMReader& esm, CellRef& cellRef, bool& deleted, MovedCellRef& movedCellRef, bool& moved) + { + deleted = false; + moved = false; + + if (!esm.hasMoreSubs()) + return false; + + if (esm.isNextSub("MVRF")) + { + moved = true; + getNextMVRF(esm, movedCellRef); + } + + if (!esm.peekNextSub("FRMR")) + return false; + + cellRef.load(esm, deleted); + adjustRefNum(cellRef.mRefNum, esm); + + return true; + } + bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefNum.mIndex); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index c49dc20c59..3a8133d881 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -181,12 +181,9 @@ struct Cell All fields of the CellRef struct are overwritten. You can safely reuse one memory location without blanking it between calls. */ - /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. - static bool getNextRef(ESMReader &esm, - CellRef &ref, - bool &isDeleted, - bool ignoreMoves = false, - MovedCellRef *mref = nullptr); + static bool getNextRef(ESMReader& esm, CellRef& ref, bool& deleted); + + static bool getNextRef(ESMReader& esm, CellRef& cellRef, bool& deleted, MovedCellRef& movedCellRef, bool& moved); /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this.