1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 06:23:53 +00:00

Fix possible reference duplication when the refID is modified by a plugin (Bug #3471)

This commit is contained in:
MiroslavR 2016-07-22 03:58:23 +02:00
parent dafe184220
commit 4a3529488b
3 changed files with 57 additions and 5 deletions

View file

@ -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;
}
}
};
}

View file

@ -516,6 +516,8 @@ namespace MWWorld
if (mCell->mContextList.empty())
return; // this is a dynamically generated cell -> skipping.
std::map<ESM::RefNum, std::string> 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<ESM::CellRef&>(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<ESM::RefNum, std::string>& refNumToID)
{
Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
const MWWorld::ESMStore& store = mStore;
std::map<ESM::RefNum, std::string>::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)

View file

@ -385,7 +385,7 @@ namespace MWWorld
void loadRefs();
void loadRef (ESM::CellRef& ref, bool deleted);
void loadRef (ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID);
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.