From a62e75fd19ccc81a24bdffb0cfb07e4424b2c540 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 22 Apr 2023 13:59:53 +0200 Subject: [PATCH 01/22] Initial attempt at loading esm4 exteriors --- apps/openmw/mwgui/mapwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.cpp | 4 +- apps/openmw/mwlua/luabindings.cpp | 6 +- .../mwscript/transformationextensions.cpp | 12 +- apps/openmw/mwstate/statemanagerimp.cpp | 3 +- apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/esmstore.hpp | 3 +- apps/openmw/mwworld/scene.cpp | 32 +++--- apps/openmw/mwworld/store.cpp | 27 +++++ apps/openmw/mwworld/store.hpp | 3 + apps/openmw/mwworld/worldimp.cpp | 8 +- apps/openmw/mwworld/worldmodel.cpp | 105 ++++++++++++------ apps/openmw/mwworld/worldmodel.hpp | 4 +- components/esm3/loadcell.cpp | 1 + components/esm3/loadcell.hpp | 1 + components/esm4/loadwrld.cpp | 7 +- components/esm4/loadwrld.hpp | 6 +- 17 files changed, 163 insertions(+), 67 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 44306c30a5..d158755736 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -583,8 +583,8 @@ namespace MWGui if (!entry.mMapTexture) { if (!mInterior) - requestMapRender( - &MWBase::Environment::get().getWorldModel()->getExterior(entry.mCellX, entry.mCellY)); + requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior( + entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)); osg::ref_ptr texture = mLocalMapRender->getMapTexture(entry.mCellX, entry.mCellY); if (texture) @@ -641,7 +641,8 @@ namespace MWGui for (MapEntry& entry : mMaps) { if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap)) - world->getDoorMarkers(worldModel->getExterior(entry.mCellX, entry.mCellY), doors); + world->getDoorMarkers( + worldModel->getExterior(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId), doors); } if (doors.empty()) return; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 55ff9fa601..c01b9361b1 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -130,8 +130,8 @@ namespace MWGui = MWWorld::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); if (cellname.empty()) { - MWWorld::CellStore& cell - = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex.x(), cellIndex.y()); + MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( + cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId); cellname = MWBase::Environment::get().getWorld()->getCellName(&cell); interior = false; } diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index e05466740c..3e40503fbe 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -113,8 +113,10 @@ namespace MWLua addTimeBindings(api, context, true); api["getCellByName"] = [](std::string_view name) { return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name) }; }; - api["getExteriorCell"] - = [](int x, int y) { return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior(x, y) }; }; + api["getExteriorCell"] = [](int x, int y) { + return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior( + x, y, ESM::Cell::sDefaultWorldspaceId) }; + }; api["activeActors"] = GObjectList{ worldView->getActorsInScene() }; api["createObject"] = [](std::string_view recordId, sol::optional count) -> GObject { // Doesn't matter which cell to use because the new object will be in disabled state. diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 110309ae1a..4f7a136764 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -402,7 +402,8 @@ namespace MWScript if (store->isExterior()) { const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store = &worldModel->getExterior(cellIndex.x(), cellIndex.y()); + store + = &worldModel->getExterior(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace()); } } catch (std::exception&) @@ -417,7 +418,7 @@ namespace MWScript if (!isPlayer) return; const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store = &worldModel->getExterior(cellIndex.x(), cellIndex.y()); + store = &worldModel->getExterior(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace()); } if (store) { @@ -473,8 +474,8 @@ namespace MWScript MWWorld::Ptr base = ptr; if (isPlayer) { - MWWorld::CellStore* cell - = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex.x(), cellIndex.y()); + MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior( + cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId); ptr = world->moveObject(ptr, cell, osg::Vec3(x, y, z)); } else @@ -568,7 +569,8 @@ namespace MWScript if (player.getCell()->isExterior()) { const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex.x(), cellIndex.y()); + store = &MWBase::Environment::get().getWorldModel()->getExterior( + cellIndex.x(), cellIndex.y(), player.getCell()->getCell()->getWorldSpace()); } else store = player.getCell(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 38bba75c05..836f4a765a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -563,7 +563,8 @@ void MWState::StateManager::loadGame(const Character* character, const std::file { // Cell no longer exists (i.e. changed game files), choose a default cell Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell"; - MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(0, 0); + MWWorld::CellStore& cell + = MWBase::Environment::get().getWorldModel()->getExterior(0, 0, ESM::Cell::sDefaultWorldspaceId); float x, y; MWBase::Environment::get().getWorld()->indexToPosition(0, 0, x, y, false); ESM::Position pos; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index ad1a3ff428..d569b155cb 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 004c456ff1..792ba6f46a 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -42,6 +42,7 @@ namespace ESM4 struct Ingredient; struct MiscItem; struct Weapon; + struct World; } namespace ESM @@ -120,7 +121,7 @@ namespace MWWorld Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, - Store>; + Store, Store>; private: template diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 65dd36c691..c82c3f95b1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -551,12 +551,13 @@ namespace MWWorld else unloadCell(cell, navigatorUpdateGuard.get()); } - - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(mWorld.getWorldModel() - .getExterior(playerCellX, playerCellY) - .getCell() - ->getWorldSpace() - .serializeText()), + ESM::RefId currentWorldSpace = mCurrentCell->getCell()->getWorldSpace(); + mNavigator.setWorldspace( + Misc::StringUtils::lowerCase(mWorld.getWorldModel() + .getExterior(playerCellX, playerCellY, currentWorldSpace) + .getCell() + ->getWorldSpace() + .serializeText()), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -580,7 +581,7 @@ namespace MWWorld { if (!isCellInCollection(x, y, collection)) { - refsToLoad += mWorld.getWorldModel().getExterior(x, y).count(); + refsToLoad += mWorld.getWorldModel().getExterior(x, y, currentWorldSpace).count(); cellsPositionsToLoad.emplace_back(x, y); } } @@ -614,7 +615,7 @@ namespace MWWorld { if (!isCellInCollection(x, y, mActiveCells)) { - CellStore& cell = mWorld.getWorldModel().getExterior(x, y); + CellStore& cell = mWorld.getWorldModel().getExterior(x, y, currentWorldSpace); loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); } } @@ -623,7 +624,7 @@ namespace MWWorld navigatorUpdateGuard.reset(); - CellStore& current = mWorld.getWorldModel().getExterior(playerCellX, playerCellY); + CellStore& current = mWorld.getWorldModel().getExterior(playerCellX, playerCellY, currentWorldSpace); MWBase::Environment::get().getWindowManager()->changeCell(¤t); if (changeEvent) @@ -676,7 +677,8 @@ namespace MWWorld loadingListener->setLabel("#{OMWEngine:TestingExteriorCells} (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")..."); - CellStore& cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); + CellStore& cell + = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId); mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell.getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get()); const osg::Vec3f position @@ -1177,7 +1179,8 @@ namespace MWWorld + mPreloadDistance; if (dist < loadDist) - preloadCell(mWorld.getWorldModel().getExterior(cellX + dx, cellY + dy)); + preloadCell( + mWorld.getWorldModel().getExterior(cellX + dx, cellY + dy, ESM::Cell::sDefaultWorldspaceId)); } } } @@ -1194,7 +1197,8 @@ namespace MWWorld for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) { mPreloader->preload( - mWorld.getWorldModel().getExterior(x + dx, y + dy), mRendering.getReferenceTime()); + mWorld.getWorldModel().getExterior(x + dx, y + dy, cell.getCell()->getWorldSpace()), + mRendering.getReferenceTime()); if (++numpreloaded >= mPreloader->getMaxCacheSize()) break; } @@ -1277,7 +1281,9 @@ namespace MWWorld { osg::Vec3f pos = dest.mPos.asVec3(); const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); - preloadCell(mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y()), true); + preloadCell( + mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId), + true); exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); } } diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 9936b1e999..95cf1bca22 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -1104,10 +1105,32 @@ namespace MWWorld return foundCell->second; } + const ESM4::Cell* Store::searchExterior(int x, int y, ESM::RefId worldSpace) const + { + const auto foundWorldSpace = mExteriors.find(worldSpace); + if (foundWorldSpace == mExteriors.end()) + { + return nullptr; + } + const auto foundCell = foundWorldSpace->second.find(std::make_pair(x, y)); + if (foundCell == foundWorldSpace->second.end()) + return nullptr; + return foundCell->second; + } + + bool Store::exteriorExists(ESM::RefId worldspace) const + { + const auto foundWorldSpace = mExteriors.find(worldspace); + return (foundWorldSpace != mExteriors.end()); + } + ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) { auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); mCellNameIndex[cellPtr->mEditorId] = cellPtr; + if (cellPtr->isExterior()) + mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + return cellPtr; } @@ -1115,6 +1138,9 @@ namespace MWWorld { auto cellPtr = TypedDynamicStore::insertStatic(item); mCellNameIndex[cellPtr->mEditorId] = cellPtr; + if (cellPtr->isExterior()) + mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + return cellPtr; } } @@ -1177,3 +1203,4 @@ template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 79bd4df536..95591d67b8 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -282,9 +282,12 @@ namespace MWWorld { std::unordered_map mCellNameIndex; + std::unordered_map, ESM4::Cell*>> mExteriors; public: const ESM4::Cell* searchCellName(std::string_view) const; + const ESM4::Cell* searchExterior(int x, int y, ESM::RefId worldSpace) const; + bool exteriorExists(ESM::RefId worldspace) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8c13a9a4c0..b5ab3f2b4b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1266,7 +1266,9 @@ namespace MWWorld const osg::Vec2i index = positionToCellIndex(position.x(), position.y()); CellStore* cell = ptr.getCell(); - CellStore& newCell = mWorldModel.getExterior(index.x(), index.y()); + ESM::RefId worldspaceId + = cell->isExterior() ? cell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; + CellStore& newCell = mWorldModel.getExterior(index.x(), index.y(), worldspaceId); bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() && mWorldScene->isCellActive(newCell); @@ -2069,7 +2071,7 @@ namespace MWWorld if (cell->isExterior()) { const osg::Vec2i index = positionToCellIndex(pos.pos[0], pos.pos[1]); - cell = &mWorldModel.getExterior(index.x(), index.y()); + cell = &mWorldModel.getExterior(index.x(), index.y(), cell->getCell()->getWorldSpace()); } MWWorld::Ptr dropped = object.getClass().copyToCell(object, *cell, pos, count); @@ -2753,7 +2755,7 @@ namespace MWWorld if (xResult.ec == std::errc::result_out_of_range || yResult.ec == std::errc::result_out_of_range) throw std::runtime_error("Cell coordinates out of range."); else if (xResult.ec == std::errc{} && yResult.ec == std::errc{}) - ext = mWorldModel.getExterior(x, y).getCell(); + ext = mWorldModel.getExterior(x, y, ESM::Cell::sDefaultWorldspaceId).getCell(); // ignore std::errc::invalid_argument, as this means that name probably refers to a interior cell // instead of comma separated coordinates } diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 58f47eb8aa..ecc3a97cd3 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -76,11 +76,12 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) } else { + auto& Esm3Exteriors = mExteriors[ESM::Cell::sDefaultWorldspaceId]; std::map, CellStore*>::iterator result - = mExteriors.find(std::make_pair(cell->getGridX(), cell->getGridY())); + = Esm3Exteriors.find(std::make_pair(cell->getGridX(), cell->getGridY())); - if (result == mExteriors.end()) - result = mExteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first; + if (result == Esm3Exteriors.end()) + result = Esm3Exteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first; return *result->second; } @@ -160,31 +161,69 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach { } -MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y) +MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId exteriorWorldspace) { - std::map, CellStore*>::iterator result = mExteriors.find(std::make_pair(x, y)); - - if (result == mExteriors.end()) + auto foundWorldspace = mExteriors.find(exteriorWorldspace); + std::map, CellStore*>::iterator result; + if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) { - const ESM::Cell* cell = mStore.get().search(x, y); + auto& esm3Exteriors = mExteriors[exteriorWorldspace]; + result = esm3Exteriors.find(std::make_pair(x, y)); - if (!cell) + if (result == esm3Exteriors.end()) { - // Cell isn't predefined. Make one on the fly. - ESM::Cell record; - record.mData.mFlags = ESM::Cell::HasWater; - record.mData.mX = x; - record.mData.mY = y; - record.mWater = 0; - record.mMapColor = 0; - record.updateId(); - - cell = MWBase::Environment::get().getESMStore()->insert(record); + const ESM::Cell* cell = mStore.get().search(x, y); + + if (!cell) + { + // Cell isn't predefined. Make one on the fly. + ESM::Cell record; + record.mData.mFlags = ESM::Cell::HasWater; + record.mData.mX = x; + record.mData.mY = y; + record.mWater = 0; + record.mMapColor = 0; + record.updateId(); + + cell = MWBase::Environment::get().getESMStore()->insert(record); + } + + CellStore* cellStore + = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; + result = esm3Exteriors.emplace(std::make_pair(x, y), cellStore).first; } + } + else + { + const Store& cell4Store = mStore.get(); + if (cell4Store.exteriorExists(exteriorWorldspace)) + { + auto& exteriors = mExteriors[exteriorWorldspace]; + + result = exteriors.find(std::make_pair(x, y)); - 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 == exteriors.end()) + { + const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); + if (!cell) + { + ESM4::Cell record; + record.mId = MWBase::Environment::get().getESMStore()->generateId(); + record.mParent = exteriorWorldspace; + record.mX = x; + record.mY = y; + record.mCellFlags = !ESM4::CELL_Interior; + cell = MWBase::Environment::get().getESMStore()->insert(record); + } + CellStore* cellStore + = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; + result = exteriors.emplace(std::make_pair(x, y), cellStore).first; + } + } + else + { + throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); + } } if (result->second->getState() != CellStore::State_Loaded) @@ -232,7 +271,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) return result->second; if (const auto* exteriorId = id.getIf()) - return getExterior(exteriorId->getX(), exteriorId->getY()); + return getExterior(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId); const ESM4::Cell* cell4 = mStore.get().search(id); CellStore* newCellStore = nullptr; @@ -249,7 +288,7 @@ 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); + mExteriors[newCellStore->getCell()->getWorldSpace()].emplace(coord, newCellStore); } else { @@ -293,7 +332,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name) if (!cell) throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name)); - return getExterior(cell->getGridX(), cell->getGridY()); + return getExterior(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId); } MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( @@ -302,7 +341,9 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( if (cellInSameWorldSpace && !cellInSameWorldSpace->isExterior()) return *cellInSameWorldSpace; const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); - return getExterior(cellIndex.x(), cellIndex.y()); + ESM::RefId exteriorWorldspace + = cellInSameWorldSpace ? cellInSameWorldSpace->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; + return getExterior(cellIndex.x(), cellIndex.y(), exteriorWorldspace); } MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name, CellStore& cell) @@ -342,12 +383,14 @@ 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(); - iter != mExteriors.rend(); ++iter) + for (auto iterExt = mExteriors.rbegin(); iterExt != mExteriors.rend(); ++iterExt) { - Ptr ptr = getPtrAndCache(name, *iter->second); - if (!ptr.isEmpty()) - return ptr; + for (auto iter = iterExt->second.rbegin(); iter != iterExt->second.rend(); iter++) + { + Ptr ptr = getPtrAndCache(name, *iter->second); + if (!ptr.isEmpty()) + return ptr; + } } for (auto iter = mInteriors.begin(); iter != mInteriors.end(); ++iter) diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index c9c7cf52ea..464cc89d18 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -42,7 +42,7 @@ namespace MWWorld ESM::ReadersCache& mReaders; mutable std::unordered_map mCells; mutable std::map mInteriors; - mutable std::map, CellStore*> mExteriors; + mutable std::map, CellStore*>> mExteriors; IdCache mIdCache; std::size_t mIdCacheIndex = 0; std::unordered_map mPtrIndex; @@ -63,7 +63,7 @@ namespace MWWorld void clear(); - CellStore& getExterior(int x, int y); + CellStore& getExterior(int x, int y, ESM::RefId exteriorWorldSpace); CellStore& getInterior(std::string_view name); CellStore& getCell(std::string_view name); // interior or named exterior CellStore& getCell(const ESM::RefId& Id); diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 73fd8967bd..6bfb0fe8a1 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -40,6 +40,7 @@ namespace ESM namespace ESM { const std::string Cell::sDefaultWorldspace = "sys::default"; + const RefId Cell::sDefaultWorldspaceId = ESM::RefId::stringRefId(Cell::sDefaultWorldspace); // Some overloaded compare operators. bool operator==(const MovedCellRef& ref, const RefNum& refNum) diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index c889a5a620..c5794aa5a2 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -67,6 +67,7 @@ namespace ESM struct Cell { static const std::string sDefaultWorldspace; + static const ESM::RefId sDefaultWorldspaceId; constexpr static RecNameInts sRecordId = REC_CELL; diff --git a/components/esm4/loadwrld.cpp b/components/esm4/loadwrld.cpp index f421a8e7ff..cc16ab4fa7 100644 --- a/components/esm4/loadwrld.cpp +++ b/components/esm4/loadwrld.cpp @@ -34,8 +34,8 @@ void ESM4::World::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + FormId formid = reader.hdr().record.getFormId(); + reader.adjustFormId(formid); mFlags = reader.hdr().record.flags; // It should be possible to save the current world formId automatically while reading in @@ -45,7 +45,8 @@ void ESM4::World::load(ESM4::Reader& reader) // Alternatively it may be possible to figure it out by examining the group headers, but // apparently the label field is not reliable so the parent world formid may have been // corrupted by the use of ignore flag (TODO: should check to verify). - reader.setCurrWorld(mFormId); // save for CELL later + reader.setCurrWorld(formid); // save for CELL later + mId = ESM::FormIdRefId(formid); std::uint32_t subSize = 0; // for XXXX sub record diff --git a/components/esm4/loadwrld.hpp b/components/esm4/loadwrld.hpp index f5ba010ba8..7dc42cd035 100644 --- a/components/esm4/loadwrld.hpp +++ b/components/esm4/loadwrld.hpp @@ -34,6 +34,9 @@ #include "formid.hpp" #include "grid.hpp" +#include +#include + namespace ESM4 { class Reader; @@ -81,7 +84,7 @@ namespace ESM4 float initialPitch; }; - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; @@ -129,6 +132,7 @@ namespace ESM4 void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const; + static constexpr ESM::RecNameInts sRecordId = ESM::REC_WRLD4; }; } From 81d9686541f2bfeed6e8a84dbd1b29a2f894b802 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sat, 22 Apr 2023 19:12:24 +0200 Subject: [PATCH 02/22] crashfix dynamic exterior cells --- apps/openmw/mwworld/store.cpp | 21 +++++++++++++++++++-- apps/openmw/mwworld/store.hpp | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 95cf1bca22..be6196c3fb 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1127,7 +1127,8 @@ namespace MWWorld ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) { auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); - mCellNameIndex[cellPtr->mEditorId] = cellPtr; + if (!cellPtr->mEditorId.empty()) + mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; @@ -1137,12 +1138,28 @@ namespace MWWorld ESM4::Cell* Store::insertStatic(const ESM4::Cell& item) { auto cellPtr = TypedDynamicStore::insertStatic(item); - mCellNameIndex[cellPtr->mEditorId] = cellPtr; + if (!cellPtr->mEditorId.empty()) + mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; return cellPtr; } + + void Store::clearDynamic() + { + for (auto& cellToDeleteIt : mDynamic) + { + ESM4::Cell& cellToDelete = cellToDeleteIt.second; + if (cellToDelete.isExterior()) + { + mExteriors[cellToDelete.mParent].erase(std::make_pair(cellToDelete.mX, cellToDelete.mY)); + } + if (!cellToDelete.mEditorId.empty()) + mCellNameIndex.erase(cellToDelete.mEditorId); + } + MWWorld::TypedDynamicStore::clearDynamic(); + } } template class MWWorld::TypedDynamicStore; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 95591d67b8..b17fde68b6 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -177,6 +177,7 @@ namespace MWWorld template class TypedDynamicStore : public DynamicStoreBase { + protected: typedef std::unordered_map Static; Static mStatic; /// @par mShared usually preserves the record order as it came from the content files (this @@ -290,6 +291,7 @@ namespace MWWorld bool exteriorExists(ESM::RefId worldspace) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); + void clearDynamic() override; }; template <> From eb48f8724f27147a37faa210c1c3d5b2ff12a424 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 23 Apr 2023 00:12:24 +0200 Subject: [PATCH 03/22] change grid and preload takes the right exterior also fixes some crashes --- apps/openmw/mwworld/scene.cpp | 22 ++++++++++++---------- apps/openmw/mwworld/scene.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 9 +++++---- apps/openmw/mwworld/worldmodel.cpp | 1 - 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c82c3f95b1..d0f755fece 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -305,7 +305,8 @@ namespace MWWorld if (mChangeCellGridRequest.has_value()) { changeCellGrid(mChangeCellGridRequest->mPosition, mChangeCellGridRequest->mCell.x(), - mChangeCellGridRequest->mCell.y(), mChangeCellGridRequest->mChangeEvent); + mChangeCellGridRequest->mCell.y(), mChangeCellGridRequest->exteriorWorldspace, + mChangeCellGridRequest->mChangeEvent); mChangeCellGridRequest.reset(); } @@ -531,10 +532,11 @@ namespace MWWorld void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent) { - mChangeCellGridRequest = ChangeCellGridRequest{ position, cell, changeEvent }; + mChangeCellGridRequest = ChangeCellGridRequest{ position, cell, ESM::Cell::sDefaultWorldspaceId, changeEvent }; } - void Scene::changeCellGrid(const osg::Vec3f& pos, int playerCellX, int playerCellY, bool changeEvent) + void Scene::changeCellGrid( + const osg::Vec3f& pos, int playerCellX, int playerCellY, ESM::RefId exteriorWorldspace, bool changeEvent) { auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); @@ -551,10 +553,9 @@ namespace MWWorld else unloadCell(cell, navigatorUpdateGuard.get()); } - ESM::RefId currentWorldSpace = mCurrentCell->getCell()->getWorldSpace(); mNavigator.setWorldspace( Misc::StringUtils::lowerCase(mWorld.getWorldModel() - .getExterior(playerCellX, playerCellY, currentWorldSpace) + .getExterior(playerCellX, playerCellY, exteriorWorldspace) .getCell() ->getWorldSpace() .serializeText()), @@ -581,7 +582,7 @@ namespace MWWorld { if (!isCellInCollection(x, y, collection)) { - refsToLoad += mWorld.getWorldModel().getExterior(x, y, currentWorldSpace).count(); + refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count(); cellsPositionsToLoad.emplace_back(x, y); } } @@ -615,7 +616,7 @@ namespace MWWorld { if (!isCellInCollection(x, y, mActiveCells)) { - CellStore& cell = mWorld.getWorldModel().getExterior(x, y, currentWorldSpace); + CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace); loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); } } @@ -624,7 +625,7 @@ namespace MWWorld navigatorUpdateGuard.reset(); - CellStore& current = mWorld.getWorldModel().getExterior(playerCellX, playerCellY, currentWorldSpace); + CellStore& current = mWorld.getWorldModel().getExterior(playerCellX, playerCellY, exteriorWorldspace); MWBase::Environment::get().getWindowManager()->changeCell(¤t); if (changeEvent) @@ -934,7 +935,8 @@ namespace MWWorld const osg::Vec2i cellIndex(current.getCell()->getGridX(), current.getCell()->getGridY()); - changeCellGrid(position.asVec3(), cellIndex.x(), cellIndex.y(), changeEvent); + changeCellGrid( + position.asVec3(), cellIndex.x(), cellIndex.y(), current.getCell()->getWorldSpace(), changeEvent); changePlayerCell(current, position, adjustPlayerPos); @@ -1094,7 +1096,7 @@ namespace MWWorld mLastPlayerPos = playerPos; - if (mPreloadEnabled) + if (mPreloadEnabled && mCurrentCell->getCell()->getWorldSpace() == ESM::Cell::sDefaultWorldspaceId) { if (mPreloadDoors) preloadTeleportDoorDestinations(playerPos, predictedPos, exteriorPositions); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 06b4221332..2bc0aae145 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -80,6 +80,7 @@ namespace MWWorld { osg::Vec3f mPosition; osg::Vec2i mCell; + ESM::RefId exteriorWorldspace; bool mChangeEvent; }; @@ -117,7 +118,8 @@ namespace MWWorld osg::Vec2i mCurrentGridCenter; // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center - void changeCellGrid(const osg::Vec3f& pos, int playerCellX, int playerCellY, bool changeEvent = true); + void changeCellGrid(const osg::Vec3f& pos, int playerCellX, int playerCellY, ESM::RefId exteriorWorldspace, + bool changeEvent = true); void requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent = true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b5ab3f2b4b..8f38a9e081 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1268,12 +1268,13 @@ namespace MWWorld CellStore* cell = ptr.getCell(); ESM::RefId worldspaceId = cell->isExterior() ? cell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - CellStore& newCell = mWorldModel.getExterior(index.x(), index.y(), worldspaceId); - bool isCellActive - = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() && mWorldScene->isCellActive(newCell); + CellStore* newCell + = cell->isExterior() ? &mWorldModel.getExterior(index.x(), index.y(), worldspaceId) : nullptr; + bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() + && mWorldScene->isCellActive(*newCell); if (cell->isExterior() || (moveToActive && isCellActive && ptr.getClass().isActor())) - cell = &newCell; + cell = newCell; return moveObject(ptr, cell, position, movePhysics); } diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index ecc3a97cd3..90a065d9eb 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -208,7 +208,6 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex if (!cell) { ESM4::Cell record; - record.mId = MWBase::Environment::get().getESMStore()->generateId(); record.mParent = exteriorWorldspace; record.mX = x; record.mY = y; From d8a782425b81408566abc897e477b47ef26b38ac Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 24 Apr 2023 21:20:07 +0200 Subject: [PATCH 04/22] can actually load and teleport to esm4 exterior spaces --- apps/openmw/mwbase/world.hpp | 3 ++- apps/openmw/mwphysics/physicssystem.cpp | 4 +++- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwrender/landmanager.cpp | 5 ++++- apps/openmw/mwrender/landmanager.hpp | 2 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- apps/openmw/mwworld/cellpreloader.cpp | 2 +- apps/openmw/mwworld/cellutils.hpp | 6 +++--- apps/openmw/mwworld/scene.cpp | 28 +++++++++++++++---------- apps/openmw/mwworld/worldimp.cpp | 7 ++++--- apps/openmw/mwworld/worldimp.hpp | 3 ++- components/misc/constants.hpp | 1 + 12 files changed, 40 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 71bb85c798..e0d64fba9f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -316,7 +316,8 @@ namespace MWBase /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// obstructed). - virtual void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const = 0; + virtual void indexToPosition( + int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const = 0; ///< Convert cell numbers to position. virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d2076a6280..5f4c09842a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -483,8 +483,10 @@ namespace MWPhysics mHeightFields.erase(heightfield); } - const HeightField* PhysicsSystem::getHeightField(int x, int y) const + const HeightField* PhysicsSystem::getHeightField(int x, int y, ESM::RefId worldspace) const { + if (worldspace != ESM::Cell::sDefaultWorldspaceId) + return nullptr; const auto heightField = mHeightFields.find(std::make_pair(x, y)); if (heightField == mHeightFields.end()) return nullptr; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 923ace45bb..d61b0f38d9 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -189,7 +189,7 @@ namespace MWPhysics void removeHeightField(int x, int y); - const HeightField* getHeightField(int x, int y) const; + const HeightField* getHeightField(int x, int y, ESM::RefId worldspace) const; bool toggleCollisionMode(); diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 59b9fdbde4..74811677a0 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -18,8 +18,11 @@ namespace MWRender mCache = new CacheType; } - osg::ref_ptr LandManager::getLand(int x, int y) + osg::ref_ptr LandManager::getLand(int x, int y, ESM::RefId worldspace) { + if (worldspace != ESM::Cell::sDefaultWorldspaceId) + return osg::ref_ptr(nullptr); + osg::ref_ptr obj = mCache->getRefFromObjectCache(std::make_pair(x, y)); if (obj) return static_cast(obj.get()); diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 4c00cefe9b..959647fadc 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -20,7 +20,7 @@ namespace MWRender LandManager(int loadFlags); /// @note Will return nullptr if not found. - osg::ref_ptr getLand(int x, int y); + osg::ref_ptr getLand(int x, int y, ESM::RefId worldspace); void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index c85ee62f88..e23efbd2a3 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -68,7 +68,7 @@ namespace MWRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - return mLandManager->getLand(cellX, cellY); + return mLandManager->getLand(cellX, cellY, ESM::Cell::sDefaultWorldspaceId); } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 3ba20d635e..0e2e773b74 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -102,7 +102,7 @@ namespace MWWorld try { mTerrain->cacheCell(mTerrainView.get(), mX, mY); - mPreloadedObjects.insert(mLandManager->getLand(mX, mY)); + mPreloadedObjects.insert(mLandManager->getLand(mX, mY, ESM::Cell::sDefaultWorldspaceId)); } catch (std::exception&) { diff --git a/apps/openmw/mwworld/cellutils.hpp b/apps/openmw/mwworld/cellutils.hpp index a7e8e88c78..978e358c8b 100644 --- a/apps/openmw/mwworld/cellutils.hpp +++ b/apps/openmw/mwworld/cellutils.hpp @@ -9,10 +9,10 @@ namespace MWWorld { - inline osg::Vec2i positionToCellIndex(float x, float y) + inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false) { - return { static_cast(std::floor(x / Constants::CellSizeInUnits)), - static_cast(std::floor(y / Constants::CellSizeInUnits)) }; + const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d0f755fece..ec63e6429b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -247,12 +248,13 @@ namespace return std::abs(cellPosition.first) + std::abs(cellPosition.second); } - bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection) + bool isCellInCollection(int x, int y, ESM::RefId worldspace, MWWorld::Scene::CellStoreCollection& collection) { for (auto* cell : collection) { assert(cell->getCell()->isExterior()); - if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY()) + if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY() + && cell->getCell()->getWorldSpace() == worldspace) return true; } return false; @@ -346,7 +348,7 @@ namespace MWWorld if (cell->getCell()->isExterior()) { - if (mPhysics->getHeightField(cellX, cellY) != nullptr) + if (mPhysics->getHeightField(cellX, cellY, cell->getCell()->getWorldSpace()) != nullptr) mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mPhysics->removeHeightField(cellX, cellY); @@ -391,10 +393,12 @@ namespace MWWorld const int cellX = cell.getCell()->getGridX(); const int cellY = cell.getCell()->getGridY(); const MWWorld::Cell& cellVariant = *cell.getCell(); + ESM::RefId worldspace = cellVariant.getWorldSpace(); if (cellVariant.isExterior()) { - osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + osg::ref_ptr land + = mRendering.getLandManager()->getLand(cellX, cellY, worldspace); const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; const int verts = ESM::Land::LAND_SIZE; const int worldsize = ESM::Land::REAL_SIZE; @@ -410,7 +414,7 @@ namespace MWWorld mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); } - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) { const osg::Vec2i cellPosition(cellX, cellY); const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); @@ -465,7 +469,7 @@ namespace MWWorld if (cellVariant.isExterior()) { - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) mNavigator.addWater( osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard); } @@ -507,17 +511,18 @@ namespace MWWorld osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const { + bool isEsm4Ext = mCurrentCell && mCurrentCell->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; if (currentGridCenter) { float centerX, centerY; - mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true); + mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext); float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y())); const float maxDistance = Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; } - return positionToCellIndex(pos.x(), pos.y()); + return positionToCellIndex(pos.x(), pos.y(), isEsm4Ext); } void Scene::playerMoved(const osg::Vec3f& pos) @@ -532,7 +537,8 @@ namespace MWWorld void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent) { - mChangeCellGridRequest = ChangeCellGridRequest{ position, cell, ESM::Cell::sDefaultWorldspaceId, changeEvent }; + mChangeCellGridRequest + = ChangeCellGridRequest{ position, cell, mCurrentCell->getCell()->getWorldSpace(), changeEvent }; } void Scene::changeCellGrid( @@ -580,7 +586,7 @@ namespace MWWorld { for (int y = playerCellY - range; y <= playerCellY + range; ++y) { - if (!isCellInCollection(x, y, collection)) + if (!isCellInCollection(x, y, exteriorWorldspace, collection)) { refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count(); cellsPositionsToLoad.emplace_back(x, y); @@ -614,7 +620,7 @@ namespace MWWorld for (const auto& [x, y] : cellsPositionsToLoad) { - if (!isCellInCollection(x, y, mActiveCells)) + if (!isCellInCollection(x, y, exteriorWorldspace, mActiveCells)) { CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace); loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8f38a9e081..ff1b7842f7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1512,9 +1512,9 @@ namespace MWWorld return placed; } - void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre) const + void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const { - const int cellSize = Constants::CellSizeInUnits; + const int cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; x = static_cast(cellSize * cellX); y = static_cast(cellSize * cellY); @@ -2766,7 +2766,8 @@ namespace MWWorld { int x = ext->getGridX(); int y = ext->getGridY(); - indexToPosition(x, y, pos.pos[0], pos.pos[1], true); + bool esm4Ext = ext->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + indexToPosition(x, y, pos.pos[0], pos.pos[1], true, esm4Ext); // Note: Z pos will be adjusted by adjustPosition later pos.pos[2] = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8e9ba5bd8..b181e6d49d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -403,7 +403,8 @@ namespace MWWorld float getMaxActivationDistance() const override; - void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const override; + void indexToPosition( + int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const override; ///< Convert cell numbers to position. void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override; diff --git a/components/misc/constants.hpp b/components/misc/constants.hpp index deb47a7667..545db87094 100644 --- a/components/misc/constants.hpp +++ b/components/misc/constants.hpp @@ -23,6 +23,7 @@ namespace Constants // Size of one exterior cell in game units constexpr int CellSizeInUnits = 8192; + constexpr int ESM4CellSizeInUnits = 4096; // Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side) constexpr int CellGridRadius = 1; From 1d03b5469412a1bad3b2357e3919ea00d09aec06 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 2 May 2023 22:37:18 +0200 Subject: [PATCH 05/22] maps with tuple key instead of map of map instead of using a map with key as exterior and map of , Cell as value we use a single map with a tuple x,y,exterior as key --- apps/openmw/mwworld/store.cpp | 23 ++++------- apps/openmw/mwworld/store.hpp | 5 ++- apps/openmw/mwworld/worldmodel.cpp | 66 +++++++++++++----------------- apps/openmw/mwworld/worldmodel.hpp | 4 +- components/esm/util.hpp | 37 +++++++++++++++++ 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index be6196c3fb..23d32a9707 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1107,30 +1107,21 @@ namespace MWWorld const ESM4::Cell* Store::searchExterior(int x, int y, ESM::RefId worldSpace) const { - const auto foundWorldSpace = mExteriors.find(worldSpace); - if (foundWorldSpace == mExteriors.end()) - { - return nullptr; - } - const auto foundCell = foundWorldSpace->second.find(std::make_pair(x, y)); - if (foundCell == foundWorldSpace->second.end()) + const auto foundCell = mExteriors.find({ x, y, worldSpace }); + if (foundCell == mExteriors.end()) return nullptr; return foundCell->second; } - bool Store::exteriorExists(ESM::RefId worldspace) const - { - const auto foundWorldSpace = mExteriors.find(worldspace); - return (foundWorldSpace != mExteriors.end()); - } - ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) { auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); if (!cellPtr->mEditorId.empty()) mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) - mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + { + mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; + } return cellPtr; } @@ -1141,7 +1132,7 @@ namespace MWWorld if (!cellPtr->mEditorId.empty()) mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) - mExteriors[cellPtr->mParent][std::make_pair(cellPtr->getGridX(), cellPtr->getGridY())] = cellPtr; + mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; return cellPtr; } @@ -1153,7 +1144,7 @@ namespace MWWorld ESM4::Cell& cellToDelete = cellToDeleteIt.second; if (cellToDelete.isExterior()) { - mExteriors[cellToDelete.mParent].erase(std::make_pair(cellToDelete.mX, cellToDelete.mY)); + mExteriors.erase({ cellToDelete.mX, cellToDelete.mY, cellToDelete.mParent }); } if (!cellToDelete.mEditorId.empty()) mCellNameIndex.erase(cellToDelete.mEditorId); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index b17fde68b6..a60842eb95 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -283,12 +284,12 @@ namespace MWWorld { std::unordered_map mCellNameIndex; - std::unordered_map, ESM4::Cell*>> mExteriors; + + std::unordered_map mExteriors; public: const ESM4::Cell* searchCellName(std::string_view) const; const ESM4::Cell* searchExterior(int x, int y, ESM::RefId worldSpace) const; - bool exteriorExists(ESM::RefId worldspace) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); void clearDynamic() override; diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 90a065d9eb..e155a45b09 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -76,12 +76,11 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) } else { - auto& Esm3Exteriors = mExteriors[ESM::Cell::sDefaultWorldspaceId]; - std::map, CellStore*>::iterator result - = Esm3Exteriors.find(std::make_pair(cell->getGridX(), cell->getGridY())); + ESM::ExteriorCellIndex extIndex = { cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId }; + std::map::iterator result = mExteriors.find(extIndex); - if (result == Esm3Exteriors.end()) - result = Esm3Exteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first; + if (result == mExteriors.end()) + result = mExteriors.emplace(extIndex, cellStore).first; return *result->second; } @@ -163,14 +162,14 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId exteriorWorldspace) { - auto foundWorldspace = mExteriors.find(exteriorWorldspace); - std::map, CellStore*>::iterator result; - if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) - { - auto& esm3Exteriors = mExteriors[exteriorWorldspace]; - result = esm3Exteriors.find(std::make_pair(x, y)); + std::map::iterator result; + ESM::ExteriorCellIndex extIndex = { x, y, exteriorWorldspace }; + + result = mExteriors.find({ x, y, exteriorWorldspace }); - if (result == esm3Exteriors.end()) + if (result == mExteriors.end()) + { + if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) { const ESM::Cell* cell = mStore.get().search(x, y); @@ -190,21 +189,15 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = esm3Exteriors.emplace(std::make_pair(x, y), cellStore).first; + result = mExteriors.emplace(extIndex, cellStore).first; } - } - else - { - const Store& cell4Store = mStore.get(); - if (cell4Store.exteriorExists(exteriorWorldspace)) + else { - auto& exteriors = mExteriors[exteriorWorldspace]; - - result = exteriors.find(std::make_pair(x, y)); - - if (result == exteriors.end()) + const Store& cell4Store = mStore.get(); + bool exteriorExists = mStore.get().search(exteriorWorldspace); + const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); + if (exteriorExists) { - const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); if (!cell) { ESM4::Cell record; @@ -216,15 +209,14 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex } CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = exteriors.emplace(std::make_pair(x, y), cellStore).first; + result = mExteriors.emplace(extIndex, cellStore).first; + } + else + { + throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); } - } - else - { - throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); } } - if (result->second->getState() != CellStore::State_Loaded) { result->second->load(); @@ -287,7 +279,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) { std::pair coord = std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY()); - mExteriors[newCellStore->getCell()->getWorldSpace()].emplace(coord, newCellStore); + ESM::ExteriorCellIndex extIndex = { coord.first, coord.second, newCellStore->getCell()->getWorldSpace() }; + mExteriors.emplace(extIndex, newCellStore); } else { @@ -382,14 +375,11 @@ MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name) // Then check cells that are already listed // Search in reverse, this is a workaround for an ambiguous chargen_plank reference in the vanilla game. // there is one at -22,16 and one at -2,-9, the latter should be used. - for (auto iterExt = mExteriors.rbegin(); iterExt != mExteriors.rend(); ++iterExt) + for (auto iter = mExteriors.rbegin(); iter != mExteriors.rend(); ++iter) { - for (auto iter = iterExt->second.rbegin(); iter != iterExt->second.rend(); iter++) - { - Ptr ptr = getPtrAndCache(name, *iter->second); - if (!ptr.isEmpty()) - return ptr; - } + Ptr ptr = getPtrAndCache(name, *iter->second); + if (!ptr.isEmpty()) + return ptr; } for (auto iter = mInteriors.begin(); iter != mInteriors.end(); ++iter) diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 464cc89d18..7506d93292 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "cellstore.hpp" @@ -42,7 +43,8 @@ namespace MWWorld ESM::ReadersCache& mReaders; mutable std::unordered_map mCells; mutable std::map mInteriors; - mutable std::map, CellStore*>> mExteriors; + + mutable std::map mExteriors; IdCache mIdCache; std::size_t mIdCacheIndex = 0; std::unordered_map mPtrIndex; diff --git a/components/esm/util.hpp b/components/esm/util.hpp index b1a40bd015..9014f31ab2 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace ESM { @@ -42,6 +44,41 @@ namespace ESM operator osg::Vec3f() const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); } }; + struct ExteriorCellIndex + { + int mX, mY; + ESM::RefId mWorldspace; + + bool operator==(const ExteriorCellIndex& other) const + { + return mX == other.mX && mY == other.mY && mWorldspace == other.mWorldspace; + } + + bool operator<(const ExteriorCellIndex& other) const + { + return std::make_tuple(mX, mY, mWorldspace) < std::make_tuple(other.mX, other.mY, other.mWorldspace); + } + + friend struct std::hash; + }; + +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(const ESM::ExteriorCellIndex& toHash) const + { + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return ((hash()(toHash.mX) ^ (hash()(toHash.mY) << 1)) >> 1) + ^ (hash()(toHash.mWorldspace) << 1); + } + }; } #endif From 43e247d4581f5422347c0458a7feb513d66fddd8 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 2 May 2023 22:58:15 +0200 Subject: [PATCH 06/22] fixes tests fix linux build + clang-tidy --- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldmodel.cpp | 1 + apps/openmw_test_suite/mwworld/test_store.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ff1b7842f7..e388f040d8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1271,7 +1271,7 @@ namespace MWWorld CellStore* newCell = cell->isExterior() ? &mWorldModel.getExterior(index.x(), index.y(), worldspaceId) : nullptr; bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() - && mWorldScene->isCellActive(*newCell); + && (newCell && mWorldScene->isCellActive(*newCell)); if (cell->isExterior() || (moveToActive && isCellActive && ptr.getClass().isActor())) cell = newCell; diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index e155a45b09..b4ee5726ca 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index aea74fab71..6a038af9dc 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include From 141878f30d082b1f91c4742816499c1691df0347 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 5 May 2023 10:31:06 +0200 Subject: [PATCH 07/22] int x, int y , ESM::RefId worldspace => ESM::ExteriorCellIndex also removed the changeToExteriorCell that only took a position as input, didn't work with esm4. --- apps/openmw/mwbase/world.hpp | 4 -- apps/openmw/mwgui/mapwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwlua/luabindings.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 6 +- apps/openmw/mwphysics/physicssystem.hpp | 3 +- apps/openmw/mwrender/landmanager.cpp | 7 +- apps/openmw/mwrender/landmanager.hpp | 3 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- .../mwscript/transformationextensions.cpp | 13 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 4 +- apps/openmw/mwworld/cellpreloader.cpp | 3 +- apps/openmw/mwworld/scene.cpp | 72 +++++++++---------- apps/openmw/mwworld/scene.hpp | 7 +- apps/openmw/mwworld/store.cpp | 4 +- apps/openmw/mwworld/store.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 35 +++------ apps/openmw/mwworld/worldimp.hpp | 5 -- apps/openmw/mwworld/worldmodel.cpp | 36 +++++----- apps/openmw/mwworld/worldmodel.hpp | 2 +- components/esm/util.hpp | 7 ++ 21 files changed, 107 insertions(+), 119 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index e0d64fba9f..a8bec3b1a5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -250,10 +250,6 @@ namespace MWBase ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) - = 0; - ///< Move to exterior cell. - ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes 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 d158755736..8c1e0263a3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -584,7 +584,7 @@ namespace MWGui { if (!mInterior) requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior( - entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)); + ESM::ExteriorCellIndex(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId))); osg::ref_ptr texture = mLocalMapRender->getMapTexture(entry.mCellX, entry.mCellY); if (texture) @@ -641,8 +641,9 @@ namespace MWGui for (MapEntry& entry : mMaps) { if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap)) - world->getDoorMarkers( - worldModel->getExterior(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId), doors); + world->getDoorMarkers(worldModel->getExterior(ESM::ExteriorCellIndex( + entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)), + doors); } if (doors.empty()) return; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index c01b9361b1..8637e98a06 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -131,7 +131,7 @@ namespace MWGui if (cellname.empty()) { MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( - cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId); + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)); cellname = MWBase::Environment::get().getWorld()->getCellName(&cell); interior = false; } diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 3e40503fbe..b1c762440c 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -115,7 +115,7 @@ namespace MWLua = [](std::string_view name) { return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name) }; }; api["getExteriorCell"] = [](int x, int y) { return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior( - x, y, ESM::Cell::sDefaultWorldspaceId) }; + ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId)) }; }; api["activeActors"] = GObjectList{ worldView->getActorsInScene() }; api["createObject"] = [](std::string_view recordId, sol::optional count) -> GObject { diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5f4c09842a..a86e02ff06 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -483,11 +483,11 @@ namespace MWPhysics mHeightFields.erase(heightfield); } - const HeightField* PhysicsSystem::getHeightField(int x, int y, ESM::RefId worldspace) const + const HeightField* PhysicsSystem::getHeightField(ESM::ExteriorCellIndex cellIndex) const { - if (worldspace != ESM::Cell::sDefaultWorldspaceId) + if (cellIndex.mWorldspace != ESM::Cell::sDefaultWorldspaceId) return nullptr; - const auto heightField = mHeightFields.find(std::make_pair(x, y)); + const auto heightField = mHeightFields.find(std::make_pair(cellIndex.mX, cellIndex.mY)); if (heightField == mHeightFields.end()) return nullptr; return heightField->second.get(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index d61b0f38d9..1e1d7bdb61 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -17,6 +17,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -189,7 +190,7 @@ namespace MWPhysics void removeHeightField(int x, int y); - const HeightField* getHeightField(int x, int y, ESM::RefId worldspace) const; + const HeightField* getHeightField(ESM::ExteriorCellIndex cellIndex) const; bool toggleCollisionMode(); diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 74811677a0..3563f88ec7 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -18,11 +18,12 @@ namespace MWRender mCache = new CacheType; } - osg::ref_ptr LandManager::getLand(int x, int y, ESM::RefId worldspace) + osg::ref_ptr LandManager::getLand(ESM::ExteriorCellIndex cellIndex) { - if (worldspace != ESM::Cell::sDefaultWorldspaceId) + if (cellIndex.mWorldspace != ESM::Cell::sDefaultWorldspaceId) return osg::ref_ptr(nullptr); - + int x = cellIndex.mX; + int y = cellIndex.mY; osg::ref_ptr obj = mCache->getRefFromObjectCache(std::make_pair(x, y)); if (obj) return static_cast(obj.get()); diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 959647fadc..f7ebf5ddb8 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -20,7 +21,7 @@ namespace MWRender LandManager(int loadFlags); /// @note Will return nullptr if not found. - osg::ref_ptr getLand(int x, int y, ESM::RefId worldspace); + osg::ref_ptr getLand(ESM::ExteriorCellIndex cellIndex); void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index e23efbd2a3..b950e4fe5c 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -68,7 +68,7 @@ namespace MWRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - return mLandManager->getLand(cellX, cellY, ESM::Cell::sDefaultWorldspaceId); + return mLandManager->getLand(ESM::ExteriorCellIndex(cellX, cellY, ESM::Cell::sDefaultWorldspaceId)); } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 4f7a136764..a14a2f0ede 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -402,8 +402,8 @@ namespace MWScript if (store->isExterior()) { const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store - = &worldModel->getExterior(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace()); + store = &worldModel->getExterior( + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); } } catch (std::exception&) @@ -418,7 +418,8 @@ namespace MWScript if (!isPlayer) return; const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store = &worldModel->getExterior(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace()); + store = &worldModel->getExterior( + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); } if (store) { @@ -475,7 +476,7 @@ namespace MWScript if (isPlayer) { MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior( - cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId); + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)); ptr = world->moveObject(ptr, cell, osg::Vec3(x, y, z)); } else @@ -569,8 +570,8 @@ namespace MWScript if (player.getCell()->isExterior()) { const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); - store = &MWBase::Environment::get().getWorldModel()->getExterior( - cellIndex.x(), cellIndex.y(), player.getCell()->getCell()->getWorldSpace()); + store = &MWBase::Environment::get().getWorldModel()->getExterior(ESM::ExteriorCellIndex( + cellIndex.x(), cellIndex.y(), player.getCell()->getCell()->getWorldSpace())); } else store = player.getCell(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 836f4a765a..3d31da8263 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -563,8 +563,8 @@ void MWState::StateManager::loadGame(const Character* character, const std::file { // Cell no longer exists (i.e. changed game files), choose a default cell Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell"; - MWWorld::CellStore& cell - = MWBase::Environment::get().getWorldModel()->getExterior(0, 0, ESM::Cell::sDefaultWorldspaceId); + MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( + ESM::ExteriorCellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId)); float x, y; MWBase::Environment::get().getWorld()->indexToPosition(0, 0, x, y, false); ESM::Position pos; diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 0e2e773b74..9881595123 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -102,7 +102,8 @@ namespace MWWorld try { mTerrain->cacheCell(mTerrainView.get(), mX, mY); - mPreloadedObjects.insert(mLandManager->getLand(mX, mY, ESM::Cell::sDefaultWorldspaceId)); + mPreloadedObjects.insert( + mLandManager->getLand(ESM::ExteriorCellIndex(mX, mY, ESM::Cell::sDefaultWorldspaceId))); } catch (std::exception&) { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ec63e6429b..f28d6f8f7c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -248,13 +248,13 @@ namespace return std::abs(cellPosition.first) + std::abs(cellPosition.second); } - bool isCellInCollection(int x, int y, ESM::RefId worldspace, MWWorld::Scene::CellStoreCollection& collection) + bool isCellInCollection(ESM::ExteriorCellIndex cellIndex, MWWorld::Scene::CellStoreCollection& collection) { for (auto* cell : collection) { assert(cell->getCell()->isExterior()); - if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY() - && cell->getCell()->getWorldSpace() == worldspace) + if (cellIndex.mX == cell->getCell()->getGridX() && cellIndex.mY == cell->getCell()->getGridY() + && cell->getCell()->getWorldSpace() == cellIndex.mWorldspace) return true; } return false; @@ -306,8 +306,7 @@ namespace MWWorld { if (mChangeCellGridRequest.has_value()) { - changeCellGrid(mChangeCellGridRequest->mPosition, mChangeCellGridRequest->mCell.x(), - mChangeCellGridRequest->mCell.y(), mChangeCellGridRequest->exteriorWorldspace, + changeCellGrid(mChangeCellGridRequest->mPosition, mChangeCellGridRequest->mCellIndex, mChangeCellGridRequest->mChangeEvent); mChangeCellGridRequest.reset(); } @@ -348,7 +347,8 @@ namespace MWWorld if (cell->getCell()->isExterior()) { - if (mPhysics->getHeightField(cellX, cellY, cell->getCell()->getWorldSpace()) != nullptr) + if (mPhysics->getHeightField(ESM::ExteriorCellIndex(cellX, cellY, cell->getCell()->getWorldSpace())) + != nullptr) mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mPhysics->removeHeightField(cellX, cellY); @@ -394,11 +394,11 @@ namespace MWWorld const int cellY = cell.getCell()->getGridY(); const MWWorld::Cell& cellVariant = *cell.getCell(); ESM::RefId worldspace = cellVariant.getWorldSpace(); + ESM::ExteriorCellIndex cellIndex(cellX, cellY, worldspace); if (cellVariant.isExterior()) { - osg::ref_ptr land - = mRendering.getLandManager()->getLand(cellX, cellY, worldspace); + osg::ref_ptr land = mRendering.getLandManager()->getLand(cellIndex); const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; const int verts = ESM::Land::LAND_SIZE; const int worldsize = ESM::Land::REAL_SIZE; @@ -414,7 +414,7 @@ namespace MWWorld mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); } - if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) + if (const auto heightField = mPhysics->getHeightField(cellIndex)) { const osg::Vec2i cellPosition(cellX, cellY); const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); @@ -469,7 +469,7 @@ namespace MWWorld if (cellVariant.isExterior()) { - if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) + if (const auto heightField = mPhysics->getHeightField(cellIndex)) mNavigator.addWater( osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard); } @@ -537,14 +537,16 @@ namespace MWWorld void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent) { - mChangeCellGridRequest - = ChangeCellGridRequest{ position, cell, mCurrentCell->getCell()->getWorldSpace(), changeEvent }; + mChangeCellGridRequest = ChangeCellGridRequest{ position, + ESM::ExteriorCellIndex(cell.x(), cell.y(), mCurrentCell->getCell()->getWorldSpace()), changeEvent }; } - void Scene::changeCellGrid( - const osg::Vec3f& pos, int playerCellX, int playerCellY, ESM::RefId exteriorWorldspace, bool changeEvent) + void Scene::changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellIndex playerCellIndex, bool changeEvent) { auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); + int playerCellX = playerCellIndex.mX; + int playerCellY = playerCellIndex.mY; + ESM::RefId exteriorWorldspace = playerCellIndex.mWorldspace; for (auto iter = mActiveCells.begin(); iter != mActiveCells.end();) { @@ -560,11 +562,8 @@ namespace MWWorld unloadCell(cell, navigatorUpdateGuard.get()); } mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(mWorld.getWorldModel() - .getExterior(playerCellX, playerCellY, exteriorWorldspace) - .getCell() - ->getWorldSpace() - .serializeText()), + Misc::StringUtils::lowerCase( + mWorld.getWorldModel().getExterior(playerCellIndex).getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -586,9 +585,9 @@ namespace MWWorld { for (int y = playerCellY - range; y <= playerCellY + range; ++y) { - if (!isCellInCollection(x, y, exteriorWorldspace, collection)) + if (!isCellInCollection(playerCellIndex, collection)) { - refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count(); + refsToLoad += mWorld.getWorldModel().getExterior(playerCellIndex).count(); cellsPositionsToLoad.emplace_back(x, y); } } @@ -620,9 +619,10 @@ namespace MWWorld for (const auto& [x, y] : cellsPositionsToLoad) { - if (!isCellInCollection(x, y, exteriorWorldspace, mActiveCells)) + ESM::ExteriorCellIndex indexToLoad = { x, y, exteriorWorldspace }; + if (!isCellInCollection(indexToLoad, mActiveCells)) { - CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace); + CellStore& cell = mWorld.getWorldModel().getExterior(indexToLoad); loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); } } @@ -631,7 +631,7 @@ namespace MWWorld navigatorUpdateGuard.reset(); - CellStore& current = mWorld.getWorldModel().getExterior(playerCellX, playerCellY, exteriorWorldspace); + CellStore& current = mWorld.getWorldModel().getExterior(playerCellIndex); MWBase::Environment::get().getWindowManager()->changeCell(¤t); if (changeEvent) @@ -684,8 +684,8 @@ namespace MWWorld loadingListener->setLabel("#{OMWEngine:TestingExteriorCells} (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")..."); - CellStore& cell - = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId); + CellStore& cell = mWorld.getWorldModel().getExterior( + ESM::ExteriorCellIndex(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId)); mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell.getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get()); const osg::Vec3f position @@ -941,8 +941,8 @@ namespace MWWorld const osg::Vec2i cellIndex(current.getCell()->getGridX(), current.getCell()->getGridY()); - changeCellGrid( - position.asVec3(), cellIndex.x(), cellIndex.y(), current.getCell()->getWorldSpace(), changeEvent); + changeCellGrid(position.asVec3(), + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), current.getCell()->getWorldSpace()), changeEvent); changePlayerCell(current, position, adjustPlayerPos); @@ -1187,8 +1187,8 @@ namespace MWWorld + mPreloadDistance; if (dist < loadDist) - preloadCell( - mWorld.getWorldModel().getExterior(cellX + dx, cellY + dy, ESM::Cell::sDefaultWorldspaceId)); + preloadCell(mWorld.getWorldModel().getExterior( + ESM::ExteriorCellIndex(cellX + dx, cellY + dy, ESM::Cell::sDefaultWorldspaceId))); } } } @@ -1204,8 +1204,8 @@ namespace MWWorld { for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) { - mPreloader->preload( - mWorld.getWorldModel().getExterior(x + dx, y + dy, cell.getCell()->getWorldSpace()), + mPreloader->preload(mWorld.getWorldModel().getExterior( + ESM::ExteriorCellIndex(x + dx, y + dy, cell.getCell()->getWorldSpace())), mRendering.getReferenceTime()); if (++numpreloaded >= mPreloader->getMaxCacheSize()) break; @@ -1269,8 +1269,8 @@ namespace MWWorld }; void Scene::preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& /*predictedPos*/, - std::vector& - exteriorPositions) // ignore predictedPos here since opening dialogue with travel service takes extra time + std::vector& exteriorPositions) // ignore predictedPos here since opening dialogue with + // travel service takes extra time { const MWWorld::ConstPtr player = mWorld.getPlayerPtr(); ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3()); @@ -1289,8 +1289,8 @@ namespace MWWorld { osg::Vec3f pos = dest.mPos.asVec3(); const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); - preloadCell( - mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId), + preloadCell(mWorld.getWorldModel().getExterior( + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)), true); exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 2bc0aae145..3dcd33a3c0 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -13,6 +13,7 @@ #include #include +#include #include namespace osg @@ -79,8 +80,7 @@ namespace MWWorld struct ChangeCellGridRequest { osg::Vec3f mPosition; - osg::Vec2i mCell; - ESM::RefId exteriorWorldspace; + ESM::ExteriorCellIndex mCellIndex; bool mChangeEvent; }; @@ -118,8 +118,7 @@ namespace MWWorld osg::Vec2i mCurrentGridCenter; // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center - void changeCellGrid(const osg::Vec3f& pos, int playerCellX, int playerCellY, ESM::RefId exteriorWorldspace, - bool changeEvent = true); + void changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellIndex playerCellIndex, bool changeEvent = true); void requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent = true); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 23d32a9707..16bc188e83 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1105,9 +1105,9 @@ namespace MWWorld return foundCell->second; } - const ESM4::Cell* Store::searchExterior(int x, int y, ESM::RefId worldSpace) const + const ESM4::Cell* Store::searchExterior(ESM::ExteriorCellIndex cellIndex) const { - const auto foundCell = mExteriors.find({ x, y, worldSpace }); + const auto foundCell = mExteriors.find(cellIndex); if (foundCell == mExteriors.end()) return nullptr; return foundCell->second; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a60842eb95..e21c85d850 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -289,7 +289,7 @@ namespace MWWorld public: const ESM4::Cell* searchCellName(std::string_view) const; - const ESM4::Cell* searchExterior(int x, int y, ESM::RefId worldSpace) const; + const ESM4::Cell* searchExterior(ESM::ExteriorCellIndex cellIndex) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); void clearDynamic() override; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e388f040d8..78afca2766 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -353,9 +353,10 @@ namespace MWWorld if (bypass && !mStartCell.empty()) { ESM::Position pos; - if (!findExteriorPosition(mStartCell, pos).empty()) + ESM::RefId cellId = findExteriorPosition(mStartCell, pos); + if (!cellId.empty()) { - changeToExteriorCell(pos, true); + changeToCell(cellId, pos, true); adjustPosition(getPlayerPtr(), false); } else @@ -967,25 +968,6 @@ namespace MWWorld mRendering->getCamera()->instantTransition(); } - void World::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) - { - mPhysics->clearQueuedMovement(); - mDiscardMovements = true; - - if (changeEvent && mCurrentWorldSpace != ESM::Cell::sDefaultWorldspace) - { - // changed worldspace - mProjectileManager->clear(); - mRendering->notifyWorldSpaceChanged(); - } - removeContainerScripts(getPlayerPtr()); - osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]); - ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); - mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent); - addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); - mRendering->getCamera()->instantTransition(); - } - void World::changeToCell( const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) { @@ -1268,8 +1250,9 @@ namespace MWWorld CellStore* cell = ptr.getCell(); ESM::RefId worldspaceId = cell->isExterior() ? cell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - CellStore* newCell - = cell->isExterior() ? &mWorldModel.getExterior(index.x(), index.y(), worldspaceId) : nullptr; + CellStore* newCell = cell->isExterior() + ? &mWorldModel.getExterior(ESM::ExteriorCellIndex(index.x(), index.y(), worldspaceId)) + : nullptr; bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() && (newCell && mWorldScene->isCellActive(*newCell)); @@ -2072,7 +2055,8 @@ namespace MWWorld if (cell->isExterior()) { const osg::Vec2i index = positionToCellIndex(pos.pos[0], pos.pos[1]); - cell = &mWorldModel.getExterior(index.x(), index.y(), cell->getCell()->getWorldSpace()); + cell = &mWorldModel.getExterior( + ESM::ExteriorCellIndex(index.x(), index.y(), cell->getCell()->getWorldSpace())); } MWWorld::Ptr dropped = object.getClass().copyToCell(object, *cell, pos, count); @@ -2756,7 +2740,8 @@ namespace MWWorld if (xResult.ec == std::errc::result_out_of_range || yResult.ec == std::errc::result_out_of_range) throw std::runtime_error("Cell coordinates out of range."); else if (xResult.ec == std::errc{} && yResult.ec == std::errc{}) - ext = mWorldModel.getExterior(x, y, ESM::Cell::sDefaultWorldspaceId).getCell(); + ext = mWorldModel.getExterior(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId)) + .getCell(); // ignore std::errc::invalid_argument, as this means that name probably refers to a interior cell // instead of comma separated coordinates } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b181e6d49d..83268ddfc5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -345,11 +345,6 @@ namespace MWWorld ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - void changeToExteriorCell( - const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; - ///< Move to exterior cell. - ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - 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 b4ee5726ca..0dc30569bc 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -161,26 +161,25 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach { } -MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId exteriorWorldspace) +MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellIndex cellIndex) { std::map::iterator result; - ESM::ExteriorCellIndex extIndex = { x, y, exteriorWorldspace }; - result = mExteriors.find({ x, y, exteriorWorldspace }); + result = mExteriors.find(cellIndex); if (result == mExteriors.end()) { - if (exteriorWorldspace == ESM::Cell::sDefaultWorldspaceId) + if (cellIndex.mWorldspace == ESM::Cell::sDefaultWorldspaceId) { - const ESM::Cell* cell = mStore.get().search(x, y); + const ESM::Cell* cell = mStore.get().search(cellIndex.mX, cellIndex.mY); if (!cell) { // Cell isn't predefined. Make one on the fly. ESM::Cell record; record.mData.mFlags = ESM::Cell::HasWater; - record.mData.mX = x; - record.mData.mY = y; + record.mData.mX = cellIndex.mX; + record.mData.mY = cellIndex.mY; record.mWater = 0; record.mMapColor = 0; record.updateId(); @@ -190,31 +189,31 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(int x, int y, ESM::RefId ex CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = mExteriors.emplace(extIndex, cellStore).first; + result = mExteriors.emplace(cellIndex, cellStore).first; } else { const Store& cell4Store = mStore.get(); - bool exteriorExists = mStore.get().search(exteriorWorldspace); - const ESM4::Cell* cell = cell4Store.searchExterior(x, y, exteriorWorldspace); + bool exteriorExists = mStore.get().search(cellIndex.mWorldspace); + const ESM4::Cell* cell = cell4Store.searchExterior(cellIndex); if (exteriorExists) { if (!cell) { ESM4::Cell record; - record.mParent = exteriorWorldspace; - record.mX = x; - record.mY = y; + record.mParent = cellIndex.mWorldspace; + record.mX = cellIndex.mX; + record.mY = cellIndex.mY; record.mCellFlags = !ESM4::CELL_Interior; cell = MWBase::Environment::get().getESMStore()->insert(record); } CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = mExteriors.emplace(extIndex, cellStore).first; + result = mExteriors.emplace(cellIndex, cellStore).first; } else { - throw std::runtime_error("exterior not found: '" + exteriorWorldspace.toDebugString() + "'"); + throw std::runtime_error("exterior not found: '" + cellIndex.mWorldspace.toDebugString() + "'"); } } } @@ -263,7 +262,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) return result->second; if (const auto* exteriorId = id.getIf()) - return getExterior(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId); + return getExterior( + ESM::ExteriorCellIndex(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId)); const ESM4::Cell* cell4 = mStore.get().search(id); CellStore* newCellStore = nullptr; @@ -325,7 +325,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name) if (!cell) throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name)); - return getExterior(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId); + return getExterior(ESM::ExteriorCellIndex(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId)); } MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( @@ -336,7 +336,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); ESM::RefId exteriorWorldspace = cellInSameWorldSpace ? cellInSameWorldSpace->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - return getExterior(cellIndex.x(), cellIndex.y(), exteriorWorldspace); + return getExterior(ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), exteriorWorldspace)); } MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name, CellStore& cell) diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 7506d93292..cca916a917 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -65,7 +65,7 @@ namespace MWWorld void clear(); - CellStore& getExterior(int x, int y, ESM::RefId exteriorWorldSpace); + CellStore& getExterior(ESM::ExteriorCellIndex cellIndex); CellStore& getInterior(std::string_view name); CellStore& getCell(std::string_view name); // interior or named exterior CellStore& getCell(const ESM::RefId& Id); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 9014f31ab2..8735b301f6 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -49,6 +49,13 @@ namespace ESM int mX, mY; ESM::RefId mWorldspace; + ExteriorCellIndex(int x, int y, ESM::RefId worldspace) + : mX(x) + , mY(y) + , mWorldspace(worldspace) + { + } + bool operator==(const ExteriorCellIndex& other) const { return mX == other.mX && mY == other.mY && mWorldspace == other.mWorldspace; From 56cb2a83ecd6f1f1fa718b5a794d247dbfa9e21c Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 5 May 2023 10:51:59 +0200 Subject: [PATCH 08/22] removed sDefaultWorldspace, only sDefaultWorldspaceId now. sDefaultWorldspaceId is a StringRefId to be able to getvalue easily. --- apps/navmeshtool/worldspacedata.cpp | 3 +-- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/view/world/regionmap.cpp | 3 ++- apps/opencs/view/world/scenesubview.cpp | 5 +++-- apps/openmw/mwworld/cell.cpp | 2 +- components/esm3/loadcell.cpp | 3 +-- components/esm3/loadcell.hpp | 3 +-- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/navmeshtool/worldspacedata.cpp b/apps/navmeshtool/worldspacedata.cpp index 04347f6c8f..e6f1dca6b0 100644 --- a/apps/navmeshtool/worldspacedata.cpp +++ b/apps/navmeshtool/worldspacedata.cpp @@ -264,8 +264,7 @@ namespace NavMeshTool const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY); const std::size_t cellObjectsBegin = data.mObjects.size(); const auto cellWorldspace = Misc::StringUtils::lowerCase( - (cell.isExterior() ? ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace) : cell.mId) - .serializeText()); + (cell.isExterior() ? ESM::Cell::sDefaultWorldspaceId : cell.mId).serializeText()); WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& { auto it = navMeshInputs.find(cellWorldspace); if (it == navMeshInputs.end()) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 23e772afcd..b91035f758 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -337,7 +337,7 @@ std::pair CSMWorld::IdTable::view(int row) c return std::make_pair(UniversalId::Type_None, ""); if (id[0] == '#') - id = ESM::Cell::sDefaultWorldspace; + id = ESM::Cell::sDefaultWorldspaceId.getValue(); 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 f7a495c9df..a2847848d0 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -305,7 +305,8 @@ void CSVWorld::RegionMap::view() } emit editRequest( - CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace), hint.str()); + CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspaceId.getValue()), + hint.str()); } void CSVWorld::RegionMap::viewInTable() diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index ffdf1c66bf..3b3ada43b5 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -47,7 +47,7 @@ CSVWorld::SceneSubView::SceneSubView(const CSMWorld::UniversalId& id, CSMDoc::Do CSVRender::WorldspaceWidget* worldspaceWidget = nullptr; widgetType whatWidget; - if (Misc::StringUtils::ciEqual(id.getId(), ESM::Cell::sDefaultWorldspace)) + if (Misc::StringUtils::ciEqual(id.getId(), ESM::Cell::sDefaultWorldspaceId.getValue())) { whatWidget = widget_Paged; @@ -168,7 +168,8 @@ void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::UniversalId& i void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::CellSelection& selection) { - setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace)); + setUniversalId( + CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspaceId.getValue())); int size = selection.getSize(); std::ostringstream stream; diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index e6a288c68c..e06c4fd07c 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -39,7 +39,7 @@ namespace MWWorld , mNameID(cell.mName) , mRegion(cell.mRegion) , mId(cell.mId) - , mParent(ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace)) + , mParent(ESM::Cell::sDefaultWorldspaceId) , mMood{ .mAmbiantColor = cell.mAmbi.mAmbient, .mDirectionalColor = cell.mAmbi.mSunlight, diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 6bfb0fe8a1..5a328d8f03 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -39,8 +39,7 @@ namespace ESM namespace ESM { - const std::string Cell::sDefaultWorldspace = "sys::default"; - const RefId Cell::sDefaultWorldspaceId = ESM::RefId::stringRefId(Cell::sDefaultWorldspace); + const StringRefId Cell::sDefaultWorldspaceId = StringRefId("sys::default"); // Some overloaded compare operators. bool operator==(const MovedCellRef& ref, const RefNum& refNum) diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index c5794aa5a2..3d33c7c370 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -66,8 +66,7 @@ namespace ESM */ struct Cell { - static const std::string sDefaultWorldspace; - static const ESM::RefId sDefaultWorldspaceId; + static const ESM::StringRefId sDefaultWorldspaceId; constexpr static RecNameInts sRecordId = REC_CELL; From 3de08e654ff12338c7e6da25a273823b23597b08 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 5 May 2023 16:31:31 +0200 Subject: [PATCH 09/22] Better handling of water levels for exterior cells. Especially for skyrim and it's weird water level values in exteriors. If we don't have a valid exterior water level we use the world's water level --- apps/openmw/mwworld/cell.cpp | 12 ++++++++++++ apps/openmw/mwworld/cellstore.cpp | 2 +- components/esm4/loadcell.cpp | 8 ++++++-- components/esm4/loadcell.hpp | 2 ++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index e06c4fd07c..cf94f24f88 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -2,8 +2,12 @@ #include #include +#include #include +#include "../mwbase/environment.hpp" +#include "esmstore.hpp" + namespace MWWorld { Cell::Cell(const ESM4::Cell& cell) @@ -26,6 +30,12 @@ namespace MWWorld .mFogDensity = 1.f,} ,mWaterHeight(cell.mWaterHeight) { + if (isExterior() && mWaterHeight == ESM4::Cell::sInvalidWaterLevel) + { + auto& worldStore = MWBase::Environment::get().getESMStore()->get(); + const ESM4::World* cellWorld = worldStore.find(mParent); + mWaterHeight = cellWorld->mWaterLevel; + } } Cell::Cell(const ESM::Cell& cell) @@ -48,6 +58,8 @@ namespace MWWorld } ,mWaterHeight(cell.mWater) { + if (isExterior()) + mWaterHeight = -1.f; } std::string Cell::getDescription() const diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 2c5ab8d3ea..f000af01e5 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -664,7 +664,7 @@ namespace MWWorld float CellStore::getWaterLevel() const { if (isExterior()) - return -1; + return getCell()->getWaterHeight(); return mWaterLevel; } diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 22d9a1035d..a9d8db0003 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -33,6 +33,7 @@ #include #include // FLT_MAX for gcc #include // FIXME: debug only +#include #include #include "grouptype.hpp" @@ -41,6 +42,8 @@ #include +float ESM4::Cell::sInvalidWaterLevel = std::numeric_limits::min(); + // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // // But, for external cells we may be scanning the whole record since we don't know if there is @@ -55,7 +58,7 @@ void ESM4::Cell::load(ESM4::Reader& reader) mId = ESM::RefId::formIdRefId(mFormId); mFlags = reader.hdr().record.flags; mParent = ESM::RefId::formIdRefId(reader.currWorld()); - + mWaterHeight = sInvalidWaterLevel; reader.clearCellGrid(); // clear until XCLC FIXME: somehow do this automatically? // Sometimes cell 0,0 does not have an XCLC sub record (e.g. ToddLand 000009BF) @@ -237,7 +240,8 @@ void ESM4::Cell::load(ESM4::Reader& reader) throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); } } - + if (mWaterHeight > 1e8) // A Bit of a hack for skyrim, there is a value for the cell but it is all wrong. + mWaterHeight = sInvalidWaterLevel; mReaderContext = reader.getContext(); } diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 97abb88751..5fd32a598d 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -107,6 +107,8 @@ namespace ESM4 int getGridX() const { return mX; } int getGridY() const { return mY; } bool isExterior() const { return !(mCellFlags & CELL_Interior); } + + static float sInvalidWaterLevel; }; } From 93b3d9238c9e4bb8f8ea23ee869545904e234270 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 5 May 2023 22:13:16 +0200 Subject: [PATCH 10/22] mWater level disabled for skyrim. --- components/esm4/loadcell.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index a9d8db0003..21f50ff9d9 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -42,7 +42,7 @@ #include -float ESM4::Cell::sInvalidWaterLevel = std::numeric_limits::min(); +float ESM4::Cell::sInvalidWaterLevel = -200000.f; // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // @@ -79,6 +79,7 @@ void ESM4::Cell::load(ESM4::Reader& reader) reader.setCurrCell(mFormId); // save for LAND (and other children) to access later std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; + bool isSkyrim = (esmVer == ESM::VER_170 || esmVer == ESM::VER_094); while (reader.getSubRecordHeader()) { @@ -240,8 +241,11 @@ void ESM4::Cell::load(ESM4::Reader& reader) throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); } } - if (mWaterHeight > 1e8) // A Bit of a hack for skyrim, there is a value for the cell but it is all wrong. + if (isSkyrim) // Skyrim seems to have broken water level records. But the subrecord exists so it + // shouldn't be skipped. + { mWaterHeight = sInvalidWaterLevel; + } mReaderContext = reader.getContext(); } From 5648e03e9e197661ce67491b5a3189c5e0346bb2 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 5 May 2023 23:20:02 +0200 Subject: [PATCH 11/22] function to get cellsize depending on the context. --- apps/openmw/mwworld/scene.cpp | 11 ++++++----- apps/openmw/mwworld/worldimp.cpp | 19 +++++++++++++++---- apps/openmw/mwworld/worldimp.hpp | 2 ++ components/misc/constants.hpp | 4 ++++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f28d6f8f7c..ffb6be9958 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -517,8 +517,8 @@ namespace MWWorld float centerX, centerY; mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext); float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y())); - const float maxDistance - = Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold + float cellSize = Constants::getCellSize(isEsm4Ext); + const float maxDistance = cellSize / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; } @@ -1166,6 +1166,8 @@ namespace MWWorld float centerX, centerY; mWorld.indexToPosition(cellX, cellY, centerX, centerY, true); + float cellSize = mWorld.getCurrentCellSize(); + bool esm4Ext = cellSize == Constants::ESM4CellSizeInUnits; for (int dx = -halfGridSizePlusOne; dx <= halfGridSizePlusOne; ++dx) { @@ -1176,15 +1178,14 @@ namespace MWWorld continue; // only care about the outer (not yet loaded) part of the grid float thisCellCenterX, thisCellCenterY; - mWorld.indexToPosition(cellX + dx, cellY + dy, thisCellCenterX, thisCellCenterY, true); + mWorld.indexToPosition(cellX + dx, cellY + dy, thisCellCenterX, thisCellCenterY, true, esm4Ext); float dist = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y())); dist = std::min(dist, std::max( std::abs(thisCellCenterX - predictedPos.x()), std::abs(thisCellCenterY - predictedPos.y()))); - float loadDist = Constants::CellSizeInUnits / 2 + Constants::CellSizeInUnits - mCellLoadingThreshold - + mPreloadDistance; + float loadDist = cellSize / 2 + cellSize - mCellLoadingThreshold + mPreloadDistance; if (dist < loadDist) preloadCell(mWorld.getWorldModel().getExterior( diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 78afca2766..9eeddc32e4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,7 +1374,9 @@ namespace MWWorld && !(ptr.getClass().isPersistent(ptr) && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()); if (force || !ptr.getClass().isActor() || (!isFlying(ptr) && !swims && isActorCollisionEnabled(ptr))) { - osg::Vec3f traced = mPhysics->traceDown(ptr, pos, Constants::CellSizeInUnits); + bool esm4Ext = ptr.getCell()->isExterior() + && ptr.getCell()->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + osg::Vec3f traced = mPhysics->traceDown(ptr, pos, Constants::getCellSize(esm4Ext)); pos.z() = std::min(pos.z(), traced.z()); } @@ -1409,9 +1411,10 @@ namespace MWWorld if (!mPhysics->castRay(pos, targetPos, MWPhysics::CollisionType_World | MWPhysics::CollisionType_Door).mHit) break; } - + bool esm4Ext = actor.getCell()->isExterior() + && actor.getCell()->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; targetPos.z() += distance / 2.f; // move up a bit to get out from geometry, will snap down later - osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, Constants::CellSizeInUnits); + osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, Constants::getCellSize(esm4Ext)); if (traced != pos) { esmPos.pos[0] = traced.x(); @@ -1497,7 +1500,7 @@ namespace MWWorld void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const { - const int cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + const int cellSize = Constants::getCellSize(esm4Ext); x = static_cast(cellSize * cellX); y = static_cast(cellSize * cellY); @@ -1907,6 +1910,14 @@ namespace MWWorld return false; } + float World::getCurrentCellSize() const + { + const CellStore* cellStore = mWorldScene->getCurrentCell(); + if (cellStore) + return Constants::getCellSize(cellStore->getCell()->isEsm4()); + return Constants::getCellSize(false); + } + int World::getCurrentWeather() const { return mWeatherManager->getWeatherID(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 83268ddfc5..306372dbb1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -246,6 +246,8 @@ namespace MWWorld bool isCellQuasiExterior() const override; + float getCurrentCellSize() const; + void getDoorMarkers(MWWorld::CellStore& cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map diff --git a/components/misc/constants.hpp b/components/misc/constants.hpp index 545db87094..07ea0b6ca8 100644 --- a/components/misc/constants.hpp +++ b/components/misc/constants.hpp @@ -24,6 +24,10 @@ namespace Constants // Size of one exterior cell in game units constexpr int CellSizeInUnits = 8192; constexpr int ESM4CellSizeInUnits = 4096; + static inline int getCellSize(bool isESM4Ext) + { + return isESM4Ext ? ESM4CellSizeInUnits : CellSizeInUnits; + } // Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side) constexpr int CellGridRadius = 1; From 75561abfcadf7041804168664359a2a85f134765 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 9 May 2023 22:08:17 +0200 Subject: [PATCH 12/22] Factorises code and fixes preload bug. --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwrender/landmanager.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 16 +++++++++------- apps/openmw/mwworld/worldimp.cpp | 20 +++++++++----------- apps/openmw/mwworld/worldimp.hpp | 2 +- apps/openmw/mwworld/worldmodel.cpp | 2 +- components/esm/util.hpp | 11 +++++++++++ components/misc/constants.hpp | 4 ---- 8 files changed, 33 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index a86e02ff06..dbc31fccb1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -485,7 +485,7 @@ namespace MWPhysics const HeightField* PhysicsSystem::getHeightField(ESM::ExteriorCellIndex cellIndex) const { - if (cellIndex.mWorldspace != ESM::Cell::sDefaultWorldspaceId) + if (ESM::isEsm4Ext(cellIndex.mWorldspace)) return nullptr; const auto heightField = mHeightFields.find(std::make_pair(cellIndex.mX, cellIndex.mY)); if (heightField == mHeightFields.end()) diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 3563f88ec7..a3248d21a7 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -20,7 +20,7 @@ namespace MWRender osg::ref_ptr LandManager::getLand(ESM::ExteriorCellIndex cellIndex) { - if (cellIndex.mWorldspace != ESM::Cell::sDefaultWorldspaceId) + if (ESM::isEsm4Ext(cellIndex.mWorldspace)) return osg::ref_ptr(nullptr); int x = cellIndex.mX; int y = cellIndex.mY; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ffb6be9958..dd55488719 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -511,13 +511,13 @@ namespace MWWorld osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const { - bool isEsm4Ext = mCurrentCell && mCurrentCell->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + bool isEsm4Ext = mCurrentCell && ESM::isEsm4Ext(mCurrentCell->getCell()->getWorldSpace()); if (currentGridCenter) { float centerX, centerY; mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext); float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y())); - float cellSize = Constants::getCellSize(isEsm4Ext); + float cellSize = ESM::getCellSize(isEsm4Ext); const float maxDistance = cellSize / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; @@ -585,7 +585,7 @@ namespace MWWorld { for (int y = playerCellY - range; y <= playerCellY + range; ++y) { - if (!isCellInCollection(playerCellIndex, collection)) + if (!isCellInCollection(ESM::ExteriorCellIndex(x, y, playerCellIndex.mWorldspace), collection)) { refsToLoad += mWorld.getWorldModel().getExterior(playerCellIndex).count(); cellsPositionsToLoad.emplace_back(x, y); @@ -1102,7 +1102,7 @@ namespace MWWorld mLastPlayerPos = playerPos; - if (mPreloadEnabled && mCurrentCell->getCell()->getWorldSpace() == ESM::Cell::sDefaultWorldspaceId) + if (mPreloadEnabled && !ESM::isEsm4Ext(mCurrentCell->getCell()->getWorldSpace())) { if (mPreloadDoors) preloadTeleportDoorDestinations(playerPos, predictedPos, exteriorPositions); @@ -1166,8 +1166,10 @@ namespace MWWorld float centerX, centerY; mWorld.indexToPosition(cellX, cellY, centerX, centerY, true); - float cellSize = mWorld.getCurrentCellSize(); - bool esm4Ext = cellSize == Constants::ESM4CellSizeInUnits; + + ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); + bool esm4Ext = ESM::isEsm4Ext(extWorldspace); + float cellSize = ESM::getCellSize(esm4Ext); for (int dx = -halfGridSizePlusOne; dx <= halfGridSizePlusOne; ++dx) { @@ -1189,7 +1191,7 @@ namespace MWWorld if (dist < loadDist) preloadCell(mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(cellX + dx, cellY + dy, ESM::Cell::sDefaultWorldspaceId))); + ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace))); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9eeddc32e4..6ba7659f39 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,9 +1374,8 @@ namespace MWWorld && !(ptr.getClass().isPersistent(ptr) && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()); if (force || !ptr.getClass().isActor() || (!isFlying(ptr) && !swims && isActorCollisionEnabled(ptr))) { - bool esm4Ext = ptr.getCell()->isExterior() - && ptr.getCell()->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; - osg::Vec3f traced = mPhysics->traceDown(ptr, pos, Constants::getCellSize(esm4Ext)); + bool esm4Ext = ptr.getCell()->isExterior() && ESM::isEsm4Ext(ptr.getCell()->getCell()->getWorldSpace()); + osg::Vec3f traced = mPhysics->traceDown(ptr, pos, ESM::getCellSize(esm4Ext)); pos.z() = std::min(pos.z(), traced.z()); } @@ -1411,10 +1410,9 @@ namespace MWWorld if (!mPhysics->castRay(pos, targetPos, MWPhysics::CollisionType_World | MWPhysics::CollisionType_Door).mHit) break; } - bool esm4Ext = actor.getCell()->isExterior() - && actor.getCell()->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + bool esm4Ext = actor.getCell()->isExterior() && ESM::isEsm4Ext(actor.getCell()->getCell()->getWorldSpace()); targetPos.z() += distance / 2.f; // move up a bit to get out from geometry, will snap down later - osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, Constants::getCellSize(esm4Ext)); + osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, ESM::getCellSize(esm4Ext)); if (traced != pos) { esmPos.pos[0] = traced.x(); @@ -1500,7 +1498,7 @@ namespace MWWorld void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const { - const int cellSize = Constants::getCellSize(esm4Ext); + const int cellSize = ESM::getCellSize(esm4Ext); x = static_cast(cellSize * cellX); y = static_cast(cellSize * cellY); @@ -1910,12 +1908,12 @@ namespace MWWorld return false; } - float World::getCurrentCellSize() const + ESM::RefId World::getCurrentWorldspace() const { const CellStore* cellStore = mWorldScene->getCurrentCell(); if (cellStore) - return Constants::getCellSize(cellStore->getCell()->isEsm4()); - return Constants::getCellSize(false); + return cellStore->getCell()->getWorldSpace(); + return ESM::Cell::sDefaultWorldspaceId; } int World::getCurrentWeather() const @@ -2762,7 +2760,7 @@ namespace MWWorld { int x = ext->getGridX(); int y = ext->getGridY(); - bool esm4Ext = ext->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + bool esm4Ext = ESM::isEsm4Ext(ext->getWorldSpace()); indexToPosition(x, y, pos.pos[0], pos.pos[1], true, esm4Ext); // Note: Z pos will be adjusted by adjustPosition later diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 306372dbb1..7189c8b4be 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -246,7 +246,7 @@ namespace MWWorld bool isCellQuasiExterior() const override; - float getCurrentCellSize() const; + ESM::RefId getCurrentWorldspace() const; void getDoorMarkers(MWWorld::CellStore& cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 0dc30569bc..16564b4e91 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -169,7 +169,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellIndex cell if (result == mExteriors.end()) { - if (cellIndex.mWorldspace == ESM::Cell::sDefaultWorldspaceId) + if (!ESM::isEsm4Ext(cellIndex.mWorldspace)) { const ESM::Cell* cell = mStore.get().search(cellIndex.mX, cellIndex.mY); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 8735b301f6..d6d9feb3c4 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -5,6 +5,8 @@ #include #include +#include +#include namespace ESM { @@ -69,6 +71,15 @@ namespace ESM friend struct std::hash; }; + static inline bool isEsm4Ext(ESM::RefId worldspaceId) + { + return worldspaceId != ESM::Cell::sDefaultWorldspaceId; + } + + static inline int getCellSize(bool isESM4Ext) + { + return isESM4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + } } namespace std diff --git a/components/misc/constants.hpp b/components/misc/constants.hpp index 07ea0b6ca8..545db87094 100644 --- a/components/misc/constants.hpp +++ b/components/misc/constants.hpp @@ -24,10 +24,6 @@ namespace Constants // Size of one exterior cell in game units constexpr int CellSizeInUnits = 8192; constexpr int ESM4CellSizeInUnits = 4096; - static inline int getCellSize(bool isESM4Ext) - { - return isESM4Ext ? ESM4CellSizeInUnits : CellSizeInUnits; - } // Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side) constexpr int CellGridRadius = 1; From f731c5eadb28e729aa1445e7c5731fa28ea30c30 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 9 May 2023 22:28:37 +0200 Subject: [PATCH 13/22] preloader compatible with esm4 exteriors. --- apps/openmw/mwworld/scene.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index dd55488719..3cdf36d86e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1102,7 +1102,7 @@ namespace MWWorld mLastPlayerPos = playerPos; - if (mPreloadEnabled && !ESM::isEsm4Ext(mCurrentCell->getCell()->getWorldSpace())) + if (mPreloadEnabled) { if (mPreloadDoors) preloadTeleportDoorDestinations(playerPos, predictedPos, exteriorPositions); @@ -1277,7 +1277,7 @@ namespace MWWorld { const MWWorld::ConstPtr player = mWorld.getPlayerPtr(); ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3()); - + ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); for (MWWorld::CellStore* cellStore : mActiveCells) { cellStore->forEachType(listVisitor); @@ -1293,7 +1293,7 @@ namespace MWWorld osg::Vec3f pos = dest.mPos.asVec3(); const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); preloadCell(mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)), + ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), extWorldspace)), true); exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); } From 1fdecaaa34700345bc09a1cb10bf5de56f1073f7 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 9 May 2023 22:46:59 +0200 Subject: [PATCH 14/22] seperate permanent and non permanent exterior cells. --- apps/openmw/mwworld/store.cpp | 24 ++++++++++++++---------- apps/openmw/mwworld/store.hpp | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 16bc188e83..7fbbb0c695 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1116,25 +1116,29 @@ namespace MWWorld ESM4::Cell* Store::insert(const ESM4::Cell& item, bool overrideOnly) { auto cellPtr = TypedDynamicStore::insert(item, overrideOnly); - if (!cellPtr->mEditorId.empty()) - mCellNameIndex[cellPtr->mEditorId] = cellPtr; - if (cellPtr->isExterior()) - { - mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; - } - + insertCell(cellPtr); return cellPtr; } ESM4::Cell* Store::insertStatic(const ESM4::Cell& item) { auto cellPtr = TypedDynamicStore::insertStatic(item); + insertCell(cellPtr); + return cellPtr; + } + + void Store::insertCell(ESM4::Cell* cellPtr) + { if (!cellPtr->mEditorId.empty()) mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) - mExteriors[{ cellPtr->mX, cellPtr->mY, cellPtr->mParent }] = cellPtr; - - return cellPtr; + { + ESM::ExteriorCellIndex cellindex = { cellPtr->mX, cellPtr->mY, cellPtr->mParent }; + if (cellPtr->mCellFlags & ESM4::Rec_Persistent) + mPersistentExteriors[cellindex] = cellPtr; + else + mExteriors[cellindex] = cellPtr; + } } void Store::clearDynamic() diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index e21c85d850..45706dc793 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -286,12 +286,14 @@ namespace MWWorld mCellNameIndex; std::unordered_map mExteriors; + std::unordered_map mPersistentExteriors; public: const ESM4::Cell* searchCellName(std::string_view) const; const ESM4::Cell* searchExterior(ESM::ExteriorCellIndex cellIndex) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); + void insertCell(ESM4::Cell* cell); void clearDynamic() override; }; From f261f59809e325a7662e068253d0abff8206b5b7 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 9 May 2023 23:44:57 +0200 Subject: [PATCH 15/22] World::indexToPosition is modified to be less error prone. --- apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwscript/cellextensions.cpp | 5 ++++- apps/openmw/mwstate/statemanagerimp.cpp | 11 +++++----- apps/openmw/mwworld/scene.cpp | 28 +++++++++++++------------ apps/openmw/mwworld/worldimp.cpp | 14 +++++++------ apps/openmw/mwworld/worldimp.hpp | 3 +-- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a8bec3b1a5..79f709e224 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -55,6 +55,7 @@ namespace ESM struct ItemLevList; struct TimeStamp; class RefId; + struct ExteriorCellIndex; } namespace MWPhysics @@ -312,8 +313,7 @@ namespace MWBase /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// obstructed). - virtual void indexToPosition( - int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const = 0; + virtual osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false) const = 0; ///< Convert cell numbers to position. virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0; diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 1c212d5f8c..bd7592561c 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -123,7 +123,10 @@ namespace MWScript MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::Ptr playerPtr = world->getPlayerPtr(); - world->indexToPosition(x, y, pos.pos[0], pos.pos[1], true); + osg::Vec2 posFromIndex + = world->indexToPosition(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId), true); + pos.pos[0] = posFromIndex.x(); + pos.pos[1] = posFromIndex.y(); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 3d31da8263..7a544e9016 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -563,13 +563,12 @@ void MWState::StateManager::loadGame(const Character* character, const std::file { // Cell no longer exists (i.e. changed game files), choose a default cell Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell"; - MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId)); - float x, y; - MWBase::Environment::get().getWorld()->indexToPosition(0, 0, x, y, false); + ESM::ExteriorCellIndex cellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId); + MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); + osg::Vec2 posFromIndex = MWBase::Environment::get().getWorld()->indexToPosition(cellIndex, false); ESM::Position pos; - pos.pos[0] = x; - pos.pos[1] = y; + pos.pos[0] = posFromIndex.x(); + pos.pos[1] = posFromIndex.y(); pos.pos[2] = 0; // should be adjusted automatically (adjustPlayerPos=true) pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 3cdf36d86e..5dc35ef2d3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -511,12 +511,15 @@ namespace MWWorld osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const { - bool isEsm4Ext = mCurrentCell && ESM::isEsm4Ext(mCurrentCell->getCell()->getWorldSpace()); + ESM::RefId worldspace + = mCurrentCell ? mCurrentCell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; + bool isEsm4Ext = ESM::isEsm4Ext(worldspace); + if (currentGridCenter) { - float centerX, centerY; - mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext); - float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y())); + osg::Vec2 center = mWorld.indexToPosition( + ESM::ExteriorCellIndex(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); + float distance = std::max(std::abs(center.x() - pos.x()), std::abs(center.y() - pos.y())); float cellSize = ESM::getCellSize(isEsm4Ext); const float maxDistance = cellSize / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) @@ -1163,11 +1166,10 @@ namespace MWWorld int cellX, cellY; cellX = mCurrentGridCenter.x(); cellY = mCurrentGridCenter.y(); + ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); - float centerX, centerY; - mWorld.indexToPosition(cellX, cellY, centerX, centerY, true); + osg::Vec2 center = mWorld.indexToPosition(ESM::ExteriorCellIndex(cellX, cellY, extWorldspace), true); - ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); bool esm4Ext = ESM::isEsm4Ext(extWorldspace); float cellSize = ESM::getCellSize(esm4Ext); @@ -1179,14 +1181,14 @@ namespace MWWorld && dx != -halfGridSizePlusOne) continue; // only care about the outer (not yet loaded) part of the grid - float thisCellCenterX, thisCellCenterY; - mWorld.indexToPosition(cellX + dx, cellY + dy, thisCellCenterX, thisCellCenterY, true, esm4Ext); + osg::Vec2 thisCellCenter + = mWorld.indexToPosition(ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace), true); - float dist - = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y())); + float dist = std::max( + std::abs(thisCellCenter.x() - playerPos.x()), std::abs(thisCellCenter.y() - playerPos.y())); dist = std::min(dist, - std::max( - std::abs(thisCellCenterX - predictedPos.x()), std::abs(thisCellCenterY - predictedPos.y()))); + std::max(std::abs(thisCellCenter.x() - predictedPos.x()), + std::abs(thisCellCenter.y() - predictedPos.y()))); float loadDist = cellSize / 2 + cellSize - mCellLoadingThreshold + mPreloadDistance; if (dist < loadDist) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6ba7659f39..5d889f5a44 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1496,18 +1496,19 @@ namespace MWWorld return placed; } - void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const + osg::Vec2 World::indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre) const { - const int cellSize = ESM::getCellSize(esm4Ext); + const int cellSize = ESM::getCellSize(ESM::isEsm4Ext(cellIndex.mWorldspace)); - x = static_cast(cellSize * cellX); - y = static_cast(cellSize * cellY); + float x = static_cast(cellSize * cellIndex.mX); + float y = static_cast(cellSize * cellIndex.mY); if (centre) { x += cellSize / 2; y += cellSize / 2; } + return osg::Vec2(x, y); } void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) @@ -2760,8 +2761,9 @@ namespace MWWorld { int x = ext->getGridX(); int y = ext->getGridY(); - bool esm4Ext = ESM::isEsm4Ext(ext->getWorldSpace()); - indexToPosition(x, y, pos.pos[0], pos.pos[1], true, esm4Ext); + osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellIndex(x, y, ext->getWorldSpace()), true); + pos.pos[0] = posFromIndex.x(); + pos.pos[1] = posFromIndex.y(); // Note: Z pos will be adjusted by adjustPosition later pos.pos[2] = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7189c8b4be..675ccd5b34 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -400,8 +400,7 @@ namespace MWWorld float getMaxActivationDistance() const override; - void indexToPosition( - int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const override; + osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false) const override; ///< Convert cell numbers to position. void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override; From 1cf0cd56284ae1c48b33f187fbf6642323705658 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 10 May 2023 00:06:40 +0200 Subject: [PATCH 16/22] moved mwworld/cellutils.hpp -> esm/util.hpp --- apps/openmw/mwclass/door.cpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 3 +-- apps/openmw/mwgui/travelwindow.cpp | 6 ++---- apps/openmw/mwlua/worldview.cpp | 1 - .../mwscript/transformationextensions.cpp | 9 ++++----- apps/openmw/mwworld/actionteleport.cpp | 1 - apps/openmw/mwworld/cellref.cpp | 3 +-- apps/openmw/mwworld/cellutils.hpp | 19 ------------------- apps/openmw/mwworld/scene.cpp | 5 ++--- apps/openmw/mwworld/worldimp.cpp | 7 +++---- apps/openmw/mwworld/worldmodel.cpp | 3 +-- components/esm/util.hpp | 10 ++++++++++ 12 files changed, 24 insertions(+), 44 deletions(-) delete mode 100644 apps/openmw/mwworld/cellutils.hpp diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3b9aae37d4..24866fe365 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -17,7 +17,6 @@ #include "../mwworld/actionteleport.hpp" #include "../mwworld/actiontrap.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8c1e0263a3..cedd09b4b2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -23,7 +23,6 @@ #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" #include "../mwworld/worldmodel.hpp" @@ -277,7 +276,7 @@ namespace MWGui if (!mInterior) { - cellIndex = MWWorld::positionToCellIndex(worldX, worldY); + cellIndex = ESM::positionToCellIndex(worldX, worldY); nX = (worldX - cellSize * cellIndex.x()) / cellSize; // Image space is -Y up, cells are Y up nY = 1 - (worldY - cellSize * cellIndex.y()) / cellSize; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8637e98a06..21d503aac8 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -15,7 +15,6 @@ #include "../mwworld/actionteleport.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" @@ -126,8 +125,7 @@ namespace MWGui { std::string_view cellname = transport[i].mCellName; bool interior = true; - const osg::Vec2i cellIndex - = MWWorld::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); if (cellname.empty()) { MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( @@ -194,7 +192,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); - osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]); + osg::Vec2i posCell = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.x(), posCell.y()); // Teleports any followers, too. diff --git a/apps/openmw/mwlua/worldview.cpp b/apps/openmw/mwlua/worldview.cpp index 9ccc1caaf8..f5699dff89 100644 --- a/apps/openmw/mwlua/worldview.cpp +++ b/apps/openmw/mwlua/worldview.cpp @@ -10,7 +10,6 @@ #include "../mwclass/container.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/class.hpp" #include "../mwworld/timestamp.hpp" #include "../mwworld/worldmodel.hpp" diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a14a2f0ede..e493f3d911 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -14,7 +14,6 @@ #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" @@ -401,7 +400,7 @@ namespace MWScript store = &worldModel->getCell(cellID); if (store->isExterior()) { - const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); store = &worldModel->getExterior( ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); } @@ -417,7 +416,7 @@ namespace MWScript Log(Debug::Warning) << error; if (!isPlayer) return; - const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); store = &worldModel->getExterior( ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); } @@ -468,7 +467,7 @@ namespace MWScript { world->getPlayer().setTeleported(true); } - const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. @@ -569,7 +568,7 @@ namespace MWScript MWWorld::CellStore* store = nullptr; if (player.getCell()->isExterior()) { - const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); store = &MWBase::Environment::get().getWorldModel()->getExterior(ESM::ExteriorCellIndex( cellIndex.x(), cellIndex.y(), player.getCell()->getCell()->getWorldSpace())); } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 03efcff742..926e958e95 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -11,7 +11,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwworld/cellutils.hpp" #include "../mwworld/class.hpp" #include "../mwworld/worldmodel.hpp" diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index dcfc7ae6b7..917d9e16d5 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -10,7 +10,6 @@ #include #include -#include #include namespace MWWorld @@ -89,7 +88,7 @@ namespace MWWorld } else { - const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); + const osg::Vec2i index = ESM::positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); return ESM::RefId::esm3ExteriorCell(index.x(), index.y()); } }; diff --git a/apps/openmw/mwworld/cellutils.hpp b/apps/openmw/mwworld/cellutils.hpp deleted file mode 100644 index 978e358c8b..0000000000 --- a/apps/openmw/mwworld/cellutils.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef OPENMW_MWWORLD_CELLUTILS_H -#define OPENMW_MWWORLD_CELLUTILS_H - -#include - -#include - -#include - -namespace MWWorld -{ - inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false) - { - const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; - return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; - } -} - -#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 5dc35ef2d3..228f0892bb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -40,7 +40,6 @@ #include "cellpreloader.hpp" #include "cellstore.hpp" -#include "cellutils.hpp" #include "cellvisitors.hpp" #include "class.hpp" #include "esmstore.hpp" @@ -525,7 +524,7 @@ namespace MWWorld if (distance <= maxDistance) return *currentGridCenter; } - return positionToCellIndex(pos.x(), pos.y(), isEsm4Ext); + return ESM::positionToCellIndex(pos.x(), pos.y(), isEsm4Ext); } void Scene::playerMoved(const osg::Vec3f& pos) @@ -1293,7 +1292,7 @@ namespace MWWorld else { osg::Vec3f pos = dest.mPos.asVec3(); - const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(pos.x(), pos.y()); preloadCell(mWorld.getWorldModel().getExterior( ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), extWorldspace)), true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5d889f5a44..40d774d7d4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -95,7 +95,6 @@ #include "projectilemanager.hpp" #include "weather.hpp" -#include "cellutils.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -380,7 +379,7 @@ namespace MWWorld pos.rot[1] = 0; pos.rot[2] = 0; - osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]); + osg::Vec2i exteriorCellPos = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); mWorldScene->changeToExteriorCell(cellId, pos, true); } @@ -1245,7 +1244,7 @@ namespace MWWorld MWWorld::Ptr World::moveObject(const Ptr& ptr, const osg::Vec3f& position, bool movePhysics, bool moveToActive) { - const osg::Vec2i index = positionToCellIndex(position.x(), position.y()); + const osg::Vec2i index = ESM::positionToCellIndex(position.x(), position.y()); CellStore* cell = ptr.getCell(); ESM::RefId worldspaceId @@ -2064,7 +2063,7 @@ namespace MWWorld throw std::runtime_error("copyObjectToCell(): cannot copy object to null cell"); if (cell->isExterior()) { - const osg::Vec2i index = positionToCellIndex(pos.pos[0], pos.pos[1]); + const osg::Vec2i index = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); cell = &mWorldModel.getExterior( ESM::ExteriorCellIndex(index.x(), index.y(), cell->getCell()->getWorldSpace())); } diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 16564b4e91..d0c47dd6b1 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -16,7 +16,6 @@ #include "../mwbase/world.hpp" #include "cellstore.hpp" -#include "cellutils.hpp" #include "esmstore.hpp" namespace @@ -333,7 +332,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( { if (cellInSameWorldSpace && !cellInSameWorldSpace->isExterior()) return *cellInSameWorldSpace; - const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y()); + const osg::Vec2i cellIndex = ESM::positionToCellIndex(pos.x(), pos.y()); ESM::RefId exteriorWorldspace = cellInSameWorldSpace ? cellInSameWorldSpace->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; return getExterior(ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), exteriorWorldspace)); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index d6d9feb3c4..b5eeb1fa65 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,7 +1,10 @@ #ifndef OPENMW_ESM_UTIL_H #define OPENMW_ESM_UTIL_H +#include #include +#include +#include #include #include @@ -80,6 +83,13 @@ namespace ESM { return isESM4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; } + + inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false) + { + const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; + } + } namespace std From 3d06cabf6a18227b44300bd9ca713865a0fbc5e4 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 10 May 2023 00:20:05 +0200 Subject: [PATCH 17/22] indexToPosition moved from world -> esm/util.hpp --- apps/openmw/mwbase/world.hpp | 3 --- apps/openmw/mwscript/cellextensions.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 15 --------------- apps/openmw/mwworld/worldimp.hpp | 3 --- components/esm/util.cpp | 16 ++++++++++++++++ components/esm/util.hpp | 2 ++ 8 files changed, 23 insertions(+), 26 deletions(-) create mode 100644 components/esm/util.cpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 79f709e224..963a22d065 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -313,9 +313,6 @@ namespace MWBase /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// obstructed). - virtual osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false) const = 0; - ///< Convert cell numbers to position. - virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index bd7592561c..041476492d 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -124,7 +124,7 @@ namespace MWScript const MWWorld::Ptr playerPtr = world->getPlayerPtr(); osg::Vec2 posFromIndex - = world->indexToPosition(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId), true); + = ESM::indexToPosition(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId), true); pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); pos.pos[2] = 0; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 7a544e9016..796f820999 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -565,7 +565,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell"; ESM::ExteriorCellIndex cellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId); MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); - osg::Vec2 posFromIndex = MWBase::Environment::get().getWorld()->indexToPosition(cellIndex, false); + osg::Vec2 posFromIndex = ESM::indexToPosition(cellIndex, false); ESM::Position pos; pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 228f0892bb..9d5ae68aae 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -516,7 +516,7 @@ namespace MWWorld if (currentGridCenter) { - osg::Vec2 center = mWorld.indexToPosition( + osg::Vec2 center = ESM::indexToPosition( ESM::ExteriorCellIndex(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); float distance = std::max(std::abs(center.x() - pos.x()), std::abs(center.y() - pos.y())); float cellSize = ESM::getCellSize(isEsm4Ext); @@ -1167,7 +1167,7 @@ namespace MWWorld cellY = mCurrentGridCenter.y(); ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); - osg::Vec2 center = mWorld.indexToPosition(ESM::ExteriorCellIndex(cellX, cellY, extWorldspace), true); + osg::Vec2 center = ESM::indexToPosition(ESM::ExteriorCellIndex(cellX, cellY, extWorldspace), true); bool esm4Ext = ESM::isEsm4Ext(extWorldspace); float cellSize = ESM::getCellSize(esm4Ext); @@ -1181,7 +1181,7 @@ namespace MWWorld continue; // only care about the outer (not yet loaded) part of the grid osg::Vec2 thisCellCenter - = mWorld.indexToPosition(ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace), true); + = ESM::indexToPosition(ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace), true); float dist = std::max( std::abs(thisCellCenter.x() - playerPos.x()), std::abs(thisCellCenter.y() - playerPos.y())); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40d774d7d4..2d0700bd4f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1495,21 +1495,6 @@ namespace MWWorld return placed; } - osg::Vec2 World::indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre) const - { - const int cellSize = ESM::getCellSize(ESM::isEsm4Ext(cellIndex.mWorldspace)); - - float x = static_cast(cellSize * cellIndex.mX); - float y = static_cast(cellSize * cellIndex.mY); - - if (centre) - { - x += cellSize / 2; - y += cellSize / 2; - } - return osg::Vec2(x, y); - } - void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) { mPhysics->queueObjectMovement(ptr, velocity); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 675ccd5b34..0bf223f9ba 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -400,9 +400,6 @@ namespace MWWorld float getMaxActivationDistance() const override; - osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false) const override; - ///< Convert cell numbers to position. - void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. diff --git a/components/esm/util.cpp b/components/esm/util.cpp new file mode 100644 index 0000000000..69277ad5a0 --- /dev/null +++ b/components/esm/util.cpp @@ -0,0 +1,16 @@ +#include "util.hpp" + +osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre) +{ + const int cellSize = ESM::getCellSize(ESM::isEsm4Ext(cellIndex.mWorldspace)); + + float x = static_cast(cellSize * cellIndex.mX); + float y = static_cast(cellSize * cellIndex.mY); + + if (centre) + { + x += cellSize / 2; + y += cellSize / 2; + } + return osg::Vec2(x, y); +} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index b5eeb1fa65..a6818e562c 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -90,6 +90,8 @@ namespace ESM return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; } + osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false); + ///< Convert cell numbers to position. } namespace std From 39cfe9c2fb26c5643a11bdc01bd28192309258c5 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 10 May 2023 09:11:20 +0200 Subject: [PATCH 18/22] Removed unused variable, factorised code. --- apps/openmw/mwworld/scene.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 9d5ae68aae..c6623998b9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1167,8 +1167,6 @@ namespace MWWorld cellY = mCurrentGridCenter.y(); ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); - osg::Vec2 center = ESM::indexToPosition(ESM::ExteriorCellIndex(cellX, cellY, extWorldspace), true); - bool esm4Ext = ESM::isEsm4Ext(extWorldspace); float cellSize = ESM::getCellSize(esm4Ext); @@ -1179,9 +1177,8 @@ namespace MWWorld if (dy != halfGridSizePlusOne && dy != -halfGridSizePlusOne && dx != halfGridSizePlusOne && dx != -halfGridSizePlusOne) continue; // only care about the outer (not yet loaded) part of the grid - - osg::Vec2 thisCellCenter - = ESM::indexToPosition(ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace), true); + ESM::ExteriorCellIndex cellIndex(cellX + dx, cellY + dy, extWorldspace); + osg::Vec2 thisCellCenter = ESM::indexToPosition(cellIndex, true); float dist = std::max( std::abs(thisCellCenter.x() - playerPos.x()), std::abs(thisCellCenter.y() - playerPos.y())); @@ -1191,8 +1188,7 @@ namespace MWWorld float loadDist = cellSize / 2 + cellSize - mCellLoadingThreshold + mPreloadDistance; if (dist < loadDist) - preloadCell(mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(cellX + dx, cellY + dy, extWorldspace))); + preloadCell(mWorld.getWorldModel().getExterior(cellIndex)); } } } From 559830f59a8ad6e4d86816b3fdf46d8e319e727d Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 10 May 2023 14:51:33 +0200 Subject: [PATCH 19/22] applies review comments Removes ToLowercase after .serializeText removed unused variable !ptr => ptr == nullptr better indentation + error message on throw friend struct std::hash<...> useless on struct with all public fields. --- apps/openmw/mwworld/scene.cpp | 15 +++++-------- apps/openmw/mwworld/worldmodel.cpp | 35 +++++++++++++----------------- components/esm/util.hpp | 2 -- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c6623998b9..10145fbf17 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -548,7 +548,6 @@ namespace MWWorld auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); int playerCellX = playerCellIndex.mX; int playerCellY = playerCellIndex.mY; - ESM::RefId exteriorWorldspace = playerCellIndex.mWorldspace; for (auto iter = mActiveCells.begin(); iter != mActiveCells.end();) { @@ -564,8 +563,7 @@ namespace MWWorld unloadCell(cell, navigatorUpdateGuard.get()); } mNavigator.setWorldspace( - Misc::StringUtils::lowerCase( - mWorld.getWorldModel().getExterior(playerCellIndex).getCell()->getWorldSpace().serializeText()), + mWorld.getWorldModel().getExterior(playerCellIndex).getCell()->getWorldSpace().serializeText(), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -621,7 +619,7 @@ namespace MWWorld for (const auto& [x, y] : cellsPositionsToLoad) { - ESM::ExteriorCellIndex indexToLoad = { x, y, exteriorWorldspace }; + ESM::ExteriorCellIndex indexToLoad = { x, y, playerCellIndex.mWorldspace }; if (!isCellInCollection(indexToLoad, mActiveCells)) { CellStore& cell = mWorld.getWorldModel().getExterior(indexToLoad); @@ -688,8 +686,7 @@ namespace MWWorld CellStore& cell = mWorld.getWorldModel().getExterior( ESM::ExteriorCellIndex(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId)); - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell.getCell()->getWorldSpace().serializeText()), - navigatorUpdateGuard.get()); + mNavigator.setWorldspace(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()); @@ -746,8 +743,7 @@ namespace MWWorld + std::to_string(cells.getIntSize()) + ")..."); CellStore& cell = mWorld.getWorldModel().getInterior(it->mName); - mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell.getCell()->getWorldSpace().serializeText()), - navigatorUpdateGuard.get()); + mNavigator.setWorldspace(cell.getCell()->getWorldSpace().serializeText(), navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -902,8 +898,7 @@ namespace MWWorld loadingListener->setProgressRange(cell.count()); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell.getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(cell.getCell()->getWorldSpace().serializeText(), 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 d0c47dd6b1..7491415630 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -76,7 +76,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) } else { - ESM::ExteriorCellIndex extIndex = { cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId }; + ESM::ExteriorCellIndex extIndex(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId); std::map::iterator result = mExteriors.find(extIndex); if (result == mExteriors.end()) @@ -172,7 +172,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellIndex cell { const ESM::Cell* cell = mStore.get().search(cellIndex.mX, cellIndex.mY); - if (!cell) + if (cell == nullptr) { // Cell isn't predefined. Make one on the fly. ESM::Cell record; @@ -193,27 +193,22 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellIndex cell else { const Store& cell4Store = mStore.get(); - bool exteriorExists = mStore.get().search(cellIndex.mWorldspace); + bool exteriorExists = mStore.get().search(cellIndex.mWorldspace) != nullptr; const ESM4::Cell* cell = cell4Store.searchExterior(cellIndex); - if (exteriorExists) + if (!exteriorExists) + throw std::runtime_error("Exterior ESM4 world is not found: " + cellIndex.mWorldspace.toDebugString()); + if (cell == nullptr) { - if (!cell) - { - ESM4::Cell record; - record.mParent = cellIndex.mWorldspace; - record.mX = cellIndex.mX; - record.mY = cellIndex.mY; - record.mCellFlags = !ESM4::CELL_Interior; - cell = MWBase::Environment::get().getESMStore()->insert(record); - } - CellStore* cellStore - = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; - result = mExteriors.emplace(cellIndex, cellStore).first; - } - else - { - throw std::runtime_error("exterior not found: '" + cellIndex.mWorldspace.toDebugString() + "'"); + ESM4::Cell record; + record.mParent = cellIndex.mWorldspace; + record.mX = cellIndex.mX; + record.mY = cellIndex.mY; + record.mCellFlags = !ESM4::CELL_Interior; + cell = MWBase::Environment::get().getESMStore()->insert(record); } + CellStore* cellStore + = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second; + result = mExteriors.emplace(cellIndex, cellStore).first; } } if (result->second->getState() != CellStore::State_Loaded) diff --git a/components/esm/util.hpp b/components/esm/util.hpp index a6818e562c..3ae244bd20 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -70,8 +70,6 @@ namespace ESM { return std::make_tuple(mX, mY, mWorldspace) < std::make_tuple(other.mX, other.mY, other.mWorldspace); } - - friend struct std::hash; }; static inline bool isEsm4Ext(ESM::RefId worldspaceId) From 393357abc04b728884570db0a7f374c6bd6956ac Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 12 May 2023 12:04:04 +0200 Subject: [PATCH 20/22] ESM::Cell::positionToCellIndex returns a ESM::ExteriorCellIndex and takes a worldspace id as input ESM::getCellSize takes a wordspace as input. removed useless static in static inline funcs --- apps/openmw/mwgui/mapwindow.cpp | 5 +++- apps/openmw/mwgui/travelwindow.cpp | 10 +++---- .../mwscript/transformationextensions.cpp | 24 ++++++++--------- apps/openmw/mwworld/cellref.cpp | 4 +-- apps/openmw/mwworld/scene.cpp | 14 +++++----- apps/openmw/mwworld/worldimp.cpp | 26 +++++++++---------- apps/openmw/mwworld/worldmodel.cpp | 5 ++-- components/esm/util.cpp | 2 +- components/esm/util.hpp | 14 +++++----- 9 files changed, 53 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index cedd09b4b2..691d096450 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -276,7 +276,10 @@ namespace MWGui if (!mInterior) { - cellIndex = ESM::positionToCellIndex(worldX, worldY); + ESM::ExteriorCellIndex cellPos = ESM::positionToCellIndex(worldX, worldY); + cellIndex.x() = cellPos.mX; + cellIndex.y() = cellPos.mY; + nX = (worldX - cellSize * cellIndex.x()) / cellSize; // Image space is -Y up, cells are Y up nY = 1 - (worldY - cellSize * cellIndex.y()) / cellSize; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 21d503aac8..4ad90547b5 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -125,11 +125,11 @@ namespace MWGui { std::string_view cellname = transport[i].mCellName; bool interior = true; - const osg::Vec2i cellIndex = ESM::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); + const ESM::ExteriorCellIndex cellIndex + = ESM::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); if (cellname.empty()) { - MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)); + MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); cellname = MWBase::Environment::get().getWorld()->getCellName(&cell); interior = false; } @@ -192,8 +192,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); - osg::Vec2i posCell = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); - ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.x(), posCell.y()); + const ESM::ExteriorCellIndex posCell = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); + ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.mX, posCell.mY); // Teleports any followers, too. MWWorld::ActionTeleport action(cellId, pos, true); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e493f3d911..4bf1f148e5 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -400,9 +400,9 @@ namespace MWScript store = &worldModel->getCell(cellID); if (store->isExterior()) { - const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); - store = &worldModel->getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); + const ESM::ExteriorCellIndex cellIndex + = ESM::positionToCellIndex(x, y, store->getCell()->getWorldSpace()); + store = &worldModel->getExterior(cellIndex); } } catch (std::exception&) @@ -416,9 +416,9 @@ namespace MWScript Log(Debug::Warning) << error; if (!isPlayer) return; - const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); - store = &worldModel->getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), store->getCell()->getWorldSpace())); + const ESM::ExteriorCellIndex cellIndex + = ESM::positionToCellIndex(x, y, store->getCell()->getWorldSpace()); + store = &worldModel->getExterior(cellIndex); } if (store) { @@ -467,15 +467,15 @@ namespace MWScript { world->getPlayer().setTeleported(true); } - const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); + const ESM::ExteriorCellIndex cellIndex + = ESM::positionToCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId); // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. MWWorld::Ptr base = ptr; if (isPlayer) { - MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), ESM::Cell::sDefaultWorldspaceId)); + MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); ptr = world->moveObject(ptr, cell, osg::Vec3(x, y, z)); } else @@ -568,9 +568,9 @@ namespace MWScript MWWorld::CellStore* store = nullptr; if (player.getCell()->isExterior()) { - const osg::Vec2i cellIndex = ESM::positionToCellIndex(x, y); - store = &MWBase::Environment::get().getWorldModel()->getExterior(ESM::ExteriorCellIndex( - cellIndex.x(), cellIndex.y(), player.getCell()->getCell()->getWorldSpace())); + const ESM::ExteriorCellIndex cellIndex + = ESM::positionToCellIndex(x, y, player.getCell()->getCell()->getWorldSpace()); + store = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); } else store = player.getCell(); diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 917d9e16d5..3e81ba1c37 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -88,8 +88,8 @@ namespace MWWorld } else { - const osg::Vec2i index = ESM::positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); - return ESM::RefId::esm3ExteriorCell(index.x(), index.y()); + const auto cellPos = ESM::positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]); + return ESM::RefId::esm3ExteriorCell(cellPos.mX, cellPos.mY); } }; auto esm4Visit = [&](const ESM4::Reference& ref) -> ESM::RefId { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 10145fbf17..08208b93b3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -519,12 +519,13 @@ namespace MWWorld osg::Vec2 center = ESM::indexToPosition( ESM::ExteriorCellIndex(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); float distance = std::max(std::abs(center.x() - pos.x()), std::abs(center.y() - pos.y())); - float cellSize = ESM::getCellSize(isEsm4Ext); + float cellSize = ESM::getCellSize(worldspace); const float maxDistance = cellSize / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; } - return ESM::positionToCellIndex(pos.x(), pos.y(), isEsm4Ext); + ESM::ExteriorCellIndex cellPos = ESM::positionToCellIndex(pos.x(), pos.y(), worldspace); + return { cellPos.mX, cellPos.mY }; } void Scene::playerMoved(const osg::Vec3f& pos) @@ -1162,8 +1163,7 @@ namespace MWWorld cellY = mCurrentGridCenter.y(); ESM::RefId extWorldspace = mWorld.getCurrentWorldspace(); - bool esm4Ext = ESM::isEsm4Ext(extWorldspace); - float cellSize = ESM::getCellSize(esm4Ext); + float cellSize = ESM::getCellSize(extWorldspace); for (int dx = -halfGridSizePlusOne; dx <= halfGridSizePlusOne; ++dx) { @@ -1283,10 +1283,8 @@ namespace MWWorld else { osg::Vec3f pos = dest.mPos.asVec3(); - const osg::Vec2i cellIndex = ESM::positionToCellIndex(pos.x(), pos.y()); - preloadCell(mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), extWorldspace)), - true); + const ESM::ExteriorCellIndex cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), extWorldspace); + preloadCell(mWorld.getWorldModel().getExterior(cellIndex), true); exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2d0700bd4f..d61c1b2334 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -379,8 +379,8 @@ namespace MWWorld pos.rot[1] = 0; pos.rot[2] = 0; - osg::Vec2i exteriorCellPos = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); - ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y()); + ESM::ExteriorCellIndex exteriorCellPos = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); + ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.mX, exteriorCellPos.mY); mWorldScene->changeToExteriorCell(cellId, pos, true); } } @@ -1244,14 +1244,12 @@ namespace MWWorld MWWorld::Ptr World::moveObject(const Ptr& ptr, const osg::Vec3f& position, bool movePhysics, bool moveToActive) { - const osg::Vec2i index = ESM::positionToCellIndex(position.x(), position.y()); - CellStore* cell = ptr.getCell(); ESM::RefId worldspaceId = cell->isExterior() ? cell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - CellStore* newCell = cell->isExterior() - ? &mWorldModel.getExterior(ESM::ExteriorCellIndex(index.x(), index.y(), worldspaceId)) - : nullptr; + const ESM::ExteriorCellIndex index = ESM::positionToCellIndex(position.x(), position.y(), worldspaceId); + + CellStore* newCell = cell->isExterior() ? &mWorldModel.getExterior(index) : nullptr; bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() && (newCell && mWorldScene->isCellActive(*newCell)); @@ -1373,8 +1371,8 @@ namespace MWWorld && !(ptr.getClass().isPersistent(ptr) && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()); if (force || !ptr.getClass().isActor() || (!isFlying(ptr) && !swims && isActorCollisionEnabled(ptr))) { - bool esm4Ext = ptr.getCell()->isExterior() && ESM::isEsm4Ext(ptr.getCell()->getCell()->getWorldSpace()); - osg::Vec3f traced = mPhysics->traceDown(ptr, pos, ESM::getCellSize(esm4Ext)); + osg::Vec3f traced + = mPhysics->traceDown(ptr, pos, ESM::getCellSize(ptr.getCell()->getCell()->getWorldSpace())); pos.z() = std::min(pos.z(), traced.z()); } @@ -1409,9 +1407,9 @@ namespace MWWorld if (!mPhysics->castRay(pos, targetPos, MWPhysics::CollisionType_World | MWPhysics::CollisionType_Door).mHit) break; } - bool esm4Ext = actor.getCell()->isExterior() && ESM::isEsm4Ext(actor.getCell()->getCell()->getWorldSpace()); targetPos.z() += distance / 2.f; // move up a bit to get out from geometry, will snap down later - osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, ESM::getCellSize(esm4Ext)); + osg::Vec3f traced + = mPhysics->traceDown(actor, targetPos, ESM::getCellSize(actor.getCell()->getCell()->getWorldSpace())); if (traced != pos) { esmPos.pos[0] = traced.x(); @@ -2048,9 +2046,9 @@ namespace MWWorld throw std::runtime_error("copyObjectToCell(): cannot copy object to null cell"); if (cell->isExterior()) { - const osg::Vec2i index = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); - cell = &mWorldModel.getExterior( - ESM::ExteriorCellIndex(index.x(), index.y(), cell->getCell()->getWorldSpace())); + const ESM::ExteriorCellIndex index + = ESM::positionToCellIndex(pos.pos[0], pos.pos[1], cell->getCell()->getWorldSpace()); + cell = &mWorldModel.getExterior(index); } MWWorld::Ptr dropped = object.getClass().copyToCell(object, *cell, pos, count); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 7491415630..dacbe63587 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -327,10 +327,11 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( { if (cellInSameWorldSpace && !cellInSameWorldSpace->isExterior()) return *cellInSameWorldSpace; - const osg::Vec2i cellIndex = ESM::positionToCellIndex(pos.x(), pos.y()); ESM::RefId exteriorWorldspace = cellInSameWorldSpace ? cellInSameWorldSpace->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - return getExterior(ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), exteriorWorldspace)); + const ESM::ExteriorCellIndex cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), exteriorWorldspace); + + return getExterior(cellIndex); } MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name, CellStore& cell) diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 69277ad5a0..514472211b 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -2,7 +2,7 @@ osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre) { - const int cellSize = ESM::getCellSize(ESM::isEsm4Ext(cellIndex.mWorldspace)); + const int cellSize = ESM::getCellSize(cellIndex.mWorldspace); float x = static_cast(cellSize * cellIndex.mX); float y = static_cast(cellSize * cellIndex.mY); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 3ae244bd20..6a5c664ecc 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -72,20 +72,22 @@ namespace ESM } }; - static inline bool isEsm4Ext(ESM::RefId worldspaceId) + inline bool isEsm4Ext(ESM::RefId worldspaceId) { return worldspaceId != ESM::Cell::sDefaultWorldspaceId; } - static inline int getCellSize(bool isESM4Ext) + inline int getCellSize(ESM::RefId worldspaceId) { - return isESM4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + + return isEsm4Ext(worldspaceId) ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; } - inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false) + inline ESM::ExteriorCellIndex positionToCellIndex( + float x, float y, ESM::RefId worldspaceId = ESM::Cell::sDefaultWorldspaceId) { - const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; - return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; + const float cellSize = getCellSize(worldspaceId); + return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)), worldspaceId }; } osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false); From a3bd6e7e47fa8291c1e9a848930177fcde60ffde Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 12 May 2023 13:24:59 +0200 Subject: [PATCH 21/22] ESM::ExteriorCellIndex => ESM::ExteriorCellLocation --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 6 ++-- apps/openmw/mwgui/travelwindow.cpp | 4 +-- apps/openmw/mwlua/luabindings.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwrender/landmanager.cpp | 2 +- apps/openmw/mwrender/landmanager.hpp | 2 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- apps/openmw/mwscript/cellextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 8 ++--- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- apps/openmw/mwworld/cellpreloader.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 30 +++++++++---------- apps/openmw/mwworld/scene.hpp | 4 +-- apps/openmw/mwworld/store.cpp | 4 +-- apps/openmw/mwworld/store.hpp | 6 ++-- apps/openmw/mwworld/worldimp.cpp | 10 +++---- apps/openmw/mwworld/worldmodel.cpp | 16 +++++----- apps/openmw/mwworld/worldmodel.hpp | 4 +-- components/esm/util.cpp | 2 +- components/esm/util.hpp | 16 +++++----- 22 files changed, 64 insertions(+), 66 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 963a22d065..31a93e9201 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -55,7 +55,7 @@ namespace ESM struct ItemLevList; struct TimeStamp; class RefId; - struct ExteriorCellIndex; + struct ExteriorCellLocation; } namespace MWPhysics diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 691d096450..f3d3b346e4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -276,7 +276,7 @@ namespace MWGui if (!mInterior) { - ESM::ExteriorCellIndex cellPos = ESM::positionToCellIndex(worldX, worldY); + ESM::ExteriorCellLocation cellPos = ESM::positionToCellIndex(worldX, worldY); cellIndex.x() = cellPos.mX; cellIndex.y() = cellPos.mY; @@ -586,7 +586,7 @@ namespace MWGui { if (!mInterior) requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellIndex(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId))); + ESM::ExteriorCellLocation(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId))); osg::ref_ptr texture = mLocalMapRender->getMapTexture(entry.mCellX, entry.mCellY); if (texture) @@ -643,7 +643,7 @@ namespace MWGui for (MapEntry& entry : mMaps) { if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap)) - world->getDoorMarkers(worldModel->getExterior(ESM::ExteriorCellIndex( + world->getDoorMarkers(worldModel->getExterior(ESM::ExteriorCellLocation( entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)), doors); } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 4ad90547b5..e5f840874d 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -125,7 +125,7 @@ namespace MWGui { std::string_view cellname = transport[i].mCellName; bool interior = true; - const ESM::ExteriorCellIndex cellIndex + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(transport[i].mPos.pos[0], transport[i].mPos.pos[1]); if (cellname.empty()) { @@ -192,7 +192,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); - const ESM::ExteriorCellIndex posCell = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); + const ESM::ExteriorCellLocation posCell = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.mX, posCell.mY); // Teleports any followers, too. diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index b1c762440c..0084c4a901 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -115,7 +115,7 @@ namespace MWLua = [](std::string_view name) { return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name) }; }; api["getExteriorCell"] = [](int x, int y) { return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId)) }; + ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId)) }; }; api["activeActors"] = GObjectList{ worldView->getActorsInScene() }; api["createObject"] = [](std::string_view recordId, sol::optional count) -> GObject { diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index dbc31fccb1..1c37ac029e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -483,7 +483,7 @@ namespace MWPhysics mHeightFields.erase(heightfield); } - const HeightField* PhysicsSystem::getHeightField(ESM::ExteriorCellIndex cellIndex) const + const HeightField* PhysicsSystem::getHeightField(ESM::ExteriorCellLocation cellIndex) const { if (ESM::isEsm4Ext(cellIndex.mWorldspace)) return nullptr; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 1e1d7bdb61..32899dd711 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -190,7 +190,7 @@ namespace MWPhysics void removeHeightField(int x, int y); - const HeightField* getHeightField(ESM::ExteriorCellIndex cellIndex) const; + const HeightField* getHeightField(ESM::ExteriorCellLocation cellIndex) const; bool toggleCollisionMode(); diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index a3248d21a7..e7a647f348 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -18,7 +18,7 @@ namespace MWRender mCache = new CacheType; } - osg::ref_ptr LandManager::getLand(ESM::ExteriorCellIndex cellIndex) + osg::ref_ptr LandManager::getLand(ESM::ExteriorCellLocation cellIndex) { if (ESM::isEsm4Ext(cellIndex.mWorldspace)) return osg::ref_ptr(nullptr); diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index f7ebf5ddb8..1a95038eea 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -21,7 +21,7 @@ namespace MWRender LandManager(int loadFlags); /// @note Will return nullptr if not found. - osg::ref_ptr getLand(ESM::ExteriorCellIndex cellIndex); + osg::ref_ptr getLand(ESM::ExteriorCellLocation cellIndex); void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index b950e4fe5c..ebbe3fa18b 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -68,7 +68,7 @@ namespace MWRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - return mLandManager->getLand(ESM::ExteriorCellIndex(cellX, cellY, ESM::Cell::sDefaultWorldspaceId)); + return mLandManager->getLand(ESM::ExteriorCellLocation(cellX, cellY, ESM::Cell::sDefaultWorldspaceId)); } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 041476492d..147b9a5d82 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -124,7 +124,7 @@ namespace MWScript const MWWorld::Ptr playerPtr = world->getPlayerPtr(); osg::Vec2 posFromIndex - = ESM::indexToPosition(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId), true); + = ESM::indexToPosition(ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId), true); pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); pos.pos[2] = 0; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 4bf1f148e5..fd091711c8 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -400,7 +400,7 @@ namespace MWScript store = &worldModel->getCell(cellID); if (store->isExterior()) { - const ESM::ExteriorCellIndex cellIndex + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(x, y, store->getCell()->getWorldSpace()); store = &worldModel->getExterior(cellIndex); } @@ -416,7 +416,7 @@ namespace MWScript Log(Debug::Warning) << error; if (!isPlayer) return; - const ESM::ExteriorCellIndex cellIndex + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(x, y, store->getCell()->getWorldSpace()); store = &worldModel->getExterior(cellIndex); } @@ -467,7 +467,7 @@ namespace MWScript { world->getPlayer().setTeleported(true); } - const ESM::ExteriorCellIndex cellIndex + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId); // another morrowind oddity: player will be moved to the exterior cell at this location, @@ -568,7 +568,7 @@ namespace MWScript MWWorld::CellStore* store = nullptr; if (player.getCell()->isExterior()) { - const ESM::ExteriorCellIndex cellIndex + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(x, y, player.getCell()->getCell()->getWorldSpace()); store = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 796f820999..c14a221187 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -563,7 +563,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file { // Cell no longer exists (i.e. changed game files), choose a default cell Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell"; - ESM::ExteriorCellIndex cellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId); + ESM::ExteriorCellLocation cellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId); MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); osg::Vec2 posFromIndex = ESM::indexToPosition(cellIndex, false); ESM::Position pos; diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 9881595123..8e5c539ae0 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -103,7 +103,7 @@ namespace MWWorld { mTerrain->cacheCell(mTerrainView.get(), mX, mY); mPreloadedObjects.insert( - mLandManager->getLand(ESM::ExteriorCellIndex(mX, mY, ESM::Cell::sDefaultWorldspaceId))); + mLandManager->getLand(ESM::ExteriorCellLocation(mX, mY, ESM::Cell::sDefaultWorldspaceId))); } catch (std::exception&) { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 08208b93b3..1f4a7d526a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -247,7 +247,7 @@ namespace return std::abs(cellPosition.first) + std::abs(cellPosition.second); } - bool isCellInCollection(ESM::ExteriorCellIndex cellIndex, MWWorld::Scene::CellStoreCollection& collection) + bool isCellInCollection(ESM::ExteriorCellLocation cellIndex, MWWorld::Scene::CellStoreCollection& collection) { for (auto* cell : collection) { @@ -346,7 +346,7 @@ namespace MWWorld if (cell->getCell()->isExterior()) { - if (mPhysics->getHeightField(ESM::ExteriorCellIndex(cellX, cellY, cell->getCell()->getWorldSpace())) + if (mPhysics->getHeightField(ESM::ExteriorCellLocation(cellX, cellY, cell->getCell()->getWorldSpace())) != nullptr) mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); @@ -393,7 +393,7 @@ namespace MWWorld const int cellY = cell.getCell()->getGridY(); const MWWorld::Cell& cellVariant = *cell.getCell(); ESM::RefId worldspace = cellVariant.getWorldSpace(); - ESM::ExteriorCellIndex cellIndex(cellX, cellY, worldspace); + ESM::ExteriorCellLocation cellIndex(cellX, cellY, worldspace); if (cellVariant.isExterior()) { @@ -512,19 +512,17 @@ namespace MWWorld { ESM::RefId worldspace = mCurrentCell ? mCurrentCell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - bool isEsm4Ext = ESM::isEsm4Ext(worldspace); - if (currentGridCenter) { osg::Vec2 center = ESM::indexToPosition( - ESM::ExteriorCellIndex(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); + ESM::ExteriorCellLocation(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); float distance = std::max(std::abs(center.x() - pos.x()), std::abs(center.y() - pos.y())); float cellSize = ESM::getCellSize(worldspace); const float maxDistance = cellSize / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; } - ESM::ExteriorCellIndex cellPos = ESM::positionToCellIndex(pos.x(), pos.y(), worldspace); + ESM::ExteriorCellLocation cellPos = ESM::positionToCellIndex(pos.x(), pos.y(), worldspace); return { cellPos.mX, cellPos.mY }; } @@ -541,10 +539,10 @@ namespace MWWorld void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent) { mChangeCellGridRequest = ChangeCellGridRequest{ position, - ESM::ExteriorCellIndex(cell.x(), cell.y(), mCurrentCell->getCell()->getWorldSpace()), changeEvent }; + ESM::ExteriorCellLocation(cell.x(), cell.y(), mCurrentCell->getCell()->getWorldSpace()), changeEvent }; } - void Scene::changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellIndex playerCellIndex, bool changeEvent) + void Scene::changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellLocation playerCellIndex, bool changeEvent) { auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); int playerCellX = playerCellIndex.mX; @@ -586,7 +584,7 @@ namespace MWWorld { for (int y = playerCellY - range; y <= playerCellY + range; ++y) { - if (!isCellInCollection(ESM::ExteriorCellIndex(x, y, playerCellIndex.mWorldspace), collection)) + if (!isCellInCollection(ESM::ExteriorCellLocation(x, y, playerCellIndex.mWorldspace), collection)) { refsToLoad += mWorld.getWorldModel().getExterior(playerCellIndex).count(); cellsPositionsToLoad.emplace_back(x, y); @@ -620,7 +618,7 @@ namespace MWWorld for (const auto& [x, y] : cellsPositionsToLoad) { - ESM::ExteriorCellIndex indexToLoad = { x, y, playerCellIndex.mWorldspace }; + ESM::ExteriorCellLocation indexToLoad = { x, y, playerCellIndex.mWorldspace }; if (!isCellInCollection(indexToLoad, mActiveCells)) { CellStore& cell = mWorld.getWorldModel().getExterior(indexToLoad); @@ -686,7 +684,7 @@ namespace MWWorld + std::to_string(cells.getExtSize()) + ")..."); CellStore& cell = mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId)); + ESM::ExteriorCellLocation(it->mData.mX, it->mData.mY, ESM::Cell::sDefaultWorldspaceId)); mNavigator.setWorldspace(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; @@ -940,7 +938,7 @@ namespace MWWorld const osg::Vec2i cellIndex(current.getCell()->getGridX(), current.getCell()->getGridY()); changeCellGrid(position.asVec3(), - ESM::ExteriorCellIndex(cellIndex.x(), cellIndex.y(), current.getCell()->getWorldSpace()), changeEvent); + ESM::ExteriorCellLocation(cellIndex.x(), cellIndex.y(), current.getCell()->getWorldSpace()), changeEvent); changePlayerCell(current, position, adjustPlayerPos); @@ -1172,7 +1170,7 @@ namespace MWWorld if (dy != halfGridSizePlusOne && dy != -halfGridSizePlusOne && dx != halfGridSizePlusOne && dx != -halfGridSizePlusOne) continue; // only care about the outer (not yet loaded) part of the grid - ESM::ExteriorCellIndex cellIndex(cellX + dx, cellY + dy, extWorldspace); + ESM::ExteriorCellLocation cellIndex(cellX + dx, cellY + dy, extWorldspace); osg::Vec2 thisCellCenter = ESM::indexToPosition(cellIndex, true); float dist = std::max( @@ -1200,7 +1198,7 @@ namespace MWWorld for (int dy = -mHalfGridSize; dy <= mHalfGridSize; ++dy) { mPreloader->preload(mWorld.getWorldModel().getExterior( - ESM::ExteriorCellIndex(x + dx, y + dy, cell.getCell()->getWorldSpace())), + ESM::ExteriorCellLocation(x + dx, y + dy, cell.getCell()->getWorldSpace())), mRendering.getReferenceTime()); if (++numpreloaded >= mPreloader->getMaxCacheSize()) break; @@ -1283,7 +1281,7 @@ namespace MWWorld else { osg::Vec3f pos = dest.mPos.asVec3(); - const ESM::ExteriorCellIndex cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), extWorldspace); + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), extWorldspace); preloadCell(mWorld.getWorldModel().getExterior(cellIndex), true); exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 3dcd33a3c0..cec284a693 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -80,7 +80,7 @@ namespace MWWorld struct ChangeCellGridRequest { osg::Vec3f mPosition; - ESM::ExteriorCellIndex mCellIndex; + ESM::ExteriorCellLocation mCellIndex; bool mChangeEvent; }; @@ -118,7 +118,7 @@ namespace MWWorld osg::Vec2i mCurrentGridCenter; // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center - void changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellIndex playerCellIndex, bool changeEvent = true); + void changeCellGrid(const osg::Vec3f& pos, ESM::ExteriorCellLocation playerCellIndex, bool changeEvent = true); void requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent = true); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 7fbbb0c695..b87cf6e445 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1105,7 +1105,7 @@ namespace MWWorld return foundCell->second; } - const ESM4::Cell* Store::searchExterior(ESM::ExteriorCellIndex cellIndex) const + const ESM4::Cell* Store::searchExterior(ESM::ExteriorCellLocation cellIndex) const { const auto foundCell = mExteriors.find(cellIndex); if (foundCell == mExteriors.end()) @@ -1133,7 +1133,7 @@ namespace MWWorld mCellNameIndex[cellPtr->mEditorId] = cellPtr; if (cellPtr->isExterior()) { - ESM::ExteriorCellIndex cellindex = { cellPtr->mX, cellPtr->mY, cellPtr->mParent }; + ESM::ExteriorCellLocation cellindex = { cellPtr->mX, cellPtr->mY, cellPtr->mParent }; if (cellPtr->mCellFlags & ESM4::Rec_Persistent) mPersistentExteriors[cellindex] = cellPtr; else diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 45706dc793..662fc2b558 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -285,12 +285,12 @@ namespace MWWorld std::unordered_map mCellNameIndex; - std::unordered_map mExteriors; - std::unordered_map mPersistentExteriors; + std::unordered_map mExteriors; + std::unordered_map mPersistentExteriors; public: const ESM4::Cell* searchCellName(std::string_view) const; - const ESM4::Cell* searchExterior(ESM::ExteriorCellIndex cellIndex) const; + const ESM4::Cell* searchExterior(ESM::ExteriorCellLocation cellIndex) const; ESM4::Cell* insert(const ESM4::Cell& item, bool overrideOnly = false); ESM4::Cell* insertStatic(const ESM4::Cell& item); void insertCell(ESM4::Cell* cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d61c1b2334..546b564d56 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -379,7 +379,7 @@ namespace MWWorld pos.rot[1] = 0; pos.rot[2] = 0; - ESM::ExteriorCellIndex exteriorCellPos = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); + ESM::ExteriorCellLocation exteriorCellPos = ESM::positionToCellIndex(pos.pos[0], pos.pos[1]); ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.mX, exteriorCellPos.mY); mWorldScene->changeToExteriorCell(cellId, pos, true); } @@ -1247,7 +1247,7 @@ namespace MWWorld CellStore* cell = ptr.getCell(); ESM::RefId worldspaceId = cell->isExterior() ? cell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - const ESM::ExteriorCellIndex index = ESM::positionToCellIndex(position.x(), position.y(), worldspaceId); + const ESM::ExteriorCellLocation index = ESM::positionToCellIndex(position.x(), position.y(), worldspaceId); CellStore* newCell = cell->isExterior() ? &mWorldModel.getExterior(index) : nullptr; bool isCellActive = getPlayerPtr().isInCell() && getPlayerPtr().getCell()->isExterior() @@ -2046,7 +2046,7 @@ namespace MWWorld throw std::runtime_error("copyObjectToCell(): cannot copy object to null cell"); if (cell->isExterior()) { - const ESM::ExteriorCellIndex index + const ESM::ExteriorCellLocation index = ESM::positionToCellIndex(pos.pos[0], pos.pos[1], cell->getCell()->getWorldSpace()); cell = &mWorldModel.getExterior(index); } @@ -2732,7 +2732,7 @@ namespace MWWorld if (xResult.ec == std::errc::result_out_of_range || yResult.ec == std::errc::result_out_of_range) throw std::runtime_error("Cell coordinates out of range."); else if (xResult.ec == std::errc{} && yResult.ec == std::errc{}) - ext = mWorldModel.getExterior(ESM::ExteriorCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId)) + ext = mWorldModel.getExterior(ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId)) .getCell(); // ignore std::errc::invalid_argument, as this means that name probably refers to a interior cell // instead of comma separated coordinates @@ -2743,7 +2743,7 @@ namespace MWWorld { int x = ext->getGridX(); int y = ext->getGridY(); - osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellIndex(x, y, ext->getWorldSpace()), true); + osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellLocation(x, y, ext->getWorldSpace()), true); pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index dacbe63587..e9b1cf1300 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -76,8 +76,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) } else { - ESM::ExteriorCellIndex extIndex(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId); - std::map::iterator result = mExteriors.find(extIndex); + ESM::ExteriorCellLocation extIndex(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId); + std::map::iterator result = mExteriors.find(extIndex); if (result == mExteriors.end()) result = mExteriors.emplace(extIndex, cellStore).first; @@ -160,9 +160,9 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach { } -MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellIndex cellIndex) +MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation cellIndex) { - std::map::iterator result; + std::map::iterator result; result = mExteriors.find(cellIndex); @@ -257,7 +257,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) if (const auto* exteriorId = id.getIf()) return getExterior( - ESM::ExteriorCellIndex(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId)); + ESM::ExteriorCellLocation(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId)); const ESM4::Cell* cell4 = mStore.get().search(id); CellStore* newCellStore = nullptr; @@ -274,7 +274,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) { std::pair coord = std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY()); - ESM::ExteriorCellIndex extIndex = { coord.first, coord.second, newCellStore->getCell()->getWorldSpace() }; + ESM::ExteriorCellLocation extIndex = { coord.first, coord.second, newCellStore->getCell()->getWorldSpace() }; mExteriors.emplace(extIndex, newCellStore); } else @@ -319,7 +319,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name) if (!cell) throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name)); - return getExterior(ESM::ExteriorCellIndex(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId)); + return getExterior(ESM::ExteriorCellLocation(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId)); } MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( @@ -329,7 +329,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( return *cellInSameWorldSpace; ESM::RefId exteriorWorldspace = cellInSameWorldSpace ? cellInSameWorldSpace->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; - const ESM::ExteriorCellIndex cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), exteriorWorldspace); + const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(pos.x(), pos.y(), exteriorWorldspace); return getExterior(cellIndex); } diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index cca916a917..b90a063c69 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -44,7 +44,7 @@ namespace MWWorld mutable std::unordered_map mCells; mutable std::map mInteriors; - mutable std::map mExteriors; + mutable std::map mExteriors; IdCache mIdCache; std::size_t mIdCacheIndex = 0; std::unordered_map mPtrIndex; @@ -65,7 +65,7 @@ namespace MWWorld void clear(); - CellStore& getExterior(ESM::ExteriorCellIndex cellIndex); + CellStore& getExterior(ESM::ExteriorCellLocation cellIndex); CellStore& getInterior(std::string_view name); CellStore& getCell(std::string_view name); // interior or named exterior CellStore& getCell(const ESM::RefId& Id); diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 514472211b..30a477641e 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -1,6 +1,6 @@ #include "util.hpp" -osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre) +osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre) { const int cellSize = ESM::getCellSize(cellIndex.mWorldspace); diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 6a5c664ecc..6edf087854 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -49,24 +49,24 @@ namespace ESM operator osg::Vec3f() const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); } }; - struct ExteriorCellIndex + struct ExteriorCellLocation { int mX, mY; ESM::RefId mWorldspace; - ExteriorCellIndex(int x, int y, ESM::RefId worldspace) + ExteriorCellLocation(int x, int y, ESM::RefId worldspace) : mX(x) , mY(y) , mWorldspace(worldspace) { } - bool operator==(const ExteriorCellIndex& other) const + bool operator==(const ExteriorCellLocation& other) const { return mX == other.mX && mY == other.mY && mWorldspace == other.mWorldspace; } - bool operator<(const ExteriorCellIndex& other) const + bool operator<(const ExteriorCellLocation& other) const { return std::make_tuple(mX, mY, mWorldspace) < std::make_tuple(other.mX, other.mY, other.mWorldspace); } @@ -83,23 +83,23 @@ namespace ESM return isEsm4Ext(worldspaceId) ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; } - inline ESM::ExteriorCellIndex positionToCellIndex( + inline ESM::ExteriorCellLocation positionToCellIndex( float x, float y, ESM::RefId worldspaceId = ESM::Cell::sDefaultWorldspaceId) { const float cellSize = getCellSize(worldspaceId); return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)), worldspaceId }; } - osg::Vec2 indexToPosition(const ESM::ExteriorCellIndex& cellIndex, bool centre = false); + osg::Vec2 indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre = false); ///< Convert cell numbers to position. } namespace std { template <> - struct hash + struct hash { - std::size_t operator()(const ESM::ExteriorCellIndex& toHash) const + std::size_t operator()(const ESM::ExteriorCellLocation& toHash) const { // Compute individual hash values for first, // second and third and combine them using XOR From 7c6471b0dc888b7e32602dc722b97ce89d52e6ab Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 12 May 2023 22:54:52 +0200 Subject: [PATCH 22/22] getExteriorCellLocation() added to MWWorld::Cell --- apps/openmw/mwworld/cell.cpp | 5 +++++ apps/openmw/mwworld/cell.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 3 +-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cell.cpp b/apps/openmw/mwworld/cell.cpp index cf94f24f88..92b6ee9fc9 100644 --- a/apps/openmw/mwworld/cell.cpp +++ b/apps/openmw/mwworld/cell.cpp @@ -77,4 +77,9 @@ namespace MWWorld else return mId; } + + ESM::ExteriorCellLocation Cell::getExteriorCellLocation() const + { + return { mGridPos.x(), mGridPos.y(), getWorldSpace() }; + } } diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index eb5a4e0de7..827b360a4b 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace ESM { @@ -48,6 +49,7 @@ namespace MWWorld float getWaterHeight() const { return mWaterHeight; } const ESM::RefId& getId() const { return mId; } ESM::RefId getWorldSpace() const; + ESM::ExteriorCellLocation getExteriorCellLocation() const; private: bool mIsExterior; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1f4a7d526a..027e66a88a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -252,8 +252,7 @@ namespace for (auto* cell : collection) { assert(cell->getCell()->isExterior()); - if (cellIndex.mX == cell->getCell()->getGridX() && cellIndex.mY == cell->getCell()->getGridY() - && cell->getCell()->getWorldSpace() == cellIndex.mWorldspace) + if (cellIndex == cell->getCell()->getExteriorCellLocation()) return true; } return false;