From 1d03b5469412a1bad3b2357e3919ea00d09aec06 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 2 May 2023 22:37:18 +0200 Subject: [PATCH] maps with tuple key instead of map of map instead of using a map with key as exterior and map of , Cell as value we use a single map with a tuple x,y,exterior as key --- apps/openmw/mwworld/store.cpp | 23 ++++------- apps/openmw/mwworld/store.hpp | 5 ++- apps/openmw/mwworld/worldmodel.cpp | 66 +++++++++++++----------------- apps/openmw/mwworld/worldmodel.hpp | 4 +- components/esm/util.hpp | 37 +++++++++++++++++ 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index be6196c3fb..23d32a9707 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1107,30 +1107,21 @@ namespace MWWorld const ESM4::Cell* Store::searchExterior(int x, int y, ESM::RefId worldSpace) const { - const auto foundWorldSpace = mExteriors.find(worldSpace); - if (foundWorldSpace == mExteriors.end()) - { - return nullptr; - } - const auto foundCell = foundWorldSpace->second.find(std::make_pair(x, y)); - if (foundCell == foundWorldSpace->second.end()) + const auto foundCell = mExteriors.find({ x, y, worldSpace }); + if (foundCell == mExteriors.end()) return nullptr; return foundCell->second; } - bool Store::exteriorExists(ESM::RefId worldspace) const - { - const auto foundWorldSpace = mExteriors.find(worldspace); - return (foundWorldSpace != mExteriors.end()); - } - ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) { auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); if (!cellPtr->mEditorId.empty()) mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) - mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + { + mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; + } return cellPtr; } @@ -1141,7 +1132,7 @@ namespace MWWorld if (!cellPtr->mEditorId.empty()) mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) - mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; return cellPtr; } @@ -1153,7 +1144,7 @@ namespace MWWorld ESM4::Cell& cellToDelete = cellToDeleteIt.second; if (cellToDelete.isExterior()) { - mExteriors[cellToDelete.mParent].erase(std::make_pair(cellToDelete.mX, cellToDelete.mY)); + mExteriors.erase({ cellToDelete.mX, cellToDelete.mY, cellToDelete.mParent }); } if (!cellToDelete.mEditorId.empty()) mCellNameIndex.erase(cellToDelete.mEditorId); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index b17fde68b6..a60842eb95 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -283,12 +284,12 @@ namespace MWWorld { std::unordered_map mCellNameIndex; - std::unordered_map, ESM4::Cell*>> mExteriors; + + std::unordered_map mExteriors; public: const ESM4::Cell* searchCellName(std::string_view) const; const ESM4::Cell* searchExterior(int x, int y, ESM::RefId worldSpace) const; - bool exteriorExists(ESM::RefId worldspace) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); void clearDynamic() override; diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 90a065d9eb..e155a45b09 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -76,12 +76,11 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) } else { - auto& Esm3Exteriors = mExteriors[ESM::Cell::sDefaultWorldspaceId]; - std::map, CellStore*>::iterator result - = Esm3Exteriors.find(std::make_pair(cell->getGridX(), cell->getGridY())); + ESM::ExteriorCellIndex extIndex = { cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId }; + std::map::iterator result = mExteriors.find(extIndex); - if (result == Esm3Exteriors.end()) - result = Esm3Exteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first; + if (result == mExteriors.end()) + result = mExteriors.emplace(extIndex, cellStore).first; return *result->second; } @@ -163,14 +162,14 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId exteriorWorldspace) { - auto foundWorldspace = mExteriors.find(exteriorWorldspace); - std::map, CellStore*>::iterator result; - if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) - { - auto& esm3Exteriors = mExteriors[exteriorWorldspace]; - result = esm3Exteriors.find(std::make_pair(x, y)); + std::map::iterator result; + ESM::ExteriorCellIndex extIndex = { x, y, exteriorWorldspace }; + + result = mExteriors.find({ x, y, exteriorWorldspace }); - if (result == esm3Exteriors.end()) + if (result == mExteriors.end()) + { + if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) { const ESM::Cell* cell = mStore.get().search(x, y); @@ -190,21 +189,15 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = esm3Exteriors.emplace(std::make_pair(x, y), cellStore).first; + result = mExteriors.emplace(extIndex, cellStore).first; } - } - else - { - const Store& cell4Store = mStore.get(); - if (cell4Store.exteriorExists(exteriorWorldspace)) + else { - auto& exteriors = mExteriors[exteriorWorldspace]; - - result = exteriors.find(std::make_pair(x, y)); - - if (result == exteriors.end()) + const Store& cell4Store = mStore.get(); + bool exteriorExists = mStore.get().search(exteriorWorldspace); + const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); + if (exteriorExists) { - const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); if (!cell) { ESM4::Cell record; @@ -216,15 +209,14 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex } CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = exteriors.emplace(std::make_pair(x, y), cellStore).first; + result = mExteriors.emplace(extIndex, cellStore).first; + } + else + { + throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); } - } - else - { - throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); } } - if (result->second->getState() != CellStore::State_Loaded) { result->second->load(); @@ -287,7 +279,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) { std::pair coord = std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY()); - mExteriors[newCellStore->getCell()->getWorldSpace()].emplace(coord, newCellStore); + ESM::ExteriorCellIndex extIndex = { coord.first, coord.second, newCellStore->getCell()->getWorldSpace() }; + mExteriors.emplace(extIndex, newCellStore); } else { @@ -382,14 +375,11 @@ MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name) // Then check cells that are already listed // Search in reverse, this is a workaround for an ambiguous chargen_plank reference in the vanilla game. // there is one at -22,16 and one at -2,-9, the latter should be used. - for (auto iterExt = mExteriors.rbegin(); iterExt != mExteriors.rend(); ++iterExt) + for (auto iter = mExteriors.rbegin(); iter != mExteriors.rend(); ++iter) { - for (auto iter = iterExt->second.rbegin(); iter != iterExt->second.rend(); iter++) - { - Ptr ptr = getPtrAndCache(name, *iter->second); - if (!ptr.isEmpty()) - return ptr; - } + Ptr ptr = getPtrAndCache(name, *iter->second); + if (!ptr.isEmpty()) + return ptr; } for (auto iter = mInteriors.begin(); iter != mInteriors.end(); ++iter) diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 464cc89d18..7506d93292 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "cellstore.hpp" @@ -42,7 +43,8 @@ namespace MWWorld ESM::ReadersCache& mReaders; mutable std::unordered_map mCells; mutable std::map mInteriors; - mutable std::map, CellStore*>> mExteriors; + + mutable std::map mExteriors; IdCache mIdCache; std::size_t mIdCacheIndex = 0; std::unordered_map mPtrIndex; diff --git a/components/esm/util.hpp b/components/esm/util.hpp index b1a40bd015..9014f31ab2 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace ESM { @@ -42,6 +44,41 @@ namespace ESM operator osg::Vec3f() const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); } }; + struct ExteriorCellIndex + { + int mX, mY; + ESM::RefId mWorldspace; + + bool operator==(const ExteriorCellIndex& other) const + { + return mX == other.mX && mY == other.mY && mWorldspace == other.mWorldspace; + } + + bool operator<(const ExteriorCellIndex& other) const + { + return std::make_tuple(mX, mY, mWorldspace) < std::make_tuple(other.mX, other.mY, other.mWorldspace); + } + + friend struct std::hash; + }; + +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(const ESM::ExteriorCellIndex& toHash) const + { + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return ((hash()(toHash.mX) ^ (hash()(toHash.mY) << 1)) >> 1) + ^ (hash()(toHash.mWorldspace) << 1); + } + }; } #endif