From eefbdde6de862e15f27ae90c410687eb8a988729 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 9 Feb 2013 13:00:57 +0100 Subject: [PATCH] - For pull request: remove all instances of maps used to track refnumbers. - new file: apps/openmw/mwworld/store.cpp, had to move reference merging method out of the header file to prevent three-way recursion/unresolved forward references in custom compare operators. --- apps/openmw/main.cpp | 6 +- apps/openmw/mwworld/cells.cpp | 12 ++-- apps/openmw/mwworld/cellstore.cpp | 42 ++++++++++++- apps/openmw/mwworld/cellstore.hpp | 84 ++++---------------------- apps/openmw/mwworld/containerstore.cpp | 28 ++++----- apps/openmw/mwworld/containerstore.hpp | 72 +++++++++++----------- apps/openmw/mwworld/localscripts.cpp | 6 +- apps/openmw/mwworld/scene.cpp | 6 +- apps/openmw/mwworld/store.cpp | 65 ++++++++++++++++++++ apps/openmw/mwworld/store.hpp | 64 +++----------------- apps/openmw/mwworld/worldimp.cpp | 14 ++--- components/esm/loadcell.cpp | 26 +++++--- components/esm/loadcell.hpp | 33 +++++----- 13 files changed, 233 insertions(+), 225 deletions(-) create mode 100644 apps/openmw/mwworld/store.cpp diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 1be669ae0..86978c9b1 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -213,8 +213,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat StringsVector plugin = variables["plugin"].as(); // Removed check for 255 files, which would be the hard-coded limit in Morrowind. - // I'll keep the following variable in, maybe we can use it for somethng different. - int cnt = master.size() + plugin.size(); + // I'll keep the following variable in, maybe we can use it for something different. + // Say, a feedback like "loading file x/cnt". + // Commenting this out for now to silence compiler warning. + //int cnt = master.size() + plugin.size(); // Prepare loading master/plugin files (i.e. send filenames to engine) for (std::vector::size_type i = 0; i < master.size(); i++) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 7e421dc55..59c62e37d 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -42,30 +42,30 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) cellStore.mContainers.mList.begin()); iter!=cellStore.mContainers.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mCreatures.mList.begin()); iter!=cellStore.mCreatures.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mNpcs.mList.begin()); iter!=cellStore.mNpcs.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 7f1cdc469..baf4fea32 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -10,6 +10,41 @@ namespace MWWorld { + + template + void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + { + // Get existing reference, in case we need to overwrite it. + typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum); + + // Skip this when reference was deleted. + // TODO: Support respawning references, in this case, we need to track it somehow. + if (ref.mDeleted) { + mList.erase(iter); + return; + } + + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.search(ref.mRefID); + + /// \note no longer redundant - changed to Store::search(), don't throw + /// an exception on miss, try to continue (that's how MW does it, anyway) + if (ptr == NULL) { + std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; + } else { + if (iter != mList.end()) + *iter = LiveRef(ref, ptr); + else + mList.push_back(LiveRef(ref, ptr)); + } + } + + template bool operator==(const LiveCellRef& ref, int pRefnum) + { + return (ref.mRef.mRefnum == pRefnum); + } + CellStore::CellStore (const ESM::Cell *cell) : mCell (cell), mState (State_Unloaded) { @@ -95,7 +130,8 @@ namespace MWWorld { // Don't load reference if it was moved to a different cell. std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); - if (mCell->mMovedRefs.find(ref.mRefnum) != mCell->mMovedRefs.end()) { + ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); + if (iter != mCell->mMovedRefs.end()) { continue; } int rec = store.find(ref.mRefID); @@ -141,8 +177,8 @@ namespace MWWorld for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++) { // Doesn't seem to work in one line... huh? Too sleepy to check... - //const ESM::CellRef &ref0 = it->second; - ESM::CellRef &ref = const_cast(it->second); + ESM::CellRef &ref = const_cast(*it); + //ESM::CellRef &ref = const_cast(it->second); std::string lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cbaf56458..c182f196b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,11 +9,12 @@ #include "refdata.hpp" #include "esmstore.hpp" +struct C; namespace MWWorld { class Ptr; class ESMStore; - + /// A reference to one object (of any type) in a cell. /// /// Constructing this with a CellRef instance in the constructor means that @@ -42,88 +43,25 @@ namespace MWWorld /// runtime-data RefData mData; }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template struct CellRefList { typedef LiveCellRef LiveRef; - typedef std::map List; + typedef std::list List; List mList; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is // found. If not, throw an exception. - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // Skip this when reference was deleted. - // TODO: Support respawning references, in this case, we need to track it somehow. - if (ref.mDeleted) { - mList.erase(ref.mRefnum); - return; - } - - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.search(ref.mRefID); - - /// \note no longer redundant - changed to Store::search(), don't throw - /// an exception on miss, try to continue (that's how MW does it, anyway) - if (ptr == NULL) { - std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; - } else - mList[ref.mRefnum] = LiveRef(ref, ptr); - } - - LiveRef *find (const std::string& name) - { - for (typename std::map::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - { - if (iter->second.mData.getCount() > 0 && iter->second.mRef.mRefID == name) - return &iter->second; - } - - return 0; - } - - LiveRef &insert(const LiveRef &item) { - mList[item.mRef.mRefnum] = item; - return mList[item.mRef.mRefnum]; - } - }; - - /// A list of container references. These references do not track their mRefnumber. - /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects - /// with the same reference. - /// Unfortunately, this also means that we need a different STL container. - /// (cells use CellRefList, where refs can be located according to their refnumner, - /// which uses a map; container items do not make use of the refnumber, so we - /// can't use a map with refnumber keys.) - template - struct ContainerRefList - { - typedef LiveCellRef LiveRef; - typedef std::list List; - List mList; - - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.find(ref.mRefID); - - /// \note redundant because Store::find() throws exception on miss - if (ptr == NULL) { - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - } - mList.push_back(LiveRef(ref, ptr)); - } + // Moved to cpp file, as we require a custom compare operator for it, + // and the build will fail with an ugly three-way cyclic header dependence + // so we need to pass the instantiation of the method to the lnker, when + // all methods are known. + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { @@ -236,7 +174,7 @@ namespace MWWorld { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) - if (!functor (iter->second.mRef, iter->second.mData)) + if (!functor (iter->mRef, iter->mData)) return false; return true; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 36addee86..bca4073b5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -21,11 +21,11 @@ namespace { template - float getTotalWeight (const MWWorld::ContainerRefList& cellRefList) + float getTotalWeight (const MWWorld::CellRefList& cellRefList) { float sum = 0; - for (typename MWWorld::ContainerRefList::List::const_iterator iter ( + for (typename MWWorld::CellRefList::List::const_iterator iter ( cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) @@ -300,29 +300,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 63695c0df..e4f75d547 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -37,18 +37,18 @@ namespace MWWorld private: - MWWorld::ContainerRefList potions; - MWWorld::ContainerRefList appas; - MWWorld::ContainerRefList armors; - MWWorld::ContainerRefList books; - MWWorld::ContainerRefList clothes; - MWWorld::ContainerRefList ingreds; - MWWorld::ContainerRefList lights; - MWWorld::ContainerRefList lockpicks; - MWWorld::ContainerRefList miscItems; - MWWorld::ContainerRefList probes; - MWWorld::ContainerRefList repairs; - MWWorld::ContainerRefList weapons; + MWWorld::CellRefList potions; + MWWorld::CellRefList appas; + MWWorld::CellRefList armors; + MWWorld::CellRefList books; + MWWorld::CellRefList clothes; + MWWorld::CellRefList ingreds; + MWWorld::CellRefList lights; + MWWorld::CellRefList lockpicks; + MWWorld::CellRefList miscItems; + MWWorld::CellRefList probes; + MWWorld::CellRefList repairs; + MWWorld::CellRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -120,18 +120,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - MWWorld::ContainerRefList::List::iterator mPotion; - MWWorld::ContainerRefList::List::iterator mApparatus; - MWWorld::ContainerRefList::List::iterator mArmor; - MWWorld::ContainerRefList::List::iterator mBook; - MWWorld::ContainerRefList::List::iterator mClothing; - MWWorld::ContainerRefList::List::iterator mIngredient; - MWWorld::ContainerRefList::List::iterator mLight; - MWWorld::ContainerRefList::List::iterator mLockpick; - MWWorld::ContainerRefList::List::iterator mMiscellaneous; - MWWorld::ContainerRefList::List::iterator mProbe; - MWWorld::ContainerRefList::List::iterator mRepair; - MWWorld::ContainerRefList::List::iterator mWeapon; + MWWorld::CellRefList::List::iterator mPotion; + MWWorld::CellRefList::List::iterator mApparatus; + MWWorld::CellRefList::List::iterator mArmor; + MWWorld::CellRefList::List::iterator mBook; + MWWorld::CellRefList::List::iterator mClothing; + MWWorld::CellRefList::List::iterator mIngredient; + MWWorld::CellRefList::List::iterator mLight; + MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mMiscellaneous; + MWWorld::CellRefList::List::iterator mProbe; + MWWorld::CellRefList::List::iterator mRepair; + MWWorld::CellRefList::List::iterator mWeapon; private: @@ -142,18 +142,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 91622c354..5ec5ca9b5 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -17,9 +17,9 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -34,7 +34,7 @@ namespace iter!=cellRefList.mList.end(); ++iter) { - MWWorld::Ptr containerPtr (&iter->second, cell); + MWWorld::Ptr containerPtr (&*iter, cell); MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 768ca9e11..b917a8916 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -23,7 +23,7 @@ namespace if (!cellRefList.mList.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&cellRefList.mList.begin()->second, &cell)); + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); int numRefs = cellRefList.mList.size(); int current = 0; @@ -33,9 +33,9 @@ namespace MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; - if (it->second.mData.getCount() || it->second.mData.isEnabled()) + if (it->mData.getCount() || it->mData.isEnabled()) { - MWWorld::Ptr ptr (&it->second, &cell); + MWWorld::Ptr ptr (&*it, &cell); try { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp new file mode 100644 index 000000000..005601cd1 --- /dev/null +++ b/apps/openmw/mwworld/store.cpp @@ -0,0 +1,65 @@ +#include "store.hpp" + +namespace MWWorld { + + +void Store::load(ESM::ESMReader &esm, const std::string &id) +{ + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell *cell = new ESM::Cell; + cell->mName = id; + + // The cell itself takes care of some of the hairy details + cell->load(esm, *mEsmStore); + + if(cell->mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mInt[idLower] = *cell; + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // merge lists of leased references, use newer data in case of conflict + 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 + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + } + cell->mMovedRefs = oldcell->mMovedRefs; + // have new cell replace old cell + *oldcell = *cell; + } else + mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; + } + delete cell; +} + +} \ No newline at end of file diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dbad7432f..cb18873cc 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,7 +187,7 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - typename std::map::const_iterator it = mStatic.find(item.mId); + typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); @@ -523,62 +523,12 @@ namespace MWWorld } } - void load(ESM::ESMReader &esm, const std::string &id) { - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded! So first, proceed as usual. - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm, *mEsmStore); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // have new cell replace old cell - *oldcell = *cell; - } else - mInt[idLower] = *cell; - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // merge lists of leased references, use newer data in case of conflict - 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 - if (oldcell->mMovedRefs.find(it->second.mRefnum) != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = oldcell->mMovedRefs[it->second.mRefnum]; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - wipecell->mLeasedRefs.erase(it->second.mRefnum); - } - oldcell->mMovedRefs[it->second.mRefnum] = it->second; - } - cell->mMovedRefs = oldcell->mMovedRefs; - // have new cell replace old cell - *oldcell = *cell; - } else - mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; - } - delete cell; - } - + // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get + // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. + // There some nasty three-way cyclic header dependency involved, which I could only fix by moving + // this method. + void load(ESM::ESMReader &esm, const std::string &id); + iterator intBegin() const { return iterator(mSharedInt.begin()); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 62b4f3037..db4fb67ff 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -33,13 +33,13 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - if (const ESM::Script *script = store.get().find (iter->second.mBase->mScript)) + if (const ESM::Script *script = store.get().find (iter->mBase->mScript)) { iter->mData.setLocals (*script); - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -53,10 +53,10 @@ namespace for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter) { - if (iter->second.mData.getCount() > 0 && iter->second.mData.getBaseNode()){ - if (iter->second.mData.getHandle()==handle) + if (iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ + if (iter->mData.getHandle()==handle) { - return &iter->second; + return &*iter; } } } @@ -1261,7 +1261,7 @@ namespace MWWorld CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = it->second; + MWWorld::LiveCellRef& ref = *it; if (ref.mRef.mTeleport) { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 76a1e4f95..7400fd026 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,6 +14,17 @@ namespace ESM { +/// Some overloaded copare operators. +bool operator==(const MovedCellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + +bool operator==(const CellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + void CellRef::save(ESMWriter &esm) { esm.writeHNT("FRMR", mRefnum); @@ -134,13 +145,14 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) (int(*)(int)) std::tolower); // Add data required to make reference appear in the correct cell. - /* - std::cout << "Moving refnumber! First cell: " << mData.mX << " " << mData.mY << std::endl; - std::cout << " New cell: " << cMRef.mTarget[0] << " " << cMRef.mTarget[0] << std::endl; - std::cout << "Refnumber (MVRF): " << cMRef.mRefnum << " (FRMR) " << ref.mRefnum << std::endl; - */ - mMovedRefs[cMRef.mRefnum] = cMRef; - cellAlt->mLeasedRefs[ref.mRefnum] = ref; + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; } // Save position of the cell references and move on diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 6862dbc5c..27bdd77ce 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -6,7 +6,7 @@ #include "esmcommon.hpp" #include "defs.hpp" -#include +#include "apps/openmw/mwbase/world.hpp" /* namespace MWWorld { @@ -95,24 +95,29 @@ public: }; /* Moved cell reference tracking object. This mainly stores the target cell - of the reference, so we can easily know where it has been moved when another - plugin tries to move it independently. - */ + of the reference, so we can easily know where it has been moved when another + plugin tries to move it independently. + Unfortunately, we need to implement this here. + */ class MovedCellRef { public: - int mRefnum; - - // Target cell (if exterior) - int mTarget[2]; - - // TODO: Support moving references between exterior and interior cells! - // This may happen in saves, when an NPC follows the player. Tribunal - // introduces a henchman (which no one uses), so we may need this as well. + int mRefnum; + + // Target cell (if exterior) + int mTarget[2]; + + // TODO: Support moving references between exterior and interior cells! + // This may happen in saves, when an NPC follows the player. Tribunal + // introduces a henchman (which no one uses), so we may need this as well. }; -typedef std::map MovedCellRefTracker; -typedef std::map CellRefTracker; +/// Overloaded copare operator used to search inside a list of cell refs. +bool operator==(const MovedCellRef& ref, int pRefnum); +bool operator==(const CellRef& ref, int pRefnum); + +typedef std::list MovedCellRefTracker; +typedef std::list CellRefTracker; /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently