From 08b68fcd48762582b4f4bd5f57e1aa735f1978f1 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 22 Jan 2023 19:03:19 +0100 Subject: [PATCH] Cannot load a cell yet, but getting more necessary parts in --- apps/openmw/mwclass/classes.cpp | 2 + apps/openmw/mwclass/static.cpp | 50 +++++++++++++ apps/openmw/mwclass/static.hpp | 27 +++++++ apps/openmw/mwworld/cellstore.cpp | 97 +++++++++++++++++++++---- apps/openmw/mwworld/cellstore.hpp | 52 ++++++++++++-- apps/openmw/mwworld/livecellref.hpp | 14 +++- apps/openmw/mwworld/scene.cpp | 106 +++++++++++++++------------- apps/openmw/mwworld/store.cpp | 14 ---- apps/openmw/mwworld/store.hpp | 2 - apps/openmw/mwworld/worldimp.cpp | 22 +++++- apps/openmw/mwworld/worldmodel.cpp | 12 +++- components/esm/defs.hpp | 15 ++++ 12 files changed, 322 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index 8303a3a74d..e96350294e 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -47,5 +47,7 @@ namespace MWClass Repair::registerSelf(); Static::registerSelf(); BodyPart::registerSelf(); + + ESM4Static::registerSelf(); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index c54e1088d3..0f29fa4e22 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,6 +1,7 @@ #include "static.hpp" #include +#include #include #include "../mwphysics/physicssystem.hpp" @@ -63,4 +64,53 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + + ESM4Static::ESM4Static() + : MWWorld::RegisteredClass(ESM4::Static::sRecordId) + { + } + + void ESM4Static ::insertObjectRendering( + const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const + { + if (!model.empty()) + { + renderingInterface.getObjects().insertModel(ptr, model); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); + } + } + + void ESM4Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + insertObjectPhysics(ptr, model, rotation, physics); + } + + void ESM4Static::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); + } + + std::string ESM4Static::getModel(const MWWorld::ConstPtr& ptr) const + { + return getClassModel(ptr); + } + + std::string_view ESM4Static ::getName(const MWWorld::ConstPtr& ptr) const + { + return {}; + } + + bool ESM4Static::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + + MWWorld::Ptr ESM4Static::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const + { + const MWWorld::LiveCellRef* ref = ptr.get(); + + return MWWorld::Ptr(cell.insert(ref), &cell); + } } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index c6b2c3e6f9..f16dfdd2a6 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -31,6 +31,33 @@ namespace MWClass std::string getModel(const MWWorld::ConstPtr& ptr) const override; }; + + class ESM4Static : public MWWorld::RegisteredClass + { + friend MWWorld::RegisteredClass; + + ESM4Static(); + + MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override; + + public: + void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model, + MWRender::RenderingInterface& renderingInterface) const override; + ///< Add reference into a cell for rendering + + void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + + std::string_view getName(const MWWorld::ConstPtr& ptr) const override; + ///< \return name or ID; can return an empty string. + + bool hasToolTip(const MWWorld::ConstPtr& ptr) const override; + ///< @return true if this object has a tooltip when focused (default implementation: true) + + std::string getModel(const MWWorld::ConstPtr& ptr) const override; + }; } #endif diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ee8f90ef9f..0e69961758 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include "../mwbase/environment.hpp" @@ -503,18 +505,22 @@ namespace MWWorld return false; } - CellStore::CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) + CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) : mStore(esmStore) , mReaders(readers) - , mCell(cell) + , mCellVariant(cell) , mState(State_Unloaded) , mHasState(false) , mLastRespawn(0, 0) , mCellStoreImp(std::make_unique()) , mRechargingItemsUpToDate(false) { + + mCell = mCellVariant.getEsm3(); + std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists); - mWaterLevel = cell->mWater; + if (mCell) + mWaterLevel = mCell->mWater; } CellStore::~CellStore() = default; @@ -525,6 +531,24 @@ namespace MWWorld return mCell; } + CellVariant CellStore::getCellVariant() const + { + return mCellVariant; + } + + std::string_view CellStore::getEditorName() const + { + const ESM4::Cell* cell4 = mCellVariant.getEsm4(); + if (cell4) + { + return cell4->mEditorId; + } + else + { + return mCellVariant.getEsm3()->mName; + } + } + CellStore::State CellStore::getState() const { return mState; @@ -735,7 +759,24 @@ namespace MWWorld void CellStore::loadRefs() { - assert(mCell); + assert(mCellVariant.getEsm4() || mCellVariant.getEsm3()); + const ESM4::Cell* cell4 = mCellVariant.getEsm4(); + if (cell4) + { + + auto& refs = MWBase::Environment::get().getWorld()->getStore().get(); + auto it = refs.begin(); + + while (it != refs.end()) + { + if (it->mParent == cell4->mId) + { + loadRef(*it, false); + } + ++it; + } + return; + } if (mCell->mContextList.empty()) return; // this is a dynamically generated cell -> skipping. @@ -795,12 +836,15 @@ namespace MWWorld bool CellStore::isExterior() const { - return mCell->isExterior(); + auto cell3 = mCellVariant.getEsm3(); + return cell3 ? cell3->isExterior() : false; } bool CellStore::isQuasiExterior() const { - return (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0; + auto cell3 = mCellVariant.getEsm3(); + + return cell3 ? (mCell->mData.mFlags & ESM::Cell::QuasiEx) != 0 : false; } Ptr CellStore::searchInContainer(const ESM::RefId& id) @@ -823,6 +867,28 @@ namespace MWWorld return Ptr(); } + template + static void loadRefESM4( + const MWWorld::ESMStore& store, const ESM4::Reference& ref, MWWorld::CellRefList& storeIn, bool deleted) + { + if constexpr (ESM::isESM4Rec(T::sRecordId)) + { + // storeIn.load(ref, deleted, store); + } + } + + void CellStore::loadRef(const ESM4::Reference& ref, bool deleted) + { + const MWWorld::ESMStore& store = mStore; + + ESM::RecNameInts foundType = static_cast(store.find(ref.mBaseObj)); + + Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType](auto& x) { + recNameSwitcher( + x, foundType, [&ref, &deleted, &store](auto& storeIn) { loadRefESM4(store, ref, storeIn, deleted); }); + }); + } + void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID) { const MWWorld::ESMStore& store = mStore; @@ -999,8 +1065,8 @@ namespace MWWorld Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location."; - // Note by dropping tag the object will automatically re-appear in its original cell, though potentially - // at inapproriate coordinates. Restore original coordinates: + // Note by dropping tag the object will automatically re-appear in its original cell, though + // potentially at inapproriate coordinates. Restore original coordinates: movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition()); continue; } @@ -1016,14 +1082,17 @@ namespace MWWorld } } - bool operator==(const CellStore& left, const CellStore& right) + bool CellStore::operator==(const CellStore& right) const { - return left.getCell()->getCellId() == right.getCell()->getCellId(); - } + auto cell4Left = mCellVariant.getEsm4(); + auto cell4Right = right.mCellVariant.getEsm4(); - bool operator!=(const CellStore& left, const CellStore& right) - { - return !(left == right); + if (!cell4Left && !cell4Right) + return getCell()->getCellId() == right.getCell()->getCellId(); + else if (cell4Left && cell4Right) + return cell4Left->mId == cell4Right->mId; + else + return false; } void CellStore::setFog(std::unique_ptr&& fog) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ebe6febf72..76b2485cd4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -55,20 +55,56 @@ namespace ESM4 { class Reader; struct Cell; + struct Reference; + struct Static; } namespace MWWorld { class ESMStore; struct CellStoreImp; - typedef std::variant CellVariant; + + struct CellVariant + { + std::variant mVariant; + + CellVariant(const ESM4::Cell* cell) + : mVariant(cell) + { + } + + CellVariant(const ESM::Cell* cell) + : mVariant(cell) + { + } + + bool isEsm4() const { return getEsm4(); } + + const ESM4::Cell* getEsm4() const + { + auto cell4 = std::get_if(&mVariant); + if (cell4) + return *cell4; + return nullptr; + } + + const ESM::Cell* getEsm3() const + { + auto cell3 = std::get_if(&mVariant); + if (cell3) + return *cell3; + return nullptr; + } + }; using CellStoreTuple = std::tuple, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, - CellRefList, CellRefList, CellRefList, CellRefList>; + CellRefList, CellRefList, CellRefList, CellRefList, + + CellRefList>; /// \brief Mutable state of a cell class CellStore @@ -188,11 +224,14 @@ namespace MWWorld } /// @param readerList The readers to use for loading of the cell on-demand. - CellStore(const ESM::Cell* cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); + CellStore(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(CellStore&&); ~CellStore(); const ESM::Cell* getCell() const; + CellVariant getCellVariant() const; + + std::string_view getEditorName() const; State getState() const; @@ -339,6 +378,7 @@ namespace MWWorld // Should be phased out when we have const version of forEach inline const CellRefList& getReadOnlyDoors() const { return get(); } inline const CellRefList& getReadOnlyStatics() const { return get(); } + inline const CellRefList& getReadOnlyEsm4Statics() const { return get(); } bool isExterior() const; @@ -374,20 +414,22 @@ namespace MWWorld Ptr getMovedActor(int actorId) const; + bool operator==(const CellStore& right) const; + private: /// Run through references and store IDs void listRefs(); void loadRefs(); + void loadRef(const ESM4::Reference& ref, bool deleted); void loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. + /// }; - bool operator==(const CellStore& left, const CellStore& right); - bool operator!=(const CellStore& left, const CellStore& right); } #endif diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 128546bb65..4e3cb322cc 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -87,7 +87,8 @@ namespace MWWorld { if (const LiveCellRef* ref = dynamic_cast*>(value)) return ref; - throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType())); + throw std::runtime_error( + makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView())); } template @@ -95,7 +96,8 @@ namespace MWWorld { if (LiveCellRef* ref = dynamic_cast*>(value)) return ref; - throw std::runtime_error(makeDynamicCastErrorMessage(value, T::getRecordType())); + throw std::runtime_error( + makeDynamicCastErrorMessage(value, ESM::getRecNameString(T::sRecordId).toStringView())); } /// A reference to one object (of any type) in a cell. @@ -130,7 +132,13 @@ namespace MWWorld void save(ESM::ObjectState& state) const override; ///< Save LiveCellRef state into \a state. - std::string_view getTypeDescription() const override { return X::getRecordType(); } + std::string_view getTypeDescription() const override + { + if constexpr (ESM::isESM4Rec(X::sRecordId)) + return ESM::getRecNameString(X::sRecordId).toStringView(); + else + return X::getRecordType(); + } static bool checkState(const ESM::ObjectState& state); ///< Check if state is valid and report errors. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aab2c4fc7f..b776a76856 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -380,55 +380,62 @@ namespace MWWorld assert(mActiveCells.find(cell) == mActiveCells.end()); mActiveCells.insert(cell); - Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription(); + Log(Debug::Info) << "Loading cell " << cell->getEditorName(); - const int cellX = cell->getCell()->getGridX(); - const int cellY = cell->getCell()->getGridY(); - - if (cell->getCell()->isExterior()) + auto cell3 = cell->getCellVariant().getEsm3(); + int cellX = 0; + int cellY = 0; + if (cell3 != nullptr) { - osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); - 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; - if (data) - { - mPhysics->addHeightField( - data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); - } - else - { - static std::vector defaultHeight; - defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); - 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)) + + int cellX = cell3->getGridX(); + int cellY = cell3->getGridY(); + + if (cell3->isExterior()) { - const osg::Vec2i cellPosition(cellX, cellY); - const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); - const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); - const HeightfieldShape shape = [&]() -> HeightfieldShape { - if (data == nullptr) - { - return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; - } - else - { - DetourNavigator::HeightfieldSurface heights; - heights.mHeights = data->mHeights; - heights.mSize = static_cast(ESM::Land::LAND_SIZE); - heights.mMinHeight = data->mMinHeight; - heights.mMaxHeight = data->mMaxHeight; - return heights; - } - }(); - mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); + osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + 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; + if (data) + { + mPhysics->addHeightField( + data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get()); + } + else + { + static std::vector defaultHeight; + defaultHeight.resize(verts * verts, ESM::Land::DEFAULT_HEIGHT); + 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)) + { + const osg::Vec2i cellPosition(cellX, cellY); + const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); + const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); + const HeightfieldShape shape = [&]() -> HeightfieldShape { + if (data == nullptr) + { + return DetourNavigator::HeightfieldPlane{ static_cast(ESM::Land::DEFAULT_HEIGHT) }; + } + else + { + DetourNavigator::HeightfieldSurface heights; + heights.mHeights = data->mHeights; + heights.mSize = static_cast(ESM::Land::LAND_SIZE); + heights.mMinHeight = data->mMinHeight; + heights.mMaxHeight = data->mMaxHeight; + return heights; + } + }(); + mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); + } } - } - if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) - mNavigator.addPathgrid(*cell->getCell(), *pathgrid); + if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) + mNavigator.addPathgrid(*cell3, *pathgrid); + } // register local scripts // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice @@ -442,7 +449,7 @@ namespace MWWorld mRendering.addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell); - bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); + bool waterEnabled = cell3 && (cell3->hasWater() || cell->isExterior()); float waterLevel = cell->getWaterLevel(); mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) @@ -450,7 +457,7 @@ namespace MWWorld mPhysics->enableWater(waterLevel); mRendering.setWaterHeight(waterLevel); - if (cell->getCell()->isExterior()) + if (cell3->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) mNavigator.addWater( @@ -465,8 +472,8 @@ namespace MWWorld else mPhysics->disableWater(); - if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) - mRendering.configureAmbient(cell->getCell()); + if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx)) + mRendering.configureAmbient(cell3); mPreloader->notifyLoaded(cell); } @@ -879,8 +886,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); - mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getEditorName()), navigatorUpdateGuard.get()); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2265712509..e995a6c1ab 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1170,20 +1170,6 @@ namespace MWWorld return mKeywordSearch; } - ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName) - { - ESM::FixedString<6> name; - name.assign(""); - ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag); - for (int i = 0; i < 4; i++) - name.mData[i] = fourCCName.mData[i]; - if (ESM::isESM4Rec(recName)) - { - name.mData[4] = '4'; - } - return name; - } - // ESM4 Cell //========================================================================= diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 1b89604e0a..59b3b8a172 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -533,8 +533,6 @@ namespace MWWorld const MWDialogue::KeywordSearch& getDialogIdKeywordSearch() const; }; - ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName); - } // end namespace #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0e415739d9..cec624898d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include #include @@ -2804,6 +2806,24 @@ namespace MWWorld } } } + for (const MWWorld::LiveCellRef& stat4 : cellStore->getReadOnlyEsm4Statics().mList) + { + if (Misc::StringUtils::lowerCase(stat4.mBase->mEditorId) == "cocmarkerheading") + { + // found the COC position? + pos = stat4.mRef.getPosition(); + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + return true; + } + } + // Fall back to the first static location. + const MWWorld::CellRefList::List& statics4 = cellStore->getReadOnlyEsm4Statics().mList; + if (!statics4.empty()) + { + pos = statics4.begin()->mRef.getPosition(); + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + return true; + } // Fall back to the first static location. const MWWorld::CellRefList::List& statics = cellStore->getReadOnlyStatics().mList; if (!statics.empty()) @@ -3253,7 +3273,7 @@ namespace MWWorld std::set checkedCells; std::set currentCells; std::set nextCells; - nextCells.insert(cell->getCell()->mName); + nextCells.insert(cell->getEditorName()); while (!nextCells.empty()) { diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index 66156a2a5e..ac754eae60 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -202,9 +202,17 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) if (result == mInteriors.end()) { - const ESM::Cell* cell = mStore.get().find(name); + const ESM4::Cell* cell4 = mStore.get().searchCellName(name); - result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + if (!cell4) + { + const ESM::Cell* cell = mStore.get().find(name); + result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + } + else + { + result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first; + } } if (result->second.getState() != CellStore::State_Loaded) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 431b85b9ae..122f922837 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -9,6 +9,7 @@ #include #include "components/esm/fourcc.hpp" +#include #include namespace ESM @@ -338,6 +339,20 @@ namespace ESM return RecName & sEsm4RecnameFlag; } + inline FixedString<6> getRecNameString(ESM::RecNameInts recName) + { + ESM::FixedString<6> name; + name.assign(""); + ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag); + for (int i = 0; i < 4; i++) + name.mData[i] = fourCCName.mData[i]; + if (ESM::isESM4Rec(recName)) + { + name.mData[4] = '4'; + } + return name; + } + /// Common subrecords enum SubRecNameInts {