diff --git a/libsave/include/SatisfactorySave/GameTypes/Properties/ArrayProperty.h b/libsave/include/SatisfactorySave/GameTypes/Properties/ArrayProperty.h index e216a15a..6c64650e 100644 --- a/libsave/include/SatisfactorySave/GameTypes/Properties/ArrayProperty.h +++ b/libsave/include/SatisfactorySave/GameTypes/Properties/ArrayProperty.h @@ -1,29 +1,20 @@ #pragma once #include "../Arrays/Base/Array.h" -#include "Base/Property.h" +#include "Base/PropertyImpl.h" namespace SatisfactorySave { - class SATISFACTORYSAVE_API ArrayProperty : public Property { + class SATISFACTORYSAVE_API ArrayProperty : public PropertyImplBase> { public: static constexpr std::string_view TypeName = "ArrayProperty"; - using Property::Property; + using PropertyImplBase>::PropertyImplBase; void serialize(Archive& ar) override; - void accept(PropertyVisitor& v) override; - [[nodiscard]] inline FName& arrayType() { return tag_.InnerType; } - - [[nodiscard]] const std::unique_ptr& array() const { - return array_; - } - - protected: - std::unique_ptr array_; }; } // namespace SatisfactorySave diff --git a/libsave/include/SatisfactorySave/GameTypes/Properties/Base/PropertyImpl.h b/libsave/include/SatisfactorySave/GameTypes/Properties/Base/PropertyImpl.h index ec183a78..8e7a2940 100644 --- a/libsave/include/SatisfactorySave/GameTypes/Properties/Base/PropertyImpl.h +++ b/libsave/include/SatisfactorySave/GameTypes/Properties/Base/PropertyImpl.h @@ -6,20 +6,10 @@ namespace SatisfactorySave { template - class PropertyImpl : public Property { + class PropertyImplBase : public Property { public: - PropertyImpl() : Property(FName(std::string(Impl::TypeName))) {} - explicit PropertyImpl(PropertyTag tag) : Property(std::move(tag)) {} - - void serialize(Archive& ar) override { - if constexpr (IsSerializable) { - ar << Value; - } else { - // Function must be overwritten by derived class! - // Runtime exception is a workaround for virtual functions not supporting concepts. - throw std::runtime_error("Invalid PropertyImpl serialize!"); - } - } + PropertyImplBase() : Property(FName(std::string(Impl::TypeName))) {} + explicit PropertyImplBase(PropertyTag tag) : Property(std::move(tag)) {} void accept(PropertyVisitor& v) override { v.visit(static_cast(*this)); @@ -27,4 +17,16 @@ namespace SatisfactorySave { T Value{}; }; + + // Split into two classes to force subclasses with not serializable type to implement serialize(). Maybe in future + // override methods support concepts, e.g., `void serialize(Archive& ar) requires IsSerializable override`. + template + class PropertyImpl : public PropertyImplBase { + public: + using PropertyImplBase::PropertyImplBase; + + void serialize(Archive& ar) override { + ar << this->Value; + } + }; } // namespace SatisfactorySave diff --git a/libsave/include/SatisfactorySave/GameTypes/Properties/SetProperty.h b/libsave/include/SatisfactorySave/GameTypes/Properties/SetProperty.h index 569dc03e..3f38e68a 100644 --- a/libsave/include/SatisfactorySave/GameTypes/Properties/SetProperty.h +++ b/libsave/include/SatisfactorySave/GameTypes/Properties/SetProperty.h @@ -1,29 +1,20 @@ #pragma once #include "../Sets/Base/Set.h" -#include "Base/Property.h" +#include "Base/PropertyImpl.h" namespace SatisfactorySave { - class SATISFACTORYSAVE_API SetProperty : public Property { + class SATISFACTORYSAVE_API SetProperty : public PropertyImplBase> { public: static constexpr std::string_view TypeName = "SetProperty"; - SetProperty(PropertyTag tag); + using PropertyImplBase>::PropertyImplBase; void serialize(Archive& ar) override; - void accept(PropertyVisitor& v) override; - [[nodiscard]] inline FName& setType() { return tag_.InnerType; } - - [[nodiscard]] const std::unique_ptr& set() const { - return set_; - } - - protected: - std::unique_ptr set_; }; } // namespace SatisfactorySave diff --git a/libsave/include/SatisfactorySave/GameTypes/Properties/StructProperty.h b/libsave/include/SatisfactorySave/GameTypes/Properties/StructProperty.h index 438f87d4..e1f861ae 100644 --- a/libsave/include/SatisfactorySave/GameTypes/Properties/StructProperty.h +++ b/libsave/include/SatisfactorySave/GameTypes/Properties/StructProperty.h @@ -4,20 +4,18 @@ #include "../Structs/Base/Struct.h" #include "../UE/Misc/Guid.h" -#include "Base/Property.h" +#include "Base/PropertyImpl.h" namespace SatisfactorySave { - class SATISFACTORYSAVE_API StructProperty : public Property { + class SATISFACTORYSAVE_API StructProperty : public PropertyImplBase> { public: static constexpr std::string_view TypeName = "StructProperty"; - using Property::Property; + using PropertyImplBase>::PropertyImplBase; void serialize(Archive& ar) override; - void accept(PropertyVisitor& v) override; - [[nodiscard]] inline FName& structName() { return tag_.StructName; } @@ -25,12 +23,5 @@ namespace SatisfactorySave { [[nodiscard]] inline FGuid& structGuid() { return tag_.StructGuid; } - - [[nodiscard]] const std::unique_ptr& value() const { - return struct_; - } - - protected: - std::unique_ptr struct_; }; } // namespace SatisfactorySave diff --git a/libsave/src/GameTypes/Properties/ArrayProperty.cpp b/libsave/src/GameTypes/Properties/ArrayProperty.cpp index d951df19..a14717d2 100644 --- a/libsave/src/GameTypes/Properties/ArrayProperty.cpp +++ b/libsave/src/GameTypes/Properties/ArrayProperty.cpp @@ -1,15 +1,9 @@ #include "GameTypes/Properties/ArrayProperty.h" -#include "GameTypes/Properties/Base/PropertyVisitor.h" - void SatisfactorySave::ArrayProperty::serialize(SatisfactorySave::Archive& ar) { if (ar.isIArchive()) { - array_ = Array::create(arrayType(), ar); + Value = Array::create(arrayType(), ar); } else { - ar << *array_; + ar << *Value; } } - -void SatisfactorySave::ArrayProperty::accept(SatisfactorySave::PropertyVisitor& v) { - v.visit(*this); -} diff --git a/libsave/src/GameTypes/Properties/SetProperty.cpp b/libsave/src/GameTypes/Properties/SetProperty.cpp index 0069265e..746efcfb 100644 --- a/libsave/src/GameTypes/Properties/SetProperty.cpp +++ b/libsave/src/GameTypes/Properties/SetProperty.cpp @@ -1,11 +1,5 @@ #include "GameTypes/Properties/SetProperty.h" -#include - -#include "GameTypes/Properties/Base/PropertyVisitor.h" - -SatisfactorySave::SetProperty::SetProperty(SatisfactorySave::PropertyTag tag) : Property(std::move(tag)) {} - void SatisfactorySave::SetProperty::serialize(Archive& ar) { // https://github.com/EpicGames/UnrealEngine/blob/4.26.2-release/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp#L298 int32_t NumElementsToRemove = 0; @@ -16,12 +10,8 @@ void SatisfactorySave::SetProperty::serialize(Archive& ar) { if (ar.isIArchive()) { auto& inAr = dynamic_cast(ar); - set_ = Set::create(setType(), name(), inAr); + Value = Set::create(setType(), name(), inAr); } else { - ar << *set_; + ar << *Value; } } - -void SatisfactorySave::SetProperty::accept(SatisfactorySave::PropertyVisitor& v) { - v.visit(*this); -} diff --git a/libsave/src/GameTypes/Properties/StructProperty.cpp b/libsave/src/GameTypes/Properties/StructProperty.cpp index e6aa261e..97c89bc3 100644 --- a/libsave/src/GameTypes/Properties/StructProperty.cpp +++ b/libsave/src/GameTypes/Properties/StructProperty.cpp @@ -1,15 +1,9 @@ #include "GameTypes/Properties/StructProperty.h" -#include "GameTypes/Properties/Base/PropertyVisitor.h" - void SatisfactorySave::StructProperty::serialize(Archive& ar) { if (ar.isIArchive()) { - struct_ = Struct::create(structName(), ar); + Value = Struct::create(structName(), ar); } else { - ar << *struct_; + ar << *Value; } } - -void SatisfactorySave::StructProperty::accept(SatisfactorySave::PropertyVisitor& v) { - v.visit(*this); -} diff --git a/libsavepy/GameTypes/Properties.cpp b/libsavepy/GameTypes/Properties.cpp index 4bf2eab5..28521195 100644 --- a/libsavepy/GameTypes/Properties.cpp +++ b/libsavepy/GameTypes/Properties.cpp @@ -64,7 +64,7 @@ void init_GameTypes_Properties(py::module_& m) { ; py::class_(m, "ArrayProperty") - .def(py::init()) + .def(py::init<>()) //.def_readwrite("Value", &s::ArrayProperty::Value) // TODO ; @@ -125,7 +125,7 @@ void init_GameTypes_Properties(py::module_& m) { .def_readwrite("Value", &s::ObjectProperty::Value); py::class_(m, "SetProperty") - //.def(py::init()) // TODO + .def(py::init<>()) // TODO ; @@ -138,7 +138,7 @@ void init_GameTypes_Properties(py::module_& m) { .def_readwrite("Value", &s::StrProperty::Value); py::class_(m, "StructProperty") - .def(py::init()) + .def(py::init<>()) // TODO ; diff --git a/map/src/MapWindow/DataView/ModelManager.cpp b/map/src/MapWindow/DataView/ModelManager.cpp index 3448cd09..25a49ea7 100644 --- a/map/src/MapWindow/DataView/ModelManager.cpp +++ b/map/src/MapWindow/DataView/ModelManager.cpp @@ -187,7 +187,7 @@ std::size_t Satisfactory3DMap::ModelManager::loadAsset(const std::string& classN asset << instanceDataProperties; const auto* instances = dynamic_cast( - instanceDataProperties.get("Instances").array().get()); + instanceDataProperties.get("Instances").Value.get()); if (instances == nullptr || instances->Values.empty()) { throw std::runtime_error("Instances not found or empty!"); } @@ -233,7 +233,7 @@ std::size_t Satisfactory3DMap::ModelManager::loadAsset(const std::string& classN glm::mat4 translationMx(1.0f); try { - const auto& locationStructProp = properties.get("RelativeLocation").value(); + const auto& locationStructProp = properties.get("RelativeLocation").Value; const auto* locationStruct = dynamic_cast(locationStructProp.get()); if (locationStruct != nullptr) { translationMx = glm::translate(glm::mat4(1.0f), glmCast(locationStruct->Data)); @@ -242,7 +242,7 @@ std::size_t Satisfactory3DMap::ModelManager::loadAsset(const std::string& classN glm::mat4 rotationMx(1.0f); try { - const auto& rotationStructProp = properties.get("RelativeRotation").value(); + const auto& rotationStructProp = properties.get("RelativeRotation").Value; const auto* rotationStruct = dynamic_cast(rotationStructProp.get()); if (rotationStruct != nullptr) { rotationMx = glm::toMat4(glmCast(rotationStruct->Data.Quaternion())); @@ -288,17 +288,17 @@ Satisfactory3DMap::ModelManager::MeshInfo Satisfactory3DMap::ModelManager::getSt try { const auto& relativeTransform = instanceData->Data.get("RelativeTransform"); const auto* relativeTransformStruct = - dynamic_cast(relativeTransform.value().get()); + dynamic_cast(relativeTransform.Value.get()); if (relativeTransformStruct == nullptr) { throw std::runtime_error("Bad struct type!"); } const auto* Rotation = dynamic_cast( - relativeTransformStruct->Data.get("Rotation").value().get()); + relativeTransformStruct->Data.get("Rotation").Value.get()); const auto* Translation = dynamic_cast( - relativeTransformStruct->Data.get("Translation").value().get()); + relativeTransformStruct->Data.get("Translation").Value.get()); const auto* Scale3D = dynamic_cast( - relativeTransformStruct->Data.get("Scale3D").value().get()); + relativeTransformStruct->Data.get("Scale3D").Value.get()); if (Rotation == nullptr || Translation == nullptr || Scale3D == nullptr) { throw std::runtime_error("Bad struct types!"); } diff --git a/map/src/MapWindow/DataView/SplineData.cpp b/map/src/MapWindow/DataView/SplineData.cpp index df6c345b..5eb6efc9 100644 --- a/map/src/MapWindow/DataView/SplineData.cpp +++ b/map/src/MapWindow/DataView/SplineData.cpp @@ -21,7 +21,7 @@ namespace { throw std::runtime_error("Expect StructProperty!"); } - auto& sa = dynamic_cast(*ap.array()); + auto& sa = dynamic_cast(*ap.Value); if (sa.structName() != "SplinePointData") { throw std::runtime_error("Expect SplinePointData!"); } @@ -32,11 +32,11 @@ namespace { if (ps.Data.size() != 3) { throw std::runtime_error("Unexpected struct size!"); } - const auto& locationStruct = *dynamic_cast(ps.Data.at(0)).value(); + const auto& locationStruct = *dynamic_cast(ps.Data.at(0)).Value; const auto& arriveTangentStruct = - *dynamic_cast(ps.Data.at(1)).value(); + *dynamic_cast(ps.Data.at(1)).Value; const auto& leaveTangentStruct = - *dynamic_cast(ps.Data.at(2)).value(); + *dynamic_cast(ps.Data.at(2)).Value; SplinePointData data; data.location = diff --git a/map/src/MapWindow/UI/PropertyTableGuiRenderer.cpp b/map/src/MapWindow/UI/PropertyTableGuiRenderer.cpp index b8f73713..ee00c9fa 100644 --- a/map/src/MapWindow/UI/PropertyTableGuiRenderer.cpp +++ b/map/src/MapWindow/UI/PropertyTableGuiRenderer.cpp @@ -360,7 +360,7 @@ namespace { void visit(SatisfactorySave::ArrayProperty& p) override { ImGui::TextDisabled("ArrayType: %s", p.arrayType().toString().c_str()); ArraySetValueGuiRenderer r(callback_); - p.array()->accept(r); + p.Value->accept(r); } void visit(SatisfactorySave::BoolProperty& p) override { @@ -461,7 +461,7 @@ namespace { void visit(SatisfactorySave::SetProperty& p) override { ImGui::TextDisabled("SetType: %s", p.setType().toString().c_str()); ArraySetValueGuiRenderer r(callback_); - p.set()->accept(r); + p.Value->accept(r); } void visit(SatisfactorySave::SoftObjectProperty& p) override { @@ -479,7 +479,7 @@ namespace { ImGui::Text("%s", p.structName().toString().c_str()); ImGui::TextDisabled("%s", p.structGuid().toString().c_str()); StructValueGuiRenderer s(callback_); - p.value()->accept(s); + p.Value->accept(s); } void visit(SatisfactorySave::TextProperty& p) override {