diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 835fb9b204..f8a3ebd962 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -20,10 +21,17 @@ namespace MWRender osg::ref_ptr LandManager::getLand(ESM::ExteriorCellLocation cellIndex) { + const MWBase::World& world = *MWBase::Environment::get().getWorld(); + if (ESM::isEsm4Ext(cellIndex.mWorldspace)) + { + const ESM4::World* worldspace = world.getStore().get().find(cellIndex.mWorldspace); + if (!worldspace->mParent.isZeroOrUnset() && worldspace->mParentUseFlags & ESM4::World::UseFlag_Land) + cellIndex.mWorldspace = worldspace->mParent; + } + if (const std::optional> obj = mCache->getRefFromObjectCacheOrNone(cellIndex)) return static_cast(obj->get()); - const MWBase::World& world = *MWBase::Environment::get().getWorld(); osg::ref_ptr landObj = nullptr; if (ESM::isEsm4Ext(cellIndex.mWorldspace)) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 11fdbd774f..a20da97f0f 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -1,6 +1,7 @@ #include "terrainstorage.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" @@ -33,6 +34,10 @@ namespace MWRender if (ESM::isEsm4Ext(cellLocation.mWorldspace)) { + const ESM4::World* worldspace = esmStore.get().find(cellLocation.mWorldspace); + if (!worldspace->mParent.isZeroOrUnset() && worldspace->mParentUseFlags & ESM4::World::UseFlag_Land) + cellLocation.mWorldspace = worldspace->mParent; + return esmStore.get().search(cellLocation) != nullptr; } else @@ -64,6 +69,10 @@ namespace MWRender if (ESM::isEsm4Ext(worldspace)) { + const ESM4::World* worldRec = esmStore.get().find(worldspace); + if (!worldRec->mParent.isZeroOrUnset() && worldRec->mParentUseFlags & ESM4::World::UseFlag_Land) + worldspace = worldRec->mParent; + const auto& lands = esmStore.get().getLands(); for (const auto& [landPos, _] : lands) { diff --git a/components/esm4/loadwrld.cpp b/components/esm4/loadwrld.cpp index c0a3044437..b29cb37eb5 100644 --- a/components/esm4/loadwrld.cpp +++ b/components/esm4/loadwrld.cpp @@ -185,6 +185,10 @@ void ESM4::World::load(ESM4::Reader& reader) mWaterLevel = 0.f; } } + + // TES4 doesn't define PNAM. Exact parent worldspace behavior needs research + if (!reader.hasFormVersion()) + mParentUseFlags = 0xFFFF; } } diff --git a/components/esm4/loadwrld.hpp b/components/esm4/loadwrld.hpp index d8b0ba2177..f951ce4e8b 100644 --- a/components/esm4/loadwrld.hpp +++ b/components/esm4/loadwrld.hpp @@ -55,6 +55,18 @@ namespace ESM4 WLD_NoGrass = 0x80 // No Grass }; + enum UseFlags + { + UseFlag_Land = 0x01, + UseFlag_LOD = 0x02, + UseFlag_Map = 0x04, + UseFlag_Water = 0x08, + UseFlag_Climate = 0x10, + UseFlag_Imagespace = 0x20, // Unused in TES5 + UseFlag_SkyCell = 0x40, + // cc9cii: 0x80 == needs water adjustment? Set for WastelandNV + }; + struct REFRcoord { ESM::FormId formId; @@ -115,15 +127,7 @@ namespace ESM4 // ---------------------- ESM::FormId mMusic; - // 0x01 use Land data - // 0x02 use LOD data - // 0x04 use Map data - // 0x08 use Water data - // 0x10 use Climate data - // 0x20 use Image Space data (Climate for TES5) - // 0x40 use SkyCell (TES5) - // 0x80 needs water adjustment (this isn't for parent I think? FONV only set for wastelandnv) - std::uint16_t mParentUseFlags; // FO3/FONV + std::uint16_t mParentUseFlags{ 0 }; // cache formId's of children (e.g. CELL, ROAD) std::vector mCells;