diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 4d503dcc8..30be4a661 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -29,6 +29,18 @@ namespace MWWorld mList.push_back(item); return mList.back(); } + + /// Remove all references with the given refNum from this list. + void remove (const ESM::RefNum &refNum) + { + for (typename List::iterator it = mList.begin(); it != mList.end();) + { + if (*it == refNum) + mList.erase(it++); + else + ++it; + } + } }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 31b8a1515..db3707441 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -516,6 +516,8 @@ namespace MWWorld if (mCell->mContextList.empty()) return; // this is a dynamically generated cell -> skipping. + std::map refNumToID; // used to detect refID modifications + // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { @@ -539,7 +541,7 @@ namespace MWWorld continue; } - loadRef (ref, deleted); + loadRef (ref, deleted, refNumToID); } } catch (std::exception& e) @@ -554,7 +556,7 @@ namespace MWWorld ESM::CellRef &ref = const_cast(it->first); bool deleted = it->second; - loadRef (ref, deleted); + loadRef (ref, deleted, refNumToID); } updateMergedRefs(); @@ -585,12 +587,47 @@ namespace MWWorld return Ptr(); } - void CellStore::loadRef (ESM::CellRef& ref, bool deleted) + void CellStore::loadRef (ESM::CellRef& ref, bool deleted, std::map& refNumToID) { Misc::StringUtils::lowerCaseInPlace (ref.mRefID); const MWWorld::ESMStore& store = mStore; + std::map::iterator it = refNumToID.find(ref.mRefNum); + if (it != refNumToID.end()) + { + if (it->second != ref.mRefID) + { + // refID was modified, make sure we don't end up with duplicated refs + switch (store.find(it->second)) + { + case ESM::REC_ACTI: mActivators.remove(ref.mRefNum); break; + case ESM::REC_ALCH: mPotions.remove(ref.mRefNum); break; + case ESM::REC_APPA: mAppas.remove(ref.mRefNum); break; + case ESM::REC_ARMO: mArmors.remove(ref.mRefNum); break; + case ESM::REC_BOOK: mBooks.remove(ref.mRefNum); break; + case ESM::REC_CLOT: mClothes.remove(ref.mRefNum); break; + case ESM::REC_CONT: mContainers.remove(ref.mRefNum); break; + case ESM::REC_CREA: mCreatures.remove(ref.mRefNum); break; + case ESM::REC_DOOR: mDoors.remove(ref.mRefNum); break; + case ESM::REC_INGR: mIngreds.remove(ref.mRefNum); break; + case ESM::REC_LEVC: mCreatureLists.remove(ref.mRefNum); break; + case ESM::REC_LEVI: mItemLists.remove(ref.mRefNum); break; + case ESM::REC_LIGH: mLights.remove(ref.mRefNum); break; + case ESM::REC_LOCK: mLockpicks.remove(ref.mRefNum); break; + case ESM::REC_MISC: mMiscItems.remove(ref.mRefNum); break; + case ESM::REC_NPC_: mNpcs.remove(ref.mRefNum); break; + case ESM::REC_PROB: mProbes.remove(ref.mRefNum); break; + case ESM::REC_REPA: mRepairs.remove(ref.mRefNum); break; + case ESM::REC_STAT: mStatics.remove(ref.mRefNum); break; + case ESM::REC_WEAP: mWeapons.remove(ref.mRefNum); break; + case ESM::REC_BODY: mBodyParts.remove(ref.mRefNum); break; + default: + break; + } + } + } + switch (store.find (ref.mRefID)) { case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; @@ -615,12 +652,15 @@ namespace MWWorld case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; case ESM::REC_BODY: mBodyParts.load(ref, deleted, store); break; - case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; break; + case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; return; default: std::cerr << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + return; } + + refNumToID[ref.mRefNum] = ref.mRefID; } void CellStore::loadState (const ESM::CellState& state) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 36cc7f5eb..1aee13132 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -385,7 +385,7 @@ namespace MWWorld void loadRefs(); - void loadRef (ESM::CellRef& ref, bool deleted); + void loadRef (ESM::CellRef& ref, bool deleted, std::map& refNumToID); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped.