diff --git a/components/esm/decompose.hpp b/components/esm/decompose.hpp index eb6f5070d4..f9fecec067 100644 --- a/components/esm/decompose.hpp +++ b/components/esm/decompose.hpp @@ -5,6 +5,13 @@ namespace ESM { template void decompose(T&& value, const auto& apply) = delete; + + std::size_t getCompositeSize(const auto& value) + { + std::size_t result = 0; + decompose(value, [&](const auto&... args) { result = (0 + ... + sizeof(args)); }); + return result; + } } #endif diff --git a/components/esm3/loadnpc.cpp b/components/esm3/loadnpc.cpp index 58a8bfa55e..03c47d4d73 100644 --- a/components/esm3/loadnpc.cpp +++ b/components/esm3/loadnpc.cpp @@ -3,8 +3,34 @@ #include "esmreader.hpp" #include "esmwriter.hpp" +#include + namespace ESM { + namespace + { + struct NPDTstruct12 + { + NPC::NPDTstruct52& mStruct; + }; + } + + template T> + void decompose(T&& v, const auto& f) + { + char padding1 = 0; + char padding2 = 0; + f(v.mLevel, v.mAttributes, v.mSkills, padding1, v.mHealth, v.mMana, v.mFatigue, v.mDisposition, v.mReputation, + v.mRank, padding2, v.mGold); + } + + template T> + void decompose(T&& v, const auto& f) + { + char padding[] = { 0, 0, 0 }; + f(v.mStruct.mLevel, v.mStruct.mDisposition, v.mStruct.mReputation, v.mStruct.mRank, padding, v.mStruct.mGold); + } + void NPC::load(ESMReader& esm, bool& isDeleted) { isDeleted = false; @@ -56,37 +82,25 @@ namespace ESM case fourCC("NPDT"): hasNpdt = true; esm.getSubHeader(); - if (esm.getSubSize() == 52) + if (esm.getSubSize() == getCompositeSize(mNpdt)) { mNpdtType = NPC_DEFAULT; - esm.getT(mNpdt.mLevel); - esm.getT(mNpdt.mAttributes); - esm.getT(mNpdt.mSkills); - esm.getT(mNpdt.mUnknown1); - esm.getT(mNpdt.mHealth); - esm.getT(mNpdt.mMana); - esm.getT(mNpdt.mFatigue); - esm.getT(mNpdt.mDisposition); - esm.getT(mNpdt.mReputation); - esm.getT(mNpdt.mRank); - esm.getT(mNpdt.mUnknown2); - esm.getT(mNpdt.mGold); - } - else if (esm.getSubSize() == 12) - { - mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - - // Clearing the mNdpt struct to initialize all values - blankNpdt(); - esm.getT(mNpdt.mLevel); - esm.getT(mNpdt.mDisposition); - esm.getT(mNpdt.mReputation); - esm.getT(mNpdt.mRank); - esm.skip(3); - esm.getT(mNpdt.mGold); + esm.getComposite(mNpdt); } else - esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + { + NPDTstruct12 data{ mNpdt }; + if (esm.getSubSize() == getCompositeSize(data)) + { + mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; + + // Clearing the mNdpt struct to initialize all values + blankNpdt(); + esm.getComposite(data); + } + else + esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + } break; case fourCC("FLAG"): hasFlags = true; @@ -154,32 +168,11 @@ namespace ESM if (mNpdtType == NPC_DEFAULT) { - esm.startSubRecord("NPDT"); - esm.writeT(mNpdt.mLevel); - esm.writeT(mNpdt.mAttributes); - esm.writeT(mNpdt.mSkills); - esm.writeT(mNpdt.mUnknown1); - esm.writeT(mNpdt.mHealth); - esm.writeT(mNpdt.mMana); - esm.writeT(mNpdt.mFatigue); - esm.writeT(mNpdt.mDisposition); - esm.writeT(mNpdt.mReputation); - esm.writeT(mNpdt.mRank); - esm.writeT(mNpdt.mUnknown2); - esm.writeT(mNpdt.mGold); - esm.endRecord("NPDT"); + esm.writeNamedComposite("NPDT", mNpdt); } else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) { - esm.startSubRecord("NPDT"); - esm.writeT(mNpdt.mLevel); - esm.writeT(mNpdt.mDisposition); - esm.writeT(mNpdt.mReputation); - esm.writeT(mNpdt.mRank); - constexpr char padding[] = { 0, 0, 0 }; - esm.writeT(padding); - esm.writeT(mNpdt.mGold); - esm.endRecord("NPDT"); + esm.writeNamedComposite("NPDT", NPDTstruct12{ const_cast(mNpdt) }); } esm.writeHNT("FLAG", ((mBloodType << 10) + mFlags)); @@ -238,9 +231,7 @@ namespace ESM mNpdt.mReputation = 0; mNpdt.mHealth = mNpdt.mMana = mNpdt.mFatigue = 0; mNpdt.mDisposition = 0; - mNpdt.mUnknown1 = 0; mNpdt.mRank = 0; - mNpdt.mUnknown2 = 0; mNpdt.mGold = 0; } diff --git a/components/esm3/loadnpc.hpp b/components/esm3/loadnpc.hpp index 76930365c8..40ec0f0347 100644 --- a/components/esm3/loadnpc.hpp +++ b/components/esm3/loadnpc.hpp @@ -83,10 +83,8 @@ namespace ESM // mSkill can grow up to 200, it must be unsigned std::array mSkills; - char mUnknown1; uint16_t mHealth, mMana, mFatigue; unsigned char mDisposition, mReputation, mRank; - char mUnknown2; int32_t mGold; }; // 52 bytes diff --git a/components/esm3/loadpgrd.cpp b/components/esm3/loadpgrd.cpp index ebd51dcff0..c438fd73eb 100644 --- a/components/esm3/loadpgrd.cpp +++ b/components/esm3/loadpgrd.cpp @@ -73,7 +73,7 @@ namespace ESM { esm.getSubHeader(); uint32_t size = esm.getSubSize(); - if (size != 16u * mData.mPoints) + if (size != getCompositeSize(Point{}) * mData.mPoints) esm.fail("Path point subrecord size mismatch"); else {