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:
parent
3592dc4c88
commit
6451750890
8 changed files with 104 additions and 28 deletions
|
@ -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));
|
||||
}
|
||||
|
|
10
components/esm/decompose.hpp
Normal file
10
components/esm/decompose.hpp
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
13
components/misc/concepts.hpp
Normal file
13
components/misc/concepts.hpp
Normal 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
|
Loading…
Reference in a new issue