From 9b511fdf7a5df8871b3e82b9157d63e79eb329f2 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Tue, 25 Jul 2023 02:17:18 +0200 Subject: [PATCH] Load ESM4 actors --- apps/openmw/mwclass/classes.cpp | 2 + apps/openmw/mwclass/esm4base.hpp | 33 ++++++++ apps/openmw/mwworld/cellref.cpp | 71 ++++++++++++++---- apps/openmw/mwworld/cellref.hpp | 36 ++++++++- apps/openmw/mwworld/cellreflist.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 56 +++++++++++--- apps/openmw/mwworld/cellstore.hpp | 7 +- apps/openmw/mwworld/esmstore.cpp | 9 +++ apps/openmw/mwworld/esmstore.hpp | 11 ++- apps/openmw/mwworld/livecellref.cpp | 7 ++ apps/openmw/mwworld/livecellref.hpp | 7 ++ apps/openmw/mwworld/refdata.cpp | 15 ++++ apps/openmw/mwworld/refdata.hpp | 2 + apps/openmw/mwworld/store.cpp | 34 ++------- apps/openmw/mwworld/store.hpp | 46 ++++++++++-- apps/openmw_test_suite/esm4/includes.cpp | 1 - components/CMakeLists.txt | 1 - components/esm/esmbridge.hpp | 17 ++--- components/esm/records.hpp | 5 ++ components/esm4/loadachr.cpp | 16 ++-- components/esm4/loadachr.hpp | 26 ++++--- components/esm4/loadacre.cpp | 96 ------------------------ components/esm4/loadacre.hpp | 64 ---------------- components/esm4/loadcrea.cpp | 5 +- components/esm4/loadcrea.hpp | 6 +- components/esm4/loadlvlc.cpp | 3 +- components/esm4/loadlvlc.hpp | 6 +- components/esm4/loadlvln.cpp | 3 +- components/esm4/loadlvln.hpp | 6 +- components/esm4/loadnpc.cpp | 3 +- components/esm4/loadnpc.hpp | 6 +- components/esm4/loadrace.cpp | 3 +- components/esm4/loadrace.hpp | 6 +- components/esm4/loadrefr.cpp | 14 +--- components/esm4/loadrefr.hpp | 24 +++--- components/esm4/records.hpp | 1 - components/esm4/reference.hpp | 25 ++---- 37 files changed, 360 insertions(+), 314 deletions(-) delete mode 100644 components/esm4/loadacre.cpp delete mode 100644 components/esm4/loadacre.hpp diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index 5b53da317e..5942385264 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -68,5 +68,7 @@ namespace MWClass ESM4Tree::registerSelf(); ESM4Named::registerSelf(); ESM4Light::registerSelf(); + ESM4Actor::registerSelf(); + ESM4Actor::registerSelf(); } } diff --git a/apps/openmw/mwclass/esm4base.hpp b/apps/openmw/mwclass/esm4base.hpp index abd4989a68..3d2184e5fe 100644 --- a/apps/openmw/mwclass/esm4base.hpp +++ b/apps/openmw/mwclass/esm4base.hpp @@ -124,6 +124,39 @@ namespace MWClass return ptr.get()->mBase->mFullName; } }; + + template + class ESM4Actor : public MWWorld::RegisteredClass, ESM4Base> + { + public: + friend MWWorld::RegisteredClass>; + + ESM4Actor() + : MWWorld::RegisteredClass>(Record::sRecordId) + { + } + + void insertObjectPhysics( + const MWWorld::Ptr&, const std::string&, const osg::Quat&, MWPhysics::PhysicsSystem&) const override + { + } + + bool hasToolTip(const MWWorld::ConstPtr& ptr) const override { return true; } + + MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override + { + return ESM4Impl::getToolTipInfo(ptr.get()->mBase->mEditorId, count); + } + + std::string getModel(const MWWorld::ConstPtr& ptr) const override + { + // TODO: Not clear where to get something renderable: + // ESM4::Npc::mModel is usually an empty string + // ESM4::Race::mModelMale is only a skeleton + // For now show error marker as a dummy model. + return "meshes/marker_error.nif"; + } + }; } #endif // GAME_MWCLASS_ESM4BASE_H diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index bb204e0515..37e1be0ddf 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -25,10 +25,16 @@ namespace MWWorld { } + CellRef::CellRef(const ESM4::ActorCharacter& ref) + : mCellRef(ESM::ReferenceVariant(ref)) + { + } + const ESM::RefNum& CellRef::getRefNum() const { return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mId; }, + [&](const ESM4::ActorCharacter& ref) -> const ESM::RefNum& { return ref.mId; }, [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; }, }, mCellRef.mVariant); @@ -38,6 +44,7 @@ namespace MWWorld { ESM::RefNum& refNum = std::visit(ESM::VisitOverload{ [&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mId; }, + [&](ESM4::ActorCharacter& ref) -> ESM::RefNum& { return ref.mId; }, [&](ESM::CellRef& ref) -> ESM::RefNum& { return ref.mRefNum; }, }, mCellRef.mVariant); @@ -63,6 +70,7 @@ namespace MWWorld { std::visit(ESM::VisitOverload{ [&](ESM4::Reference& ref) { ref.mId = refNum; }, + [&](ESM4::ActorCharacter& ref) { ref.mId = refNum; }, [&](ESM::CellRef& ref) { ref.mRefNum = refNum; }, }, mCellRef.mVariant); @@ -73,10 +81,12 @@ namespace MWWorld ESM::Position CellRef::getDoorDest() const { - return std::visit(ESM::VisitOverload{ - [&](const ESM4::Reference& ref) { return ref.mDoor.destPos; }, - [&](const ESM::CellRef& ref) -> ESM::Position { return ref.mDoorDest; }, - }, + return std::visit( + ESM::VisitOverload{ + [&](const ESM4::Reference& ref) { return ref.mDoor.destPos; }, + [&](const ESM::CellRef& ref) -> ESM::Position { return ref.mDoorDest; }, + [&](const ESM4::ActorCharacter&) -> ESM::Position { throw std::logic_error("Not applicable"); }, + }, mCellRef.mVariant); } @@ -102,8 +112,10 @@ namespace MWWorld return refDest->mParent; return ESM::RefId(); }; + auto actorDestCell + = [&](const ESM4::ActorCharacter&) -> ESM::RefId { throw std::logic_error("Not applicable"); }; - return std::visit(ESM::VisitOverload{ esm3Visit, esm4Visit }, mCellRef.mVariant); + return std::visit(ESM::VisitOverload{ esm3Visit, esm4Visit, actorDestCell }, mCellRef.mVariant); } void CellRef::setScale(float scale) @@ -126,6 +138,7 @@ namespace MWWorld return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) { return 0.f; }, [&](const ESM::CellRef& ref) { return ref.mEnchantmentCharge; }, + [&](const ESM4::ActorCharacter&) -> float { throw std::logic_error("Not applicable"); }, }, mCellRef.mVariant); } @@ -155,6 +168,7 @@ namespace MWWorld std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mEnchantmentCharge = charge; }, }, mCellRef.mVariant); @@ -165,6 +179,7 @@ namespace MWWorld { std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mChargeInt = charge; }, }, mCellRef.mVariant); @@ -188,11 +203,11 @@ namespace MWWorld cellRef3.mChargeIntRemainder = newChargeRemainder; } }; - std::visit( - ESM::VisitOverload{ - [&](ESM4::Reference& /*ref*/) {}, - esm3Visit, - }, + std::visit(ESM::VisitOverload{ + [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, + esm3Visit, + }, mCellRef.mVariant); } @@ -200,6 +215,7 @@ namespace MWWorld { std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mChargeFloat = charge; }, }, mCellRef.mVariant); @@ -209,6 +225,7 @@ namespace MWWorld { return std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; }, + [&](const ESM4::ActorCharacter& /*ref*/) -> const std::string& { return emptyString; }, [&](const ESM::CellRef& ref) -> const std::string& { return ref.mGlobalVariable; }, }, mCellRef.mVariant); @@ -221,6 +238,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter& /*ref*/) {}, [&](ESM::CellRef& ref) { ref.mGlobalVariable.erase(); }, }, mCellRef.mVariant); @@ -232,7 +250,9 @@ namespace MWWorld if (factionRank != getFactionRank()) { mChanged = true; - std::visit([&](auto&& ref) { ref.mFactionRank = factionRank; }, mCellRef.mVariant); + std::visit(ESM::VisitOverload{ + [&](ESM4::ActorCharacter&) {}, [&](auto&& ref) { ref.mFactionRank = factionRank; } }, + mCellRef.mVariant); } } @@ -242,6 +262,7 @@ namespace MWWorld { std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mOwner = owner; }, }, mCellRef.mVariant); @@ -255,6 +276,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mSoul = soul; }, }, mCellRef.mVariant); @@ -268,6 +290,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mFaction = faction; }, }, mCellRef.mVariant); @@ -279,7 +302,12 @@ namespace MWWorld if (lockLevel != getLockLevel()) { mChanged = true; - std::visit([&](auto&& ref) { ref.mLockLevel = lockLevel; }, mCellRef.mVariant); + std::visit(ESM::VisitOverload{ + [&](ESM4::Reference& ref) { ref.mLockLevel = lockLevel; }, + [&](ESM4::ActorCharacter&) {}, + [&](ESM::CellRef& ref) { ref.mLockLevel = lockLevel; }, + }, + mCellRef.mVariant); } } @@ -297,12 +325,23 @@ namespace MWWorld bool CellRef::isLocked() const { - return std::visit([](auto&& ref) { return ref.mIsLocked; }, mCellRef.mVariant); + struct Visitor + { + bool operator()(const ESM::CellRef& ref) { return ref.mIsLocked; } + bool operator()(const ESM4::Reference& ref) { return ref.mIsLocked; } + bool operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } + }; + return std::visit(Visitor(), mCellRef.mVariant); } void CellRef::setLocked(bool locked) { - std::visit([=](auto&& ref) { ref.mIsLocked = locked; }, mCellRef.mVariant); + std::visit(ESM::VisitOverload{ + [&](ESM4::Reference& ref) { ref.mIsLocked = locked; }, + [&](ESM4::ActorCharacter&) {}, + [&](ESM::CellRef& ref) { ref.mIsLocked = locked; }, + }, + mCellRef.mVariant); } void CellRef::setTrap(const ESM::RefId& trap) @@ -312,6 +351,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mTrap = trap; }, }, mCellRef.mVariant); @@ -325,6 +365,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mKey = key; }, }, mCellRef.mVariant); @@ -338,6 +379,7 @@ namespace MWWorld mChanged = true; std::visit(ESM::VisitOverload{ [&](ESM4::Reference& /*ref*/) {}, + [&](ESM4::ActorCharacter&) {}, [&](ESM::CellRef& ref) { ref.mGoldValue = value; }, }, mCellRef.mVariant); @@ -348,6 +390,7 @@ namespace MWWorld { std::visit(ESM::VisitOverload{ [&](const ESM4::Reference& /*ref*/) {}, + [&](const ESM4::ActorCharacter&) {}, [&](const ESM::CellRef& ref) { state.mRef = ref; }, }, mCellRef.mVariant); diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index b470644bf7..98648f9467 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -24,6 +24,7 @@ namespace MWWorld explicit CellRef(const ESM::CellRef& ref); explicit CellRef(const ESM4::Reference& ref); + explicit CellRef(const ESM4::ActorCharacter& ref); // Note: Currently unused for items in containers const ESM::RefNum& getRefNum() const; @@ -47,6 +48,7 @@ namespace MWWorld { ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mRefID; } ESM::RefId operator()(const ESM4::Reference& ref) { return ref.mBaseObj; } + ESM::RefId operator()(const ESM4::ActorCharacter& ref) { return ref.mBaseObj; } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -59,6 +61,7 @@ namespace MWWorld { bool operator()(const ESM::CellRef& ref) { return ref.mTeleport; } bool operator()(const ESM4::Reference& ref) { return !ref.mDoor.destDoor.isZeroOrUnset(); } + bool operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -101,6 +104,7 @@ namespace MWWorld { int operator()(const ESM::CellRef& ref) { return ref.mChargeInt; } int operator()(const ESM4::Reference& /*ref*/) { return 0; } + int operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -110,6 +114,7 @@ namespace MWWorld { float operator()(const ESM::CellRef& ref) { return ref.mChargeFloat; } float operator()(const ESM4::Reference& /*ref*/) { return 0; } + float operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } // Implemented as union with int charge @@ -123,7 +128,8 @@ namespace MWWorld struct Visitor { ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mOwner; } - ESM::RefId operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId(); } + ESM::RefId operator()(const ESM4::Reference& ref) { return ESM::RefId::formIdRefId(ref.mOwner); } + ESM::RefId operator()(const ESM4::ActorCharacter& ref) { return ESM::RefId::formIdRefId(ref.mOwner); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -143,6 +149,7 @@ namespace MWWorld { ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mSoul; } ESM::RefId operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId(); } + ESM::RefId operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -156,6 +163,7 @@ namespace MWWorld { ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mFaction; } ESM::RefId operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId(); } + ESM::RefId operator()(const ESM4::ActorCharacter& /*ref*/) { return ESM::RefId(); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -165,7 +173,13 @@ namespace MWWorld void setFactionRank(int factionRank); int getFactionRank() const { - return std::visit([&](auto&& ref) { return ref.mFactionRank; }, mCellRef.mVariant); + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mFactionRank; } + int operator()(const ESM4::Reference& ref) { return ref.mFactionRank; } + int operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } + }; + return std::visit(Visitor(), mCellRef.mVariant); } // Lock level for doors and containers @@ -173,7 +187,13 @@ namespace MWWorld // For an unlocked door, it is set to -(previous locklevel) int getLockLevel() const { - return std::visit([](auto&& ref) { return static_cast(ref.mLockLevel); }, mCellRef.mVariant); + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mLockLevel; } + int operator()(const ESM4::Reference& ref) { return ref.mLockLevel; } + int operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } + }; + return std::visit(Visitor(), mCellRef.mVariant); } void setLockLevel(int lockLevel); void lock(int lockLevel); @@ -183,7 +203,13 @@ namespace MWWorld // Key and trap ID names, if any ESM::RefId getKey() const { - return std::visit([](auto&& ref) -> const ESM::RefId& { return ref.mKey; }, mCellRef.mVariant); + struct Visitor + { + ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mKey; } + ESM::RefId operator()(const ESM4::Reference& ref) { return ref.mKey; } + ESM::RefId operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } + }; + return std::visit(Visitor(), mCellRef.mVariant); } void setKey(const ESM::RefId& key); ESM::RefId getTrap() const @@ -192,6 +218,7 @@ namespace MWWorld { ESM::RefId operator()(const ESM::CellRef& ref) { return ref.mTrap; } ESM::RefId operator()(const ESM4::Reference& /*ref*/) { return ESM::RefId(); } + ESM::RefId operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } @@ -204,6 +231,7 @@ namespace MWWorld { int operator()(const ESM::CellRef& ref) { return ref.mGoldValue; } int operator()(const ESM4::Reference& /*ref*/) { return 0; } + int operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); } }; return std::visit(Visitor(), mCellRef.mVariant); } diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index e996ba163c..12f086e15d 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -29,6 +29,7 @@ namespace MWWorld void load(ESM::CellRef& ref, bool deleted, const MWWorld::ESMStore& esmStore); void load(const ESM4::Reference& ref, const MWWorld::ESMStore& esmStore); + void load(const ESM4::ActorCharacter& ref, const MWWorld::ESMStore& esmStore); LiveRef& insert(const LiveRef& item) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a360ab6314..e094edb903 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -384,24 +385,32 @@ namespace MWWorld } } - template - void CellRefList::load(const ESM4::Reference& ref, const MWWorld::ESMStore& esmStore) + static constexpr bool isESM4ActorRec(unsigned int rec) { + return rec == ESM::REC_NPC_4 || rec == ESM::REC_CREA4 || rec == ESM::REC_LVLN4 || rec == ESM::REC_LVLC4; + } - if constexpr (!ESM::isESM4Rec(X::sRecordId)) - return; - + template + static void loadImpl(const R& ref, const MWWorld::ESMStore& esmStore, auto& list) + { const MWWorld::Store& store = esmStore.get(); - if (const X* ptr = store.search(ref.mBaseObj)) - { - LiveRef liveCellRef(ref, ptr); - mList.push_back(liveCellRef); - } + list.emplace_back(ref, ptr); else - { Log(Debug::Warning) << "Warning: could not resolve cell reference " << ref.mId << " (dropping reference)"; - } + } + + template + void CellRefList::load(const ESM4::Reference& ref, const MWWorld::ESMStore& esmStore) + { + if constexpr (ESM::isESM4Rec(X::sRecordId) && !isESM4ActorRec(X::sRecordId)) + loadImpl(ref, esmStore, mList); + } + template + void CellRefList::load(const ESM4::ActorCharacter& ref, const MWWorld::ESMStore& esmStore) + { + if constexpr (isESM4ActorRec(X::sRecordId)) + loadImpl(ref, esmStore, mList); } template @@ -769,9 +778,21 @@ namespace MWWorld invocable(*ref); } + template + static void visitCell4ActorReferences( + const ESM4::Cell& cell, const ESMStore& esmStore, ESM::ReadersCache& readers, ReferenceInvocable&& invocable) + { + for (const ESM4::ActorCharacter* ref : esmStore.get().getByCell(cell.mId)) + invocable(*ref); + for (const ESM4::ActorCharacter* ref : esmStore.get().getByCell(cell.mId)) + invocable(*ref); + } + void CellStore::listRefs(const ESM4::Cell& cell) { visitCell4References(cell, mStore, mReaders, [&](const ESM4::Reference& ref) { mIds.push_back(ref.mBaseObj); }); + visitCell4ActorReferences( + cell, mStore, mReaders, [&](const ESM4::ActorCharacter& ref) { mIds.push_back(ref.mBaseObj); }); } void CellStore::listRefs() @@ -836,6 +857,7 @@ namespace MWWorld void CellStore::loadRefs(const ESM4::Cell& cell, std::map& refNumToID) { visitCell4References(cell, mStore, mReaders, [&](const ESM4::Reference& ref) { loadRef(ref); }); + visitCell4ActorReferences(cell, mStore, mReaders, [&](const ESM4::ActorCharacter& ref) { loadRef(ref); }); } void CellStore::loadRefs() @@ -888,6 +910,16 @@ namespace MWWorld }); } + void CellStore::loadRef(const ESM4::ActorCharacter& ref) + { + const MWWorld::ESMStore& store = mStore; + ESM::RecNameInts foundType = static_cast(store.find(ref.mBaseObj)); + + Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &store, foundType](auto& x) { + recNameSwitcher(x, foundType, [&ref, &store](auto& storeIn) { storeIn.load(ref, store); }); + }); + } + void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID) { const MWWorld::ESMStore& store = mStore; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 3ffa55a0a9..dda15049d1 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -58,6 +58,7 @@ namespace ESM4 class Reader; struct Cell; struct Reference; + struct ActorCharacter; struct Static; struct Light; struct Activator; @@ -73,6 +74,8 @@ namespace ESM4 struct MiscItem; struct Tree; struct Weapon; + struct Creature; + struct Npc; } namespace MWWorld @@ -90,7 +93,8 @@ namespace MWWorld 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 @@ -420,6 +424,7 @@ namespace MWWorld void loadRefs(); void loadRef(const ESM4::Reference& ref); + void loadRef(const ESM4::ActorCharacter& ref); void loadRef(ESM::CellRef& ref, bool deleted, std::map& refNumToID); ///< Make case-adjustments to \a ref and insert it into the respective container. /// diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 00a229e047..b808bb7a4e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -278,6 +278,8 @@ namespace MWWorld case ESM::REC_STAT: case ESM::REC_WEAP: case ESM::REC_BODY: + case ESM::REC_ACHR4: + case ESM::REC_ACRE4: case ESM::REC_STAT4: case ESM::REC_LIGH4: case ESM::REC_ACTI4: @@ -286,10 +288,15 @@ namespace MWWorld case ESM::REC_ARMO4: case ESM::REC_BOOK4: case ESM::REC_CONT4: + case ESM::REC_CREA4: case ESM::REC_DOOR4: case ESM::REC_FURN4: case ESM::REC_INGR4: + case ESM::REC_LVLC4: + case ESM::REC_LVLN4: case ESM::REC_MISC4: + case ESM::REC_NPC_4: + case ESM::REC_RACE4: case ESM::REC_TREE4: case ESM::REC_WEAP4: return true; @@ -439,6 +446,8 @@ namespace MWWorld getWritable().setUp(get()); getWritable().updateLandPositions(get()); getWritable().preprocessReferences(get()); + getWritable().preprocessReferences(get()); + getWritable().preprocessReferences(get()); rebuildIdsIndex(); mStoreImp->mStaticIds = mStoreImp->mIds; diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 7d0447c494..8cadf62d88 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -31,6 +31,8 @@ namespace ESM4 struct Cell; struct Light; struct Reference; + struct ActorCharacter; + struct ActorCreature; struct Activator; struct Potion; struct Ammunition; @@ -38,10 +40,15 @@ namespace ESM4 struct Book; struct Clothing; struct Container; + struct Creature; struct Door; struct Furniture; struct Ingredient; + struct LevelledCreature; + struct LevelledNpc; struct MiscItem; + struct Npc; + struct Race; struct Tree; struct Weapon; struct World; @@ -124,7 +131,9 @@ namespace MWWorld Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, - 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/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 1b14664ba2..93470a593a 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -28,6 +28,13 @@ MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Referen { } +MWWorld::LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::ActorCharacter& cref) + : mClass(&Class::get(type)) + , mRef(cref) + , mData(cref) +{ +} + void MWWorld::LiveCellRefBase::loadImp(const ESM::ObjectState& state) { mRef = MWWorld::CellRef(state.mRef); diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 8a3121e9c4..f80690fbe8 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -36,6 +36,7 @@ namespace MWWorld LiveCellRefBase(unsigned int type, const ESM::CellRef& cref = ESM::CellRef()); LiveCellRefBase(unsigned int type, const ESM4::Reference& cref); + LiveCellRefBase(unsigned int type, const ESM4::ActorCharacter& cref); /* Need this for the class to be recognized as polymorphic */ virtual ~LiveCellRefBase() {} @@ -122,6 +123,12 @@ namespace MWWorld { } + LiveCellRef(const ESM4::ActorCharacter& cref, const X* b = nullptr) + : LiveCellRefBase(X::sRecordId, cref) + , mBase(b) + { + } + LiveCellRef(const X* b = nullptr) : LiveCellRefBase(X::sRecordId) , mBase(b) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index dc7c336809..87c085ebd4 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,6 +1,8 @@ #include "refdata.hpp" #include +#include +#include #include #include "customdata.hpp" @@ -98,6 +100,19 @@ namespace MWWorld { } + RefData::RefData(const ESM4::ActorCharacter& ref) + : mBaseNode(nullptr) + , mDeletedByContentFile(ref.mFlags & ESM4::Rec_Deleted) + , mEnabled(!(ref.mFlags & ESM4::Rec_Disabled)) + , mPhysicsPostponed(false) + , mCount(mDeletedByContentFile ? 0 : 1) + , mPosition(ref.mPos) + , mCustomData(nullptr) + , mChanged(false) + , mFlags(0) + { + } + RefData::RefData(const ESM::ObjectState& objectState, bool deletedByContentFile) : mBaseNode(nullptr) , mDeletedByContentFile(deletedByContentFile) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index e067cc1456..a6a45623f5 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -27,6 +27,7 @@ namespace ESM namespace ESM4 { + struct ActorCharacter; struct Reference; } @@ -82,6 +83,7 @@ namespace MWWorld /// to reset the position as the original data is still held in the CellRef RefData(const ESM::CellRef& cellRef); RefData(const ESM4::Reference& cellRef); + RefData(const ESM4::ActorCharacter& cellRef); RefData(const ESM::ObjectState& objectState, bool deletedByContentFile); ///< Ignores local variables and custom data (not enough context available here to diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index a2114648a0..ed105b56d9 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1326,33 +1326,6 @@ namespace MWWorld return nullptr; return foundLand->second; } - - // ESM4 Reference - //========================================================================= - - void Store::preprocessReferences(const Store& cells) - { - for (auto& [_, ref] : mStatic) - { - const ESM4::Cell* cell = cells.find(ref.mParent); - if (cell->isExterior() && (cell->mFlags & ESM4::Rec_Persistent)) - { - const ESM4::Cell* actualCell = cells.searchExterior( - positionToExteriorCellLocation(ref.mPos.pos[0], ref.mPos.pos[1], cell->mParent)); - if (actualCell) - ref.mParent = actualCell->mId; - } - mPerCellReferences[ref.mParent].push_back(&ref); - } - } - - std::span Store::getByCell(ESM::RefId cellId) const - { - auto it = mPerCellReferences.find(cellId); - if (it == mPerCellReferences.end()) - return {}; - return it->second; - } } template class MWWorld::TypedDynamicStore; @@ -1405,14 +1378,21 @@ template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; +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 47463dd91f..b8fbda4118 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -581,16 +582,51 @@ namespace MWWorld const MWDialogue::KeywordSearch& getDialogIdKeywordSearch() const; }; - template <> - class Store : public TypedDynamicStore + template + class ESM4RefsStore : public TypedDynamicStore { public: - void preprocessReferences(const Store& cells); + void preprocessReferences(const Store& cells) + { + for (auto& [_, ref] : this->mStatic) + { + const ESM4::Cell* cell = cells.find(ref.mParent); + if (cell->isExterior() && (cell->mFlags & ESM4::Rec_Persistent)) + { + const ESM4::Cell* actualCell = cells.searchExterior( + positionToExteriorCellLocation(ref.mPos.pos[0], ref.mPos.pos[1], cell->mParent)); + if (actualCell) + ref.mParent = actualCell->mId; + } + mPerCellReferences[ref.mParent].push_back(&ref); + } + } - std::span getByCell(ESM::RefId cellId) const; + std::span getByCell(ESM::RefId cellId) const + { + auto it = mPerCellReferences.find(cellId); + if (it == mPerCellReferences.end()) + return {}; + return it->second; + } private: - std::unordered_map> mPerCellReferences; + std::unordered_map> mPerCellReferences; + }; + + template <> + class Store : public ESM4RefsStore + { + }; + + template <> + class Store : public ESM4RefsStore + { + }; + + template <> + class Store : public ESM4RefsStore + { }; } // end namespace diff --git a/apps/openmw_test_suite/esm4/includes.cpp b/apps/openmw_test_suite/esm4/includes.cpp index 3c6be55230..049d6605d2 100644 --- a/apps/openmw_test_suite/esm4/includes.cpp +++ b/apps/openmw_test_suite/esm4/includes.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cb3b74dc8b..cd15f8cdfe 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -161,7 +161,6 @@ add_component_dir (esm4 inventory lighting loadachr - loadacre loadacti loadalch loadaloc diff --git a/components/esm/esmbridge.hpp b/components/esm/esmbridge.hpp index 26283bb44f..3e8591d44d 100644 --- a/components/esm/esmbridge.hpp +++ b/components/esm/esmbridge.hpp @@ -1,10 +1,12 @@ #ifndef COMPONENTS_ESM_ESMBRIDGE #define COMPONENTS_ESM_ESMBRIDGE + #include #include #include #include +#include #include namespace ESM4 @@ -52,25 +54,22 @@ namespace ESM struct ReferenceVariant { - std::variant mVariant; + std::variant mVariant; explicit ReferenceVariant(const ESM4::Reference& ref) : mVariant(ref) { } - explicit ReferenceVariant(const ESM::CellRef& ref) + explicit ReferenceVariant(const ESM4::ActorCharacter& ref) : mVariant(ref) { } - bool isESM4() const { return std::holds_alternative(mVariant); } - - const ESM::CellRef& getEsm3() const { return std::get(mVariant); } - const ESM4::Reference& getEsm4() const { return std::get(mVariant); } - - ESM::CellRef& getEsm3() { return std::get(mVariant); } - ESM4::Reference& getEsm4() { return std::get(mVariant); } + explicit ReferenceVariant(const ESM::CellRef& ref) + : mVariant(ref) + { + } }; template diff --git a/components/esm/records.hpp b/components/esm/records.hpp index fe5e6176f8..25922a79d1 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -51,11 +51,16 @@ #include #include #include +#include #include #include #include #include +#include +#include #include +#include +#include #include #include #include diff --git a/components/esm4/loadachr.cpp b/components/esm4/loadachr.cpp index 7559a699da..9560fc970d 100644 --- a/components/esm4/loadachr.cpp +++ b/components/esm4/loadachr.cpp @@ -33,10 +33,10 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.hdr().record.getFormId(); + reader.adjustFormId(mId); mFlags = reader.hdr().record.flags; - mParent = reader.currCell(); // NOTE: only for persistent achr? (aren't they all persistent?) + mParent = ESM::RefId::formIdRefId(reader.currCell()); while (reader.getSubRecordHeader()) { @@ -50,10 +50,14 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader) reader.getZString(mFullName); break; case ESM4::SUB_NAME: - reader.getFormId(mBaseObj); + { + FormId baseId; + reader.getFormId(baseId); + mBaseObj = ESM::RefId::formIdRefId(baseId); break; + } case ESM4::SUB_DATA: - reader.get(mPlacement); + reader.get(mPos); break; case ESM4::SUB_XSCL: reader.get(mScale); @@ -97,7 +101,7 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader) reader.skipSubRecordData(); break; default: - throw std::runtime_error("ESM4::ACHR::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); + throw std::runtime_error("ESM4 ACHR/ACRE load - Unknown subrecord " + ESM::printName(subHdr.typeId)); } } } diff --git a/components/esm4/loadachr.hpp b/components/esm4/loadachr.hpp index a5c0a11518..2d07c5a059 100644 --- a/components/esm4/loadachr.hpp +++ b/components/esm4/loadachr.hpp @@ -29,6 +29,9 @@ #include +#include +#include + #include "reference.hpp" // FormId, Placement, EnableParent namespace ESM4 @@ -38,22 +41,19 @@ namespace ESM4 struct ActorCharacter { - FormId mParent; // cell formId, from the loading sequence - // NOTE: for exterior cells it will be the dummy cell FormId - - FormId mFormId; // from the header + ESM::FormId mId; // from the header + ESM::RefId mParent; // cell FormId , from the loading sequence + // NOTE: for exterior cells it will be the dummy cell FormId std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; std::string mFullName; - FormId mBaseObj; + ESM::RefId mBaseObj; - Placement mPlacement; + ESM::Position mPos; float mScale = 1.0f; - FormId mOwner; - FormId mGlobal; - - bool mInitiallyDisabled; // TODO may need to check mFlags & 0x800 (initially disabled) + ESM::FormId mOwner; + ESM::FormId mGlobal; EnableParent mEsp; @@ -61,6 +61,12 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::REC_ACHR4; + }; + + struct ActorCreature : public ActorCharacter + { + static constexpr ESM::RecNameInts sRecordId = ESM::REC_ACRE4; }; } diff --git a/components/esm4/loadacre.cpp b/components/esm4/loadacre.cpp deleted file mode 100644 index 9760d1c9aa..0000000000 --- a/components/esm4/loadacre.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (C) 2016, 2018, 2020 cc9cii - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - cc9cii cc9c@iinet.net.au - - Much of the information on the data structures are based on the information - from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by - trial & error. See http://en.uesp.net/wiki for details. - -*/ -#include "loadacre.hpp" - -#include - -#include "reader.hpp" -//#include "writer.hpp" - -void ESM4::ActorCreature::load(ESM4::Reader& reader) -{ - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); - mFlags = reader.hdr().record.flags; - - while (reader.getSubRecordHeader()) - { - const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); - switch (subHdr.typeId) - { - case ESM4::SUB_EDID: - reader.getZString(mEditorId); - break; - case ESM4::SUB_NAME: - reader.getFormId(mBaseObj); - break; - case ESM4::SUB_DATA: - reader.get(mPlacement); - break; - case ESM4::SUB_XSCL: - reader.get(mScale); - break; - case ESM4::SUB_XESP: - reader.getFormId(mEsp.parent); - reader.get(mEsp.flags); - break; - case ESM4::SUB_XOWN: - reader.getFormId(mOwner); - break; - case ESM4::SUB_XGLB: - reader.getFormId(mGlobal); - break; - case ESM4::SUB_XRNK: - reader.get(mFactionRank); - break; - case ESM4::SUB_XLKR: // FO3 - case ESM4::SUB_XLCM: // FO3 - case ESM4::SUB_XEZN: // FO3 - case ESM4::SUB_XMRC: // FO3 - case ESM4::SUB_XAPD: // FO3 - case ESM4::SUB_XAPR: // FO3 - case ESM4::SUB_XRDS: // FO3 - case ESM4::SUB_XPRD: // FO3 - case ESM4::SUB_XATO: // FONV - // seems to occur only for dead bodies, e.g. DeadMuffy, DeadDogVicious - case ESM4::SUB_XRGD: // ragdoll - case ESM4::SUB_XRGB: // ragdoll biped - reader.skipSubRecordData(); - break; - default: - throw std::runtime_error("ESM4::ACRE::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); - } - } -} - -// void ESM4::ActorCreature::save(ESM4::Writer& writer) const -//{ -// } - -// void ESM4::ActorCreature::blank() -//{ -// } diff --git a/components/esm4/loadacre.hpp b/components/esm4/loadacre.hpp deleted file mode 100644 index 8272d608d0..0000000000 --- a/components/esm4/loadacre.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2016, 2018, 2020 cc9cii - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - cc9cii cc9c@iinet.net.au - - Much of the information on the data structures are based on the information - from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by - trial & error. See http://en.uesp.net/wiki for details. - -*/ -#ifndef ESM4_ACRE_H -#define ESM4_ACRE_H - -#include - -#include "reference.hpp" // FormId, Placement, EnableParent - -namespace ESM4 -{ - class Reader; - class Writer; - - struct ActorCreature - { - FormId mFormId; // from the header - std::uint32_t mFlags; // from the header, see enum type RecordFlag for details - - std::string mEditorId; - FormId mBaseObj; - - Placement mPlacement; - float mScale = 1.0f; - FormId mOwner; - FormId mGlobal; - std::uint32_t mFactionRank; - - bool mInitiallyDisabled; // TODO may need to check mFlags & 0x800 (initially disabled) - - EnableParent mEsp; - - void load(ESM4::Reader& reader); - // void save(ESM4::Writer& writer) const; - - // void blank(); - }; -} - -#endif // ESM4_ACRE_H diff --git a/components/esm4/loadcrea.cpp b/components/esm4/loadcrea.cpp index de1b362575..8ba6d8a8f4 100644 --- a/components/esm4/loadcrea.cpp +++ b/components/esm4/loadcrea.cpp @@ -37,8 +37,7 @@ void ESM4::Creature::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.getRefIdFromHeader(); mFlags = reader.hdr().record.flags; while (reader.getSubRecordHeader()) @@ -153,7 +152,7 @@ void ESM4::Creature::load(ESM4::Reader& reader) std::uint32_t nift; reader.get(nift); if (nift) - Log(Debug::Verbose) << "CREA NIFT " << mFormId << ", non-zero " << nift; + Log(Debug::Verbose) << "CREA NIFT " << mId << ", non-zero " << nift; break; } case ESM4::SUB_KFFZ: diff --git a/components/esm4/loadcrea.hpp b/components/esm4/loadcrea.hpp index d237733672..1830866773 100644 --- a/components/esm4/loadcrea.hpp +++ b/components/esm4/loadcrea.hpp @@ -31,6 +31,9 @@ #include #include +#include +#include + #include "actor.hpp" #include "inventory.hpp" @@ -103,7 +106,7 @@ namespace ESM4 }; #pragma pack(pop) - 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; @@ -142,6 +145,7 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_CREA4; }; } diff --git a/components/esm4/loadlvlc.cpp b/components/esm4/loadlvlc.cpp index bc97b15df8..b3c66e9345 100644 --- a/components/esm4/loadlvlc.cpp +++ b/components/esm4/loadlvlc.cpp @@ -33,8 +33,7 @@ void ESM4::LevelledCreature::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.getRefIdFromHeader(); mFlags = reader.hdr().record.flags; while (reader.getSubRecordHeader()) diff --git a/components/esm4/loadlvlc.hpp b/components/esm4/loadlvlc.hpp index 934e3da527..901cced32f 100644 --- a/components/esm4/loadlvlc.hpp +++ b/components/esm4/loadlvlc.hpp @@ -30,6 +30,9 @@ #include #include +#include +#include + #include "formid.hpp" #include "inventory.hpp" @@ -40,7 +43,7 @@ namespace ESM4 struct LevelledCreature { - 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; @@ -62,6 +65,7 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_LVLC4; }; } diff --git a/components/esm4/loadlvln.cpp b/components/esm4/loadlvln.cpp index 043dbcb34e..33833fade5 100644 --- a/components/esm4/loadlvln.cpp +++ b/components/esm4/loadlvln.cpp @@ -33,8 +33,7 @@ void ESM4::LevelledNpc::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.getRefIdFromHeader(); mFlags = reader.hdr().record.flags; // std::uint32_t esmVer = reader.esmVersion(); // currently unused diff --git a/components/esm4/loadlvln.hpp b/components/esm4/loadlvln.hpp index e981b2352f..ac3942f494 100644 --- a/components/esm4/loadlvln.hpp +++ b/components/esm4/loadlvln.hpp @@ -31,6 +31,9 @@ #include #include +#include +#include + #include "formid.hpp" #include "inventory.hpp" // LVLO @@ -41,7 +44,7 @@ namespace ESM4 struct LevelledNpc { - 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; @@ -61,6 +64,7 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_LVLN4; }; } diff --git a/components/esm4/loadnpc.cpp b/components/esm4/loadnpc.cpp index b7f14785f8..42b3ef3cd8 100644 --- a/components/esm4/loadnpc.cpp +++ b/components/esm4/loadnpc.cpp @@ -36,8 +36,7 @@ void ESM4::Npc::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.getRefIdFromHeader(); mFlags = reader.hdr().record.flags; std::uint32_t esmVer = reader.esmVersion(); diff --git a/components/esm4/loadnpc.hpp b/components/esm4/loadnpc.hpp index e979544213..9080779c44 100644 --- a/components/esm4/loadnpc.hpp +++ b/components/esm4/loadnpc.hpp @@ -31,6 +31,9 @@ #include #include +#include +#include + #include "actor.hpp" #include "inventory.hpp" @@ -164,7 +167,7 @@ namespace ESM4 #pragma pack(pop) - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details bool mIsTES4; @@ -221,6 +224,7 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_NPC_4; }; } diff --git a/components/esm4/loadrace.cpp b/components/esm4/loadrace.cpp index 6868cb337a..7c3bbb489b 100644 --- a/components/esm4/loadrace.cpp +++ b/components/esm4/loadrace.cpp @@ -35,8 +35,7 @@ void ESM4::Race::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.getFormId(); - reader.adjustFormId(mFormId); + mId = reader.getRefIdFromHeader(); mFlags = reader.hdr().record.flags; std::uint32_t esmVer = reader.esmVersion(); diff --git a/components/esm4/loadrace.hpp b/components/esm4/loadrace.hpp index ad2c92e43c..2010658589 100644 --- a/components/esm4/loadrace.hpp +++ b/components/esm4/loadrace.hpp @@ -32,6 +32,9 @@ #include #include +#include +#include + #include "actor.hpp" // AttributeValues, BodyTemplate #include "formid.hpp" @@ -106,7 +109,7 @@ namespace ESM4 std::string texture; // can be empty e.g. eye left, eye right }; - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details bool mIsTES5; @@ -165,6 +168,7 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_RACE4; }; } diff --git a/components/esm4/loadrefr.cpp b/components/esm4/loadrefr.cpp index d4fb4a1157..e91cabeedd 100644 --- a/components/esm4/loadrefr.cpp +++ b/components/esm4/loadrefr.cpp @@ -36,11 +36,8 @@ void ESM4::Reference::load(ESM4::Reader& reader) mId = reader.hdr().record.getFormId(); reader.adjustFormId(mId); mFlags = reader.hdr().record.flags; - mParentFormId = reader.currCell(); // NOTE: only for persistent refs? - mParent = ESM::RefId::formIdRefId(mParentFormId); + mParent = ESM::RefId::formIdRefId(reader.currCell()); - // TODO: Let the engine apply this? Saved games? - // mInitiallyDisabled = ((mFlags & ESM4::Rec_Disabled) != 0) ? true : false; std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; @@ -63,15 +60,6 @@ void ESM4::Reference::load(ESM4::Reader& reader) FormId BaseId; reader.getFormId(BaseId); mBaseObj = ESM::RefId::formIdRefId(BaseId); -#if 0 - if (mFlags & ESM4::Rec_Disabled) - std::cout << "REFR disable at start " << formIdToString(mFormId) << - " baseobj " << formIdToString(mBaseObj) << - " " << (mEditorId.empty() ? "" : mEditorId) << std::endl; // FIXME -#endif - // if (mBaseObj == 0x20) // e.g. FO3 mFormId == 0x0007E90F - // if (mBaseObj == 0x17) - // std::cout << mEditorId << std::endl; break; } case ESM4::SUB_DATA: diff --git a/components/esm4/loadrefr.hpp b/components/esm4/loadrefr.hpp index 2a795a000d..9a17bf27a1 100644 --- a/components/esm4/loadrefr.hpp +++ b/components/esm4/loadrefr.hpp @@ -29,7 +29,7 @@ #include -#include "reference.hpp" // FormId, Placement, EnableParent +#include "reference.hpp" // EnableParent #include #include @@ -58,7 +58,7 @@ namespace ESM4 struct TeleportDest { - FormId destDoor; + ESM::FormId destDoor; ESM::Position destPos; std::uint32_t flags = 0; // 0x01 no alarm (only in TES5) }; @@ -69,16 +69,15 @@ namespace ESM4 // 0 radius, 1 everywhere, 2 worldspace and linked int, 3 linked int, 4 current cell only std::uint32_t broadcastRange; float staticPercentage; - FormId posReference; // only used if broadcastRange == 0 + ESM::FormId posReference; // only used if broadcastRange == 0 }; struct Reference { - FormId mId; // from the header + ESM::FormId mId; // from the header - FormId mParentFormId; // cell FormId (currently persistent refs only), from the loading sequence - // NOTE: for exterior cells it will be the dummy cell FormId - ESM::RefId mParent; + ESM::RefId mParent; // cell FormId, from the loading sequence + // NOTE: for exterior cells it will be the dummy cell FormId std::uint32_t mFlags; // from the header, see enum type RecordFlag for details @@ -88,19 +87,18 @@ namespace ESM4 ESM::Position mPos; float mScale = 1.0f; - FormId mOwner; - FormId mGlobal; + ESM::FormId mOwner; + ESM::FormId mGlobal; std::int32_t mFactionRank = -1; - bool mInitiallyDisabled; // TODO may need to check mFlags & 0x800 (initially disabled) - bool mIsMapMarker; + bool mIsMapMarker = false; std::uint16_t mMapMarker; EnableParent mEsp; std::uint32_t mCount = 1; // only if > 1 - FormId mAudioLocation; + ESM::FormId mAudioLocation; RadioStationData mRadio; @@ -109,7 +107,7 @@ namespace ESM4 std::int8_t mLockLevel; ESM::RefId mKey; - FormId mTargetRef; + ESM::FormId mTargetRef; void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const; diff --git a/components/esm4/records.hpp b/components/esm4/records.hpp index 25bcba5cf2..88f8b77462 100644 --- a/components/esm4/records.hpp +++ b/components/esm4/records.hpp @@ -2,7 +2,6 @@ #define COMPONENTS_ESM4_RECORDS_H #include -#include #include #include #include diff --git a/components/esm4/reference.hpp b/components/esm4/reference.hpp index 6987e811f9..debb39f839 100644 --- a/components/esm4/reference.hpp +++ b/components/esm4/reference.hpp @@ -30,37 +30,22 @@ #include #include -#include "formid.hpp" +#include +#include namespace ESM4 { -#pragma pack(push, 1) - struct Vector3 - { - float x; - float y; - float z; - }; - - // REFR, ACHR, ACRE - struct Placement - { - Vector3 pos; - Vector3 rot; // angles are in radian, rz applied first and rx applied last - }; -#pragma pack(pop) - // REFR, ACHR, ACRE struct EnableParent { - FormId parent; + ESM::FormId parent; std::uint32_t flags; // 0x0001 = Set Enable State Opposite Parent, 0x0002 = Pop In }; struct LODReference { - FormId baseObj; - Placement placement; + ESM::FormId baseObj; + ESM::Position placement; float scale; }; }