mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Merge branch 'esm4_achr' into 'master'
Load ESM4 actors (no rendering yet) See merge request OpenMW/openmw!3278
This commit is contained in:
commit
3e16ef7445
37 changed files with 363 additions and 317 deletions
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
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))
|
||||
return;
|
||||
|
||||
const MWWorld::Store<X>& store = esmStore.get<X>();
|
||||
|
||||
if (const X* ptr = store.search(ref.mBaseObj))
|
||||
{
|
||||
LiveRef liveCellRef(ref, ptr);
|
||||
mList.push_back(liveCellRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: could not resolve cell reference " << ref.mId << " (dropping reference)";
|
||||
}
|
||||
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 ESM4::ActorCharacter& ref)
|
||||
: mVariant(ref)
|
||||
{
|
||||
}
|
||||
|
||||
explicit ReferenceVariant(const ESM::CellRef& 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); }
|
||||
};
|
||||
|
||||
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…
Reference in a new issue