diff --git a/src/Utilities/Savegame.h b/src/Utilities/Savegame.h index 0f90d1af5c..e4d368382c 100644 --- a/src/Utilities/Savegame.h +++ b/src/Utilities/Savegame.h @@ -5,7 +5,25 @@ #include #include -namespace Savegame { +namespace Savegame +{ + template + concept ImplementsUpperCaseSaveLoad = requires (PhobosStreamWriter& stmWriter, PhobosStreamReader& stmReader, T& value, bool registerForChange) + { + value.Save(stmWriter); + value.Load(stmReader, registerForChange); + }; + + template + concept ImplementsLowerCaseSaveLoad = requires (PhobosStreamWriter & stmWriter, PhobosStreamReader & stmReader, T& value, bool registerForChange) + { + value.save(stmWriter); + value.load(stmReader, registerForChange); + }; + + template + concept ImplementsSaveLoad = ImplementsUpperCaseSaveLoad || ImplementsLowerCaseSaveLoad; + template bool ReadPhobosStream(PhobosStreamReader& Stm, T& Value, bool RegisterForChange = true); diff --git a/src/Utilities/SavegameDef.h b/src/Utilities/SavegameDef.h index c8f7e30d96..788b74d1dd 100644 --- a/src/Utilities/SavegameDef.h +++ b/src/Utilities/SavegameDef.h @@ -21,20 +21,6 @@ namespace Savegame { - template - concept ImplementsUpperCaseSaveLoad = requires (PhobosStreamWriter& stmWriter, PhobosStreamReader& stmReader, T& value, bool registerForChange) - { - value.Save(stmWriter); - value.Load(stmReader, registerForChange); - }; - - template - concept ImplementsLowerCaseSaveLoad = requires (PhobosStreamWriter & stmWriter, PhobosStreamReader & stmReader, T& value, bool registerForChange) - { - value.save(stmWriter); - value.load(stmReader, registerForChange); - }; - #pragma warning(push) #pragma warning(disable: 4702) // MSVC isn't smart enough and yells about unreachable code diff --git a/src/Utilities/Template.h b/src/Utilities/Template.h index 526f7ec26a..1b3478f857 100644 --- a/src/Utilities/Template.h +++ b/src/Utilities/Template.h @@ -482,4 +482,95 @@ class PartialVector3D : public Vector3D // Same as Vector3D except parsing on size_t ValueCount; }; +// Designates that the type can read it's value from multiple flags. +template +concept MultiflagReadable = requires(T obj, INI_EX& const parser, const char* const pSection, const char* const pBaseFlag, TExtraArgs& const... extraArgs) +{ + { obj.Read(parser, pSection, pBaseFlag, extraArgs...) } -> std::same_as; +}; + +template +requires MultiflagReadable +class MultiflagValueableVector : public ValueableVector +{ + inline void Read(INI_EX& const parser, const char* const pSection, const char* const pBaseFlag, TExtraArgs& const... extraArgs); +}; + +template +requires MultiflagReadable +class MultiflagNullableVector : public NullableVector +{ + inline void Read(INI_EX& const parser, const char* const pSection, const char* const pBaseFlag, TExtraArgs& const... extraArgs); +}; + +// Need multiple args or multiple return values? Use std::tuple - Kerbiter +// template +// class Calculatable +// { +// public: + +// virtual TValue Get(TArg const arg) const noexcept = 0; + +// virtual void Read(INI_EX& const parser, const char* const pSection, const char* const pBaseFlag) = 0; + +// virtual bool Load(PhobosStreamReader& Stm, bool RegisterForChange) = 0; + +// virtual bool Save(PhobosStreamWriter& Stm) const = 0; +// }; + +// template +// class ArgBoundable +// { +// public: + +// virtual Vector2D GetArgBounds() const noexcept = 0; +// }; + +// template +// class ValueBoundable +// { +// public: + +// virtual Vector2D GetValueBounds() const noexcept = 0; +// }; + + +template +class Animatable // : public Calculatable //, public ArgBoundable +{ +public: + using absolute_length_t = int; + + class KeyframeDataEntry + { + public: + Valueable Percentage; + Valueable Value; + + inline bool Read(INI_EX& const parser, const char* const pSection, const char* const pBaseFlag, absolute_length_t& const absoluteLength = 0); + + inline bool Load(PhobosStreamReader& Stm, bool RegisterForChange); + + inline bool Save(PhobosStreamWriter& Stm) const; + }; + + MultiflagValueableVector KeyframeData; + + // TODO ctors and stuff + + inline TValue Get(double const percentage) const noexcept; + + // inline TValue Get(int const frame) const noexcept; + + // Vector2D GetArgBounds() const noexcept override; + + inline void Read(INI_EX& const parser, const char* const pSection, const char* const pBaseFlag, absolute_length_t& const absoluteLength = 0); + + inline bool Load(PhobosStreamReader& Stm, bool RegisterForChange); + + inline bool Save(PhobosStreamWriter& Stm) const; +}; + +static_assert(Savegame::ImplementsSaveLoad::KeyframeDataEntry>); +static_assert(Savegame::ImplementsSaveLoad>); diff --git a/src/Utilities/TemplateDef.h b/src/Utilities/TemplateDef.h index 6ba0a6506c..db6c5fca97 100644 --- a/src/Utilities/TemplateDef.h +++ b/src/Utilities/TemplateDef.h @@ -1391,6 +1391,8 @@ if(_strcmpi(parser.value(), #name) == 0){ value = __uuidof(name ## LocomotionCla Debug::INIParseFailed(pSection, pKey, pCur); } } + + // TODO detail::interpolate } @@ -1747,3 +1749,121 @@ bool Damageable::Save(PhobosStreamWriter& Stm) const && Savegame::WritePhobosStream(Stm, this->ConditionYellow) && Savegame::WritePhobosStream(Stm, this->ConditionRed); } + +// MultiflagValueableVector + +template +requires MultiflagReadable +void __declspec(noinline) MultiflagValueableVector::Read(INI_EX& parser, const char* const pSection, const char* const pBaseFlag, TExtraArgs& const... extraArgs) +{ + char flagName[0x40]; + for (size_t i = 0; ; ++i) + { + T dataEntry {}; + + // we expect %d for array number then %s for the subflag name, so we replace %s with itself (but escaped) + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, i, "%%s"); + + if (!dataEntry.Read(parser, pSection, flagName, extraArgs...)) + break; + + this->push_back(dataEntry); + } +} + +// MultiflagNullableVector + +template +requires MultiflagReadable +void __declspec(noinline) MultiflagValueableVector::Read(INI_EX& parser, const char* const pSection, const char* const pBaseFlag, TExtraArgs& const... extraArgs) +{ + char flagName[0x40]; + for (size_t i = 0; ; ++i) + { + T dataEntry {}; + + // we expect %d for array number then %s for the subflag name, so we replace %s with itself (but escaped) + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, i, "%%s"); + + if (!dataEntry.Read(parser, pSection, flagName, extraArgs...)) + break; + + this->push_back(dataEntry); + this->hasValue = true; + } +} + +// Animatable + +// Animatable::KeyframeDataEntry + +template +bool __declspec(noinline) Animatable::KeyframeDataEntry::Read(INI_EX& parser, const char* const pSection, const char* const pBaseFlag, absolute_length_t& const absoluteLength) +{ + char flagName[0x40]; + + Nullable absoluteTemp {}; + + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, "Percentage"); + this->Percentage.Read(parser, pSection, flagName); + + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, "Absolute"); + absoluteTemp.Read(parser, pSection, flagName); + + if (!this->Frame.HasValue && !absoluteTemp.HasValue) + return false; + + if (absoluteTemp.HasValue) + this->Percentage.Value = (double)absoluteTemp.Value / absoluteLength; + + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, "Value"); + this->Value.Read(parser, pSection, flagName); + + return true; +}; + +template +bool Animatable::KeyframeDataEntry::Load(PhobosStreamReader& Stm, bool RegisterForChange) +{ + return Savegame::ReadPhobosStream(Stm, this->Percentage, RegisterForChange) + && Savegame::ReadPhobosStream(Stm, this->Frame, RegisterForChange) + && Savegame::ReadPhobosStream(Stm, this->Value, RegisterForChange); +} + +template +bool Animatable::KeyframeDataEntry::Save(PhobosStreamWriter& Stm) const +{ + return Savegame::WritePhobosStream(Stm, this->Percentage) + && Savegame::WritePhobosStream(Stm, this->Frame) + && Savegame::WritePhobosStream(Stm, this->Value); +} + + +template +TValue Animatable::Get(double const percentage) const noexcept +{ + return detail::interpolate(percentage); // TODO +} + +template +void __declspec(noinline) Animatable::Read(INI_EX& parser, const char* const pSection, const char* const pBaseFlag, absolute_length_t& const absoluteLength) +{ + char flagName[0x40]; + + // we expect "BaseFlagName.%s" here + _snprintf_s(flagName, sizeof(flagName), pBaseFlag, "Keyframe%%d.%%s"); + + this->KeyframeData.Read(parser, pSection, flagName, absoluteLength); +}; + +template +bool Animatable::Load(PhobosStreamReader& Stm, bool RegisterForChange) +{ + return Savegame::ReadPhobosStream(Stm, this->KeyframeData, RegisterForChange); +} + +template +bool Animatable::Save(PhobosStreamWriter& Stm) const +{ + return Savegame::WritePhobosStream(Stm, this->KeyframeData); +}