1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-28 23:09:46 +00:00

Write AiSequence and Script data field by field via decompose function

Use the same function to load and save to have single place with field order
definition. Use concepts for overload over different types.
This commit is contained in:
elsid 2024-01-12 02:15:54 +01:00
parent 3592dc4c88
commit 6451750890
No known key found for this signature in database
GPG key ID: 4DE04C198CBA7625
8 changed files with 104 additions and 28 deletions

View file

@ -422,7 +422,6 @@ namespace ESM
std::copy(std::begin(idle), std::end(idle), record.mData.mIdle);
record.mData.mShouldRepeat = 12;
record.mDurationData.mRemainingDuration = 13;
record.mDurationData.mUnused = 14;
record.mStoredInitialActorPosition = true;
constexpr float initialActorPosition[3] = { 15, 16, 17 };
static_assert(std::size(initialActorPosition) == std::size(record.mInitialActorPosition.mValues));
@ -438,7 +437,6 @@ namespace ESM
EXPECT_THAT(result.mData.mIdle, ElementsAreArray(record.mData.mIdle));
EXPECT_EQ(result.mData.mShouldRepeat, record.mData.mShouldRepeat);
EXPECT_EQ(result.mDurationData.mRemainingDuration, record.mDurationData.mRemainingDuration);
EXPECT_EQ(result.mDurationData.mUnused, record.mDurationData.mUnused);
EXPECT_EQ(result.mStoredInitialActorPosition, record.mStoredInitialActorPosition);
EXPECT_THAT(result.mInitialActorPosition.mValues, ElementsAreArray(record.mInitialActorPosition.mValues));
}

View file

@ -0,0 +1,10 @@
#ifndef OPENMW_COMPONENTS_ESM_DECOMPOSE_H
#define OPENMW_COMPONENTS_ESM_DECOMPOSE_H
namespace ESM
{
template <class T>
void decompose(T&& value, const auto& apply) = delete;
}
#endif

View file

@ -3,32 +3,58 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include <components/misc/concepts.hpp>
#include <algorithm>
#include <memory>
namespace ESM
{
template <Misc::SameAsWithoutCvref<AiSequence::AiWanderData> T>
void decompose(T&& v, const auto& f)
{
f(v.mDistance, v.mDuration, v.mTimeOfDay, v.mIdle, v.mShouldRepeat);
}
template <Misc::SameAsWithoutCvref<AiSequence::AiWanderDuration> T>
void decompose(T&& v, const auto& f)
{
std::uint32_t unused = 0;
f(v.mRemainingDuration, unused);
}
template <Misc::SameAsWithoutCvref<AiSequence::AiTravelData> T>
void decompose(T&& v, const auto& f)
{
f(v.mX, v.mY, v.mZ);
}
template <Misc::SameAsWithoutCvref<AiSequence::AiEscortData> T>
void decompose(T&& v, const auto& f)
{
f(v.mX, v.mY, v.mZ, v.mDuration);
}
namespace AiSequence
{
void AiWander::load(ESMReader& esm)
{
esm.getHNT("DATA", mData.mDistance, mData.mDuration, mData.mTimeOfDay, mData.mIdle, mData.mShouldRepeat);
esm.getHNT("STAR", mDurationData.mRemainingDuration, mDurationData.mUnused); // was mStartTime
esm.getNamedComposite("DATA", mData);
esm.getNamedComposite("STAR", mDurationData); // was mStartTime
mStoredInitialActorPosition = esm.getHNOT("POS_", mInitialActorPosition.mValues);
}
void AiWander::save(ESMWriter& esm) const
{
esm.writeHNT("DATA", mData);
esm.writeHNT("STAR", mDurationData);
esm.writeNamedComposite("DATA", mData);
esm.writeNamedComposite("STAR", mDurationData); // was mStartTime
if (mStoredInitialActorPosition)
esm.writeHNT("POS_", mInitialActorPosition);
esm.writeHNT("POS_", mInitialActorPosition.mValues);
}
void AiTravel::load(ESMReader& esm)
{
esm.getHNT("DATA", mData.mX, mData.mY, mData.mZ);
esm.getNamedComposite("DATA", mData);
esm.getHNT(mHidden, "HIDD");
mRepeat = false;
esm.getHNOT(mRepeat, "REPT");
@ -36,7 +62,7 @@ namespace ESM
void AiTravel::save(ESMWriter& esm) const
{
esm.writeHNT("DATA", mData);
esm.writeNamedComposite("DATA", mData);
esm.writeHNT("HIDD", mHidden);
if (mRepeat)
esm.writeHNT("REPT", mRepeat);
@ -44,7 +70,7 @@ namespace ESM
void AiEscort::load(ESMReader& esm)
{
esm.getHNT("DATA", mData.mX, mData.mY, mData.mZ, mData.mDuration);
esm.getNamedComposite("DATA", mData);
mTargetId = esm.getHNRefId("TARG");
mTargetActorId = -1;
esm.getHNOT(mTargetActorId, "TAID");
@ -64,7 +90,7 @@ namespace ESM
void AiEscort::save(ESMWriter& esm) const
{
esm.writeHNT("DATA", mData);
esm.writeNamedComposite("DATA", mData);
esm.writeHNRefId("TARG", mTargetId);
esm.writeHNT("TAID", mTargetActorId);
esm.writeHNT("DURA", mRemainingDuration);
@ -76,7 +102,7 @@ namespace ESM
void AiFollow::load(ESMReader& esm)
{
esm.getHNT("DATA", mData.mX, mData.mY, mData.mZ, mData.mDuration);
esm.getNamedComposite("DATA", mData);
mTargetId = esm.getHNRefId("TARG");
mTargetActorId = -1;
esm.getHNOT(mTargetActorId, "TAID");
@ -101,7 +127,7 @@ namespace ESM
void AiFollow::save(ESMWriter& esm) const
{
esm.writeHNT("DATA", mData);
esm.writeNamedComposite("DATA", mData);
esm.writeHNRefId("TARG", mTargetId);
esm.writeHNT("TAID", mTargetActorId);
esm.writeHNT("DURA", mRemainingDuration);

View file

@ -36,32 +36,31 @@ namespace ESM
virtual ~AiPackage() {}
};
#pragma pack(push, 1)
struct AiWanderData
{
int16_t mDistance;
int16_t mDuration;
unsigned char mTimeOfDay;
unsigned char mIdle[8];
unsigned char mShouldRepeat;
std::uint8_t mTimeOfDay;
std::uint8_t mIdle[8];
std::uint8_t mShouldRepeat;
};
struct AiWanderDuration
{
float mRemainingDuration;
int32_t mUnused;
};
struct AiTravelData
{
float mX, mY, mZ;
};
struct AiEscortData
{
float mX, mY, mZ;
int16_t mDuration;
};
#pragma pack(pop)
struct AiWander : AiPackage
{
AiWanderData mData;

View file

@ -12,8 +12,10 @@
#include <components/to_utf8/to_utf8.hpp>
#include "components/esm/decompose.hpp"
#include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp"
#include "loadtes3.hpp"
namespace ESM
@ -177,6 +179,16 @@ namespace ESM
(getT(args), ...);
}
void getNamedComposite(NAME name, auto& value)
{
decompose(value, [&](auto&... args) { getHNT(name, args...); });
}
void getComposite(auto& value)
{
decompose(value, [&](auto&... args) { (getT(args), ...); });
}
template <typename T, typename = std::enable_if_t<IsReadable<T>>>
void skipHT()
{

View file

@ -5,6 +5,7 @@
#include <list>
#include <type_traits>
#include "components/esm/decompose.hpp"
#include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp"
@ -121,6 +122,20 @@ namespace ESM
endRecord(name);
}
void writeNamedComposite(NAME name, const auto& value)
{
decompose(value, [&](const auto&... args) {
startSubRecord(name);
(writeT(args), ...);
endRecord(name);
});
}
void writeComposite(const auto& value)
{
decompose(value, [&](const auto&... args) { (writeT(args), ...); });
}
// Prevent using writeHNT with strings. This already happened by accident and results in
// state being discarded without any error on writing or reading it. :(
// writeHNString and friends must be used instead.
@ -132,7 +147,7 @@ namespace ESM
void writeHNT(NAME name, const T (&data)[size], int) = delete;
template <typename T>
void writeHNT(NAME name, const T& data, int size)
void writeHNT(NAME name, const T& data, std::size_t size)
{
startSubRecord(name);
writeT(data, size);

View file

@ -4,12 +4,19 @@
#include <sstream>
#include <components/debug/debuglog.hpp>
#include <components/misc/concepts.hpp>
#include "esmreader.hpp"
#include "esmwriter.hpp"
namespace ESM
{
template <Misc::SameAsWithoutCvref<Script::SCHDstruct> T>
void decompose(T&& v, const auto& f)
{
f(v.mNumShorts, v.mNumLongs, v.mNumFloats, v.mScriptDataSize, v.mStringTableSize);
}
void Script::loadSCVR(ESMReader& esm)
{
uint32_t s = mData.mStringTableSize;
@ -99,11 +106,7 @@ namespace ESM
{
esm.getSubHeader();
mId = esm.getMaybeFixedRefIdSize(32);
esm.getT(mData.mNumShorts);
esm.getT(mData.mNumLongs);
esm.getT(mData.mNumFloats);
esm.getT(mData.mScriptDataSize);
esm.getT(mData.mStringTableSize);
esm.getComposite(mData);
hasHeader = true;
break;
@ -157,7 +160,7 @@ namespace ESM
esm.startSubRecord("SCHD");
esm.writeMaybeFixedSizeRefId(mId, 32);
esm.writeT(mData, 20);
esm.writeComposite(mData);
esm.endRecord("SCHD");
if (isDeleted)

View file

@ -0,0 +1,13 @@
#ifndef OPENMW_COMPONENTS_MISC_CONCEPTS_H
#define OPENMW_COMPONENTS_MISC_CONCEPTS_H
#include <concepts>
#include <type_traits>
namespace Misc
{
template <class T, class U>
concept SameAsWithoutCvref = std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
}
#endif