From 36502eaf752453b31cad2c6fd89b21ebb886f7c0 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 18 Feb 2023 22:32:27 +0100 Subject: [PATCH 01/19] ESM3 Cells have an Id. Store is updated to use it. --- apps/openmw/mwworld/cell.cpp | 2 + apps/openmw/mwworld/cell.hpp | 2 + apps/openmw/mwworld/store.cpp | 76 +++++++++++-------- apps/openmw/mwworld/store.hpp | 7 +- apps/openmw/mwworld/worldmodel.cpp | 1 + apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- components/esm3/loadcell.cpp | 14 ++++ components/esm3/loadcell.hpp | 3 +- 8 files changed, 71 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 56b7c1a49a..fa35af41a3 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -20,6 +20,7 @@ namespace MWWorld .mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) }, .mIndex{ cell.getGridX(), cell.getGridY() }, .mPaged = isExterior(),} + , mId(cell.mId) ,mMood{ .mAmbiantColor = cell.mLighting.ambient, .mDirectionalColor = cell.mLighting.directional, @@ -41,6 +42,7 @@ namespace MWWorld , mNameID(cell.mName) , mRegion(cell.mRegion) , mCellId(cell.getCellId()) + , mId(cell.mId) , mMood{ .mAmbiantColor = cell.mAmbi.mAmbient, .mDirectionalColor = cell.mAmbi.mSunlight, diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 52823d4dab..818968fabb 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -49,6 +49,7 @@ namespace MWWorld std::string getDescription() const; const MoodData& getMood() const { return mMood; } float getWaterHeight() const { return mWaterHeight; } + const ESM::RefId& getId() const { return mId; }; private: bool mIsExterior; @@ -61,6 +62,7 @@ namespace MWWorld std::string mNameID; // The name that will be used by the script and console commands ESM::RefId mRegion; ESM::CellId mCellId; + ESM::RefId mId; MoodData mMood; float mWaterHeight; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index dce24bfec6..bd0ef53e24 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -468,13 +468,17 @@ namespace MWWorld // Cell //========================================================================= + const ESM::Cell* Store::search(const ESM::RefId& cellId) const + { + auto foundCellIt = mCells.find(cellId); + if (foundCellIt == mCells.end()) + return &foundCellIt->second; + return nullptr; + } + const ESM::Cell* Store::search(const ESM::Cell& cell) const { - if (cell.isExterior()) - { - return search(cell.getGridX(), cell.getGridY()); - } - return search(cell.mName); + return search(cell.mId); } // this method *must* be called right after esm3.loadCell() @@ -521,13 +525,13 @@ namespace MWWorld DynamicInt::const_iterator it = mInt.find(name); if (it != mInt.end()) { - return &(it->second); + return it->second; } DynamicInt::const_iterator dit = mDynamicInt.find(name); if (dit != mDynamicInt.end()) { - return &dit->second; + return dit->second; } return nullptr; @@ -537,11 +541,11 @@ namespace MWWorld std::pair key(x, y); DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) - return &(it->second); + return it->second; DynamicExt::const_iterator dit = mDynamicExt.find(key); if (dit != mDynamicExt.end()) - return &dit->second; + return dit->second; return nullptr; } @@ -549,7 +553,7 @@ namespace MWWorld { DynamicExt::const_iterator it = mExt.find(std::make_pair(x, y)); if (it != mExt.end()) - return &(it->second); + return (it->second); return nullptr; } const ESM::Cell* Store::searchOrCreate(int x, int y) @@ -557,11 +561,11 @@ namespace MWWorld std::pair key(x, y); DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) - return &(it->second); + return (it->second); DynamicExt::const_iterator dit = mDynamicExt.find(key); if (dit != mDynamicExt.end()) - return &dit->second; + return dit->second; ESM::Cell newCell; newCell.mData.mX = x; @@ -574,8 +578,11 @@ namespace MWWorld newCell.mCellId.mPaged = true; newCell.mCellId.mIndex.mX = x; newCell.mCellId.mIndex.mY = y; + newCell.updateId(); + + ESM::Cell* newCellInserted = &mCells.insert(std::make_pair(newCell.mId, newCell)).first->second; - return &mExt.insert(std::make_pair(key, newCell)).first->second; + return mExt.insert(std::make_pair(key, newCellInserted)).first->second; } const ESM::Cell* Store::find(std::string_view id) const { @@ -607,12 +614,12 @@ namespace MWWorld mSharedInt.clear(); mSharedInt.reserve(mInt.size()); for (auto& [_, cell] : mInt) - mSharedInt.push_back(&cell); + mSharedInt.push_back(cell); mSharedExt.clear(); mSharedExt.reserve(mExt.size()); for (auto& [_, cell] : mExt) - mSharedExt.push_back(&cell); + mSharedExt.push_back(cell); } RecordId Store::load(ESM::ESMReader& esm) { @@ -622,13 +629,17 @@ namespace MWWorld // are not available until both cells have been loaded at least partially! // All cells have a name record, even nameless exterior cells. - ESM::Cell cell; + ESM::Cell* emplacedCell = nullptr; bool isDeleted = false; + { + ESM::Cell cellToLoad; + cellToLoad.loadNameAndData(esm, isDeleted); + emplacedCell = &mCells.insert(std::make_pair(cellToLoad.mId, cellToLoad)).first->second; + } + ESM::Cell& cell = *emplacedCell; // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with - cell.loadNameAndData(esm, isDeleted); - if (cell.mData.mFlags & ESM::Cell::Interior) { // Store interior cell by name, try to merge with existing parent data. @@ -647,7 +658,7 @@ namespace MWWorld // spawn a new cell cell.loadCell(esm, true); - mInt[cell.mName] = cell; + mInt[cell.mName] = &cell; } } else @@ -700,19 +711,19 @@ namespace MWWorld else { // spawn a new cell - cell.loadCell(esm, false); + emplacedCell->loadCell(esm, false); // handle moved ref (MVRF) subrecords - handleMovedCellRefs(esm, &cell); + handleMovedCellRefs(esm, emplacedCell); // push the new references on the list of references to manage - cell.postLoad(esm); + emplacedCell->postLoad(esm); - mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = &cell; } } - return RecordId(ESM::RefId::stringRefId(cell.mName), isDeleted); + return RecordId(cell.mId, isDeleted); } Store::iterator Store::intBegin() const { @@ -785,6 +796,7 @@ namespace MWWorld } ESM::Cell* Store::insert(const ESM::Cell& cell) { + ESM::Cell* insertedCell = &mCells.emplace(cell.mId, cell).first->second; if (search(cell) != nullptr) { const std::string cellType = (cell.isExterior()) ? "exterior" : "interior"; @@ -795,16 +807,16 @@ namespace MWWorld std::pair key(cell.getGridX(), cell.getGridY()); // duplicate insertions are avoided by search(ESM::Cell &) - DynamicExt::iterator result = mDynamicExt.emplace(key, cell).first; - mSharedExt.push_back(&result->second); - return &result->second; + DynamicExt::iterator result = mDynamicExt.emplace(key, insertedCell).first; + mSharedExt.push_back(result->second); + return result->second; } else { // duplicate insertions are avoided by search(ESM::Cell &) - DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, cell).first; - mSharedInt.push_back(&result->second); - return &result->second; + DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, insertedCell).first; + mSharedInt.push_back(result->second); + return result->second; } } bool Store::erase(const ESM::Cell& cell) @@ -828,7 +840,7 @@ namespace MWWorld for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { - mSharedInt.push_back(&it->second); + mSharedInt.push_back(it->second); } return true; @@ -847,7 +859,7 @@ namespace MWWorld for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { - mSharedExt.push_back(&it->second); + mSharedExt.push_back(it->second); } return true; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index bb511f9635..b73aea0924 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -347,10 +347,12 @@ namespace MWWorld } }; - typedef std::unordered_map + typedef std::unordered_map DynamicInt; - typedef std::map, ESM::Cell, DynamicExtCmp> DynamicExt; + typedef std::map, ESM::Cell*, DynamicExtCmp> DynamicExt; + + std::unordered_map mCells; DynamicInt mInt; DynamicExt mExt; @@ -367,6 +369,7 @@ namespace MWWorld public: typedef SharedIterator iterator; + const ESM::Cell* search(const ESM::RefId& id) const; const ESM::Cell* search(std::string_view id) const; const ESM::Cell* search(int x, int y) const; const ESM::Cell* searchStatic(int x, int y) const; diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 79d59de902..506919f177 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -180,6 +180,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) record.mData.mY = y; record.mWater = 0; record.mMapColor = 0; + record.updateId(); cell = MWBase::Environment::get().getWorld()->createRecord(record); } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 90294aadaa..4539478e17 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -562,7 +562,7 @@ namespace REGISTER_TYPED_TEST_SUITE_P(StoreSaveLoadTest, shouldNotChangeRefId); - static_assert(std::tuple_size_v == 38); + static_assert(std::tuple_size_v == 39); INSTANTIATE_TYPED_TEST_SUITE_P( RecordTypesTest, StoreSaveLoadTest, typename AsTestingTypes::Type); diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index a35db8cc1a..1c4477acfd 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -57,6 +57,19 @@ namespace ESM loadCell(esm, saveContext); } + const ESM::RefId& Cell::updateId() + { + if (isExterior()) + { + mId = ESM::RefId::stringRefId("#" + std::to_string(mData.mX) + "," + std::to_string(mData.mY)); + } + else + { + mId = ESM::RefId::stringRefId(mName); + } + return mId; + } + void Cell::loadNameAndData(ESMReader& esm, bool& isDeleted) { isDeleted = false; @@ -105,6 +118,7 @@ namespace ESM mCellId.mIndex.mX = 0; mCellId.mIndex.mY = 0; } + updateId(); } void Cell::loadCell(ESMReader& esm, bool saveContext) diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 3cf1834dfa..f49f4f083a 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -110,7 +110,7 @@ namespace ESM , mRefNumCounter(0) { } - + ESM::RefId mId; // Interior cells are indexed by this (it's the 'id'), for exterior // cells it is optional. std::string mName; @@ -192,6 +192,7 @@ namespace ESM ///< Set record to default state (does not touch the ID/index). const CellId& getCellId() const; + const ESM::RefId& updateId(); }; } #endif From 96e42d1666ef621a6d796f9cb0001c4b2e1cb76d Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 18 Feb 2023 23:42:20 +0100 Subject: [PATCH 02/19] Cellstore uses RefId. --- apps/openmw/mwworld/cellstore.cpp | 14 +----- apps/openmw/mwworld/worldmodel.cpp | 68 +++++++++++++----------------- apps/openmw/mwworld/worldmodel.hpp | 9 ++-- 3 files changed, 34 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c41bb7c518..cd303c1ef7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1122,21 +1122,9 @@ namespace MWWorld } } - struct IsEqualVisitor - { - bool operator()(const ESM::Cell& a, const ESM::Cell& b) const { return a.getCellId() == b.getCellId(); } - bool operator()(const ESM4::Cell& a, const ESM4::Cell& b) const { return a.mId == b.mId; } - - template - bool operator()(const L&, const R&) const - { - return false; - } - }; - bool CellStore::operator==(const CellStore& right) const { - return ESM::visit(IsEqualVisitor(), this->mCellVariant, right.mCellVariant); + return right.mCellVariant.getId() == mCellVariant.getId(); } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 506919f177..ef8cad2b58 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -20,7 +20,8 @@ namespace { template - bool forEachInStore(const ESM::RefId& id, Visitor&& visitor, std::map& cellStore) + bool forEachInStore( + const ESM::RefId& id, Visitor&& visitor, std::unordered_map& cellStore) { for (auto& cell : cellStore) { @@ -62,27 +63,25 @@ namespace MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) { + CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; if (cell->mData.mFlags & ESM::Cell::Interior) { auto result = mInteriors.find(cell->mName); if (result == mInteriors.end()) - result = mInteriors.emplace(cell->mName, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first; + result = mInteriors.emplace(cell->mName, cellStore).first; - return &result->second; + return result->second; } else { - std::map, CellStore>::iterator result + std::map, CellStore*>::iterator result = mExteriors.find(std::make_pair(cell->getGridX(), cell->getGridY())); if (result == mExteriors.end()) - result = mExteriors - .emplace(std::make_pair(cell->getGridX(), cell->getGridY()), - CellStore(MWWorld::Cell(*cell), mStore, mReaders)) - .first; + result = mExteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first; - return &result->second; + return result->second; } } @@ -160,7 +159,7 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) { - std::map, CellStore>::iterator result = mExteriors.find(std::make_pair(x, y)); + std::map, CellStore*>::iterator result = mExteriors.find(std::make_pair(x, y)); if (result == mExteriors.end()) { @@ -185,15 +184,17 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) cell = MWBase::Environment::get().getWorld()->createRecord(record); } - result = mExteriors.emplace(std::make_pair(x, y), CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first; + CellStore* cellStore + = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; + result = mExteriors.emplace(std::make_pair(x, y), cellStore).first; } - if (result->second.getState() != CellStore::State_Loaded) + if (result->second->getState() != CellStore::State_Loaded) { - result->second.load(); + result->second->load(); } - return &result->second; + return result->second; } MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) @@ -203,24 +204,26 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) if (result == mInteriors.end()) { const ESM4::Cell* cell4 = mStore.get().searchCellName(name); - + CellStore* newCellStore = nullptr; if (!cell4) { const ESM::Cell* cell = mStore.get().find(name); - result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first; + newCellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; } else { - result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first; + newCellStore + = &mCells.emplace(cell4->mId, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first->second; } + result = mInteriors.emplace(name, newCellStore).first; } - if (result->second.getState() != CellStore::State_Loaded) + if (result->second->getState() != CellStore::State_Loaded) { - result->second.load(); + result->second->load(); } - return &result->second; + return result->second; } MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id) @@ -330,17 +333,17 @@ 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 (std::map, CellStore>::reverse_iterator iter = mExteriors.rbegin(); + for (std::map, CellStore*>::reverse_iterator iter = mExteriors.rbegin(); iter != mExteriors.rend(); ++iter) { - Ptr ptr = getPtrAndCache(name, iter->second); + Ptr ptr = getPtrAndCache(name, *iter->second); if (!ptr.isEmpty()) return ptr; } for (auto iter = mInteriors.begin(); iter != mInteriors.end(); ++iter) { - Ptr ptr = getPtrAndCache(name, iter->second); + Ptr ptr = getPtrAndCache(name, *iter->second); if (!ptr.isEmpty()) return ptr; } @@ -390,8 +393,7 @@ void MWWorld::WorldModel::getExteriorPtrs(const ESM::RefId& name, std::vector MWWorld::WorldModel::getAll(const ESM::RefId& id) { PtrCollector visitor; - if (forEachInStore(id, visitor, mInteriors)) - forEachInStore(id, visitor, mExteriors); + forEachInStore(id, visitor, mCells); return visitor.mPtrs; } @@ -399,12 +401,7 @@ int MWWorld::WorldModel::countSavedGameRecords() const { int count = 0; - for (auto iter(mInteriors.begin()); iter != mInteriors.end(); ++iter) - if (iter->second.hasState()) - ++count; - - for (std::map, CellStore>::const_iterator iter(mExteriors.begin()); iter != mExteriors.end(); - ++iter) + for (auto iter(mCells.begin()); iter != mCells.end(); ++iter) if (iter->second.hasState()) ++count; @@ -413,14 +410,7 @@ int MWWorld::WorldModel::countSavedGameRecords() const void MWWorld::WorldModel::write(ESM::ESMWriter& writer, Loading::Listener& progress) const { - for (std::map, CellStore>::iterator iter(mExteriors.begin()); iter != mExteriors.end(); ++iter) - if (iter->second.hasState()) - { - writeCell(writer, iter->second); - progress.increaseProgress(); - } - - for (auto iter(mInteriors.begin()); iter != mInteriors.end(); ++iter) + for (auto iter(mCells.begin()); iter != mCells.end(); ++iter) if (iter->second.hasState()) { writeCell(writer, iter->second); diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 909e85d25b..f2c5e0064a 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -42,8 +42,9 @@ namespace MWWorld typedef std::vector> IdCache; const MWWorld::ESMStore& mStore; ESM::ReadersCache& mReaders; - mutable std::map mInteriors; - mutable std::map, CellStore> mExteriors; + mutable std::unordered_map mCells; + mutable std::map mInteriors; + mutable std::map, CellStore*> mExteriors; IdCache mIdCache; std::size_t mIdCacheIndex = 0; std::unordered_map mPtrIndex; @@ -91,9 +92,7 @@ namespace MWWorld template void forEachLoadedCellStore(Fn&& fn) { - for (auto& [_, store] : mInteriors) - fn(store); - for (auto& [_, store] : mExteriors) + for (auto& [_, store] : mCells) fn(store); } From 3f678c3b0a1f70228f195608f089ee208937b664 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 19 Feb 2023 17:42:37 +0100 Subject: [PATCH 03/19] Dest Door and teleport use ESM::RefId This changes a lot of files as a consequence. Still buggy, moving to exterior doesn't bring to the right place yet coc "seyda neen" doesn't work. SO I broke somehting when fetching a cell from a name --- apps/openmw/mwbase/world.hpp | 16 ++- apps/openmw/mwclass/door.cpp | 13 +-- apps/openmw/mwgui/mapwindow.cpp | 22 ++-- apps/openmw/mwgui/mapwindow.hpp | 4 +- apps/openmw/mwgui/travelwindow.cpp | 8 +- apps/openmw/mwlua/types/door.cpp | 3 +- apps/openmw/mwmechanics/spelleffects.cpp | 4 +- apps/openmw/mwscript/cellextensions.cpp | 16 +-- apps/openmw/mwworld/actionteleport.cpp | 24 ++--- apps/openmw/mwworld/actionteleport.hpp | 4 +- apps/openmw/mwworld/cellref.cpp | 55 +++++++++- apps/openmw/mwworld/cellref.hpp | 12 +-- apps/openmw/mwworld/cellstore.cpp | 4 +- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/player.cpp | 4 +- apps/openmw/mwworld/scene.cpp | 10 +- apps/openmw/mwworld/store.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 131 ++++++++++++----------- apps/openmw/mwworld/worldimp.hpp | 9 +- apps/openmw/mwworld/worldmodel.cpp | 52 ++++++++- apps/openmw/mwworld/worldmodel.hpp | 3 +- components/esm3/cellid.cpp | 12 +++ components/esm3/cellid.hpp | 1 + components/esm3/custommarkerstate.cpp | 5 +- components/esm3/custommarkerstate.hpp | 3 +- components/esm3/loadcell.cpp | 9 +- 26 files changed, 258 insertions(+), 170 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5ebf8527c0..76b16e4cb0 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -114,7 +114,7 @@ namespace MWBase { std::string name; float x, y; // world position - ESM::CellId dest; + ESM::RefId dest; }; World() {} @@ -260,6 +260,9 @@ namespace MWBase virtual void changeToCell( const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) = 0; + virtual void changeToCell( + const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) + = 0; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes virtual MWWorld::Ptr getFacedObject() = 0; @@ -514,13 +517,16 @@ namespace MWBase virtual bool screenshot360(osg::Image* image) = 0; /// Find default position inside exterior cell specified by name - /// \return false if exterior with given name not exists, true otherwise - virtual bool findExteriorPosition(std::string_view name, ESM::Position& pos) = 0; + /// \return invalid RefId if exterior with given name not exists, the cell's RefId otherwise + virtual ESM::RefId findExteriorPosition(std::string_view name, ESM::Position& pos) = 0; /// Find default position inside interior cell specified by name - /// \return false if interior with given name not exists, true otherwise - virtual bool findInteriorPosition(std::string_view name, ESM::Position& pos) = 0; + /// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise + virtual ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) = 0; + /// Find default position inside interior or exterior cell specified by name + /// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise + virtual ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) = 0; /// Enables or disables use of teleport spell effects (recall, intervention, etc). virtual void enableTeleporting(bool enable) = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 35dec69694..30a756de0b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -23,6 +23,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/ptr.hpp" +#include "../mwworld/worldmodel.hpp" #include "../mwgui/tooltips.hpp" #include "../mwgui/ustring.hpp" @@ -298,16 +299,8 @@ namespace MWClass std::string Door::getDestination(const MWWorld::LiveCellRef& door) { - std::string_view dest = door.mRef.getDestCell(); - if (dest.empty()) - { - // door leads to exterior, use cell name (if any), otherwise translated region name - auto world = MWBase::Environment::get().getWorld(); - const osg::Vec2i index - = MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]); - const ESM::Cell* cell = world->getStore().get().search(index.x(), index.y()); - dest = world->getCellName(cell); - } + std::string_view dest + = MWBase::Environment::get().getWorldModel()->getCell(door.mRef.getDestCell())->getCell()->getDisplayName(); return "#{sCell=" + std::string{ dest } + "}"; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d94ada37e9..021cb5cc7d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -158,7 +158,7 @@ namespace MWGui return mMarkers.end(); } - CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId& cellId) const + CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::RefId& cellId) const { return mMarkers.equal_range(cellId); } @@ -356,8 +356,8 @@ namespace MWGui cellId.mWorldspace = (mInterior ? mPrefix : ESM::CellId::sDefaultWorldspace); cellId.mIndex.mX = mCurX + dX; cellId.mIndex.mY = mCurY + dY; - - CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + ESM::RefId cellRefId = cellId.getCellRefId(); + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) { @@ -885,16 +885,19 @@ namespace MWGui mEditingMarker.mWorldX = worldPos.x(); mEditingMarker.mWorldY = worldPos.y(); + ESM::CellId clickedId; - mEditingMarker.mCell.mPaged = !mInterior; + clickedId.mPaged = !mInterior; if (mInterior) - mEditingMarker.mCell.mWorldspace = LocalMapBase::mPrefix; + clickedId.mWorldspace = LocalMapBase::mPrefix; else { - mEditingMarker.mCell.mWorldspace = ESM::CellId::sDefaultWorldspace; - mEditingMarker.mCell.mIndex.mX = x; - mEditingMarker.mCell.mIndex.mY = y; + clickedId.mWorldspace = ESM::CellId::sDefaultWorldspace; + clickedId.mIndex.mX = x; + clickedId.mIndex.mY = y; } + mEditingMarker.mCell = clickedId.getCellRefId(); + mEditingMarker.mCellId = clickedId; mEditNoteDialog.setVisible(true); mEditNoteDialog.showDeleteButton(false); @@ -1125,7 +1128,8 @@ namespace MWGui cellId.mIndex.mY = y; cellId.mWorldspace = ESM::CellId::sDefaultWorldspace; cellId.mPaged = true; - CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + ESM::RefId cellRefId = cellId.getCellRefId(); + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); std::vector destNotes; for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) destNotes.push_back(it->second.mNote); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index c5a2083da0..93387c983a 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -56,14 +56,14 @@ namespace MWGui size_t size() const; - typedef std::multimap ContainerType; + typedef std::multimap ContainerType; typedef std::pair RangeType; ContainerType::const_iterator begin() const; ContainerType::const_iterator end() const; - RangeType getMarkers(const ESM::CellId& cellId) const; + RangeType getMarkers(const ESM::RefId& cellId) const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index f9dcbf9ce2..7798bf7105 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -195,9 +195,15 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); + ESM::CellId cellId; + osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]); + cellId.mPaged = !interior; + cellId.mWorldspace = Misc::StringUtils::lowerCase(cellname); + cellId.mIndex.mX = posCell.x(); + cellId.mIndex.mY = posCell.y(); // Teleports any followers, too. - MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); + MWWorld::ActionTeleport action(cellId.getCellRefId(), pos, true); action.execute(player); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0); diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index 9473ddf565..db54a77277 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -36,8 +36,7 @@ namespace MWLua const MWWorld::CellRef& cellRef = doorPtr(o).getCellRef(); if (!cellRef.getTeleport()) return sol::nil; - MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCellByPosition( - cellRef.getDoorDest().asVec3(), cellRef.getDestCell()); + MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell()); assert(cell); return o.getCell(lua, cell); }; diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index 31b82b4a14..34115bf882 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -487,9 +487,9 @@ namespace MWMechanics world->getPlayer().getMarkedPosition(markedCell, markedPosition); if (markedCell) { - std::string_view dest; + ESM::RefId dest; if (!markedCell->isExterior()) - dest = markedCell->getCell()->getNameId(); + dest = markedCell->getCell()->getId(); MWWorld::ActionTeleport action(dest, markedPosition, false); action.execute(target); if (!caster.isEmpty()) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index b5a540fd81..aafb98240f 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -92,19 +92,9 @@ namespace MWScript ESM::Position pos; MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::Ptr playerPtr = world->getPlayerPtr(); - - if (world->findExteriorPosition(cell, pos)) - { - MWWorld::ActionTeleport({}, pos, false).execute(playerPtr); - world->adjustPosition(playerPtr, false); - } - else - { - // Change to interior even if findInteriorPosition() - // yields false. In this case position will be zero-point. - world->findInteriorPosition(cell, pos); - MWWorld::ActionTeleport(cell, pos, false).execute(playerPtr); - } + ESM::RefId cellId = world->findCellPosition(cell, pos); + MWWorld::ActionTeleport(cellId, pos, false).execute(playerPtr); + world->adjustPosition(playerPtr, false); } }; diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 7b3d73057e..f1b6934ae2 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -19,9 +19,9 @@ namespace MWWorld { - ActionTeleport::ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers) + ActionTeleport::ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers) : Action(true) - , mCellName(cellName) + , mCellId(cellId) , mPosition(position) , mTeleportFollowers(teleportFollowers) { @@ -33,7 +33,9 @@ namespace MWWorld { // Find any NPCs that are following the actor and teleport them with him std::set followers; - getFollowers(actor, followers, mCellName.empty(), true); + + bool toExterior = MWBase::Environment::get().getWorldModel()->getCell(mCellId)->isExterior(); + getFollowers(actor, followers, toExterior, true); for (std::set::iterator it = followers.begin(); it != followers.end(); ++it) teleport(*it); @@ -52,10 +54,8 @@ namespace MWWorld if (actor == world->getPlayerPtr()) { world->getPlayer().setTeleported(true); - if (mCellName.empty()) - world->changeToExteriorCell(mPosition, true); - else - world->changeToInteriorCell(mCellName, mPosition, true); + if (!mCellId.empty()) + world->changeToCell(mCellId, mPosition, true); teleported = world->getPlayerPtr(); } else @@ -65,15 +65,9 @@ namespace MWWorld actor.getClass().getCreatureStats(actor).getAiSequence().stopCombat(); return; } - else if (mCellName.empty()) - { - const osg::Vec2i index = positionToCellIndex(mPosition.pos[0], mPosition.pos[1]); - teleported = world->moveObject( - actor, worldModel->getExterior(index.x(), index.y()), mPosition.asVec3(), true, true); - } + else - teleported - = world->moveObject(actor, worldModel->getInterior(mCellName), mPosition.asVec3(), true, true); + teleported = world->moveObject(actor, worldModel->getCell(mCellId), mPosition.asVec3(), true, true); } if (!world->isWaterWalkingCastableOnTarget(teleported) && MWMechanics::hasWaterWalking(teleported)) diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index cbdd59cc87..377e0ce512 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -13,7 +13,7 @@ namespace MWWorld { class ActionTeleport : public Action { - std::string mCellName; + ESM::RefId mCellId; ESM::Position mPosition; bool mTeleportFollowers; @@ -26,7 +26,7 @@ namespace MWWorld public: /// If cellName is empty, an exterior cell is assumed. /// @param teleportFollowers Whether to teleport any following actors of the target actor as well. - ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers); + ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers); /// @param includeHostiles If true, include hostile followers (which won't actually be teleported) in the /// output, diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 2221ff0dec..a9af6e72a6 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -3,8 +3,11 @@ #include #include +#include #include +#include + namespace MWWorld { CellRef::CellRef(const ESM::CellRef& ref) @@ -67,12 +70,54 @@ namespace MWWorld static const std::string emptyString = ""; - const std::string& CellRef::getDestCell() const + ESM::Position CellRef::getDoorDest() const { - return std::visit(ESM::VisitOverload{ - [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, - [&](const ESM::CellRef& ref) -> const std::string& { return ref.mDestCell; }, - }, + + auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::Position { + // So the destinaion pos is always in relationship to the destination cells origin, interior or exterior + // alike + ESM::Position pos = ref.mDoorDest; + if (ref.mDestCell.empty()) // Exterior cell case + { + const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); + pos.pos[0] -= index.x() * Constants::CellSizeInUnits; + pos.pos[1] -= index.y() * Constants::CellSizeInUnits; + } + + return pos; + }; + + return std::visit( + ESM::VisitOverload{ + [&](const ESM4::Reference& ref) { return ref.mDoor.destPos; }, + esm3Visit, + }, + mCellRef.mVariant); + } + + ESM::RefId CellRef::getDestCell() const + { + auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::RefId { + if (!ref.mDestCell.empty()) + { + return ESM::RefId::stringRefId(ref.mDestCell); + } + else + { + const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); + ESM::CellId CellId; + CellId.mPaged = true; + CellId.mIndex.mX = index.x(); + CellId.mIndex.mY = index.y(); + return CellId.getCellRefId(); + } + }; + + return std::visit( + ESM::VisitOverload{ + [&](const ESM4::Reference& ref) -> ESM::RefId { return ESM::RefId::sEmpty; }, + esm3Visit, + }, mCellRef.mVariant); } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index cab671bd0c..7cc60832f7 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -61,18 +61,10 @@ namespace MWWorld } // Teleport location for the door, if this is a teleporting door. - const ESM::Position& getDoorDest() const - { - struct Visitor - { - const ESM::Position& operator()(const ESM::CellRef& ref) { return ref.mDoorDest; } - const ESM::Position& operator()(const ESM4::Reference& ref) { return ref.mDoor.destPos; } - }; - return std::visit(Visitor(), mCellRef.mVariant); - } + ESM::Position getDoorDest() const; // Destination cell for doors (optional) - const std::string& getDestCell() const; + ESM::RefId getDestCell() const; // Scale applied to mesh float getScale() const diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cd303c1ef7..cc9f9bfe92 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1081,7 +1081,7 @@ namespace MWWorld ESM::CellId movedTo; refnum.load(reader, true, "MVRF"); movedTo.load(reader); - + ESM::RefId movedToId = movedTo.getCellRefId(); if (refnum.hasContentFile()) { auto iter = contentFileMap.find(refnum.mContentFile); @@ -1098,7 +1098,7 @@ namespace MWWorld continue; } - CellStore* otherCell = callback->getCellStore(movedTo); + CellStore* otherCell = callback->getCellStore(movedToId); if (otherCell == nullptr) { diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 51aea9129a..d65b279bdf 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -291,7 +291,7 @@ namespace MWWorld struct GetCellStoreCallback { ///@note must return nullptr if the cell is not found - virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0; + virtual CellStore* getCellStore(const ESM::RefId& cellId) = 0; virtual ~GetCellStoreCallback() = default; }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 88faac3c52..e2000785c8 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -367,7 +367,7 @@ namespace MWWorld try { - mCellStore = MWBase::Environment::get().getWorldModel()->getCell(player.mCellId); + mCellStore = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mCellId); } catch (...) { @@ -404,7 +404,7 @@ namespace MWWorld if (player.mHasMark) { mMarkedPosition = player.mMarkedPosition; - mMarkedCell = MWBase::Environment::get().getWorldModel()->getCell(player.mMarkedCell); + mMarkedCell = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mMarkedCell); } else { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ae830f88a4..3d0d97e272 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1129,15 +1129,7 @@ namespace MWWorld { try { - if (!door.getCellRef().getDestCell().empty()) - preloadCell(mWorld.getWorldModel().getInterior(door.getCellRef().getDestCell())); - else - { - osg::Vec3f pos = door.getCellRef().getDoorDest().asVec3(); - const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); - preloadCell(mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y()), true); - exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); - } + preloadCell(mWorld.getWorldModel().getCell(door.getCellRef().getDestCell())); } catch (std::exception&) { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index bd0ef53e24..16ff60db61 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -471,7 +471,7 @@ namespace MWWorld const ESM::Cell* Store::search(const ESM::RefId& cellId) const { auto foundCellIt = mCells.find(cellId); - if (foundCellIt == mCells.end()) + if (foundCellIt != mCells.end()) return &foundCellIt->second; return nullptr; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4bb56b9176..43070632eb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -353,7 +353,7 @@ namespace MWWorld if (bypass && !mStartCell.empty()) { ESM::Position pos; - if (findExteriorPosition(mStartCell, pos)) + if (findExteriorPosition(mStartCell, pos).empty()) { changeToExteriorCell(pos, true); adjustPosition(getPlayerPtr(), false); @@ -1000,6 +1000,31 @@ namespace MWWorld mCurrentDate->setup(mGlobalVariables); } + void World::changeToCell( + const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) + { + const MWWorld::Cell* destinationCell = getWorldModel().getCell(cellId)->getCell(); + bool exteriorCell = destinationCell->isExterior(); + + mPhysics->clearQueuedMovement(); + mDiscardMovements = true; + + if (changeEvent && mCurrentWorldSpace != destinationCell->getNameId()) + { + // changed worldspace + mProjectileManager->clear(); + mRendering->notifyWorldSpaceChanged(); + mCurrentWorldSpace = destinationCell->getNameId(); + } + removeContainerScripts(getPlayerPtr()); + if (exteriorCell) + mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent); + else + mWorldScene->changeToInteriorCell(destinationCell->getNameId(), position, adjustPlayerPos, changeEvent); + addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); + mRendering->getCamera()->instantTransition(); + } + float World::getMaxActivationDistance() const { if (mActivationDistanceOverride >= 0) @@ -1420,9 +1445,9 @@ namespace MWWorld esmPos.pos[0] = traced.x(); esmPos.pos[1] = traced.y(); esmPos.pos[2] = traced.z(); - std::string_view cell; + ESM::RefId cell; if (!actor.getCell()->isExterior()) - cell = actor.getCell()->getCell()->getNameId(); + cell = actor.getCell()->getCell()->getId(); MWWorld::ActionTeleport(cell, esmPos, false).execute(actor); } } @@ -2060,24 +2085,7 @@ namespace MWWorld { World::DoorMarker newMarker; newMarker.name = MWClass::Door::getDestination(ref); - - ESM::CellId cellid; - if (!ref.mRef.getDestCell().empty()) - { - cellid.mWorldspace = ref.mRef.getDestCell(); - cellid.mPaged = false; - cellid.mIndex.mX = 0; - cellid.mIndex.mY = 0; - } - else - { - cellid.mPaged = true; - const osg::Vec2i index - = positionToCellIndex(ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1]); - cellid.mIndex.mX = index.x(); - cellid.mIndex.mY = index.y(); - } - newMarker.dest = cellid; + newMarker.dest = ref.mRef.getDestCell(); ESM::Position pos = ref.mData.getPosition(); @@ -2764,7 +2772,7 @@ namespace MWWorld physicActor->enableCollisionBody(enable); } - bool World::findInteriorPosition(std::string_view name, ESM::Position& pos) + ESM::RefId World::findInteriorPosition(std::string_view name, ESM::Position& pos) { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; @@ -2772,8 +2780,9 @@ namespace MWWorld MWWorld::CellStore* cellStore = mWorldModel.getInterior(name); if (!cellStore) - return false; + return ESM::RefId::sEmpty; + ESM::RefId cellId = cellStore->getCell()->getId(); std::vector sortedDoors; for (const MWWorld::LiveCellRef& door : cellStore->getReadOnlyDoors().mList) { @@ -2794,32 +2803,21 @@ namespace MWWorld for (const MWWorld::CellRef* door : sortedDoors) { MWWorld::CellStore* source = nullptr; + source = mWorldModel.getCell(door->getDestCell()); - // door to exterior - if (door->getDestCell().empty()) - { - ESM::Position doorDest = door->getDoorDest(); - const osg::Vec2i index = positionToCellIndex(doorDest.pos[0], doorDest.pos[1]); - source = mWorldModel.getExterior(index.x(), index.y()); - } - // door to interior - else - { - source = mWorldModel.getInterior(door->getDestCell()); - } if (source) { // Find door leading to our current teleport door // and use its destination to position inside cell. for (const MWWorld::LiveCellRef& destDoor : source->getReadOnlyDoors().mList) { - if (name == destDoor.mRef.getDestCell()) + if (ESM::RefId::stringRefId(name) == destDoor.mRef.getDestCell()) { /// \note Using _any_ door pointed to the interior, /// not the one pointed to current door. pos = destDoor.mRef.getDoorDest(); pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - return true; + return cellId; } } } @@ -2831,7 +2829,7 @@ namespace MWWorld // found the COC position? pos = stat4.mRef.getPosition(); pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - return true; + return cellId; } } // Fall back to the first static location. @@ -2840,7 +2838,7 @@ namespace MWWorld { pos = statics4.begin()->mRef.getPosition(); pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - return true; + return cellId; } // Fall back to the first static location. const MWWorld::CellRefList::List& statics = cellStore->getReadOnlyStatics().mList; @@ -2848,13 +2846,24 @@ namespace MWWorld { pos = statics.begin()->mRef.getPosition(); pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - return true; + return cellId; } - return false; + return ESM::RefId::sEmpty; + } + + ESM::RefId World::findCellPosition(std::string_view cellName, ESM::Position& pos) + { + ESM::RefId foundCell = findInteriorPosition(cellName, pos); + if (foundCell.empty()) + { + return findInteriorPosition(cellName, pos); + } + + return foundCell; } - bool World::findExteriorPosition(std::string_view nameId, ESM::Position& pos) + ESM::RefId World::findExteriorPosition(std::string_view nameId, ESM::Position& pos) { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; @@ -2863,7 +2872,7 @@ namespace MWWorld { ext = mWorldModel.getCell(nameId)->getCell(); if (!ext->isExterior()) - return false; + return ESM::RefId::sEmpty; } catch (std::exception&) { @@ -2895,10 +2904,10 @@ namespace MWWorld // Note: Z pos will be adjusted by adjustPosition later pos.pos[2] = 0; - return true; + return ext->getId(); } - return false; + return ESM::RefId::sEmpty; } void World::enableTeleporting(bool enable) @@ -3289,10 +3298,10 @@ namespace MWWorld // Search for a 'nearest' exterior, counting each cell between the starting // cell and the exterior as a distance of 1. Will fail for isolated interiors. - std::set checkedCells; - std::set currentCells; - std::set nextCells; - nextCells.insert(cell->getCell()->getNameId()); + std::set checkedCells; + std::set currentCells; + std::set nextCells; + nextCells.insert(cell->getCell()->getId()); while (!nextCells.empty()) { @@ -3300,7 +3309,7 @@ namespace MWWorld nextCells.clear(); for (const auto& currentCell : currentCells) { - MWWorld::CellStore* next = mWorldModel.getInterior(currentCell); + MWWorld::CellStore* next = mWorldModel.getCell(currentCell); if (!next) continue; @@ -3318,7 +3327,7 @@ namespace MWWorld } else { - const std::string_view dest = ref.mRef.getDestCell(); + ESM::RefId dest = ref.mRef.getDestCell(); if (!checkedCells.count(dest) && !currentCells.count(dest)) nextCells.insert(dest); } @@ -3342,19 +3351,19 @@ namespace MWWorld // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. - std::set checkedCells; - std::set currentCells; - std::set nextCells; + std::set checkedCells; + std::set currentCells; + std::set nextCells; MWWorld::ConstPtr closestMarker; - nextCells.insert(ptr.getCell()->getCell()->getNameId()); + nextCells.insert(ptr.getCell()->getCell()->getId()); while (!nextCells.empty()) { currentCells = nextCells; nextCells.clear(); for (const auto& cell : currentCells) { - MWWorld::CellStore* next = mWorldModel.getInterior(cell); + MWWorld::CellStore* next = mWorldModel.getCell(cell); checkedCells.insert(cell); if (!next) continue; @@ -3440,11 +3449,11 @@ namespace MWWorld return; } - std::string_view cellName = ""; + ESM::RefId cellId; if (!closestMarker.mCell->isExterior()) - cellName = closestMarker.mCell->getCell()->getNameId(); + cellId = closestMarker.mCell->getCell()->getId(); - MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); + MWWorld::ActionTeleport action(cellId, closestMarker.getRefData().getPosition(), false); action.execute(ptr); } @@ -3646,13 +3655,13 @@ namespace MWWorld Log(Debug::Warning) << "Failed to confiscate items: no closest prison marker found."; return; } - std::string_view prisonName = prisonMarker.getCellRef().getDestCell(); + ESM::RefId prisonName = prisonMarker.getCellRef().getDestCell(); if (prisonName.empty()) { Log(Debug::Warning) << "Failed to confiscate items: prison marker not linked to prison interior"; return; } - MWWorld::CellStore* prison = mWorldModel.getInterior(prisonName); + MWWorld::CellStore* prison = mWorldModel.getCell(prisonName); if (!prison) { Log(Debug::Warning) << "Failed to confiscate items: failed to load cell " << prisonName; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 59b308e388..e2b57c8a1a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -351,6 +351,9 @@ namespace MWWorld void changeToCell(const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; + + void changeToCell(const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, + bool changeEvent = true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes MWWorld::Ptr getFacedObject() override; @@ -601,12 +604,12 @@ namespace MWWorld /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - bool findExteriorPosition(std::string_view nameId, ESM::Position& pos) override; + ESM::RefId findExteriorPosition(std::string_view nameId, ESM::Position& pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - bool findInteriorPosition(std::string_view name, ESM::Position& pos) override; - + ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) override; + ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). void enableTeleporting(bool enable) override; diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index ef8cad2b58..e98ce190be 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -226,7 +226,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) return result->second; } -MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id) +MWWorld::CellStore* MWWorld::WorldModel::getCellFromCellId(const ESM::CellId& id) { if (id.mPaged) return getExterior(id.mIndex.mX, id.mIndex.mY); @@ -234,6 +234,52 @@ MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id) return getInterior(id.mWorldspace); } +MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id) +{ + auto result = mCells.find(id); + if (result != mCells.end()) + return &result->second; + + // TODO: in the future replace that with elsid's refId variant that can be a osg::Vec2i + const std::string& idString = id.getRefIdString(); + if (idString[0] == '#' && idString.find(',')) // That is an exterior cell Id + { + int x, y; + std::stringstream stringStream = std::stringstream(idString); + char sharp = '#'; + char comma = ','; + stringStream >> sharp >> x >> comma >> y; + return getExterior(x, y); + } + + const ESM4::Cell* cell4 = mStore.get().search(id); + CellStore* newCellStore = nullptr; + if (!cell4) + { + const ESM::Cell* cell = mStore.get().search(id); + newCellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; + } + else + { + newCellStore = &mCells.emplace(cell4->mId, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first->second; + } + if (newCellStore->getCell()->isExterior()) + { + std::pair coord + = std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY()); + mExteriors.emplace(coord, newCellStore).first; + } + else + { + mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore).first; + } + if (newCellStore->getState() != CellStore::State_Loaded) + { + newCellStore->load(); + } + return newCellStore; +} + const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name) { const ESM::Cell* cell = mStore.get().search(name); // first try interiors @@ -428,7 +474,7 @@ public: MWWorld::WorldModel& mWorldModel; - MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) override + MWWorld::CellStore* getCellStore(const ESM::RefId& cellId) override { try { @@ -452,7 +498,7 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, cons try { - cellStore = getCell(state.mId); + cellStore = getCell(state.mId.getCellRefId()); } catch (...) { diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index f2c5e0064a..04afff0095 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -70,7 +70,8 @@ namespace MWWorld CellStore* getExterior(int x, int y); CellStore* getInterior(std::string_view name); CellStore* getCell(std::string_view name); // interior or named exterior - CellStore* getCell(const ESM::CellId& Id); + CellStore* getCell(const ESM::RefId& Id); + CellStore* getCellFromCellId(const ESM::CellId& Id); // If cellNameInSameWorldSpace is an interior - returns this interior. // Otherwise returns exterior cell for given position in the same world space. diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index a8a812bf02..08b81fcd81 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -33,6 +33,18 @@ namespace ESM esm.writeHNT("CIDX", mIndex, 8); } + ESM::RefId CellId::getCellRefId() const + { + if (mPaged) + { + return ESM::RefId::stringRefId("#" + std::to_string(mIndex.mX) + "," + std::to_string(mIndex.mY)); + } + else + { + return ESM::RefId::stringRefId(mWorldspace); + } + } + bool operator==(const CellId& left, const CellId& right) { return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 33db9e7432..65cca87bb8 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -25,6 +25,7 @@ namespace ESM void load(ESMReader& esm); void save(ESMWriter& esm) const; + ESM::RefId getCellRefId() const; }; bool operator==(const CellId& left, const CellId& right); diff --git a/components/esm3/custommarkerstate.cpp b/components/esm3/custommarkerstate.cpp index f752ae7c97..4568cfa748 100644 --- a/components/esm3/custommarkerstate.cpp +++ b/components/esm3/custommarkerstate.cpp @@ -10,7 +10,7 @@ namespace ESM { esm.writeHNT("POSX", mWorldX); esm.writeHNT("POSY", mWorldY); - mCell.save(esm); + mCellId.save(esm); if (!mNote.empty()) esm.writeHNString("NOTE", mNote); } @@ -19,7 +19,8 @@ namespace ESM { esm.getHNT(mWorldX, "POSX"); esm.getHNT(mWorldY, "POSY"); - mCell.load(esm); + mCellId.load(esm); + mCell = mCellId.getCellRefId(); mNote = esm.getHNOString("NOTE"); } diff --git a/components/esm3/custommarkerstate.hpp b/components/esm3/custommarkerstate.hpp index f4cad06edb..e1a129ffbe 100644 --- a/components/esm3/custommarkerstate.hpp +++ b/components/esm3/custommarkerstate.hpp @@ -12,7 +12,8 @@ namespace ESM float mWorldX; float mWorldY; - CellId mCell; + RefId mCell; + CellId mCellId; // The CellId representation for saving/loading std::string mNote; diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 1c4477acfd..2c6060ce8a 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -59,14 +59,7 @@ namespace ESM const ESM::RefId& Cell::updateId() { - if (isExterior()) - { - mId = ESM::RefId::stringRefId("#" + std::to_string(mData.mX) + "," + std::to_string(mData.mY)); - } - else - { - mId = ESM::RefId::stringRefId(mName); - } + mId = mCellId.getCellRefId(); return mId; } From 502e4ad89208345fe0799792c89c2853af6eaa54 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 19 Feb 2023 17:58:35 +0100 Subject: [PATCH 04/19] Fix coc to exterior cells --- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 43070632eb..5e29e50bbb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2854,10 +2854,17 @@ namespace MWWorld ESM::RefId World::findCellPosition(std::string_view cellName, ESM::Position& pos) { - ESM::RefId foundCell = findInteriorPosition(cellName, pos); + ESM::RefId foundCell; + try + { + foundCell = findInteriorPosition(cellName, pos); + } + catch (std::exception&) + { + } if (foundCell.empty()) { - return findInteriorPosition(cellName, pos); + return findExteriorPosition(cellName, pos); } return foundCell; From 1bbf4a3acfb0cb7e43dfce0d017d6000171f4f81 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 19 Feb 2023 19:19:11 +0100 Subject: [PATCH 05/19] fixes teleport to exterior cells. fixes linux compile fix compile bis --- apps/essimporter/converter.cpp | 3 ++- apps/openmw/mwworld/cell.hpp | 2 +- apps/openmw/mwworld/cellref.cpp | 23 ++++------------------- apps/openmw/mwworld/scene.cpp | 8 +++++--- apps/openmw/mwworld/scene.hpp | 3 ++- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++++---- apps/openmw/mwworld/worldmodel.cpp | 4 ++-- 7 files changed, 29 insertions(+), 31 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 0da74d3251..8dcfcfe832 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -301,7 +301,8 @@ namespace ESSImport marker.mWorldX = notepos[0]; marker.mWorldY = notepos[1]; marker.mNote = note; - marker.mCell = cell.getCellId(); + marker.mCellId = cell.getCellId(); + marker.mCell = cell.getCellId().getCellRefId(); mMarkers.push_back(marker); } diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 818968fabb..fd391e870b 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -49,7 +49,7 @@ namespace MWWorld std::string getDescription() const; const MoodData& getMood() const { return mMood; } float getWaterHeight() const { return mWaterHeight; } - const ESM::RefId& getId() const { return mId; }; + const ESM::RefId& getId() const { return mId; } private: bool mIsExterior; diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index a9af6e72a6..02dd0ec4c4 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -73,25 +73,10 @@ namespace MWWorld ESM::Position CellRef::getDoorDest() const { - auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::Position { - // So the destinaion pos is always in relationship to the destination cells origin, interior or exterior - // alike - ESM::Position pos = ref.mDoorDest; - if (ref.mDestCell.empty()) // Exterior cell case - { - const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); - pos.pos[0] -= index.x() * Constants::CellSizeInUnits; - pos.pos[1] -= index.y() * Constants::CellSizeInUnits; - } - - return pos; - }; - - return std::visit( - ESM::VisitOverload{ - [&](const ESM4::Reference& ref) { return ref.mDoor.destPos; }, - esm3Visit, - }, + return std::visit(ESM::VisitOverload{ + [&](const ESM4::Reference& ref) { return ref.mDoor.destPos; }, + [&](const ESM::CellRef& ref) -> ESM::Position { return ref.mDoorDest; }, + }, mCellRef.mVariant); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 3d0d97e272..c255618dba 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -920,16 +920,18 @@ namespace MWWorld MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->isQuasiExterior()); } - void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) + void Scene::changeToExteriorCell( + const ESM::RefId& extCellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) { - const osg::Vec2i cellIndex = positionToCellIndex(position.pos[0], position.pos[1]); if (changeEvent) MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + CellStore* current = mWorld.getWorldModel().getCell(extCellId); + + const osg::Vec2i cellIndex(current->getCell()->getGridX(), current->getCell()->getGridY()); changeCellGrid(position.asVec3(), cellIndex.x(), cellIndex.y(), changeEvent); - CellStore* current = mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y()); changePlayerCell(current, position, adjustPlayerPos); if (changeEvent) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index d43842fbba..0383d0c888 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -167,7 +167,8 @@ namespace MWWorld ///< Move to interior cell. /// @param changeEvent Set cellChanged flag? - void changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); + void changeToExteriorCell( + const ESM::RefId& extCellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); ///< Move to exterior cell. /// @param changeEvent Set cellChanged flag? diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5e29e50bbb..2af2ae7faf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -378,7 +378,12 @@ namespace MWWorld pos.rot[0] = 0; pos.rot[1] = 0; pos.rot[2] = 0; - mWorldScene->changeToExteriorCell(pos, true); + + osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]); + ESM::CellId CellId; + CellId.mPaged = true; + CellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; + mWorldScene->changeToExteriorCell(CellId.getCellRefId(), pos, true); } } @@ -981,7 +986,11 @@ namespace MWWorld mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); - mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent); + osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]); + ESM::CellId CellId; + CellId.mPaged = true; + CellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; + mWorldScene->changeToExteriorCell(CellId.getCellRefId(), position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); mRendering->getCamera()->instantTransition(); } @@ -1018,7 +1027,7 @@ namespace MWWorld } removeContainerScripts(getPlayerPtr()); if (exteriorCell) - mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent); + mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent); else mWorldScene->changeToInteriorCell(destinationCell->getNameId(), position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); @@ -1194,7 +1203,7 @@ namespace MWWorld if (mWorldScene->isCellActive(*newCell)) mWorldScene->changePlayerCell(newCell, pos, false); else - mWorldScene->changeToExteriorCell(pos, false); + mWorldScene->changeToExteriorCell(newCell->getCell()->getId(), pos, false); } addContainerScripts(getPlayerPtr(), newCell); newPtr = getPlayerPtr(); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index e98ce190be..3e22ad02a6 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -267,11 +267,11 @@ MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id) { std::pair coord = std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY()); - mExteriors.emplace(coord, newCellStore).first; + mExteriors.emplace(coord, newCellStore); } else { - mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore).first; + mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore); } if (newCellStore->getState() != CellStore::State_Loaded) { From 9f597ecfeaca47e4eae2a7d807eb6c19724d3624 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 19 Feb 2023 21:18:15 +0100 Subject: [PATCH 06/19] No more Cellid used by ESM4 cells and that also means it is no longer used by MWWorld::Cell fixes tests --- apps/openmw/mwmechanics/aiescort.cpp | 3 ++- apps/openmw/mwmechanics/aipackage.cpp | 4 +-- .../mwscript/transformationextensions.cpp | 4 +-- apps/openmw/mwstate/statemanagerimp.cpp | 4 +-- apps/openmw/mwworld/cell.cpp | 5 ---- apps/openmw/mwworld/cell.hpp | 2 -- apps/openmw/mwworld/cellstore.cpp | 4 +-- apps/openmw/mwworld/player.cpp | 4 +-- apps/openmw/mwworld/scene.cpp | 8 +++--- apps/openmw/mwworld/worldmodel.cpp | 14 ++++------- apps/openmw_test_suite/mwworld/test_store.cpp | 10 ++++++++ components/esm3/cellid.cpp | 25 +++++++++++++++++++ components/esm3/cellid.hpp | 3 +++ 13 files changed, 59 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 7bf593b6da..41cb5a59cb 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -78,7 +79,7 @@ namespace MWMechanics } } - if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace) + if (!mCellId.empty() && !Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->getNameId())) return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door actor.getClass().getCreatureStats(actor).setDrawState(DrawState::Nothing); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index dec0661dd6..d4365a478f 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -330,9 +330,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore* cell) { - const ESM::CellId& id = cell->getCell()->getCellId(); + const ESM::RefId& id = cell->getCell()->getId(); // static cache is OK for now, pathgrids can never change during runtime - typedef std::map> CacheMap; + typedef std::map> CacheMap; static CacheMap cache; CacheMap::iterator found = cache.find(id); if (found == cache.end()) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7385d3a2a5..fc994c8754 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -87,8 +87,8 @@ namespace MWScript float distance; // If the objects are in different worldspaces, return a large value (just like vanilla) if (!to.isInCell() || !from.isInCell() - || to.getCell()->getCell()->getCellId().mWorldspace - != from.getCell()->getCell()->getCellId().mWorldspace) + || !Misc::StringUtils::ciEqual( + to.getCell()->getCell()->getNameId(), from.getCell()->getCell()->getNameId())) distance = std::numeric_limits::max(); else { diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index e35410b484..c4f96b3724 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -555,7 +555,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file if (ptr.isInCell()) { - const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId(); + const ESM::RefId& cellId = ptr.getCell()->getCell()->getId(); // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell(cellId, ptr.getRefData().getPosition(), false, false); @@ -574,7 +574,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file pos.rot[0] = 0; pos.rot[1] = 0; pos.rot[2] = 0; - MWBase::Environment::get().getWorld()->changeToCell(cell->getCell()->getCellId(), pos, true, false); + MWBase::Environment::get().getWorld()->changeToCell(cell->getCell()->getId(), pos, true, false); } MWBase::Environment::get().getWorld()->updateProjectilesCasters(); diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index fa35af41a3..b8a352df71 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -16,10 +16,6 @@ namespace MWWorld , mDisplayname(cell.mFullName) , mNameID(cell.mEditorId) , mRegion(ESM::RefId()) // Unimplemented for now - , mCellId{ - .mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) }, - .mIndex{ cell.getGridX(), cell.getGridY() }, - .mPaged = isExterior(),} , mId(cell.mId) ,mMood{ .mAmbiantColor = cell.mLighting.ambient, @@ -41,7 +37,6 @@ namespace MWWorld , mDisplayname(cell.mName) , mNameID(cell.mName) , mRegion(cell.mRegion) - , mCellId(cell.getCellId()) , mId(cell.mId) , mMood{ .mAmbiantColor = cell.mAmbi.mAmbient, diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index fd391e870b..60751e8797 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -42,7 +42,6 @@ namespace MWWorld bool isQuasiExterior() const { return mIsQuasiExterior; } bool hasWater() const { return mHasWater; } bool noSleep() const { return mNoSleep; } - const ESM::CellId& getCellId() const { return mCellId; } const ESM::RefId& getRegion() const { return mRegion; } std::string_view getNameId() const { return mNameID; } std::string_view getDisplayName() const { return mDisplayname; } @@ -61,7 +60,6 @@ namespace MWWorld std::string mDisplayname; // How the game displays it std::string mNameID; // The name that will be used by the script and console commands ESM::RefId mRegion; - ESM::CellId mCellId; ESM::RefId mId; MoodData mMood; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cc9f9bfe92..cf438ede74 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -988,7 +988,7 @@ namespace MWWorld void CellStore::saveState(ESM::CellState& state) const { - state.mId = mCellVariant.getCellId(); + state.mId = ESM::CellId::extractFromRefId(mCellVariant.getId()); if (!mCellVariant.isExterior() && mCellVariant.hasWater()) state.mWaterLevel = mWaterLevel; @@ -1019,7 +1019,7 @@ namespace MWWorld for (const auto& [base, store] : mMovedToAnotherCell) { ESM::RefNum refNum = base->mRef.getRefNum(); - ESM::CellId movedTo = store->getCell()->getCellId(); + ESM::CellId movedTo = ESM::CellId::extractFromRefId(store->getCell()->getId()); refNum.save(writer, true, "MVRF"); movedTo.save(writer); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index e2000785c8..f0a3f548a5 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -283,7 +283,7 @@ namespace MWWorld ESM::Player player; mPlayer.save(player.mObject); - player.mCellId = mCellStore->getCell()->getCellId(); + player.mCellId = ESM::CellId::extractFromRefId(mCellStore->getCell()->getId()); player.mCurrentCrimeId = mCurrentCrimeId; player.mPaidCrimeId = mPaidCrimeId; @@ -298,7 +298,7 @@ namespace MWWorld { player.mHasMark = true; player.mMarkedPosition = mMarkedPosition; - player.mMarkedCell = mMarkedCell->getCell()->getCellId(); + player.mMarkedCell = ESM::CellId::extractFromRefId(mMarkedCell->getCell()->getId()); } else player.mHasMark = false; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c255618dba..b3a077d23d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -554,7 +554,7 @@ namespace MWWorld mNavigator.setWorldspace( Misc::StringUtils::lowerCase( - mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace), + mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getNameId()), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -676,7 +676,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -734,7 +734,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -890,7 +890,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 3e22ad02a6..357d5915f4 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -240,16 +240,12 @@ MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id) if (result != mCells.end()) return &result->second; - // TODO: in the future replace that with elsid's refId variant that can be a osg::Vec2i - const std::string& idString = id.getRefIdString(); - if (idString[0] == '#' && idString.find(',')) // That is an exterior cell Id + // TODO tetramir: in the future replace that with elsid's refId variant that can be a osg::Vec2i + ESM::CellId cellId = ESM::CellId::extractFromRefId(id); + if (cellId.mPaged) // That is an exterior cell Id { - int x, y; - std::stringstream stringStream = std::stringstream(idString); - char sharp = '#'; - char comma = ','; - stringStream >> sharp >> x >> comma >> y; - return getExterior(x, y); + + return getExterior(cellId.mIndex.mX, cellId.mIndex.mY); } const ESM4::Cell* cell4 = mStore.get().search(id); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 4539478e17..8f2623522a 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -445,6 +445,13 @@ namespace decltype(RecordType::mId) refId; if constexpr (ESM::hasIndex && !std::is_same_v) refId = RecordType::indexToRefId(index); + else if constexpr (std::is_same_v) + { + ESM::CellId cellId; + cellId.mPaged = true; + cellId.mIndex = { 0, 0 }; + refId = cellId.getCellRefId(); + } else refId = ESM::StringRefId(stringId); @@ -484,6 +491,9 @@ namespace else result = esmStore.get().search(refId); + if (result == nullptr || result->mId != refId) + int debug = 0; + ASSERT_NE(result, nullptr); EXPECT_EQ(result->mId, refId); } diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index 08b81fcd81..c295084a91 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -2,6 +2,7 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include namespace ESM { @@ -45,6 +46,30 @@ namespace ESM } } + CellId CellId::extractFromRefId(const ESM::RefId& id) + { + // This is bad and that code should not be merged. + const std::string& idString = id.getRefIdString(); + CellId out; + if (idString[0] == '#' && idString.find(',')) // That is an exterior cell Id + { + int x, y; + std::stringstream stringStream = std::stringstream(idString); + char sharp = '#'; + char comma = ','; + stringStream >> sharp >> x >> comma >> y; + out.mPaged = true; + out.mIndex = { x, y }; + } + else + { + out.mPaged = false; + out.mWorldspace = Misc::StringUtils::lowerCase(idString); + } + + return out; + } + bool operator==(const CellId& left, const CellId& right) { return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 65cca87bb8..0b27425e35 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -26,6 +26,9 @@ namespace ESM void load(ESMReader& esm); void save(ESMWriter& esm) const; ESM::RefId getCellRefId() const; + + // TODO tetramir: this probably shouldn't exist, needs it because some CellIds are saved on disk + static CellId extractFromRefId(const ESM::RefId& id); }; bool operator==(const CellId& left, const CellId& right); From 6c6dbccd0a20ddf1c22f57025cd66f2c4c25508f Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 20 Feb 2023 00:18:34 +0100 Subject: [PATCH 07/19] fix crash on reset fix tests --- apps/openmw/mwworld/worldmodel.cpp | 1 + apps/openmw_test_suite/mwworld/test_store.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 357d5915f4..65aeca3bec 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -92,6 +92,7 @@ void MWWorld::WorldModel::clear() mLastGeneratedRefnum = ESM::RefNum{}; mInteriors.clear(); mExteriors.clear(); + mCells.clear(); std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair(ESM::RefId(), (MWWorld::CellStore*)nullptr)); mIdCacheIndex = 0; } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 8f2623522a..9dcab91f76 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -491,9 +491,6 @@ namespace else result = esmStore.get().search(refId); - if (result == nullptr || result->mId != refId) - int debug = 0; - ASSERT_NE(result, nullptr); EXPECT_EQ(result->mId, refId); } From 6895a452efaf04f679d88577ffeeed50041cf732 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 20 Feb 2023 22:33:35 +0100 Subject: [PATCH 08/19] restores the concept of worldspace for MWWorld::Cell --- apps/openmw/mwmechanics/aifollow.cpp | 4 ++-- .../mwscript/transformationextensions.cpp | 3 +-- apps/openmw/mwworld/cell.cpp | 10 +++++++++ apps/openmw/mwworld/cell.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 22 ++++++++++--------- components/esm4/loadcell.cpp | 2 +- components/esm4/loadcell.hpp | 2 +- 7 files changed, 29 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 55a5e2534c..50f8f8e3c3 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -174,8 +174,8 @@ namespace MWMechanics return true; } } - else if (Misc::StringUtils::ciEqual( - mCellId, actor.getCell()->getCell()->getNameId())) // Cell to travel to + else if (Misc::StringUtils::ciEqual(mCellId, + actor.getCell()->getCell()->getWorldSpace().getRefIdString())) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fc994c8754..6ae9c77ca2 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -87,8 +87,7 @@ namespace MWScript float distance; // If the objects are in different worldspaces, return a large value (just like vanilla) if (!to.isInCell() || !from.isInCell() - || !Misc::StringUtils::ciEqual( - to.getCell()->getCell()->getNameId(), from.getCell()->getCell()->getNameId())) + || to.getCell()->getCell()->getWorldSpace() != from.getCell()->getCell()->getWorldSpace()) distance = std::numeric_limits::max(); else { diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index b8a352df71..7680090410 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -1,5 +1,6 @@ #include "cell.hpp" +#include #include #include #include @@ -17,6 +18,7 @@ namespace MWWorld , mNameID(cell.mEditorId) , mRegion(ESM::RefId()) // Unimplemented for now , mId(cell.mId) + , mParent(cell.mParent) ,mMood{ .mAmbiantColor = cell.mLighting.ambient, .mDirectionalColor = cell.mLighting.directional, @@ -38,6 +40,7 @@ namespace MWWorld , mNameID(cell.mName) , mRegion(cell.mRegion) , mId(cell.mId) + , mParent(ESM::RefId::stringRefId(ESM::CellId::sDefaultWorldspace)) , mMood{ .mAmbiantColor = cell.mAmbi.mAmbient, .mDirectionalColor = cell.mAmbi.mSunlight, @@ -56,4 +59,11 @@ namespace MWWorld }, *this); } + ESM::RefId Cell::getWorldSpace() const + { + if (isExterior()) + return mParent; + else + return mId; + } } diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 60751e8797..4b8e9b7639 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -49,6 +49,7 @@ namespace MWWorld const MoodData& getMood() const { return mMood; } float getWaterHeight() const { return mWaterHeight; } const ESM::RefId& getId() const { return mId; } + ESM::RefId getWorldSpace() const; private: bool mIsExterior; @@ -61,6 +62,7 @@ namespace MWWorld std::string mNameID; // The name that will be used by the script and console commands ESM::RefId mRegion; ESM::RefId mId; + ESM::RefId mParent; MoodData mMood; float mWaterHeight; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b3a077d23d..7d5989baea 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -552,9 +552,11 @@ namespace MWWorld unloadCell(cell, navigatorUpdateGuard.get()); } - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase( - mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getNameId()), + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(mWorld.getWorldModel() + .getExterior(playerCellX, playerCellY) + ->getCell() + ->getWorldSpace() + .getRefIdString()), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -675,8 +677,8 @@ namespace MWWorld "Testing exterior cells (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), + navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -733,8 +735,8 @@ namespace MWWorld "Testing interior cells (" + std::to_string(i) + "/" + std::to_string(cells.getIntSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), + navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -750,7 +752,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->getNameId()) + if (it->mName == (*iter)->getCell()->getWorldSpace().getRefIdString()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; @@ -889,8 +891,8 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getNameId()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), + navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index fc199be6fc..917172265d 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -53,7 +53,7 @@ void ESM4::Cell::load(ESM4::Reader& reader) reader.adjustFormId(mFormId); mId = ESM::RefId::formIdRefId(mFormId); mFlags = reader.hdr().record.flags; - mParent = reader.currWorld(); + mParent = ESM::RefId::formIdRefId(reader.currWorld()); reader.clearCellGrid(); // clear until XCLC FIXME: somehow do this automatically? diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 264746a1c6..5fd077b068 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -68,7 +68,7 @@ namespace ESM4 ESM::RefId mId; std::uint32_t mFlags; // from the header, see enum type RecordFlag for details - FormId mParent; // world formId (for grouping cells), from the loading sequence + ESM::RefId mParent; // world formId (for grouping cells), from the loading sequence std::string mEditorId; std::string mFullName; From c39dd576f881cdcd9fcb0e674bfe139be43cb9e6 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 21 Feb 2023 23:26:40 +0100 Subject: [PATCH 09/19] Gets rid of most ESM::CellId --- apps/esmtool/record.cpp | 10 ++----- apps/essimporter/converter.cpp | 10 +++---- apps/essimporter/convertplayer.cpp | 3 +- apps/essimporter/importer.cpp | 8 ++++-- apps/essimporter/importercontext.hpp | 2 +- apps/navmeshtool/worldspacedata.cpp | 3 +- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwbase/world.hpp | 4 --- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwworld/cell.hpp | 2 -- apps/openmw/mwworld/cellref.cpp | 10 +++---- apps/openmw/mwworld/cellstore.cpp | 14 ++++----- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/groundcoverstore.cpp | 2 +- apps/openmw/mwworld/player.cpp | 15 +++++----- apps/openmw/mwworld/store.cpp | 3 -- apps/openmw/mwworld/worldimp.cpp | 30 ++++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 -- apps/openmw/mwworld/worldmodel.cpp | 23 ++++----------- apps/openmw/mwworld/worldmodel.hpp | 2 -- components/esm/esmbridge.hpp | 1 - components/esm3/cellstate.cpp | 2 +- components/esm3/cellstate.hpp | 4 +-- components/esm3/custommarkerstate.cpp | 5 ++-- components/esm3/custommarkerstate.hpp | 1 - components/esm3/esmreader.cpp | 8 ++++++ components/esm3/esmreader.hpp | 3 ++ components/esm3/esmwriter.cpp | 7 +++++ components/esm3/esmwriter.hpp | 2 ++ components/esm3/loadcell.cpp | 36 +++++++++++------------- components/esm3/loadcell.hpp | 2 -- components/esm3/player.cpp | 8 +++--- components/esm3/player.hpp | 4 +-- components/esmloader/load.cpp | 2 +- 34 files changed, 99 insertions(+), 133 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a908a2a45c..a180f87074 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -220,7 +220,7 @@ namespace EsmTool { void CellState::load(ESM::ESMReader& reader, bool& deleted) { - mCellState.mId.load(reader); + mCellState.mId = reader.getCellId(); mCellState.load(reader); if (mCellState.mHasFogOfWar) mFogState.load(reader); @@ -1358,11 +1358,8 @@ namespace EsmTool void Record::print() { std::cout << " Id:" << std::endl; - std::cout << " Worldspace: " << mData.mCellState.mId.mWorldspace << std::endl; + std::cout << " CellId: " << mData.mCellState.mId << std::endl; std::cout << " Index:" << std::endl; - std::cout << " X: " << mData.mCellState.mId.mIndex.mX << std::endl; - std::cout << " Y: " << mData.mCellState.mId.mIndex.mY << std::endl; - std::cout << " Paged: " << mData.mCellState.mId.mPaged << std::endl; std::cout << " WaterLevel: " << mData.mCellState.mWaterLevel << std::endl; std::cout << " HasFogOfWar: " << mData.mCellState.mHasFogOfWar << std::endl; std::cout << " LastRespawn:" << std::endl; @@ -1420,8 +1417,7 @@ namespace EsmTool std::string Record::getId() const { std::ostringstream stream; - stream << mData.mCellState.mId.mWorldspace << " " << mData.mCellState.mId.mIndex.mX << " " - << mData.mCellState.mId.mIndex.mY << " " << mData.mCellState.mId.mPaged; + stream << mData.mCellState.mId; return stream.str(); } diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 8dcfcfe832..4cf528c832 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -204,7 +204,7 @@ namespace ESSImport // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position if (Misc::StringUtils::ciEqual(cell.mName, mContext->mPlayerCellName)) { - mContext->mPlayer.mCellId = cell.getCellId(); + mContext->mPlayer.mCellId = cell.mId; } Cell newcell; @@ -301,8 +301,7 @@ namespace ESSImport marker.mWorldX = notepos[0]; marker.mWorldY = notepos[1]; marker.mNote = note; - marker.mCellId = cell.getCellId(); - marker.mCell = cell.getCellId().getCellRefId(); + marker.mCell = cell.mId; mMarkers.push_back(marker); } @@ -322,8 +321,9 @@ namespace ESSImport csta.mHasFogOfWar = 0; csta.mLastRespawn.mDay = 0; csta.mLastRespawn.mHour = 0; - csta.mId = esmcell.getCellId(); - csta.mId.save(esm); + csta.mId = esmcell.mId; + csta.mIsInterior = !esmcell.isExterior(); + esm.writeCellId(csta.mId); // TODO csta.mLastRespawn; // shouldn't be needed if we respawn on global schedule like in original MW csta.mWaterLevel = esmcell.mWater; diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index 5bb9897487..855a473e08 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -61,7 +61,6 @@ namespace ESSImport const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation; ESM::CellId cell; - cell.mWorldspace = ESM::CellId::sDefaultWorldspace; cell.mPaged = true; cell.mIndex.mX = mark.mCellX; @@ -74,7 +73,7 @@ namespace ESSImport cell.mPaged = false; } - out.mMarkedCell = cell; + out.mMarkedCell = cell.getCellRefId(); out.mMarkedPosition.pos[0] = mark.mX; out.mMarkedPosition.pos[1] = mark.mY; out.mMarkedPosition.pos[2] = mark.mZ; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 3fac21ec8b..38ebf41596 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -409,16 +409,18 @@ namespace ESSImport } writer.startRecord(ESM::REC_PLAY); - if (context.mPlayer.mCellId.mPaged) + ESM::CellId cellId = ESM::CellId::extractFromRefId(context.mPlayer.mCellId); + if (cellId.mPaged) { // exterior cell -> determine cell coordinates based on position int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits)); int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits)); - context.mPlayer.mCellId.mIndex.mX = cellX; - context.mPlayer.mCellId.mIndex.mY = cellY; + cellId.mIndex.mX = cellX; + cellId.mIndex.mY = cellY; } + context.mPlayer.mCellId = cellId.getCellRefId(); context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index e1ecc4074e..9e5d9c0006 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -62,7 +62,7 @@ namespace ESSImport ESM::CellId playerCellId; playerCellId.mPaged = true; playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0; - mPlayer.mCellId = playerCellId; + mPlayer.mCellId = playerCellId.getCellRefId(); mPlayer.mLastKnownExteriorPosition[0] = mPlayer.mLastKnownExteriorPosition[1] = mPlayer.mLastKnownExteriorPosition[2] = 0.0f; mPlayer.mHasMark = 0; diff --git a/apps/navmeshtool/worldspacedata.cpp b/apps/navmeshtool/worldspacedata.cpp index 740e42a099..fd66a46f4c 100644 --- a/apps/navmeshtool/worldspacedata.cpp +++ b/apps/navmeshtool/worldspacedata.cpp @@ -263,7 +263,8 @@ namespace NavMeshTool const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY); const std::size_t cellObjectsBegin = data.mObjects.size(); - const auto cellNameLowerCase = Misc::StringUtils::lowerCase(cell.mCellId.mWorldspace); + const auto cellNameLowerCase + = Misc::StringUtils::lowerCase(cell.isExterior() ? ESM::CellId::sDefaultWorldspace : cell.mName); WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& { auto it = navMeshInputs.find(cellNameLowerCase); if (it == navMeshInputs.end()) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0f61939028..198be0fdcf 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -40,7 +40,6 @@ namespace ESM { class ESMReader; class ESMWriter; - struct CellId; } namespace MWMechanics diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 76b16e4cb0..db8eabe086 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -256,10 +256,6 @@ namespace MWBase = 0; ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - - virtual void changeToCell( - const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) - = 0; virtual void changeToCell( const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) = 0; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 021cb5cc7d..733a564db5 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -897,7 +897,6 @@ namespace MWGui clickedId.mIndex.mY = y; } mEditingMarker.mCell = clickedId.getCellRefId(); - mEditingMarker.mCellId = clickedId; mEditNoteDialog.setVisible(true); mEditNoteDialog.showDeleteButton(false); diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 4b8e9b7639..eb5a4e0de7 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -5,12 +5,10 @@ #include #include -#include namespace ESM { struct Cell; - struct CellId; } namespace ESM4 diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 02dd0ec4c4..49d21f4b0e 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -90,11 +90,11 @@ namespace MWWorld else { const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); - ESM::CellId CellId; - CellId.mPaged = true; - CellId.mIndex.mX = index.x(); - CellId.mIndex.mY = index.y(); - return CellId.getCellRefId(); + ESM::CellId cellId; + cellId.mPaged = true; + cellId.mIndex.mX = index.x(); + cellId.mIndex.mY = index.y(); + return cellId.getCellRefId(); } }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index cf438ede74..6a2689c864 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -988,11 +988,11 @@ namespace MWWorld void CellStore::saveState(ESM::CellState& state) const { - state.mId = ESM::CellId::extractFromRefId(mCellVariant.getId()); + state.mId = mCellVariant.getId(); if (!mCellVariant.isExterior() && mCellVariant.hasWater()) state.mWaterLevel = mWaterLevel; - + state.mIsInterior = !mCellVariant.isExterior(); state.mHasFogOfWar = (mFogState.get() ? 1 : 0); state.mLastRespawn = mLastRespawn.toEsm(); } @@ -1019,10 +1019,10 @@ namespace MWWorld for (const auto& [base, store] : mMovedToAnotherCell) { ESM::RefNum refNum = base->mRef.getRefNum(); - ESM::CellId movedTo = ESM::CellId::extractFromRefId(store->getCell()->getId()); + ESM::RefId movedTo = store->getCell()->getId(); refNum.save(writer, true, "MVRF"); - movedTo.save(writer); + writer.writeCellId(movedTo); } } @@ -1078,10 +1078,8 @@ namespace MWWorld { reader.cacheSubName(); ESM::RefNum refnum; - ESM::CellId movedTo; refnum.load(reader, true, "MVRF"); - movedTo.load(reader); - ESM::RefId movedToId = movedTo.getCellRefId(); + ESM::RefId movedToId = reader.getCellId(); if (refnum.hasContentFile()) { auto iter = contentFileMap.find(refnum.mContentFile); @@ -1103,7 +1101,7 @@ namespace MWWorld if (otherCell == nullptr) { Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId() - << " (target cell " << movedTo.mWorldspace + << " (target cell " << movedToId << " no longer exists). Reference moved back to its original location."; // Note by dropping tag the object will automatically re-appear in its original cell, though // potentially at inapproriate coordinates. Restore original coordinates: diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index d65b279bdf..451f480e51 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -27,7 +27,6 @@ namespace ESM class ReadersCache; struct Cell; struct CellState; - struct CellId; struct RefNum; struct Activator; struct Potion; diff --git a/apps/openmw/mwworld/groundcoverstore.cpp b/apps/openmw/mwworld/groundcoverstore.cpp index 6c7ab295b6..05777bb816 100644 --- a/apps/openmw/mwworld/groundcoverstore.cpp +++ b/apps/openmw/mwworld/groundcoverstore.cpp @@ -51,7 +51,7 @@ namespace MWWorld { if (!cell.isExterior()) continue; - auto cellIndex = std::make_pair(cell.getCellId().mIndex.mX, cell.getCellId().mIndex.mY); + auto cellIndex = std::make_pair(cell.getGridX(), cell.getGridY()); mCellContexts[cellIndex] = std::move(cell.mContextList); } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index f0a3f548a5..8507f73389 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -283,7 +283,7 @@ namespace MWWorld ESM::Player player; mPlayer.save(player.mObject); - player.mCellId = ESM::CellId::extractFromRefId(mCellStore->getCell()->getId()); + player.mCellId = mCellStore->getCell()->getId(); player.mCurrentCrimeId = mCurrentCrimeId; player.mPaidCrimeId = mPaidCrimeId; @@ -298,7 +298,7 @@ namespace MWWorld { player.mHasMark = true; player.mMarkedPosition = mMarkedPosition; - player.mMarkedCell = ESM::CellId::extractFromRefId(mMarkedCell->getCell()->getId()); + player.mMarkedCell = mMarkedCell->getCell()->getId(); } else player.mHasMark = false; @@ -367,11 +367,11 @@ namespace MWWorld try { - mCellStore = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mCellId); + mCellStore = MWBase::Environment::get().getWorldModel()->getCell(player.mCellId); } catch (...) { - Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId.mWorldspace << "' no longer exists"; + Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId << "' no longer exists"; // Cell no longer exists. The loader will have to choose a default cell. mCellStore = nullptr; } @@ -392,19 +392,20 @@ namespace MWWorld mLastKnownExteriorPosition.y() = player.mLastKnownExteriorPosition[1]; mLastKnownExteriorPosition.z() = player.mLastKnownExteriorPosition[2]; - if (player.mHasMark && !player.mMarkedCell.mPaged) + bool exterior = ESM::CellId::extractFromRefId(player.mMarkedCell).mPaged; + if (player.mHasMark && !exterior) { // interior cell -> need to check if it exists (exterior cell will be // generated on the fly) - if (!world.getStore().get().search(player.mMarkedCell.mWorldspace)) + if (!world.getStore().get().search(player.mMarkedCell)) player.mHasMark = false; // drop mark silently } if (player.mHasMark) { mMarkedPosition = player.mMarkedPosition; - mMarkedCell = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mMarkedCell); + mMarkedCell = MWBase::Environment::get().getWorldModel()->getCell(player.mMarkedCell); } else { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 16ff60db61..712ec95d1a 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -575,9 +575,6 @@ namespace MWWorld newCell.mAmbi.mSunlight = 0; newCell.mAmbi.mFog = 0; newCell.mAmbi.mFogDensity = 0; - newCell.mCellId.mPaged = true; - newCell.mCellId.mIndex.mX = x; - newCell.mCellId.mIndex.mY = y; newCell.updateId(); ESM::Cell* newCellInserted = &mCells.insert(std::make_pair(newCell.mId, newCell)).first->second; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2af2ae7faf..7515404037 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -380,10 +380,10 @@ namespace MWWorld pos.rot[2] = 0; osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]); - ESM::CellId CellId; - CellId.mPaged = true; - CellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; - mWorldScene->changeToExteriorCell(CellId.getCellRefId(), pos, true); + ESM::CellId cellId; + cellId.mPaged = true; + cellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; + mWorldScene->changeToExteriorCell(cellId.getCellRefId(), pos, true); } } @@ -987,28 +987,14 @@ namespace MWWorld } removeContainerScripts(getPlayerPtr()); osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]); - ESM::CellId CellId; - CellId.mPaged = true; - CellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; - mWorldScene->changeToExteriorCell(CellId.getCellRefId(), position, adjustPlayerPos, changeEvent); + ESM::CellId cellId; + cellId.mPaged = true; + cellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; + mWorldScene->changeToExteriorCell(cellId.getCellRefId(), position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); mRendering->getCamera()->instantTransition(); } - void World::changeToCell( - const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) - { - if (!changeEvent) - mCurrentWorldSpace = cellId.mWorldspace; - - if (cellId.mPaged) - changeToExteriorCell(position, adjustPlayerPos, changeEvent); - else - changeToInteriorCell(cellId.mWorldspace, position, adjustPlayerPos, changeEvent); - - mCurrentDate->setup(mGlobalVariables); - } - void World::changeToCell( const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e2b57c8a1a..dac6df120c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,9 +349,6 @@ namespace MWWorld ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - void changeToCell(const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, - bool changeEvent = true) override; - void changeToCell(const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 65aeca3bec..a067280519 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -143,7 +143,8 @@ void MWWorld::WorldModel::writeCell(ESM::ESMWriter& writer, CellStore& cell) con cell.saveState(cellState); writer.startRecord(ESM::REC_CSTA); - cellState.mId.save(writer); + + writer.writeCellId(cellState.mId); cellState.save(writer); cell.writeFog(writer); cell.writeReferences(writer); @@ -170,11 +171,6 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) { // Cell isn't predefined. Make one on the fly. ESM::Cell record; - record.mCellId.mWorldspace = ESM::CellId::sDefaultWorldspace; - record.mCellId.mPaged = true; - record.mCellId.mIndex.mX = x; - record.mCellId.mIndex.mY = y; - record.mData.mFlags = ESM::Cell::HasWater; record.mData.mX = x; record.mData.mY = y; @@ -227,14 +223,6 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) return result->second; } -MWWorld::CellStore* MWWorld::WorldModel::getCellFromCellId(const ESM::CellId& id) -{ - if (id.mPaged) - return getExterior(id.mIndex.mX, id.mIndex.mY); - - return getInterior(id.mWorldspace); -} - MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id) { auto result = mCells.find(id); @@ -489,19 +477,18 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, cons if (type == ESM::REC_CSTA) { ESM::CellState state; - state.mId.load(reader); + state.mId = reader.getCellId(); CellStore* cellStore = nullptr; try { - cellStore = getCell(state.mId.getCellRefId()); + cellStore = getCell(state.mId); } catch (...) { // silently drop cells that don't exist anymore - Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId.mWorldspace - << " (cell no longer exists)"; + Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId << " (cell no longer exists)"; reader.skipRecord(); return true; } diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 04afff0095..10292c3ca5 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -17,7 +17,6 @@ namespace ESM class ESMReader; class ESMWriter; class ReadersCache; - struct CellId; struct Cell; struct RefNum; } @@ -71,7 +70,6 @@ namespace MWWorld CellStore* getInterior(std::string_view name); CellStore* getCell(std::string_view name); // interior or named exterior CellStore* getCell(const ESM::RefId& Id); - CellStore* getCellFromCellId(const ESM::CellId& Id); // If cellNameInSameWorldSpace is an interior - returns this interior. // Otherwise returns exterior cell for given position in the same world space. diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index ee6238cbc6..26283bb44f 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -15,7 +15,6 @@ namespace ESM4 namespace ESM { struct Cell; - struct CellId; class RefId; class CellVariant; diff --git a/components/esm3/cellstate.cpp b/components/esm3/cellstate.cpp index 830a4211b6..7855aeac40 100644 --- a/components/esm3/cellstate.cpp +++ b/components/esm3/cellstate.cpp @@ -21,7 +21,7 @@ namespace ESM void CellState::save(ESMWriter& esm) const { - if (!mId.mPaged) + if (mIsInterior) esm.writeHNT("WLVL", mWaterLevel); esm.writeHNT("HFOW", mHasFogOfWar); diff --git a/components/esm3/cellstate.hpp b/components/esm3/cellstate.hpp index 2f721b3838..703e31e81b 100644 --- a/components/esm3/cellstate.hpp +++ b/components/esm3/cellstate.hpp @@ -15,8 +15,8 @@ namespace ESM /// \note Does not include references struct CellState { - CellId mId; - + RefId mId; + bool mIsInterior; float mWaterLevel; int mHasFogOfWar; // Do we have fog of war state (0 or 1)? (see fogstate.hpp) diff --git a/components/esm3/custommarkerstate.cpp b/components/esm3/custommarkerstate.cpp index 4568cfa748..a45a6a73a6 100644 --- a/components/esm3/custommarkerstate.cpp +++ b/components/esm3/custommarkerstate.cpp @@ -10,7 +10,7 @@ namespace ESM { esm.writeHNT("POSX", mWorldX); esm.writeHNT("POSY", mWorldY); - mCellId.save(esm); + esm.writeCellId(mCell); if (!mNote.empty()) esm.writeHNString("NOTE", mNote); } @@ -19,8 +19,7 @@ namespace ESM { esm.getHNT(mWorldX, "POSX"); esm.getHNT(mWorldY, "POSY"); - mCellId.load(esm); - mCell = mCellId.getCellRefId(); + mCell = esm.getCellId(); mNote = esm.getHNOString("NOTE"); } diff --git a/components/esm3/custommarkerstate.hpp b/components/esm3/custommarkerstate.hpp index e1a129ffbe..1c0822277b 100644 --- a/components/esm3/custommarkerstate.hpp +++ b/components/esm3/custommarkerstate.hpp @@ -13,7 +13,6 @@ namespace ESM float mWorldY; RefId mCell; - CellId mCellId; // The CellId representation for saving/loading std::string mNote; diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 20ec9e47b8..5f618903c4 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -3,6 +3,7 @@ #include "readerscache.hpp" #include "savedgame.hpp" +#include #include #include #include @@ -86,6 +87,13 @@ namespace ESM } } + ESM::RefId ESMReader::getCellId() + { + ESM::CellId cellId; + cellId.load(*this); + return cellId.getCellRefId(); + } + void ESMReader::openRaw(std::unique_ptr&& stream, const std::filesystem::path& name) { close(); diff --git a/components/esm3/esmreader.hpp b/components/esm3/esmreader.hpp index 3e667e6972..703f10be0c 100644 --- a/components/esm3/esmreader.hpp +++ b/components/esm3/esmreader.hpp @@ -96,6 +96,9 @@ namespace ESM * *************************************************************************/ + // Because we want to get rid of CellId, we isolate it's uses. + ESM::RefId getCellId(); + // Read data of a given type, stored in a subrecord of a given name template void getHNT(X& x, NAME name) diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index 02c7464b33..db84f58332 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -236,6 +237,12 @@ namespace ESM writeHNRefId(name, value); } + void ESMWriter::writeCellId(const ESM::RefId& cellId) + { + ESM::CellId cell = ESM::CellId::extractFromRefId(cellId); + cell.save(*this); + } + void ESMWriter::writeMaybeFixedSizeString(const std::string& data, std::size_t size) { std::string string; diff --git a/components/esm3/esmwriter.hpp b/components/esm3/esmwriter.hpp index 54abca41f2..acf9488d9a 100644 --- a/components/esm3/esmwriter.hpp +++ b/components/esm3/esmwriter.hpp @@ -103,6 +103,8 @@ namespace ESM writeHNCRefId(name, value); } + void writeCellId(const ESM::RefId& cellId); + template void writeHNT(NAME name, const T& data) { diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 2c6060ce8a..6db783d5c6 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -59,7 +59,23 @@ namespace ESM const ESM::RefId& Cell::updateId() { - mId = mCellId.getCellRefId(); + CellId cellid; + + cellid.mPaged = !(mData.mFlags & Interior); + + if (cellid.mPaged) + { + cellid.mWorldspace = CellId::sDefaultWorldspace; + cellid.mIndex.mX = mData.mX; + cellid.mIndex.mY = mData.mY; + } + else + { + cellid.mWorldspace = Misc::StringUtils::lowerCase(mName); + cellid.mIndex.mX = 0; + cellid.mIndex.mY = 0; + } + mId = cellid.getCellRefId(); return mId; } @@ -97,20 +113,6 @@ namespace ESM if (!hasData) esm.fail("Missing DATA subrecord"); - mCellId.mPaged = !(mData.mFlags & Interior); - - if (mCellId.mPaged) - { - mCellId.mWorldspace = CellId::sDefaultWorldspace; - mCellId.mIndex.mX = mData.mX; - mCellId.mIndex.mY = mData.mY; - } - else - { - mCellId.mWorldspace = Misc::StringUtils::lowerCase(mName); - mCellId.mIndex.mX = 0; - mCellId.mIndex.mY = 0; - } updateId(); } @@ -340,8 +342,4 @@ namespace ESM mAmbi.mFogDensity = 0; } - const CellId& Cell::getCellId() const - { - return mCellId; - } } diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index f49f4f083a..d59186b6f0 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -120,7 +120,6 @@ namespace ESM std::vector mContextList; // File position; multiple positions for multiple plugin support DATAstruct mData; - CellId mCellId; AMBIstruct mAmbi; bool mHasAmbi; @@ -191,7 +190,6 @@ namespace ESM void blank(); ///< Set record to default state (does not touch the ID/index). - const CellId& getCellId() const; const ESM::RefId& updateId(); }; } diff --git a/components/esm3/player.cpp b/components/esm3/player.cpp index 0a25886ce0..4c56c7488b 100644 --- a/components/esm3/player.cpp +++ b/components/esm3/player.cpp @@ -11,7 +11,7 @@ namespace ESM mObject.mRef.loadId(esm, true); mObject.load(esm); - mCellId.load(esm); + mCellId = esm.getCellId(); esm.getHNTSized<12>(mLastKnownExteriorPosition, "LKEP"); @@ -19,7 +19,7 @@ namespace ESM { mHasMark = true; esm.getHTSized<24>(mMarkedPosition); - mMarkedCell.load(esm); + mMarkedCell = esm.getCellId(); } else mHasMark = false; @@ -92,14 +92,14 @@ namespace ESM { mObject.save(esm); - mCellId.save(esm); + esm.writeCellId(mCellId); esm.writeHNT("LKEP", mLastKnownExteriorPosition); if (mHasMark) { esm.writeHNT("MARK", mMarkedPosition, 24); - mMarkedCell.save(esm); + esm.writeCellId(mMarkedCell); } esm.writeHNRefId("SIGN", mBirthsign); diff --git a/components/esm3/player.hpp b/components/esm3/player.hpp index 82ce5e25df..25d9c76fce 100644 --- a/components/esm3/player.hpp +++ b/components/esm3/player.hpp @@ -20,12 +20,12 @@ namespace ESM struct Player { NpcState mObject; - CellId mCellId; + RefId mCellId; float mLastKnownExteriorPosition[3]; unsigned char mHasMark; bool mSetWerewolfAcrobatics; Position mMarkedPosition; - CellId mMarkedCell; + RefId mMarkedCell; ESM::RefId mBirthsign; int mCurrentCrimeId; diff --git a/components/esmloader/load.cpp b/components/esmloader/load.cpp index 46fe3717a4..5b1888f2ce 100644 --- a/components/esmloader/load.cpp +++ b/components/esmloader/load.cpp @@ -45,7 +45,7 @@ namespace EsmLoader return (v.mId); } - const ESM::CellId& operator()(const ESM::Cell& v) const { return v.mCellId; } + const ESM::RefId& operator()(const ESM::Cell& v) const { return v.mId; } std::pair operator()(const ESM::Land& v) const { return std::pair(v.mX, v.mY); } From fb6701ac1aa762d485bb5b0f77f2ab2334ddab31 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 22 Feb 2023 13:45:29 +0100 Subject: [PATCH 10/19] ESM::CellId is no longer stored on saves. --- apps/openmw_test_suite/mwworld/test_store.cpp | 1 + components/esm3/esmreader.cpp | 10 +++++++--- components/esm3/esmwriter.cpp | 3 +-- components/esm3/formatversion.hpp | 4 +++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 9dcab91f76..36999e633c 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -285,6 +285,7 @@ namespace ESM::MaxOldSkillsAndAttributesFormatVersion, ESM::MaxOldCreatureStatsFormatVersion, ESM::MaxStringRefIdFormatVersion, + ESM::MaxUseEsmCellId, }); for (ESM::FormatVersion v = result.back() + 1; v <= ESM::CurrentSaveGameFormatVersion; ++v) result.push_back(v); diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 5f618903c4..2cb5322059 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -89,9 +89,13 @@ namespace ESM ESM::RefId ESMReader::getCellId() { - ESM::CellId cellId; - cellId.load(*this); - return cellId.getCellRefId(); + if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellId) + { + ESM::CellId cellId; + cellId.load(*this); + return cellId.getCellRefId(); + } + return getHNRefId("NAME"); } void ESMReader::openRaw(std::unique_ptr&& stream, const std::filesystem::path& name) diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index db84f58332..5da6076ce3 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -239,8 +239,7 @@ namespace ESM void ESMWriter::writeCellId(const ESM::RefId& cellId) { - ESM::CellId cell = ESM::CellId::extractFromRefId(cellId); - cell.save(*this); + writeHNRefId("NAME", cellId); } void ESMWriter::writeMaybeFixedSizeString(const std::string& data, std::size_t size) diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index 144b4c23af..f273542458 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -23,7 +23,9 @@ namespace ESM inline constexpr FormatVersion MaxStringRefIdFormatVersion = 23; inline constexpr FormatVersion MaxSavedGameCellNameAsRefIdFormatVersion = 24; inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25; - inline constexpr FormatVersion CurrentSaveGameFormatVersion = 26; + inline constexpr FormatVersion MaxUseEsmCellId = 26; + inline constexpr FormatVersion CurrentSaveGameFormatVersion = 27; + } #endif From c2182c2fcccfc14c08f545663c9e175e8881ef35 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 22 Feb 2023 15:57:59 +0100 Subject: [PATCH 11/19] Get Rid of ESM::CellId almost everywhere it was a competing concept from using RefIds for cell. There is almost no point to it now, except to load older data. --- apps/essimporter/convertplayer.cpp | 16 ++++---- apps/essimporter/importer.cpp | 7 +++- apps/essimporter/importercontext.hpp | 6 +-- apps/navmeshtool/worldspacedata.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 4 +- apps/opencs/view/world/regionmap.cpp | 2 +- apps/opencs/view/world/scenesubview.cpp | 4 +- apps/openmw/mwgui/mapwindow.cpp | 37 +++++++++---------- apps/openmw/mwgui/travelwindow.cpp | 16 +++++--- apps/openmw/mwworld/cell.cpp | 2 +- apps/openmw/mwworld/cellref.cpp | 8 +--- apps/openmw/mwworld/worldimp.cpp | 14 +++---- apps/openmw_test_suite/mwworld/test_store.cpp | 5 +-- components/esm3/cellid.cpp | 14 ------- components/esm3/cellid.hpp | 3 -- components/esm3/esmreader.cpp | 10 ++++- components/esm3/loadcell.cpp | 21 +++++------ components/esm3/loadcell.hpp | 4 ++ 18 files changed, 82 insertions(+), 93 deletions(-) diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index 855a473e08..f4238a135b 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -60,20 +61,19 @@ namespace ESSImport const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation; - ESM::CellId cell; - cell.mPaged = true; - - cell.mIndex.mX = mark.mCellX; - cell.mIndex.mY = mark.mCellY; + ESM::RefId cell; // TODO: Figure out a better way to detect interiors. (0, 0) is a valid exterior cell. if (mark.mCellX == 0 && mark.mCellY == 0) { - cell.mWorldspace = pcdt.mMNAM; - cell.mPaged = false; + cell = ESM::RefId::stringRefId(pcdt.mMNAM); + } + else + { + cell = ESM::Cell::generateIdForExteriorCell(mark.mCellX, mark.mCellY); } - out.mMarkedCell = cell.getCellRefId(); + out.mMarkedCell = cell; out.mMarkedPosition.pos[0] = mark.mX; out.mMarkedPosition.pos[1] = mark.mY; out.mMarkedPosition.pos[2] = mark.mZ; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 38ebf41596..76548d16ee 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -419,8 +419,13 @@ namespace ESSImport = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits)); cellId.mIndex.mX = cellX; cellId.mIndex.mY = cellY; + + context.mPlayer.mCellId = ESM::Cell::generateIdForExteriorCell(cellX, cellY); + } + else + { + context.mPlayer.mCellId = ESM::RefId::stringRefId(cellId.mWorldspace); } - context.mPlayer.mCellId = cellId.getCellRefId(); context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 9e5d9c0006..788946b762 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -59,10 +60,7 @@ namespace ESSImport , mHour(0.f) , mNextActorId(0) { - ESM::CellId playerCellId; - playerCellId.mPaged = true; - playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0; - mPlayer.mCellId = playerCellId.getCellRefId(); + mPlayer.mCellId = ESM::Cell::generateIdForExteriorCell(0, 0); mPlayer.mLastKnownExteriorPosition[0] = mPlayer.mLastKnownExteriorPosition[1] = mPlayer.mLastKnownExteriorPosition[2] = 0.0f; mPlayer.mHasMark = 0; diff --git a/apps/navmeshtool/worldspacedata.cpp b/apps/navmeshtool/worldspacedata.cpp index fd66a46f4c..3de8d2395f 100644 --- a/apps/navmeshtool/worldspacedata.cpp +++ b/apps/navmeshtool/worldspacedata.cpp @@ -264,7 +264,7 @@ namespace NavMeshTool const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY); const std::size_t cellObjectsBegin = data.mObjects.size(); const auto cellNameLowerCase - = Misc::StringUtils::lowerCase(cell.isExterior() ? ESM::CellId::sDefaultWorldspace : cell.mName); + = Misc::StringUtils::lowerCase(cell.isExterior() ? ESM::Cell::sDefaultWorldspace : cell.mName); WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& { auto it = navMeshInputs.find(cellNameLowerCase); if (it == navMeshInputs.end()) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 4ec9c301f1..23e772afcd 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include "collectionbase.hpp" @@ -337,7 +337,7 @@ std::pair CSMWorld::IdTable::view(int row) c return std::make_pair(UniversalId::Type_None, ""); if (id[0] == '#') - id = ESM::CellId::sDefaultWorldspace; + id = ESM::Cell::sDefaultWorldspace; return std::make_pair(UniversalId(UniversalId::Type_Scene, id), hint); } diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index df5418ba76..4f4a2c6a2b 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -307,7 +307,7 @@ void CSVWorld::RegionMap::view() } emit editRequest( - CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::CellId::sDefaultWorldspace), hint.str()); + CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace), hint.str()); } void CSVWorld::RegionMap::viewInTable() diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index ed2820c542..26127bb961 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -49,7 +49,7 @@ CSVWorld::SceneSubView::SceneSubView(const CSMWorld::UniversalId& id, CSMDoc::Do CSVRender::WorldspaceWidget* worldspaceWidget = nullptr; widgetType whatWidget; - if (Misc::StringUtils::ciEqual(id.getId(), ESM::CellId::sDefaultWorldspace)) + if (Misc::StringUtils::ciEqual(id.getId(), ESM::Cell::sDefaultWorldspace)) { whatWidget = widget_Paged; @@ -170,7 +170,7 @@ void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::UniversalId& i void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::CellSelection& selection) { - setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::CellId::sDefaultWorldspace)); + setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace)); int size = selection.getSize(); std::ostringstream stream; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 733a564db5..1118fce014 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -351,12 +351,17 @@ namespace MWGui { for (int dY = -mCellDistance; dY <= mCellDistance; ++dY) { - ESM::CellId cellId; - cellId.mPaged = !mInterior; - cellId.mWorldspace = (mInterior ? mPrefix : ESM::CellId::sDefaultWorldspace); - cellId.mIndex.mX = mCurX + dX; - cellId.mIndex.mY = mCurY + dY; - ESM::RefId cellRefId = cellId.getCellRefId(); + ESM::RefId cellRefId; + + if (mInterior) + { + cellRefId = ESM::RefId::stringRefId(mPrefix); + } + else + { + cellRefId = ESM::Cell::generateIdForExteriorCell(mCurX + dX, mCurY + dY); + } + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) @@ -885,18 +890,17 @@ namespace MWGui mEditingMarker.mWorldX = worldPos.x(); mEditingMarker.mWorldY = worldPos.y(); - ESM::CellId clickedId; + ESM::RefId clickedId; - clickedId.mPaged = !mInterior; if (mInterior) - clickedId.mWorldspace = LocalMapBase::mPrefix; + { + clickedId = ESM::RefId::stringRefId(LocalMapBase::mPrefix); + } else { - clickedId.mWorldspace = ESM::CellId::sDefaultWorldspace; - clickedId.mIndex.mX = x; - clickedId.mIndex.mY = y; + clickedId = ESM::Cell::generateIdForExteriorCell(x, y); } - mEditingMarker.mCell = clickedId.getCellRefId(); + mEditingMarker.mCell = clickedId; mEditNoteDialog.setVisible(true); mEditNoteDialog.showDeleteButton(false); @@ -1122,12 +1126,7 @@ namespace MWGui void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y) { - ESM::CellId cellId; - cellId.mIndex.mX = x; - cellId.mIndex.mY = y; - cellId.mWorldspace = ESM::CellId::sDefaultWorldspace; - cellId.mPaged = true; - ESM::RefId cellRefId = cellId.getCellRefId(); + ESM::RefId cellRefId = ESM::Cell::generateIdForExteriorCell(x, y); CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); std::vector destNotes; for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7798bf7105..1a70954194 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -195,15 +195,19 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); - ESM::CellId cellId; + ESM::RefId cellId; osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]); - cellId.mPaged = !interior; - cellId.mWorldspace = Misc::StringUtils::lowerCase(cellname); - cellId.mIndex.mX = posCell.x(); - cellId.mIndex.mY = posCell.y(); + if (interior) + { + cellId = ESM::RefId::stringRefId(cellname); + } + else + { + cellId = ESM::Cell::generateIdForExteriorCell(posCell.x(), posCell.y()); + } // Teleports any followers, too. - MWWorld::ActionTeleport action(cellId.getCellRefId(), pos, true); + MWWorld::ActionTeleport action(cellId, pos, true); action.execute(player); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0); diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 7680090410..6aecbb827a 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -40,7 +40,7 @@ namespace MWWorld , mNameID(cell.mName) , mRegion(cell.mRegion) , mId(cell.mId) - , mParent(ESM::RefId::stringRefId(ESM::CellId::sDefaultWorldspace)) + , mParent(ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace)) , mMood{ .mAmbiantColor = cell.mAmbi.mAmbient, .mDirectionalColor = cell.mAmbi.mSunlight, diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 49d21f4b0e..cdfc211124 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -90,11 +90,7 @@ namespace MWWorld else { const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); - ESM::CellId cellId; - cellId.mPaged = true; - cellId.mIndex.mX = index.x(); - cellId.mIndex.mY = index.y(); - return cellId.getCellRefId(); + return ESM::Cell::generateIdForExteriorCell(index.x(), index.y()); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7515404037..163cf624f9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -380,10 +380,8 @@ namespace MWWorld pos.rot[2] = 0; osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]); - ESM::CellId cellId; - cellId.mPaged = true; - cellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; - mWorldScene->changeToExteriorCell(cellId.getCellRefId(), pos, true); + ESM::RefId cellId = ESM::Cell::generateIdForExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); + mWorldScene->changeToExteriorCell(cellId, pos, true); } } @@ -979,7 +977,7 @@ namespace MWWorld mPhysics->clearQueuedMovement(); mDiscardMovements = true; - if (changeEvent && mCurrentWorldSpace != ESM::CellId::sDefaultWorldspace) + if (changeEvent && mCurrentWorldSpace != ESM::Cell::sDefaultWorldspace) { // changed worldspace mProjectileManager->clear(); @@ -987,10 +985,8 @@ namespace MWWorld } removeContainerScripts(getPlayerPtr()); osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]); - ESM::CellId cellId; - cellId.mPaged = true; - cellId.mIndex = { exteriorCellPos.x(), exteriorCellPos.y() }; - mWorldScene->changeToExteriorCell(cellId.getCellRefId(), position, adjustPlayerPos, changeEvent); + ESM::RefId cellId = ESM::Cell::generateIdForExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); + mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); mRendering->getCamera()->instantTransition(); } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 36999e633c..1b89e79f54 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -448,10 +448,7 @@ namespace refId = RecordType::indexToRefId(index); else if constexpr (std::is_same_v) { - ESM::CellId cellId; - cellId.mPaged = true; - cellId.mIndex = { 0, 0 }; - refId = cellId.getCellRefId(); + refId = ESM::Cell::generateIdForExteriorCell(0, 0); } else refId = ESM::StringRefId(stringId); diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index c295084a91..25dd7bfc55 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -7,8 +7,6 @@ namespace ESM { - const std::string CellId::sDefaultWorldspace = "sys::default"; - void CellId::load(ESMReader& esm) { mWorldspace = esm.getHNString("SPAC"); @@ -34,18 +32,6 @@ namespace ESM esm.writeHNT("CIDX", mIndex, 8); } - ESM::RefId CellId::getCellRefId() const - { - if (mPaged) - { - return ESM::RefId::stringRefId("#" + std::to_string(mIndex.mX) + "," + std::to_string(mIndex.mY)); - } - else - { - return ESM::RefId::stringRefId(mWorldspace); - } - } - CellId CellId::extractFromRefId(const ESM::RefId& id) { // This is bad and that code should not be merged. diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 0b27425e35..eeedc5f554 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -21,11 +21,8 @@ namespace ESM CellIndex mIndex; bool mPaged; - static const std::string sDefaultWorldspace; - void load(ESMReader& esm); void save(ESMWriter& esm) const; - ESM::RefId getCellRefId() const; // TODO tetramir: this probably shouldn't exist, needs it because some CellIds are saved on disk static CellId extractFromRefId(const ESM::RefId& id); diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 2cb5322059..2797ee83e4 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -4,6 +4,7 @@ #include "savedgame.hpp" #include +#include #include #include #include @@ -93,7 +94,14 @@ namespace ESM { ESM::CellId cellId; cellId.load(*this); - return cellId.getCellRefId(); + if (cellId.mPaged) + { + return ESM::Cell::generateIdForExteriorCell(cellId.mIndex.mX, cellId.mIndex.mY); + } + else + { + return ESM::RefId::stringRefId(cellId.mWorldspace); + } } return getHNRefId("NAME"); } diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 6db783d5c6..0f18e80a9d 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -40,6 +40,8 @@ namespace ESM namespace ESM { + const std::string Cell::sDefaultWorldspace = "sys::default"; + // Some overloaded compare operators. bool operator==(const MovedCellRef& ref, const RefNum& refNum) { @@ -59,26 +61,23 @@ namespace ESM const ESM::RefId& Cell::updateId() { - CellId cellid; - - cellid.mPaged = !(mData.mFlags & Interior); - if (cellid.mPaged) + if (mData.mFlags & Interior) { - cellid.mWorldspace = CellId::sDefaultWorldspace; - cellid.mIndex.mX = mData.mX; - cellid.mIndex.mY = mData.mY; + mId = ESM::RefId::stringRefId(mName); } else { - cellid.mWorldspace = Misc::StringUtils::lowerCase(mName); - cellid.mIndex.mX = 0; - cellid.mIndex.mY = 0; + mId = generateIdForExteriorCell(getGridX(), getGridY()); } - mId = cellid.getCellRefId(); return mId; } + ESM::RefId Cell::generateIdForExteriorCell(int x, int y) + { + return ESM::RefId::stringRefId("#" + std::to_string(x) + "," + std::to_string(y)); + } + void Cell::loadNameAndData(ESMReader& esm, bool& isDeleted) { isDeleted = false; diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index d59186b6f0..f35077b509 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -67,6 +67,8 @@ namespace ESM */ struct Cell { + static const std::string sDefaultWorldspace; + constexpr static RecNameInts sRecordId = REC_CELL; /// Return a string descriptor for this record type. Currently used for debugging / error logs only. @@ -191,6 +193,8 @@ namespace ESM ///< Set record to default state (does not touch the ID/index). const ESM::RefId& updateId(); + + static ESM::RefId generateIdForExteriorCell(int x, int y); }; } #endif From f99e65843ac602410424ae492beca9d1e3ed68b4 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 22 Feb 2023 23:20:15 +0100 Subject: [PATCH 12/19] Removes most cellId.hpp include, simplifies id generation for cells. --- apps/essimporter/convertplayer.cpp | 12 ++---------- apps/essimporter/importer.cpp | 21 +++++---------------- apps/opencs/view/world/regionmap.cpp | 2 -- apps/opencs/view/world/scenesubview.cpp | 2 -- apps/openmw/mwbase/world.hpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 21 ++------------------- apps/openmw/mwgui/mapwindow.hpp | 2 -- apps/openmw/mwgui/travelwindow.cpp | 10 +--------- apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/cell.cpp | 1 - apps/openmw/mwworld/cellstore.cpp | 1 - apps/openmw/mwworld/player.cpp | 6 +----- apps/openmw/mwworld/worldimp.cpp | 1 - apps/openmw/mwworld/worldmodel.cpp | 1 + components/esm3/cellstate.hpp | 3 +-- components/esm3/custommarkerstate.hpp | 4 +++- components/esm3/esmwriter.cpp | 1 - components/esm3/loadcell.cpp | 23 +++++++++++++---------- components/esm3/loadcell.hpp | 2 +- components/esm3/player.hpp | 1 - components/esm4/loadcell.hpp | 1 - 21 files changed, 30 insertions(+), 87 deletions(-) diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index f4238a135b..eeb1ecbc11 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -61,17 +61,9 @@ namespace ESSImport const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation; - ESM::RefId cell; - // TODO: Figure out a better way to detect interiors. (0, 0) is a valid exterior cell. - if (mark.mCellX == 0 && mark.mCellY == 0) - { - cell = ESM::RefId::stringRefId(pcdt.mMNAM); - } - else - { - cell = ESM::Cell::generateIdForExteriorCell(mark.mCellX, mark.mCellY); - } + bool interior = mark.mCellX == 0 && mark.mCellY == 0; + ESM::RefId cell = ESM::Cell::generateIdForCell(!interior, pcdt.mMNAM, mark.mCellX, mark.mCellY); out.mMarkedCell = cell; out.mMarkedPosition.pos[0] = mark.mX; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 76548d16ee..1692193b93 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -410,22 +411,10 @@ namespace ESSImport writer.startRecord(ESM::REC_PLAY); ESM::CellId cellId = ESM::CellId::extractFromRefId(context.mPlayer.mCellId); - if (cellId.mPaged) - { - // exterior cell -> determine cell coordinates based on position - int cellX - = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits)); - int cellY - = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits)); - cellId.mIndex.mX = cellX; - cellId.mIndex.mY = cellY; - - context.mPlayer.mCellId = ESM::Cell::generateIdForExteriorCell(cellX, cellY); - } - else - { - context.mPlayer.mCellId = ESM::RefId::stringRefId(cellId.mWorldspace); - } + int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits)); + int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits)); + + context.mPlayer.mCellId = ESM::Cell::generateIdForCell(cellId.mPaged, cellId.mWorldspace, cellX, cellY); context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 4f4a2c6a2b..f7a495c9df 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -16,8 +16,6 @@ #include -#include - #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 26127bb961..ffdf1c66bf 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -14,8 +14,6 @@ #include #include -#include - #include "../../model/doc/document.hpp" #include "../../model/world/cellselection.hpp" diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index db8eabe086..5caacbdb4d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1118fce014..eb1099720f 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -351,16 +351,7 @@ namespace MWGui { for (int dY = -mCellDistance; dY <= mCellDistance; ++dY) { - ESM::RefId cellRefId; - - if (mInterior) - { - cellRefId = ESM::RefId::stringRefId(mPrefix); - } - else - { - cellRefId = ESM::Cell::generateIdForExteriorCell(mCurX + dX, mCurY + dY); - } + ESM::RefId cellRefId = ESM::Cell::generateIdForCell(!mInterior, mPrefix, mCurX + dX, mCurY + dY); CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; @@ -890,16 +881,8 @@ namespace MWGui mEditingMarker.mWorldX = worldPos.x(); mEditingMarker.mWorldY = worldPos.y(); - ESM::RefId clickedId; + ESM::RefId clickedId = ESM::Cell::generateIdForCell(!mInterior, LocalMapBase::mPrefix, x, y); - if (mInterior) - { - clickedId = ESM::RefId::stringRefId(LocalMapBase::mPrefix); - } - else - { - clickedId = ESM::Cell::generateIdForExteriorCell(x, y); - } mEditingMarker.mCell = clickedId; mEditNoteDialog.setVisible(true); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 93387c983a..f50ad04bce 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -10,8 +10,6 @@ #include "windowpinnablebase.hpp" -#include - #include #include diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 1a70954194..26d5c250a4 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -195,16 +195,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); - ESM::RefId cellId; osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]); - if (interior) - { - cellId = ESM::RefId::stringRefId(cellname); - } - else - { - cellId = ESM::Cell::generateIdForExteriorCell(posCell.x(), posCell.y()); - } + ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.x(), posCell.y()); // Teleports any followers, too. MWWorld::ActionTeleport action(cellId, pos, true); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c4f96b3724..a2a6171f06 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -4,7 +4,6 @@ #include -#include #include #include #include diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index 6aecbb827a..e6a288c68c 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -1,6 +1,5 @@ #include "cell.hpp" -#include #include #include #include diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 6a2689c864..eef9e757ee 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 8507f73389..5a7215b78f 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -392,12 +392,8 @@ namespace MWWorld mLastKnownExteriorPosition.y() = player.mLastKnownExteriorPosition[1]; mLastKnownExteriorPosition.z() = player.mLastKnownExteriorPosition[2]; - bool exterior = ESM::CellId::extractFromRefId(player.mMarkedCell).mPaged; - if (player.mHasMark && !exterior) + if (player.mHasMark) { - // interior cell -> need to check if it exists (exterior cell will be - // generated on the fly) - if (!world.getStore().get().search(player.mMarkedCell)) player.mHasMark = false; // drop mark silently } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 163cf624f9..265a7316ee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -13,7 +13,6 @@ #include -#include #include #include #include diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index a067280519..28b126062a 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/components/esm3/cellstate.hpp b/components/esm3/cellstate.hpp index 703e31e81b..708afb13f8 100644 --- a/components/esm3/cellstate.hpp +++ b/components/esm3/cellstate.hpp @@ -1,9 +1,8 @@ #ifndef OPENMW_ESM_CELLSTATE_H #define OPENMW_ESM_CELLSTATE_H -#include "cellid.hpp" - #include "components/esm/defs.hpp" +#include "components/esm/refid.hpp" namespace ESM { diff --git a/components/esm3/custommarkerstate.hpp b/components/esm3/custommarkerstate.hpp index 1c0822277b..117d637784 100644 --- a/components/esm3/custommarkerstate.hpp +++ b/components/esm3/custommarkerstate.hpp @@ -1,10 +1,12 @@ #ifndef OPENMW_ESM_CUSTOMMARKERSTATE_H #define OPENMW_ESM_CUSTOMMARKERSTATE_H -#include "cellid.hpp" +#include namespace ESM { + class ESMReader; + class ESMWriter; // format 0, saved games only struct CustomMarker diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index 5da6076ce3..af92a7bec9 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 0f18e80a9d..4ad8e18d0a 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -7,7 +7,6 @@ #include #include -#include "cellid.hpp" #include "esmreader.hpp" #include "esmwriter.hpp" @@ -61,15 +60,7 @@ namespace ESM const ESM::RefId& Cell::updateId() { - - if (mData.mFlags & Interior) - { - mId = ESM::RefId::stringRefId(mName); - } - else - { - mId = generateIdForExteriorCell(getGridX(), getGridY()); - } + mId = generateIdForCell(isExterior(), mName, getGridX(), getGridY()); return mId; } @@ -78,6 +69,18 @@ namespace ESM return ESM::RefId::stringRefId("#" + std::to_string(x) + "," + std::to_string(y)); } + ESM::RefId Cell::generateIdForCell(bool exterior, std::string_view cellName, int x, int y) + { + if (!exterior) + { + return ESM::RefId::stringRefId(cellName); + } + else + { + return generateIdForExteriorCell(x, y); + } + } + void Cell::loadNameAndData(ESMReader& esm, bool& isDeleted) { isDeleted = false; diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index f35077b509..077fc4213d 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -5,7 +5,6 @@ #include #include -#include "cellid.hpp" #include "cellref.hpp" #include "components/esm/defs.hpp" #include "components/esm/esmcommon.hpp" @@ -195,6 +194,7 @@ namespace ESM const ESM::RefId& updateId(); static ESM::RefId generateIdForExteriorCell(int x, int y); + static ESM::RefId generateIdForCell(bool exterior, std::string_view cellName, int x, int y); }; } #endif diff --git a/components/esm3/player.hpp b/components/esm3/player.hpp index 25d9c76fce..f691f22e86 100644 --- a/components/esm3/player.hpp +++ b/components/esm3/player.hpp @@ -3,7 +3,6 @@ #include -#include "cellid.hpp" #include "components/esm/defs.hpp" #include "npcstate.hpp" diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 5fd077b068..fd1a3043ec 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -36,7 +36,6 @@ #include #include -#include #include namespace ESM4 From 1e0c3bfdec40f84d8f7a73c9b54f9cb72609b550 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 1 Mar 2023 17:27:35 +0100 Subject: [PATCH 13/19] fixes integration tests we still want to be able to write using old formats --- apps/openmw/mwworld/store.cpp | 2 +- components/esm3/esmwriter.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 712ec95d1a..d12e53eefe 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -793,12 +793,12 @@ namespace MWWorld } ESM::Cell* Store::insert(const ESM::Cell& cell) { - ESM::Cell* insertedCell = &mCells.emplace(cell.mId, cell).first->second; if (search(cell) != nullptr) { const std::string cellType = (cell.isExterior()) ? "exterior" : "interior"; throw std::runtime_error("Failed to create " + cellType + " cell"); } + ESM::Cell* insertedCell = &mCells.emplace(cell.mId, cell).first->second; if (cell.isExterior()) { std::pair key(cell.getGridX(), cell.getGridY()); diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index af92a7bec9..6af0341a3b 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -238,7 +239,13 @@ namespace ESM void ESMWriter::writeCellId(const ESM::RefId& cellId) { - writeHNRefId("NAME", cellId); + if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellId) + { + ESM::CellId generatedCellid = ESM::CellId::extractFromRefId(cellId); + generatedCellid.save(*this); + } + else + writeHNRefId("NAME", cellId); } void ESMWriter::writeMaybeFixedSizeString(const std::string& data, std::size_t size) From 4c15064a83216ea9cf8d87928d4b0e93beff9b1c Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 22 Mar 2023 14:01:52 +0100 Subject: [PATCH 14/19] Create new Vec2i RefId for ESM3 exterior cells. Applies the necessary changes to use !2708 for the new Id type --- apps/openmw/mwmechanics/aifollow.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 14 ++++---- apps/openmw/mwworld/worldmodel.cpp | 25 ++++++++++--- components/CMakeLists.txt | 1 + components/esm/refid.hpp | 9 +++++ components/esm/vec2irefid.cpp | 26 ++++++++++++++ components/esm/vec2irefid.hpp | 52 ++++++++++++++++++++++++++++ components/esm3/cellid.cpp | 38 ++++++++++++-------- components/esm3/esmreader.cpp | 7 ++++ components/esm3/esmwriter.cpp | 9 ++++- components/esm3/loadcell.cpp | 2 +- 11 files changed, 156 insertions(+), 29 deletions(-) create mode 100644 components/esm/vec2irefid.cpp create mode 100644 components/esm/vec2irefid.hpp diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 50f8f8e3c3..66acec8770 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -175,7 +175,7 @@ namespace MWMechanics } } else if (Misc::StringUtils::ciEqual(mCellId, - actor.getCell()->getCell()->getWorldSpace().getRefIdString())) // Cell to travel to + actor.getCell()->getCell()->getWorldSpace().toString())) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 7d5989baea..db692957f2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -677,8 +677,8 @@ namespace MWWorld "Testing exterior cells (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), - navigatorUpdateGuard.get()); + mNavigator.setWorldspace( + Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -735,8 +735,8 @@ namespace MWWorld "Testing interior cells (" + std::to_string(i) + "/" + std::to_string(cells.getIntSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), - navigatorUpdateGuard.get()); + mNavigator.setWorldspace( + Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -752,7 +752,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->getWorldSpace().getRefIdString()) + if (it->mName == (*iter)->getCell()->getWorldSpace().toString()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; @@ -891,8 +891,8 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().getRefIdString()), - navigatorUpdateGuard.get()); + mNavigator.setWorldspace( + Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 28b126062a..098821d26d 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -224,18 +224,35 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) return result->second; } +struct VisitorCellIdIsESM3Ext +{ + bool operator()(const ESM::Vec2iRefId& id) + { + coordOut = { id.getValue().first, id.getValue().second }; + return true; + } + + template + bool operator()(const T&) + { + return false; + } + + std::pair coordOut = {}; +}; + MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id) { auto result = mCells.find(id); if (result != mCells.end()) return &result->second; - // TODO tetramir: in the future replace that with elsid's refId variant that can be a osg::Vec2i - ESM::CellId cellId = ESM::CellId::extractFromRefId(id); - if (cellId.mPaged) // That is an exterior cell Id + VisitorCellIdIsESM3Ext isESM3ExteriorVisitor; + + if (visit(isESM3ExteriorVisitor, id)) // That is an exterior cell Id { - return getExterior(cellId.mIndex.mX, cellId.mIndex.mY); + return getExterior(isESM3ExteriorVisitor.coordOut.first, isESM3ExteriorVisitor.coordOut.second); } const ESM4::Cell* cell4 = mStore.get().search(id); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c64c7fed65..a6fcd4604e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -91,6 +91,7 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format generatedrefid indexrefid serializerefid + vec2irefid ) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index 740160c5d3..a2c5a7174e 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -14,6 +14,7 @@ #include "generatedrefid.hpp" #include "indexrefid.hpp" #include "stringrefid.hpp" +#include "vec2irefid.hpp" namespace ESM { @@ -38,6 +39,7 @@ namespace ESM FormId = 3, Generated = 4, Index = 5, + Vec2i = 6, }; // RefId is used to represent an Id that identifies an ESM record. These Ids can then be used in @@ -70,6 +72,8 @@ namespace ESM // identified by index (i.e. ESM3 SKIL). static RefId index(RecNameInts recordType, std::uint32_t value) { return RefId(IndexRefId(recordType, value)); } + static RefId vec2i(std::pair value) { return RefId(Vec2iRefId(value)); } + constexpr RefId() = default; constexpr RefId(EmptyRefId value) noexcept @@ -97,6 +101,11 @@ namespace ESM { } + constexpr RefId(Vec2iRefId value) noexcept + : mValue(value) + { + } + // Returns a reference to the value of StringRefId if it's the underlying value or throws an exception. const std::string& getRefIdString() const; diff --git a/components/esm/vec2irefid.cpp b/components/esm/vec2irefid.cpp new file mode 100644 index 0000000000..feae473a4e --- /dev/null +++ b/components/esm/vec2irefid.cpp @@ -0,0 +1,26 @@ +#include "vec2irefid.hpp" + +#include +#include + +namespace ESM +{ + std::string Vec2iRefId::toString() const + { + std::ostringstream stream; + stream << "# " << mValue.first << ", " << mValue.second; + return stream.str(); + } + + std::string Vec2iRefId::toDebugString() const + { + std::ostringstream stream; + stream << *this; + return stream.str(); + } + + std::ostream& operator<<(std::ostream& stream, Vec2iRefId value) + { + return stream << "Vec2i{" << value.mValue.first << "," << value.mValue.second << '}'; + } +} diff --git a/components/esm/vec2irefid.hpp b/components/esm/vec2irefid.hpp new file mode 100644 index 0000000000..a8b0d0ea63 --- /dev/null +++ b/components/esm/vec2irefid.hpp @@ -0,0 +1,52 @@ +#ifndef OPENMW_COMPONENTS_ESM_VEC2IREFID_HPP +#define OPENMW_COMPONENTS_ESM_VEC2IREFID_HPP + +#include +#include + +#include + +namespace ESM +{ + class Vec2iRefId + { + public: + constexpr Vec2iRefId() = default; + + constexpr explicit Vec2iRefId(std::pair value) noexcept + : mValue(value) + { + } + + std::pair getValue() const { return mValue; } + + std::string toString() const; + + std::string toDebugString() const; + + constexpr bool operator==(Vec2iRefId rhs) const noexcept { return mValue == rhs.mValue; } + + constexpr bool operator<(Vec2iRefId rhs) const noexcept { return mValue < rhs.mValue; } + + friend std::ostream& operator<<(std::ostream& stream, Vec2iRefId value); + + friend struct std::hash; + + private: + std::pair mValue = std::pair(0, 0); + }; +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(ESM::Vec2iRefId value) const noexcept + { + return (53 + std::hash{}(value.mValue.first)) * 53 + std::hash{}(value.mValue.second); + } + }; +} + +#endif diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index 25dd7bfc55..517f6cd755 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -32,28 +32,36 @@ namespace ESM esm.writeHNT("CIDX", mIndex, 8); } - CellId CellId::extractFromRefId(const ESM::RefId& id) + struct VisitCellRefId { - // This is bad and that code should not be merged. - const std::string& idString = id.getRefIdString(); - CellId out; - if (idString[0] == '#' && idString.find(',')) // That is an exterior cell Id + CellId operator()(const ESM::StringRefId& id) + { + CellId out; + out.mPaged = false; + out.mWorldspace = id.getValue(); + out.mIndex = { 0, 0 }; + return out; + } + CellId operator()(const ESM::Vec2iRefId& id) { - int x, y; - std::stringstream stringStream = std::stringstream(idString); - char sharp = '#'; - char comma = ','; - stringStream >> sharp >> x >> comma >> y; + CellId out; out.mPaged = true; - out.mIndex = { x, y }; + out.mIndex = { id.getValue().first, id.getValue().second }; + return out; } - else + + template + CellId operator()(const T& id) { - out.mPaged = false; - out.mWorldspace = Misc::StringUtils::lowerCase(idString); + throw std::runtime_error("cannot extract CellId from this Id type"); } + }; + + CellId CellId::extractFromRefId(const ESM::RefId& id) + { + // This is bad and that code should not be merged. - return out; + return visit(VisitCellRefId(), id); } bool operator==(const CellId& left, const CellId& right) diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 2797ee83e4..2cc1a81ef8 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -491,6 +491,13 @@ namespace ESM getExact(&index, sizeof(std::uint32_t)); return RefId::index(recordType, index); } + case RefIdType::Vec2i: + { + std::pair vec2i; + getExact(&vec2i.first, sizeof(std::int32_t)); + getExact(&vec2i.second, sizeof(std::int32_t)); + return RefId::vec2i(vec2i); + } } fail("Unsupported RefIdType: " + std::to_string(static_cast(refIdType))); diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index 6af0341a3b..595d34ff3a 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include #include @@ -61,6 +61,13 @@ namespace ESM mWriter.writeT(v.getRecordType()); mWriter.writeT(v.getValue()); } + + void operator()(Vec2iRefId v) const + { + mWriter.writeT(RefIdType::Vec2i); + mWriter.writeT(v.getValue().first); + mWriter.writeT(v.getValue().second); + } }; } diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 4ad8e18d0a..04e7027e9b 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -66,7 +66,7 @@ namespace ESM ESM::RefId Cell::generateIdForExteriorCell(int x, int y) { - return ESM::RefId::stringRefId("#" + std::to_string(x) + "," + std::to_string(y)); + return ESM::RefId::vec2i({ x, y }); } ESM::RefId Cell::generateIdForCell(bool exterior, std::string_view cellName, int x, int y) From 53b14c8b42d46d3300a609a65352a7a8f0c57770 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 25 Mar 2023 17:45:49 +0100 Subject: [PATCH 15/19] fix tests hopefully also fixes clang tidy --- apps/opencs/model/world/refcollection.cpp | 20 +++++++++++--------- components/esm3/cellid.cpp | 8 ++++++++ components/esm3/formatversion.hpp | 1 - 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index a0bf5fb3b9..5d67900c10 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -53,14 +53,17 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b Cell& cell2 = base ? cell.mBase : cell.mModified; - CellRef ref; - ref.mNew = false; ESM::MovedCellRef mref; bool isDeleted = false; bool isMoved = false; - while (ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved)) + while (true) { + CellRef ref; + ref.mNew = false; + + if (!ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved)) + break; // Keep mOriginalCell empty when in modified (as an indicator that the // original cell will always be equal the current cell). ref.mOriginalCell = base ? cell2.mId : ESM::RefId(); @@ -70,7 +73,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b // Autocalculate the cell index from coordinates first std::pair index = ref.getCellIndex(); - ref.mCell = ESM::RefId::stringRefId("#" + std::to_string(index.first) + " " + std::to_string(index.second)); + ref.mCell = ESM::RefId::vec2i(index); // Handle non-base moved references if (!base && isMoved) @@ -86,12 +89,11 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) { ESM::RefId indexCell = ref.mCell; - ref.mCell = ESM::RefId::stringRefId( - "#" + std::to_string(mref.mTarget[0]) + " " + std::to_string(mref.mTarget[1])); + ref.mCell = ESM::RefId::vec2i({ mref.mTarget[0], mref.mTarget[1] }); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Cell, mCells.getId(cellIndex)); - messages.add(id, "The position of the moved reference " + ref.mRefID.getRefIdString() + " (cell " + indexCell.getRefIdString() + ")" - " does not match the target cell (" + ref.mCell.getRefIdString() + ")", + messages.add(id, "The position of the moved reference " + ref.mRefID.toDebugString() + " (cell " + indexCell.toDebugString() + ")" + " does not match the target cell (" + ref.mCell.toDebugString() + ")", std::string(), CSMDoc::Message::Severity_Warning); } } @@ -118,7 +120,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b messages.add(id, "Attempt to move a non-existent reference - RefNum index " + std::to_string(ref.mRefNum.mIndex) - + ", refID " + ref.mRefID.getRefIdString() + ", content file index " + + ", refID " + ref.mRefID.toDebugString() + ", content file index " + std::to_string(ref.mRefNum.mContentFile), /*hint*/ "", CSMDoc::Message::Severity_Warning); continue; diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index 517f6cd755..00a0b93ca4 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -34,6 +34,14 @@ namespace ESM struct VisitCellRefId { + CellId operator()(const ESM::EmptyRefId) + { + CellId out; + out.mPaged = true; + out.mIndex = {}; + return out; + } + CellId operator()(const ESM::StringRefId& id) { CellId out; diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index f273542458..bb34d2eb7c 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -25,7 +25,6 @@ namespace ESM inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25; inline constexpr FormatVersion MaxUseEsmCellId = 26; inline constexpr FormatVersion CurrentSaveGameFormatVersion = 27; - } #endif From d782d37ee28909e443e4bfbb3510863ce0a85375 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 1 Apr 2023 11:31:05 +0200 Subject: [PATCH 16/19] Make sure Vec2iRefId is trivially copyable on GCC 11.3 std::pair isn't trivially copyable on some compilers so a specific struct is defined, it's an int pair, but it should be recognised by GCC 11.3 as trivially copyable Vec2iRefId => ESM3ExteriorCellRefId more explcit name and use mX,mY instead of pair renamed files and enum --- apps/essimporter/importercontext.hpp | 2 +- apps/opencs/model/world/refcollection.cpp | 4 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwworld/cellref.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 +- apps/openmw/mwworld/worldmodel.cpp | 4 +- apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/esm3exteriorcellrefid.cpp | 26 +++++++++ components/esm/esm3exteriorcellrefid.hpp | 55 +++++++++++++++++++ components/esm/refid.hpp | 8 +-- components/esm/vec2irefid.cpp | 26 --------- components/esm/vec2irefid.hpp | 52 ------------------ components/esm3/cellid.cpp | 4 +- components/esm3/esmreader.cpp | 12 ++-- components/esm3/esmwriter.cpp | 8 +-- components/esm3/loadcell.cpp | 7 +-- components/esm3/loadcell.hpp | 1 - 18 files changed, 109 insertions(+), 112 deletions(-) create mode 100644 components/esm/esm3exteriorcellrefid.cpp create mode 100644 components/esm/esm3exteriorcellrefid.hpp delete mode 100644 components/esm/vec2irefid.cpp delete mode 100644 components/esm/vec2irefid.hpp diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 788946b762..03ea9d0943 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -60,7 +60,7 @@ namespace ESSImport , mHour(0.f) , mNextActorId(0) { - mPlayer.mCellId = ESM::Cell::generateIdForExteriorCell(0, 0); + mPlayer.mCellId = ESM::RefId::esm3ExteriorCell(0, 0); mPlayer.mLastKnownExteriorPosition[0] = mPlayer.mLastKnownExteriorPosition[1] = mPlayer.mLastKnownExteriorPosition[2] = 0.0f; mPlayer.mHasMark = 0; diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 5d67900c10..125a684f86 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -73,7 +73,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b // Autocalculate the cell index from coordinates first std::pair index = ref.getCellIndex(); - ref.mCell = ESM::RefId::vec2i(index); + ref.mCell = ESM::RefId::esm3ExteriorCell(index.first, index.second); // Handle non-base moved references if (!base && isMoved) @@ -89,7 +89,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1]) { ESM::RefId indexCell = ref.mCell; - ref.mCell = ESM::RefId::vec2i({ mref.mTarget[0], mref.mTarget[1] }); + ref.mCell = ESM::RefId::esm3ExteriorCell(mref.mTarget[0], mref.mTarget[1]); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Cell, mCells.getId(cellIndex)); messages.add(id, "The position of the moved reference " + ref.mRefID.toDebugString() + " (cell " + indexCell.toDebugString() + ")" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index eb1099720f..abd233b07f 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1109,7 +1109,7 @@ namespace MWGui void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y) { - ESM::RefId cellRefId = ESM::Cell::generateIdForExteriorCell(x, y); + ESM::RefId cellRefId = ESM::RefId::esm3ExteriorCell(x, y); CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId); std::vector destNotes; for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index cdfc211124..ced128db40 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -90,7 +90,7 @@ namespace MWWorld else { const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); - return ESM::Cell::generateIdForExteriorCell(index.x(), index.y()); + return ESM::RefId::esm3ExteriorCell(index.x(), index.y()); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 265a7316ee..8d0bc5782e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -379,7 +379,7 @@ namespace MWWorld pos.rot[2] = 0; osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]); - ESM::RefId cellId = ESM::Cell::generateIdForExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); + ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); mWorldScene->changeToExteriorCell(cellId, pos, true); } } @@ -984,7 +984,7 @@ namespace MWWorld } removeContainerScripts(getPlayerPtr()); osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]); - ESM::RefId cellId = ESM::Cell::generateIdForExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); + ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); mRendering->getCamera()->instantTransition(); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 098821d26d..f1e11e295d 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -226,9 +226,9 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) struct VisitorCellIdIsESM3Ext { - bool operator()(const ESM::Vec2iRefId& id) + bool operator()(const ESM::ESM3ExteriorCellRefId& id) { - coordOut = { id.getValue().first, id.getValue().second }; + coordOut = { id.getX(), id.getY() }; return true; } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 1b89e79f54..6a38b1cd5b 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -448,7 +448,7 @@ namespace refId = RecordType::indexToRefId(index); else if constexpr (std::is_same_v) { - refId = ESM::Cell::generateIdForExteriorCell(0, 0); + refId = ESM::RefId::esm3ExteriorCell(0, 0); } else refId = ESM::StringRefId(stringId); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6fcd4604e..55fb7a76d4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -91,7 +91,7 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format generatedrefid indexrefid serializerefid - vec2irefid + esm3exteriorcellrefid ) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/esm3exteriorcellrefid.cpp b/components/esm/esm3exteriorcellrefid.cpp new file mode 100644 index 0000000000..c4c210032a --- /dev/null +++ b/components/esm/esm3exteriorcellrefid.cpp @@ -0,0 +1,26 @@ +#include "esm3exteriorcellrefid.hpp" + +#include +#include + +namespace ESM +{ + std::string ESM3ExteriorCellRefId::toString() const + { + std::ostringstream stream; + stream << "# " << mY << ", " << mY; + return stream.str(); + } + + std::string ESM3ExteriorCellRefId::toDebugString() const + { + std::ostringstream stream; + stream << *this; + return stream.str(); + } + + std::ostream& operator<<(std::ostream& stream, ESM3ExteriorCellRefId value) + { + return stream << "Vec2i{" << value.mX << "," << value.mY << '}'; + } +} diff --git a/components/esm/esm3exteriorcellrefid.hpp b/components/esm/esm3exteriorcellrefid.hpp new file mode 100644 index 0000000000..00dd3ae26a --- /dev/null +++ b/components/esm/esm3exteriorcellrefid.hpp @@ -0,0 +1,55 @@ +#ifndef OPENMW_COMPONENTS_ESM_ESM3EXTERIORCELLREFID_HPP +#define OPENMW_COMPONENTS_ESM_ESM3EXTERIORCELLREFID_HPP + +#include +#include + +#include + +namespace ESM +{ + class ESM3ExteriorCellRefId + { + public: + constexpr ESM3ExteriorCellRefId() = default; + + constexpr explicit ESM3ExteriorCellRefId(int32_t x, int32_t y) noexcept + : mX(x) + , mY(y) + { + } + + std::string toString() const; + + std::string toDebugString() const; + + int32_t getX() const { return mX; } + int32_t getY() const { return mY; } + + constexpr bool operator==(ESM3ExteriorCellRefId rhs) const noexcept { return mX == rhs.mX && mY == rhs.mY; } + + constexpr bool operator<(ESM3ExteriorCellRefId rhs) const noexcept { return mX < rhs.mX && mY < rhs.mY; } + + friend std::ostream& operator<<(std::ostream& stream, ESM3ExteriorCellRefId value); + + friend struct std::hash; + + private: + int32_t mX = 0; + int32_t mY = 0; + }; +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(ESM::ESM3ExteriorCellRefId value) const noexcept + { + return (53 + std::hash{}(value.mX)) * 53 + std::hash{}(value.mY); + } + }; +} + +#endif diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index a2c5a7174e..e4b97ceb7b 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -10,11 +10,11 @@ #include +#include "esm3exteriorcellrefid.hpp" #include "formidrefid.hpp" #include "generatedrefid.hpp" #include "indexrefid.hpp" #include "stringrefid.hpp" -#include "vec2irefid.hpp" namespace ESM { @@ -39,7 +39,7 @@ namespace ESM FormId = 3, Generated = 4, Index = 5, - Vec2i = 6, + ESM3ExteriorCell = 6, }; // RefId is used to represent an Id that identifies an ESM record. These Ids can then be used in @@ -72,7 +72,7 @@ namespace ESM // identified by index (i.e. ESM3 SKIL). static RefId index(RecNameInts recordType, std::uint32_t value) { return RefId(IndexRefId(recordType, value)); } - static RefId vec2i(std::pair value) { return RefId(Vec2iRefId(value)); } + static RefId esm3ExteriorCell(int32_t x, int32_t y) { return RefId(ESM3ExteriorCellRefId(x, y)); } constexpr RefId() = default; @@ -101,7 +101,7 @@ namespace ESM { } - constexpr RefId(Vec2iRefId value) noexcept + constexpr RefId(ESM3ExteriorCellRefId value) noexcept : mValue(value) { } diff --git a/components/esm/vec2irefid.cpp b/components/esm/vec2irefid.cpp deleted file mode 100644 index feae473a4e..0000000000 --- a/components/esm/vec2irefid.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "vec2irefid.hpp" - -#include -#include - -namespace ESM -{ - std::string Vec2iRefId::toString() const - { - std::ostringstream stream; - stream << "# " << mValue.first << ", " << mValue.second; - return stream.str(); - } - - std::string Vec2iRefId::toDebugString() const - { - std::ostringstream stream; - stream << *this; - return stream.str(); - } - - std::ostream& operator<<(std::ostream& stream, Vec2iRefId value) - { - return stream << "Vec2i{" << value.mValue.first << "," << value.mValue.second << '}'; - } -} diff --git a/components/esm/vec2irefid.hpp b/components/esm/vec2irefid.hpp deleted file mode 100644 index a8b0d0ea63..0000000000 --- a/components/esm/vec2irefid.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef OPENMW_COMPONENTS_ESM_VEC2IREFID_HPP -#define OPENMW_COMPONENTS_ESM_VEC2IREFID_HPP - -#include -#include - -#include - -namespace ESM -{ - class Vec2iRefId - { - public: - constexpr Vec2iRefId() = default; - - constexpr explicit Vec2iRefId(std::pair value) noexcept - : mValue(value) - { - } - - std::pair getValue() const { return mValue; } - - std::string toString() const; - - std::string toDebugString() const; - - constexpr bool operator==(Vec2iRefId rhs) const noexcept { return mValue == rhs.mValue; } - - constexpr bool operator<(Vec2iRefId rhs) const noexcept { return mValue < rhs.mValue; } - - friend std::ostream& operator<<(std::ostream& stream, Vec2iRefId value); - - friend struct std::hash; - - private: - std::pair mValue = std::pair(0, 0); - }; -} - -namespace std -{ - template <> - struct hash - { - std::size_t operator()(ESM::Vec2iRefId value) const noexcept - { - return (53 + std::hash{}(value.mValue.first)) * 53 + std::hash{}(value.mValue.second); - } - }; -} - -#endif diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index 00a0b93ca4..1c9382f546 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -50,11 +50,11 @@ namespace ESM out.mIndex = { 0, 0 }; return out; } - CellId operator()(const ESM::Vec2iRefId& id) + CellId operator()(const ESM::ESM3ExteriorCellRefId& id) { CellId out; out.mPaged = true; - out.mIndex = { id.getValue().first, id.getValue().second }; + out.mIndex = { id.getX(), id.getY() }; return out; } diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 2cc1a81ef8..6c7c6cc5a7 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -96,7 +96,7 @@ namespace ESM cellId.load(*this); if (cellId.mPaged) { - return ESM::Cell::generateIdForExteriorCell(cellId.mIndex.mX, cellId.mIndex.mY); + return ESM::RefId::esm3ExteriorCell(cellId.mIndex.mX, cellId.mIndex.mY); } else { @@ -491,12 +491,12 @@ namespace ESM getExact(&index, sizeof(std::uint32_t)); return RefId::index(recordType, index); } - case RefIdType::Vec2i: + case RefIdType::ESM3ExteriorCell: { - std::pair vec2i; - getExact(&vec2i.first, sizeof(std::int32_t)); - getExact(&vec2i.second, sizeof(std::int32_t)); - return RefId::vec2i(vec2i); + int32_t x, y; + getExact(&x, sizeof(std::int32_t)); + getExact(&y, sizeof(std::int32_t)); + return RefId::esm3ExteriorCell(x, y); } } diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index 595d34ff3a..a536169970 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -62,11 +62,11 @@ namespace ESM mWriter.writeT(v.getValue()); } - void operator()(Vec2iRefId v) const + void operator()(ESM3ExteriorCellRefId v) const { - mWriter.writeT(RefIdType::Vec2i); - mWriter.writeT(v.getValue().first); - mWriter.writeT(v.getValue().second); + mWriter.writeT(RefIdType::ESM3ExteriorCell); + mWriter.writeT(v.getX()); + mWriter.writeT(v.getY()); } }; } diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 04e7027e9b..73fd8967bd 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -64,11 +64,6 @@ namespace ESM return mId; } - ESM::RefId Cell::generateIdForExteriorCell(int x, int y) - { - return ESM::RefId::vec2i({ x, y }); - } - ESM::RefId Cell::generateIdForCell(bool exterior, std::string_view cellName, int x, int y) { if (!exterior) @@ -77,7 +72,7 @@ namespace ESM } else { - return generateIdForExteriorCell(x, y); + return ESM::RefId::esm3ExteriorCell(x, y); } } diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 077fc4213d..c889a5a620 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -193,7 +193,6 @@ namespace ESM const ESM::RefId& updateId(); - static ESM::RefId generateIdForExteriorCell(int x, int y); static ESM::RefId generateIdForCell(bool exterior, std::string_view cellName, int x, int y); }; } From 21bd28542a3e7cea3db108260b9fb3bb55915b5c Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 2 Apr 2023 22:00:39 +0200 Subject: [PATCH 17/19] Applies review advice 2d coord hash moved to hash.hpp file format version adds suffix to be more coherent don't use ESM::RefId::sEmpty RefId equality with string_view, conversion to refId unecessary action teleport remove test that mCellId is empty removes some const references, when copy is enough invalid refid => empty refid removes useless change --- apps/openmw/mwbase/world.hpp | 6 +++--- apps/openmw/mwmechanics/aifollow.cpp | 3 +-- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 3 +-- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/esm3exteriorcellrefid.hpp | 4 +++- components/esm3/esmreader.cpp | 2 +- components/esm3/esmwriter.cpp | 2 +- components/esm3/formatversion.hpp | 2 +- components/misc/hash.hpp | 7 +++++++ 14 files changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5caacbdb4d..bd43d689d3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -512,15 +512,15 @@ namespace MWBase virtual bool screenshot360(osg::Image* image) = 0; /// Find default position inside exterior cell specified by name - /// \return invalid RefId if exterior with given name not exists, the cell's RefId otherwise + /// \return empty RefId if exterior with given name not exists, the cell's RefId otherwise virtual ESM::RefId findExteriorPosition(std::string_view name, ESM::Position& pos) = 0; /// Find default position inside interior cell specified by name - /// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise + /// \return empty RefId if interior with given name not exists, the cell's RefId otherwise virtual ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) = 0; /// Find default position inside interior or exterior cell specified by name - /// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise + /// \return empty RefId if interior with given name not exists, the cell's RefId otherwise virtual ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) = 0; /// Enables or disables use of teleport spell effects (recall, intervention, etc). virtual void enableTeleporting(bool enable) = 0; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 66acec8770..68162119d2 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -174,8 +174,7 @@ namespace MWMechanics return true; } } - else if (Misc::StringUtils::ciEqual(mCellId, - actor.getCell()->getCell()->getWorldSpace().toString())) // Cell to travel to + else if (mCellId == actor.getCell()->getCell()->getWorldSpace()) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index d4365a478f..6a7dcb6c7c 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -330,7 +330,7 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore* cell) { - const ESM::RefId& id = cell->getCell()->getId(); + const ESM::RefId id = cell->getCell()->getId(); // static cache is OK for now, pathgrids can never change during runtime typedef std::map> CacheMap; static CacheMap cache; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a2a6171f06..b51ab11a11 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -554,7 +554,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file if (ptr.isInCell()) { - const ESM::RefId& cellId = ptr.getCell()->getCell()->getId(); + const ESM::RefId cellId = ptr.getCell()->getCell()->getId(); // Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again MWBase::Environment::get().getWorld()->changeToCell(cellId, ptr.getRefData().getPosition(), false, false); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index f1b6934ae2..2db14338d6 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -54,8 +54,7 @@ namespace MWWorld if (actor == world->getPlayerPtr()) { world->getPlayer().setTeleported(true); - if (!mCellId.empty()) - world->changeToCell(mCellId, mPosition, true); + world->changeToCell(mCellId, mPosition, true); teleported = world->getPlayerPtr(); } else diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db692957f2..313b0ed8f9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -752,7 +752,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->getWorldSpace().toString()) + if (it->mName == (*iter)->getCell()->getNameId()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8d0bc5782e..b7c30327aa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2801,7 +2801,7 @@ namespace MWWorld // and use its destination to position inside cell. for (const MWWorld::LiveCellRef& destDoor : source->getReadOnlyDoors().mList) { - if (ESM::RefId::stringRefId(name) == destDoor.mRef.getDestCell()) + if (name == destDoor.mRef.getDestCell()) { /// \note Using _any_ door pointed to the interior, /// not the one pointed to current door. @@ -2869,7 +2869,7 @@ namespace MWWorld { ext = mWorldModel.getCell(nameId)->getCell(); if (!ext->isExterior()) - return ESM::RefId::sEmpty; + return ESM::RefId(); } catch (std::exception&) { diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 6a38b1cd5b..aea74fab71 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -285,7 +285,7 @@ namespace ESM::MaxOldSkillsAndAttributesFormatVersion, ESM::MaxOldCreatureStatsFormatVersion, ESM::MaxStringRefIdFormatVersion, - ESM::MaxUseEsmCellId, + ESM::MaxUseEsmCellIdFormatVersion, }); for (ESM::FormatVersion v = result.back() + 1; v <= ESM::CurrentSaveGameFormatVersion; ++v) result.push_back(v); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 55fb7a76d4..b8463c8af0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -392,7 +392,7 @@ if (USE_QT) ) add_component_qt_dir (misc - helpviewer utf8qtextstream + helpviewer utf8qtextstream hash ) add_component_qt_dir (files diff --git a/components/esm/esm3exteriorcellrefid.hpp b/components/esm/esm3exteriorcellrefid.hpp index 00dd3ae26a..9bb9bf17d8 100644 --- a/components/esm/esm3exteriorcellrefid.hpp +++ b/components/esm/esm3exteriorcellrefid.hpp @@ -6,6 +6,8 @@ #include +#include + namespace ESM { class ESM3ExteriorCellRefId @@ -47,7 +49,7 @@ namespace std { std::size_t operator()(ESM::ESM3ExteriorCellRefId value) const noexcept { - return (53 + std::hash{}(value.mX)) * 53 + std::hash{}(value.mY); + return Misc::hash2dCoord(value.mX, value.mY); } }; } diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 6c7c6cc5a7..42a2b2898a 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -90,7 +90,7 @@ namespace ESM ESM::RefId ESMReader::getCellId() { - if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellId) + if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellIdFormatVersion) { ESM::CellId cellId; cellId.load(*this); diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index a536169970..59a3711b2d 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -246,7 +246,7 @@ namespace ESM void ESMWriter::writeCellId(const ESM::RefId& cellId) { - if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellId) + if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellIdFormatVersion) { ESM::CellId generatedCellid = ESM::CellId::extractFromRefId(cellId); generatedCellid.save(*this); diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index bb34d2eb7c..aa0de9b0b7 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -23,7 +23,7 @@ namespace ESM inline constexpr FormatVersion MaxStringRefIdFormatVersion = 23; inline constexpr FormatVersion MaxSavedGameCellNameAsRefIdFormatVersion = 24; inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25; - inline constexpr FormatVersion MaxUseEsmCellId = 26; + inline constexpr FormatVersion MaxUseEsmCellIdFormatVersion = 26; inline constexpr FormatVersion CurrentSaveGameFormatVersion = 27; } diff --git a/components/misc/hash.hpp b/components/misc/hash.hpp index 461acee303..f87f0daeda 100644 --- a/components/misc/hash.hpp +++ b/components/misc/hash.hpp @@ -15,6 +15,13 @@ namespace Misc std::hash hasher; seed ^= static_cast(hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } + + // Comes from https://stackoverflow.com/questions/2634690/good-hash-function-for-a-2d-index + // Effective Java (2nd edition) is cited as the source + inline std::size_t hash2dCoord(int32_t x, int32_t y) + { + return (53 + std::hash{}(x)) * 53 + std::hash{}(y); + } } #endif From 3258fa4f98e3fdf2c3cd5a2d53afa2e2eefdc2fe Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 2 Apr 2023 22:11:19 +0200 Subject: [PATCH 18/19] setworldspace uses serializeText --- apps/navmeshtool/worldspacedata.cpp | 13 +++++++------ apps/openmw/mwworld/scene.cpp | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/navmeshtool/worldspacedata.cpp b/apps/navmeshtool/worldspacedata.cpp index 3de8d2395f..12c8c050a2 100644 --- a/apps/navmeshtool/worldspacedata.cpp +++ b/apps/navmeshtool/worldspacedata.cpp @@ -263,17 +263,18 @@ namespace NavMeshTool const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY); const std::size_t cellObjectsBegin = data.mObjects.size(); - const auto cellNameLowerCase - = Misc::StringUtils::lowerCase(cell.isExterior() ? ESM::Cell::sDefaultWorldspace : cell.mName); + const auto cellWorldspace = Misc::StringUtils::lowerCase( + (cell.isExterior() ? ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace) : cell.mId) + .serializeText()); WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& { - auto it = navMeshInputs.find(cellNameLowerCase); + auto it = navMeshInputs.find(cellWorldspace); if (it == navMeshInputs.end()) { it = navMeshInputs - .emplace(cellNameLowerCase, - std::make_unique(cellNameLowerCase, settings.mRecast)) + .emplace(cellWorldspace, + std::make_unique(cellWorldspace, settings.mRecast)) .first; - it->second->mTileCachedRecastMeshManager.setWorldspace(cellNameLowerCase, nullptr); + it->second->mTileCachedRecastMeshManager.setWorldspace(cellWorldspace, nullptr); } return *it->second; }(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 313b0ed8f9..92cbd468e9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -556,7 +556,7 @@ namespace MWWorld .getExterior(playerCellX, playerCellY) ->getCell() ->getWorldSpace() - .getRefIdString()), + .serializeText()), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -677,8 +677,8 @@ namespace MWWorld "Testing exterior cells (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()), + navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -735,8 +735,8 @@ namespace MWWorld "Testing interior cells (" + std::to_string(i) + "/" + std::to_string(cells.getIntSize()) + ")..."); CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()), + navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -892,7 +892,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().toString()), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. From 0d17e20490756eb92388f763ae80152d00d217df Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 3 Apr 2023 18:41:25 +0200 Subject: [PATCH 19/19] Implements serialize/deserialize fixes test compilation. --- apps/openmw_test_suite/esm/testrefid.cpp | 6 ++++++ apps/openmw_test_suite/esm3/testsaveload.cpp | 21 +++++-------------- components/esm/esm3exteriorcellrefid.cpp | 22 ++++++++++++++------ components/esm/refid.cpp | 7 +++++++ components/esm/refid.hpp | 3 ++- components/esm/serializerefid.hpp | 1 + 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/apps/openmw_test_suite/esm/testrefid.cpp b/apps/openmw_test_suite/esm/testrefid.cpp index 4fb62bcb62..6c7afb05cc 100644 --- a/apps/openmw_test_suite/esm/testrefid.cpp +++ b/apps/openmw_test_suite/esm/testrefid.cpp @@ -342,6 +342,12 @@ namespace ESM static RefId call() { return RefId::index(REC_BOOK, 7); } }; + template <> + struct GenerateRefId + { + static RefId call() { return RefId::esm3ExteriorCell(-12, 7); } + }; + template struct ESMRefIdTypesTest : Test { diff --git a/apps/openmw_test_suite/esm3/testsaveload.cpp b/apps/openmw_test_suite/esm3/testsaveload.cpp index 049fcb6f1d..8742495b3b 100644 --- a/apps/openmw_test_suite/esm3/testsaveload.cpp +++ b/apps/openmw_test_suite/esm3/testsaveload.cpp @@ -248,16 +248,10 @@ namespace ESM record.mObject.mRef.mRefID = generateRandomRefId(); std::generate_n(std::inserter(record.mPreviousItems, record.mPreviousItems.end()), 2, [&] { return std::make_pair(generateRandomRefId(), generateRandomRefId()); }); - record.mCellId.mWorldspace = "worldspace1"; - record.mCellId.mIndex.mX = 42; - record.mCellId.mIndex.mY = 13; - record.mCellId.mPaged = true; + record.mCellId = ESM::RefId::esm3ExteriorCell(0, 0); generateArray(record.mLastKnownExteriorPosition); record.mHasMark = true; - record.mMarkedCell.mWorldspace = "worldspace2"; - record.mMarkedCell.mIndex.mX = 0; - record.mMarkedCell.mIndex.mY = 0; - record.mMarkedCell.mPaged = false; + record.mMarkedCell = ESM::RefId::esm3ExteriorCell(0, 0); generateArray(record.mMarkedPosition.pos); generateArray(record.mMarkedPosition.rot); record.mCurrentCrimeId = 42; @@ -267,16 +261,11 @@ namespace ESM EXPECT_EQ(record.mBirthsign, result.mBirthsign); EXPECT_EQ(record.mPreviousItems, result.mPreviousItems); EXPECT_EQ(record.mPreviousItems, result.mPreviousItems); - EXPECT_EQ(record.mCellId.mWorldspace, result.mCellId.mWorldspace); - EXPECT_EQ(record.mCellId.mIndex.mX, result.mCellId.mIndex.mX); - EXPECT_EQ(record.mCellId.mIndex.mY, result.mCellId.mIndex.mY); - EXPECT_EQ(record.mCellId.mPaged, result.mCellId.mPaged); + EXPECT_EQ(record.mCellId, result.mCellId); + EXPECT_THAT(record.mLastKnownExteriorPosition, ElementsAreArray(result.mLastKnownExteriorPosition)); EXPECT_EQ(record.mHasMark, result.mHasMark); - EXPECT_EQ(record.mMarkedCell.mWorldspace, result.mMarkedCell.mWorldspace); - EXPECT_EQ(record.mMarkedCell.mIndex.mX, result.mMarkedCell.mIndex.mX); - EXPECT_EQ(record.mMarkedCell.mIndex.mY, result.mMarkedCell.mIndex.mY); - EXPECT_EQ(record.mMarkedCell.mPaged, result.mMarkedCell.mPaged); + EXPECT_EQ(record.mMarkedCell, result.mMarkedCell); EXPECT_THAT(record.mMarkedPosition.pos, ElementsAreArray(result.mMarkedPosition.pos)); EXPECT_THAT(record.mMarkedPosition.rot, ElementsAreArray(result.mMarkedPosition.rot)); EXPECT_EQ(record.mCurrentCrimeId, result.mCurrentCrimeId); diff --git a/components/esm/esm3exteriorcellrefid.cpp b/components/esm/esm3exteriorcellrefid.cpp index c4c210032a..72b540cfdb 100644 --- a/components/esm/esm3exteriorcellrefid.cpp +++ b/components/esm/esm3exteriorcellrefid.cpp @@ -1,4 +1,5 @@ #include "esm3exteriorcellrefid.hpp" +#include "serializerefid.hpp" #include #include @@ -7,16 +8,25 @@ namespace ESM { std::string ESM3ExteriorCellRefId::toString() const { - std::ostringstream stream; - stream << "# " << mY << ", " << mY; - return stream.str(); + std::string result; + std::size_t integralSizeX = getIntegralSize(mX); + result.resize(integralSizeX + getIntegralSize(mY) + 3, '\0'); + serializeIntegral(mX, 0, result); + result[integralSizeX] = ':'; + serializeIntegral(mY, integralSizeX + 1, result); + return result; } std::string ESM3ExteriorCellRefId::toDebugString() const { - std::ostringstream stream; - stream << *this; - return stream.str(); + std::string result; + std::size_t integralSizeX = getIntegralSize(mX); + + serializeRefIdPrefix(integralSizeX + getIntegralSize(mY) + 1, esm3ExteriorCellRefIdPrefix, result); + serializeIntegral(mX, esm3ExteriorCellRefIdPrefix.size(), result); + result[esm3ExteriorCellRefIdPrefix.size() + integralSizeX] = ':'; + serializeIntegral(mY, esm3ExteriorCellRefIdPrefix.size() + integralSizeX + 1, result); + return result; } std::ostream& operator<<(std::ostream& stream, ESM3ExteriorCellRefId value) diff --git a/components/esm/refid.cpp b/components/esm/refid.cpp index d04ad4a845..880b6da7e2 100644 --- a/components/esm/refid.cpp +++ b/components/esm/refid.cpp @@ -237,6 +237,13 @@ namespace ESM return ESM::RefId::index(recordType, deserializeIntegral(indexRefIdPrefix.size() + sizeof(recordType) + 1, value)); } + if (value.starts_with(esm3ExteriorCellRefIdPrefix)) + { + std::int32_t x = deserializeIntegral(esm3ExteriorCellRefIdPrefix.size(), value); + std::int32_t y + = deserializeIntegral(esm3ExteriorCellRefIdPrefix.size() + getIntegralSize(x) + 1, value); + return ESM::ESM3ExteriorCellRefId(x, y); + } return ESM::RefId::stringRefId(value); } diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index e4b97ceb7b..3fafdb0b74 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -50,7 +50,8 @@ namespace ESM public: const static RefId sEmpty; - using Value = std::variant; + using Value + = std::variant; // Constructs RefId from a serialized string containing byte by byte copy of RefId::mValue. static ESM::RefId deserialize(std::string_view value); diff --git a/components/esm/serializerefid.hpp b/components/esm/serializerefid.hpp index 9f43511622..d8c5fa982a 100644 --- a/components/esm/serializerefid.hpp +++ b/components/esm/serializerefid.hpp @@ -12,6 +12,7 @@ namespace ESM constexpr std::string_view formIdRefIdPrefix = "FormId:"; constexpr std::string_view generatedRefIdPrefix = "Generated:"; constexpr std::string_view indexRefIdPrefix = "Index:"; + constexpr std::string_view esm3ExteriorCellRefIdPrefix = "Esm3ExteriorCell:"; template std::size_t getIntegralSize(T value)