Merge pull request #1005 from MiroslavR/cellref-fixes

Various reference handling fixes
coverity_scan^2
scrawl 9 years ago committed by GitHub
commit 5a9b1b6a01

@ -29,6 +29,18 @@ namespace MWWorld
mList.push_back(item); mList.push_back(item);
return mList.back(); 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;
}
}
}; };
} }

@ -497,9 +497,11 @@ namespace MWWorld
// List moved references, from separately tracked list. // List moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{ {
const ESM::CellRef &ref = *it; const ESM::CellRef &ref = it->first;
bool deleted = it->second;
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); if (!deleted)
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
} }
std::sort (mIds.begin(), mIds.end()); std::sort (mIds.begin(), mIds.end());
@ -514,6 +516,8 @@ namespace MWWorld
if (mCell->mContextList.empty()) if (mCell->mContextList.empty())
return; // this is a dynamically generated cell -> skipping. 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. // Load references from all plugins that do something with this cell.
for (size_t i = 0; i < mCell->mContextList.size(); i++) for (size_t i = 0; i < mCell->mContextList.size(); i++)
{ {
@ -537,7 +541,7 @@ namespace MWWorld
continue; continue;
} }
loadRef (ref, deleted); loadRef (ref, deleted, refNumToID);
} }
} }
catch (std::exception& e) catch (std::exception& e)
@ -549,9 +553,10 @@ namespace MWWorld
// Load moved references, from separately tracked list. // Load moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{ {
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it); ESM::CellRef &ref = const_cast<ESM::CellRef&>(it->first);
bool deleted = it->second;
loadRef (ref, false); loadRef (ref, deleted, refNumToID);
} }
updateMergedRefs(); updateMergedRefs();
@ -582,12 +587,47 @@ namespace MWWorld
return Ptr(); 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); Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
const MWWorld::ESMStore& store = mStore; 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)) switch (store.find (ref.mRefID))
{ {
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
@ -612,12 +652,15 @@ namespace MWWorld
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break; case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
case ESM::REC_BODY: mBodyParts.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: default:
std::cerr std::cerr
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
return;
} }
refNumToID[ref.mRefNum] = ref.mRefID;
} }
void CellStore::loadState (const ESM::CellState& state) void CellStore::loadState (const ESM::CellState& state)

@ -385,7 +385,7 @@ namespace MWWorld
void loadRefs(); 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. ///< Make case-adjustments to \a ref and insert it into the respective container.
/// ///
/// Invalid \a ref objects are silently dropped. /// Invalid \a ref objects are silently dropped.

@ -513,19 +513,16 @@ namespace MWWorld
bool deleted = false; bool deleted = false;
cell->getNextRef(esm, ref, deleted); cell->getNextRef(esm, ref, deleted);
if (!deleted) // Add data required to make reference appear in the correct cell.
{ // We should not need to test for duplicates, as this part of the code is pre-cell merge.
// Add data required to make reference appear in the correct cell. cell->mMovedRefs.push_back(cMRef);
// We should not need to test for duplicates, as this part of the code is pre-cell merge.
cell->mMovedRefs.push_back(cMRef); // But there may be duplicates here!
ESM::CellRefTracker::iterator iter = std::find_if(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(ref.mRefNum));
// But there may be duplicates here! if (iter == cellAlt->mLeasedRefs.end())
ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); cellAlt->mLeasedRefs.push_back(std::make_pair(ref, deleted));
if (iter == cellAlt->mLeasedRefs.end()) else
cellAlt->mLeasedRefs.push_back(ref); *iter = std::make_pair(ref, deleted);
else
*iter = ref;
}
} }
} }
const ESM::Cell *Store<ESM::Cell>::search(const std::string &id) const const ESM::Cell *Store<ESM::Cell>::search(const std::string &id) const
@ -678,14 +675,17 @@ namespace MWWorld
for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) {
// remove reference from current leased ref tracker and add it to new cell // remove reference from current leased ref tracker and add it to new cell
ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum);
if (itold != oldcell->mMovedRefs.end()) { if (itold != oldcell->mMovedRefs.end())
ESM::MovedCellRef target0 = *itold; {
ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1])); if (it->mTarget[0] != itold->mTarget[0] || it->mTarget[1] != itold->mTarget[1])
ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); {
if (it_lease != wipecell->mLeasedRefs.end()) ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(itold->mTarget[0], itold->mTarget[1]));
wipecell->mLeasedRefs.erase(it_lease); ESM::CellRefTracker::iterator it_lease = std::find_if(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(it->mRefNum));
else if (it_lease != wipecell->mLeasedRefs.end())
std::cerr << "can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl; wipecell->mLeasedRefs.erase(it_lease);
else
std::cerr << "can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl;
}
*itold = *it; *itold = *it;
} }
else else

@ -43,7 +43,15 @@ bool operator==(const MovedCellRef& ref, const RefNum& refNum);
bool operator==(const CellRef& ref, const RefNum& refNum); bool operator==(const CellRef& ref, const RefNum& refNum);
typedef std::list<MovedCellRef> MovedCellRefTracker; typedef std::list<MovedCellRef> MovedCellRefTracker;
typedef std::list<CellRef> CellRefTracker; typedef std::list<std::pair<CellRef, bool> > CellRefTracker;
struct CellRefTrackerPredicate
{
RefNum mRefNum;
CellRefTrackerPredicate(const RefNum& refNum) : mRefNum(refNum) {}
bool operator() (const std::pair<CellRef, bool>& refdelPair) { return refdelPair.first == mRefNum; }
};
/* Cells hold data about objects, creatures, statics (rocks, walls, /* Cells hold data about objects, creatures, statics (rocks, walls,
buildings) and landscape (for exterior cells). Cells frequently buildings) and landscape (for exterior cells). Cells frequently

Loading…
Cancel
Save