Load ESM4 actors

revert-6246b479
Petr Mikheev 1 year ago
parent 488657d9b4
commit 9b511fdf7a

@ -68,5 +68,7 @@ namespace MWClass
ESM4Tree::registerSelf();
ESM4Named<ESM4::Weapon>::registerSelf();
ESM4Light::registerSelf();
ESM4Actor<ESM4::Npc>::registerSelf();
ESM4Actor<ESM4::Creature>::registerSelf();
}
}

@ -124,6 +124,39 @@ namespace MWClass
return ptr.get<Record>()->mBase->mFullName;
}
};
template <typename Record>
class ESM4Actor : public MWWorld::RegisteredClass<ESM4Actor<Record>, ESM4Base<Record>>
{
public:
friend MWWorld::RegisteredClass<ESM4Actor, ESM4Base<Record>>;
ESM4Actor()
: MWWorld::RegisteredClass<ESM4Actor, ESM4Base<Record>>(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<Record>()->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

@ -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);

@ -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<int>(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);
}

@ -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)
{

@ -41,6 +41,7 @@
#include <components/esm3/npcstate.hpp>
#include <components/esm3/objectstate.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadligh.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
@ -384,24 +385,32 @@ namespace MWWorld
}
}
template <typename X>
void CellRefList<X>::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 <typename X, typename R>
static void loadImpl(const R& ref, const MWWorld::ESMStore& esmStore, auto& list)
{
const MWWorld::Store<X>& store = esmStore.get<X>();
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 <typename X>
void CellRefList<X>::load(const ESM4::Reference& ref, const MWWorld::ESMStore& esmStore)
{
if constexpr (ESM::isESM4Rec(X::sRecordId) && !isESM4ActorRec(X::sRecordId))
loadImpl<X>(ref, esmStore, mList);
}
template <typename X>
void CellRefList<X>::load(const ESM4::ActorCharacter& ref, const MWWorld::ESMStore& esmStore)
{
if constexpr (isESM4ActorRec(X::sRecordId))
loadImpl<X>(ref, esmStore, mList);
}
template <typename X>
@ -769,9 +778,21 @@ namespace MWWorld
invocable(*ref);
}
template <typename ReferenceInvocable>
static void visitCell4ActorReferences(
const ESM4::Cell& cell, const ESMStore& esmStore, ESM::ReadersCache& readers, ReferenceInvocable&& invocable)
{
for (const ESM4::ActorCharacter* ref : esmStore.get<ESM4::ActorCharacter>().getByCell(cell.mId))
invocable(*ref);
for (const ESM4::ActorCharacter* ref : esmStore.get<ESM4::ActorCreature>().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<ESM::RefNum, ESM::RefId>& 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<ESM::RecNameInts>(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<ESM::RefNum, ESM::RefId>& refNumToID)
{
const MWWorld::ESMStore& store = mStore;

@ -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<ESM4::Static>, CellRefList<ESM4::Light>, CellRefList<ESM4::Activator>, CellRefList<ESM4::Potion>,
CellRefList<ESM4::Ammunition>, CellRefList<ESM4::Armor>, CellRefList<ESM4::Book>, CellRefList<ESM4::Clothing>,
CellRefList<ESM4::Container>, CellRefList<ESM4::Door>, CellRefList<ESM4::Ingredient>, CellRefList<ESM4::Tree>,
CellRefList<ESM4::MiscItem>, CellRefList<ESM4::Weapon>, CellRefList<ESM4::Furniture>>;
CellRefList<ESM4::MiscItem>, CellRefList<ESM4::Weapon>, CellRefList<ESM4::Furniture>,
CellRefList<ESM4::Creature>, CellRefList<ESM4::Npc>>;
/// \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<ESM::RefNum, ESM::RefId>& refNumToID);
///< Make case-adjustments to \a ref and insert it into the respective container.
///

@ -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<ESM::Attribute>().setUp(get<ESM::GameSetting>());
getWritable<ESM4::Land>().updateLandPositions(get<ESM4::Cell>());
getWritable<ESM4::Reference>().preprocessReferences(get<ESM4::Cell>());
getWritable<ESM4::ActorCharacter>().preprocessReferences(get<ESM4::Cell>());
getWritable<ESM4::ActorCreature>().preprocessReferences(get<ESM4::Cell>());
rebuildIdsIndex();
mStoreImp->mStaticIds = mStoreImp->mIds;

@ -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<ESM4::Static>, Store<ESM4::Cell>, Store<ESM4::Light>, Store<ESM4::Reference>, Store<ESM4::Activator>,
Store<ESM4::Potion>, Store<ESM4::Ammunition>, Store<ESM4::Armor>, Store<ESM4::Book>, Store<ESM4::Clothing>,
Store<ESM4::Container>, Store<ESM4::Door>, Store<ESM4::Ingredient>, Store<ESM4::MiscItem>,
Store<ESM4::Tree>, Store<ESM4::Weapon>, Store<ESM4::World>, Store<ESM4::Furniture>, Store<ESM4::Land>>;
Store<ESM4::Tree>, Store<ESM4::Weapon>, Store<ESM4::World>, Store<ESM4::Furniture>, Store<ESM4::Land>,
Store<ESM4::ActorCharacter>, Store<ESM4::ActorCreature>, Store<ESM4::Race>, Store<ESM4::Creature>,
Store<ESM4::LevelledCreature>, Store<ESM4::Npc>, Store<ESM4::LevelledNpc>>;
private:
template <typename T>

@ -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);

@ -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)

@ -1,6 +1,8 @@
#include "refdata.hpp"
#include <components/esm3/objectstate.hpp>
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#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)

@ -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

@ -1326,33 +1326,6 @@ namespace MWWorld
return nullptr;
return foundLand->second;
}
// ESM4 Reference
//=========================================================================
void Store<ESM4::Reference>::preprocessReferences(const Store<ESM4::Cell>& 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<const ESM4::Reference* const> Store<ESM4::Reference>::getByCell(ESM::RefId cellId) const
{
auto it = mPerCellReferences.find(cellId);
if (it == mPerCellReferences.end())
return {};
return it->second;
}
}
template class MWWorld::TypedDynamicStore<ESM::Activator>;
@ -1405,14 +1378,21 @@ template class MWWorld::TypedDynamicStore<ESM4::Armor>;
template class MWWorld::TypedDynamicStore<ESM4::Book>;
template class MWWorld::TypedDynamicStore<ESM4::Clothing>;
template class MWWorld::TypedDynamicStore<ESM4::Container>;
template class MWWorld::TypedDynamicStore<ESM4::Creature>;
template class MWWorld::TypedDynamicStore<ESM4::Door>;
template class MWWorld::TypedDynamicStore<ESM4::Furniture>;
template class MWWorld::TypedDynamicStore<ESM4::Ingredient>;
template class MWWorld::TypedDynamicStore<ESM4::MiscItem>;
template class MWWorld::TypedDynamicStore<ESM4::Static>;
template class MWWorld::TypedDynamicStore<ESM4::Tree>;
template class MWWorld::TypedDynamicStore<ESM4::LevelledCreature>;
template class MWWorld::TypedDynamicStore<ESM4::LevelledNpc>;
template class MWWorld::TypedDynamicStore<ESM4::Light>;
template class MWWorld::TypedDynamicStore<ESM4::Npc>;
template class MWWorld::TypedDynamicStore<ESM4::Reference, ESM::FormId>;
template class MWWorld::TypedDynamicStore<ESM4::ActorCharacter, ESM::FormId>;
template class MWWorld::TypedDynamicStore<ESM4::ActorCreature, ESM::FormId>;
template class MWWorld::TypedDynamicStore<ESM4::Race>;
template class MWWorld::TypedDynamicStore<ESM4::Cell>;
template class MWWorld::TypedDynamicStore<ESM4::Weapon>;
template class MWWorld::TypedDynamicStore<ESM4::World>;

@ -18,6 +18,7 @@
#include <components/esm3/loadland.hpp>
#include <components/esm3/loadpgrd.hpp>
#include <components/esm3/loadskil.hpp>
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadland.hpp>
#include <components/esm4/loadrefr.hpp>
@ -581,16 +582,51 @@ namespace MWWorld
const MWDialogue::KeywordSearch<int>& getDialogIdKeywordSearch() const;
};
template <>
class Store<ESM4::Reference> : public TypedDynamicStore<ESM4::Reference, ESM::FormId>
template <typename T>
class ESM4RefsStore : public TypedDynamicStore<T, ESM::FormId>
{
public:
void preprocessReferences(const Store<ESM4::Cell>& cells);
void preprocessReferences(const Store<ESM4::Cell>& 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<const ESM4::Reference* const> getByCell(ESM::RefId cellId) const;
std::span<const T* const> getByCell(ESM::RefId cellId) const
{
auto it = mPerCellReferences.find(cellId);
if (it == mPerCellReferences.end())
return {};
return it->second;
}
private:
std::unordered_map<ESM::RefId, std::vector<ESM4::Reference*>> mPerCellReferences;
std::unordered_map<ESM::RefId, std::vector<T*>> mPerCellReferences;
};
template <>
class Store<ESM4::Reference> : public ESM4RefsStore<ESM4::Reference>
{
};
template <>
class Store<ESM4::ActorCharacter> : public ESM4RefsStore<ESM4::ActorCharacter>
{
};
template <>
class Store<ESM4::ActorCreature> : public ESM4RefsStore<ESM4::ActorCreature>
{
};
} // end namespace

@ -6,7 +6,6 @@
#include <components/esm4/inventory.hpp>
#include <components/esm4/lighting.hpp>
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadacre.hpp>
#include <components/esm4/loadacti.hpp>
#include <components/esm4/loadalch.hpp>
#include <components/esm4/loadaloc.hpp>

@ -161,7 +161,6 @@ add_component_dir (esm4
inventory
lighting
loadachr
loadacre
loadacti
loadalch
loadaloc

@ -1,10 +1,12 @@
#ifndef COMPONENTS_ESM_ESMBRIDGE
#define COMPONENTS_ESM_ESMBRIDGE
#include <string>
#include <string_view>
#include <variant>
#include <components/esm3/cellref.hpp>
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadrefr.hpp>
namespace ESM4
@ -52,25 +54,22 @@ namespace ESM
struct ReferenceVariant
{
std::variant<ESM::CellRef, ESM4::Reference> mVariant;
std::variant<ESM::CellRef, ESM4::Reference, ESM4::ActorCharacter> 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<ESM4::Reference>(mVariant); }
const ESM::CellRef& getEsm3() const { return std::get<ESM::CellRef>(mVariant); }
const ESM4::Reference& getEsm4() const { return std::get<ESM4::Reference>(mVariant); }
ESM::CellRef& getEsm3() { return std::get<ESM::CellRef>(mVariant); }
ESM4::Reference& getEsm4() { return std::get<ESM4::Reference>(mVariant); }
explicit ReferenceVariant(const ESM::CellRef& ref)
: mVariant(ref)
{
}
};
template <class F, class... T>

@ -51,11 +51,16 @@
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadclot.hpp>
#include <components/esm4/loadcont.hpp>
#include <components/esm4/loadcrea.hpp>
#include <components/esm4/loaddoor.hpp>
#include <components/esm4/loadfurn.hpp>
#include <components/esm4/loadingr.hpp>
#include <components/esm4/loadligh.hpp>
#include <components/esm4/loadlvlc.hpp>
#include <components/esm4/loadlvln.hpp>
#include <components/esm4/loadmisc.hpp>
#include <components/esm4/loadnpc.hpp>
#include <components/esm4/loadrace.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/esm4/loadtree.hpp>

@ -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));
}
}
}

@ -29,6 +29,9 @@
#include <cstdint>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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 <stdexcept>
#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()
//{
// }

@ -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 <cstdint>
#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

@ -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:

@ -31,6 +31,9 @@
#include <string>
#include <vector>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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())

@ -30,6 +30,9 @@
#include <cstdint>
#include <vector>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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

@ -31,6 +31,9 @@
#include <string>
#include <vector>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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();

@ -31,6 +31,9 @@
#include <string>
#include <vector>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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();

@ -32,6 +32,9 @@
#include <map>
#include <vector>
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
#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;
};
}

@ -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:

@ -29,7 +29,7 @@
#include <cstdint>
#include "reference.hpp" // FormId, Placement, EnableParent
#include "reference.hpp" // EnableParent
#include <components/esm/defs.hpp>
#include <components/esm/refid.hpp>
@ -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;

@ -2,7 +2,6 @@
#define COMPONENTS_ESM4_RECORDS_H
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadacre.hpp>
#include <components/esm4/loadacti.hpp>
#include <components/esm4/loadalch.hpp>
#include <components/esm4/loadaloc.hpp>

@ -30,37 +30,22 @@
#include <cstdint>
#include <string>
#include "formid.hpp"
#include <components/esm/defs.hpp>
#include <components/esm/formid.hpp>
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;
};
}

Loading…
Cancel
Save