From 42109fc811fa03c9a037af0ee309e458ce06f149 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sun, 13 Jul 2025 05:10:14 -0700 Subject: [PATCH 1/8] CLEANUP: Remove dead code in cloneRecordImp --- apps/opencs/model/world/collection.hpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index fa42ee0f09..18fb73330c 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -273,15 +273,6 @@ namespace CSMWorld copy->mState = RecordBase::State_ModifiedOnly; setRecordId(destination, copy->get()); - if constexpr (std::is_same_v) - { - if (type == UniversalId::Type_Reference) - { - CSMWorld::CellRef* ptr = (CSMWorld::CellRef*)©->mModified; - ptr->mRefNum.mIndex = 0; - } - } - if constexpr (std::is_same_v) { copy->mModified.mStringId = copy->mModified.mId.getRefIdString(); From 85fdf2011acaebbc1e5a4184de57b60b3b7b068a Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sun, 13 Jul 2025 05:10:43 -0700 Subject: [PATCH 2/8] FIX: Do not attempt to bump refNums during savingStages --- apps/opencs/model/doc/savingstages.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 12fa6e811f..edd4329f7f 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -316,13 +316,7 @@ void CSMDoc::WriteCellCollectionStage::writeReferences( } ESM::RefId streamId = ESM::RefId::stringRefId(stream.str()); - if (refRecord.mNew || refRecord.mRefNum.mIndex == 0 - || (!interior && ref.mState == CSMWorld::RecordBase::State_ModifiedOnly && refRecord.mCell != streamId)) - { - refRecord.mRefNum.mIndex = newRefNum++; - } - else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId - && !interior) + if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId && !interior) { // An empty mOriginalCell is meant to indicate that it is the same as // the current cell. It is possible that a moved ref is moved again. From 2cb7d6c3924c022cb88b820de028f87bb5218a26 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sun, 13 Jul 2025 05:11:38 -0700 Subject: [PATCH 3/8] CLEANUP: Remove commented code & use the builtin getNewId function when cloning --- apps/opencs/view/render/instancemode.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 03872a3d6c..d48e7abcb1 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1243,9 +1243,8 @@ void CSVRender::InstanceMode::cloneSelectedInstances() if (CSVRender::ObjectTag* objectTag = dynamic_cast(tag.get())) { macro.push(new CSMWorld::CloneCommand(referencesTable, objectTag->mObject->getReferenceId(), - "ref#" + std::to_string(referencesTable.rowCount()), CSMWorld::UniversalId::Type_Reference)); + document.getData().getReferences().getNewId(), CSMWorld::UniversalId::Type_Reference)); } - // getWorldspaceWidget().clearSelection(Mask_Reference); } void CSVRender::InstanceMode::dropInstance(CSVRender::Object* object, float dropHeight) From 79d86bf2bdc4964f67d0103f53af5b55f8083c14 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sun, 13 Jul 2025 05:12:42 -0700 Subject: [PATCH 4/8] FIX: Track the highest local refNum during plugin loading and increment it for each cloned/created reference --- apps/opencs/model/world/refcollection.cpp | 13 ++++++++++--- apps/opencs/model/world/refcollection.hpp | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 124e697de8..5d2ed2cfc5 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -175,6 +175,9 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b ref.mIdNum = mNextId; // FIXME: fragile ref.mId = ESM::RefId::stringRefId(getNewId()); + if (!base && ref.mRefNum.mIndex >= mHighestUsedRefNum) + mHighestUsedRefNum = ref.mRefNum.mIndex; + cache.emplace(ref.mRefNum, ref.mIdNum); auto record = std::make_unique>(); @@ -222,6 +225,11 @@ std::string CSMWorld::RefCollection::getNewId() return "ref#" + std::to_string(mNextId++); } +uint32_t CSMWorld::RefCollection::getNextRefNum() +{ + return ++mHighestUsedRefNum; +} + unsigned int CSMWorld::RefCollection::extractIdNum(std::string_view id) const { std::string::size_type separator = id.find_last_of('#'); @@ -283,6 +291,7 @@ void CSMWorld::RefCollection::appendBlankRecord(const ESM::RefId& id, UniversalI record->get().mId = id; record->get().mIdNum = extractIdNum(id.getRefIdString()); + record->get().mRefNum.mIndex = getNextRefNum(); Collection::appendRecord(std::move(record)); } @@ -298,15 +307,13 @@ void CSMWorld::RefCollection::cloneRecord( copy->get().mId = destination; copy->get().mIdNum = extractIdNum(destination.getRefIdString()); + copy->get().mRefNum.mIndex = getNextRefNum(); if (copy->get().mRefNum.hasContentFile()) { mRefIndex.insert(std::make_pair(static_cast*>(copy.get())->get().mIdNum, index)); copy->get().mRefNum.mContentFile = -1; - copy->get().mRefNum.mIndex = index; } - else - copy->get().mRefNum.mIndex = copy->get().mIdNum; insertRecord(std::move(copy), getAppendIndex(destination, type)); // call RefCollection::insertRecord() } diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index d3d200e6c2..f70167f922 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -1,6 +1,7 @@ #ifndef CSM_WOLRD_REFCOLLECTION_H #define CSM_WOLRD_REFCOLLECTION_H +#include #include #include #include @@ -40,9 +41,12 @@ namespace CSMWorld std::map mRefIndex; // CellRef index keyed by CSMWorld::CellRef::mIdNum int mNextId; + uint32_t mHighestUsedRefNum = 0; unsigned int extractIdNum(std::string_view id) const; + uint32_t getNextRefNum(); + int getIntIndex(unsigned int id) const; int searchId(unsigned int id) const; From 7d5a9a2e2f3a49a2cbb6f33eef99a5c2f66d53fb Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Thu, 17 Jul 2025 11:26:36 -0700 Subject: [PATCH 5/8] CLEANUP: Only increment highest refNum for ones which are actually higher --- apps/opencs/model/world/refcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 5d2ed2cfc5..b2b6cec245 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -175,7 +175,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b ref.mIdNum = mNextId; // FIXME: fragile ref.mId = ESM::RefId::stringRefId(getNewId()); - if (!base && ref.mRefNum.mIndex >= mHighestUsedRefNum) + if (!base && ref.mRefNum.mIndex > mHighestUsedRefNum) mHighestUsedRefNum = ref.mRefNum.mIndex; cache.emplace(ref.mRefNum, ref.mIdNum); From dcac39aefd7849df08620ab10269472a711b15bf Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 19 Jul 2025 09:44:01 -0700 Subject: [PATCH 6/8] FIX: never serialize MVRF for refferences from the local plugin --- apps/opencs/model/doc/savingstages.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index edd4329f7f..074163c31e 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -304,6 +304,8 @@ void CSMDoc::WriteCellCollectionStage::writeReferences( { CSMWorld::CellRef refRecord = ref.get(); + const bool isLocal = refRecord.mRefNum.mContentFile == 0; + // -1 is the current file, saved indices are 1-based refRecord.mRefNum.mContentFile++; @@ -316,7 +318,8 @@ void CSMDoc::WriteCellCollectionStage::writeReferences( } ESM::RefId streamId = ESM::RefId::stringRefId(stream.str()); - if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId && !interior) + if (!isLocal && (refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId + && !interior) { // An empty mOriginalCell is meant to indicate that it is the same as // the current cell. It is possible that a moved ref is moved again. From 0f0a402ead9ca4c070297e123dfb23b53af67b16 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sun, 20 Jul 2025 08:53:14 +0000 Subject: [PATCH 7/8] Local content file index is actually -1 --- apps/opencs/model/doc/savingstages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 074163c31e..85a570d8dd 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -304,7 +304,7 @@ void CSMDoc::WriteCellCollectionStage::writeReferences( { CSMWorld::CellRef refRecord = ref.get(); - const bool isLocal = refRecord.mRefNum.mContentFile == 0; + const bool isLocal = refRecord.mRefNum.mContentFile == -1; // -1 is the current file, saved indices are 1-based refRecord.mRefNum.mContentFile++; From d68b774c10f0e7fed523029651303cb72c4ebe36 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Tue, 5 Aug 2025 14:12:50 -0700 Subject: [PATCH 8/8] CLEANUP: Don't handle refnums during saving at all --- apps/opencs/model/doc/savingstages.cpp | 13 +++---------- apps/opencs/model/doc/savingstages.hpp | 2 +- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 85a570d8dd..492807eb93 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -291,8 +291,7 @@ int CSMDoc::WriteCellCollectionStage::setup() return mDocument.getData().getCells().getSize(); } -void CSMDoc::WriteCellCollectionStage::writeReferences( - const std::deque& references, bool interior, unsigned int& newRefNum) +void CSMDoc::WriteCellCollectionStage::writeReferences(const std::deque& references, bool interior) { ESM::ESMWriter& writer = mState.getWriter(); @@ -359,9 +358,6 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages) CSMWorld::Cell cellRecord = cell.get(); const bool interior = !cellRecord.mId.startsWith("#"); - // count new references and adjust RefNumCount accordingsly - unsigned int newRefNum = cellRecord.mRefNumCounter; - if (references != nullptr) { for (std::deque::const_iterator iter(references->begin()); iter != references->end(); ++iter) @@ -387,9 +383,6 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages) ESM::RefId::stringRefId(CSMWorld::CellCoordinates(refRecord.getCellIndex()).getId("")) != refRecord.mCell)) ++cellRecord.mRefNumCounter; - - if (refRecord.mRefNum.mIndex >= newRefNum) - newRefNum = refRecord.mRefNum.mIndex + 1; } } @@ -412,9 +405,9 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages) // write references if (references != nullptr) { - writeReferences(persistentRefs, interior, newRefNum); + writeReferences(persistentRefs, interior); cellRecord.saveTempMarker(writer, static_cast(references->size()) - persistentRefs.size()); - writeReferences(tempRefs, interior, newRefNum); + writeReferences(tempRefs, interior); } writer.endRecord(cellRecord.sRecordId); diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 5423b8f504..1f86af10a2 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -167,7 +167,7 @@ namespace CSMDoc Document& mDocument; SavingState& mState; - void writeReferences(const std::deque& references, bool interior, unsigned int& newRefNum); + void writeReferences(const std::deque& references, bool interior); public: WriteCellCollectionStage(Document& document, SavingState& state);