diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 2a302e082..91233cf70 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -31,6 +31,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) ESM::Dialogue *dialogue = 0; + // Land texture loading needs to use a separate internal store for each plugin. + // We set the number of plugins here to avoid continual resizes during loading, + // and so we can properly verify if valid plugin indices are being passed to the + // LandTexture Store retrieval methods. + mLandTextures.resize(esm.getGlobalReaderList()->size()); + /// \todo Move this to somewhere else. ESMReader? // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 767a33b13..925e9c605 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -96,6 +96,245 @@ void Store::load(ESM::ESMReader &esm) wipecell->mLeasedRefs.erase(it_lease); *itold = *it; } + ++sharedIter; + } + mStatic.erase(it); + } + + return true; + } + + template + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + typename Dynamic::iterator it = mDynamic.find(key); + if (it == mDynamic.end()) { + return false; + } + mDynamic.erase(it); + + // have to reinit the whole shared part + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { + mShared.push_back(&it->second); + } + return true; + } + template + bool Store::erase(const T &item) + { + return erase(item.mId); + } + template + void Store::write (ESM::ESMWriter& writer, Loading::Listener& progress) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + template + RecordId Store::read(ESM::ESMReader& reader) + { + T record; + bool isDeleted = false; + + record.load (reader, isDeleted); + insert (record); + + return RecordId(record.mId, isDeleted); + } + + // LandTexture + //========================================================================= + Store::Store() + { + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); + } + const ESM::LandTexture *Store::search(size_t index, size_t plugin) const + { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + if (index >= ltexl.size()) + return NULL; + return <exl[index]; + } + const ESM::LandTexture *Store::find(size_t index, size_t plugin) const + { + const ESM::LandTexture *ptr = search(index, plugin); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land texture with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + size_t Store::getSize() const + { + return mStatic.size(); + } + size_t Store::getSize(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } + RecordId Store::load(ESM::ESMReader &esm, size_t plugin) + { + ESM::LandTexture lt; + bool isDeleted = false; + + lt.load(esm, isDeleted); + + assert(plugin < mStatic.size()); + + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; + + return RecordId(lt.mId, isDeleted); + } + RecordId Store::load(ESM::ESMReader &esm) + { + return load(esm, esm.getIndex()); + } + Store::iterator Store::begin(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + Store::iterator Store::end(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); + } + void Store::resize(size_t num) + { + if (mStatic.size() < num) + mStatic.resize(num); + } + + // Land + //========================================================================= + Store::~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return iterator(mStatic.begin()); + } + Store::iterator Store::end() const + { + return iterator(mStatic.end()); + } + ESM::Land *Store::search(int x, int y) const + { + ESM::Land land; + land.mX = x, land.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); + + if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { + return const_cast(*it); + } + return 0; + } + ESM::Land *Store::find(int x, int y) const + { + ESM::Land *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + RecordId Store::load(ESM::ESMReader &esm) + { + ESM::Land *ptr = new ESM::Land(); + bool isDeleted = false; + + ptr->load(esm, isDeleted); + + // Same area defined in multiple plugins? -> last plugin wins + // Can't use search() because we aren't sorted yet - is there any other way to speed this up? + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) + { + delete *it; + mStatic.erase(it); + break; + } + } + + mStatic.push_back(ptr); + + return RecordId("", isDeleted); + } + void Store::setUp() + { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + + + // Cell + //========================================================================= + + const ESM::Cell *Store::search(const ESM::Cell &cell) const + { + if (cell.isExterior()) { + return search(cell.getGridX(), cell.getGridY()); + } + return search(cell.mName); + } + void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) + { + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + bool deleted = false; + cell->getNextRef(esm, ref, 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. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + if (!deleted) + { + 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 oldcell->mMovedRefs.push_back(*it); } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index ff0ca0159..5cc66981c 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -434,9 +434,11 @@ namespace MWWorld assert(plugin < mStatic.size()); const LandTextureList <exl = mStatic[plugin]; - assert(index < ltexl.size()); - return <exl.at(index); - } + /// Resize the internal store to hold at least \a num plugins. + void resize(size_t num); + + size_t getSize() const; + size_t getSize(size_t plugin) const; const ESM::LandTexture *find(size_t index, size_t plugin) const { const ESM::LandTexture *ptr = search(index, plugin);