From d045d358c8b01a50e52cbe094031a73cd714a33e Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Thu, 4 Jun 2026 21:41:05 +1200 Subject: [PATCH 1/4] refactor: conversion of `URawFormatValue` to and from JSON Each derived class of `URawFormatValue` now is responsible for the logic to convert itself to and from JSON. Use of the `FJsonRawFormatConverter` class is now deprecated. --- .../Private/Configuration/ConfigManager.cpp | 5 +- .../Json/JsonRawFormatConverter.cpp | 62 +++++++------------ .../Json/JsonRawFormatConverter.h | 2 + .../RawFileFormat/RawFormatValue.h | 7 +++ .../RawFileFormat/RawFormatValueArray.h | 28 +++++++++ .../RawFileFormat/RawFormatValueBool.h | 15 +++++ .../RawFileFormat/RawFormatValueNumber.h | 15 +++++ .../RawFileFormat/RawFormatValueObject.h | 27 ++++++++ .../RawFileFormat/RawFormatValueString.h | 14 +++++ 9 files changed, 132 insertions(+), 43 deletions(-) mode change 100644 => 100755 Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp diff --git a/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp b/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp index fb3b176848..de4848267d 100644 --- a/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp @@ -4,6 +4,7 @@ #include "Util/SemVersion.h" #include "TimerManager.h" #include "Configuration/RootConfigValueHolder.h" +#include "Configuration/RawFileFormat/RawFormatValueObject.h" #include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Dom/JsonValue.h" #include "Engine/GameInstance.h" @@ -35,7 +36,7 @@ void UConfigManager::SaveConfigurationInternal(const FConfigId& ConfigId) { checkf(RawFormatValue, TEXT("Root RawFormatValue returned NULL for config %s"), *ConfigId.ModReference); //Root value should always be JsonObject, since root property is section property - const TSharedPtr JsonValue = FJsonRawFormatConverter::ConvertToJson(RawFormatValue); + const TSharedPtr JsonValue = RawFormatValue->ToJson(); check(JsonValue->Type == EJson::Object); TSharedRef UnderlyingObject = JsonValue->AsObject().ToSharedRef(); @@ -95,7 +96,7 @@ void UConfigManager::LoadConfigurationInternal(const FConfigId& ConfigId, URootC //Convert JSON tree into the raw value tree and feed it to root section value const TSharedRef RootValue = MakeShareable(new FJsonValueObject(JsonObject)); - URawFormatValue* RawFormatValue = FJsonRawFormatConverter::ConvertToRawFormat(this, RootValue); + URawFormatValue* RawFormatValue = URawFormatValueObject::FromJson(this, RootValue); RootConfigValueHolder->GetWrappedValue()->Deserialize(RawFormatValue); UE_LOG(LogConfigManager, Display, TEXT("Successfully loaded configuration from %s"), *ConfigurationFilePath); diff --git a/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp b/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp old mode 100644 new mode 100755 index 1e47222a32..eda50ef44b --- a/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp @@ -1,34 +1,26 @@ #include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" -#include "Configuration/RawFileFormat/RawFormatValueObject.h" #include "Configuration/RawFileFormat/RawFormatValueArray.h" +#include "Configuration/RawFileFormat/RawFormatValueBool.h" #include "Configuration/RawFileFormat/RawFormatValueNumber.h" +#include "Configuration/RawFileFormat/RawFormatValueObject.h" #include "Configuration/RawFileFormat/RawFormatValueString.h" -#include "Configuration/RawFileFormat/RawFormatValueBool.h" #include "Dom/JsonObject.h" TSharedPtr FJsonRawFormatConverter::ConvertToJson(const URawFormatValue* RawFormatValue) { if (const URawFormatValueNumber* Number = Cast(RawFormatValue)) { - return MakeShareable(new FJsonValueNumber(Number->Value)); + return Number->ToJson(); } if (const URawFormatValueString* String = Cast(RawFormatValue)) { - return MakeShareable(new FJsonValueString(String->Value)); + return String->ToJson(); } if (const URawFormatValueBool* Boolean = Cast(RawFormatValue)) { - return MakeShareable(new FJsonValueBoolean(Boolean->Value)); + return Boolean->ToJson(); } if (const URawFormatValueArray* Array = Cast(RawFormatValue)) { - TArray> OutJsonArray; - for (const URawFormatValue* ChildValue : Array->GetUnderlyingArrayRef()) { - OutJsonArray.Add(ConvertToJson(ChildValue)); - } - return MakeShareable(new FJsonValueArray(OutJsonArray)); + return Array->ToJson(); } if (const URawFormatValueObject* Object = Cast(RawFormatValue)) { - TSharedPtr JsonObject = MakeShareable(new FJsonObject()); - for (TPair Pair : Object->Values) { - JsonObject->SetField(Pair.Key, ConvertToJson(Pair.Value)); - } - return MakeShareable(new FJsonValueObject(JsonObject)); + return Object->ToJson(); } checkf(false, TEXT("Unreachable code")); return NULL; @@ -37,39 +29,27 @@ TSharedPtr FJsonRawFormatConverter::ConvertToJson(const URawFormatVa URawFormatValue* FJsonRawFormatConverter::ConvertToRawFormat(UObject* Outer, const TSharedPtr& JsonValue) { switch (JsonValue->Type) { case EJson::Number: { - URawFormatValueNumber* Number = NewObject(Outer); - Number->Value = JsonValue->AsNumber(); - return Number; - } + return URawFormatValueNumber::FromJson(Outer, JsonValue); + } case EJson::String: { - URawFormatValueString* String = NewObject(Outer); - String->Value = JsonValue->AsString(); - return String; - } + return URawFormatValueString::FromJson(Outer, JsonValue); + } case EJson::Boolean: { - URawFormatValueBool* Boolean = NewObject(Outer); - Boolean->Value = JsonValue->AsBool(); - return Boolean; - } + return URawFormatValueBool::FromJson(Outer, JsonValue); + } case EJson::Array: { - URawFormatValueArray* Array = NewObject(Outer); - for (const TSharedPtr& ChildValue : JsonValue->AsArray()) { - Array->AddValue(ConvertToRawFormat(Array, ChildValue)); - } - return Array; - } + return URawFormatValueArray::FromJson(Outer, JsonValue); + } case EJson::Object: { - URawFormatValueObject* Object = NewObject(Outer); - for (const TPair>& Pair : JsonValue->AsObject()->Values) { - Object->AddValue(Pair.Key, ConvertToRawFormat(Object, Pair.Value)); - } - return Object; - } - case EJson::Null: + return URawFormatValueObject::FromJson(Outer, JsonValue); + } + case EJson::Null: { checkf(false, TEXT("JSON Null value is not supported")); return NULL; - default: + } + default: { checkf(false, TEXT("Unreachable code")); return NULL; + } } } diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/Json/JsonRawFormatConverter.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/Json/JsonRawFormatConverter.h index b1fc858b79..2636b2b6c6 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/Json/JsonRawFormatConverter.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/Json/JsonRawFormatConverter.h @@ -12,8 +12,10 @@ class SML_API FJsonRawFormatConverter { public: /** Converts raw format value into the corresponding JSON element */ + [[deprecated("Use ToJson on the raw format value directly")]] static TSharedPtr ConvertToJson(const URawFormatValue* RawFormatValue); /** Converts JSON element into the raw format value, using specified object as Outer for raw value */ + [[deprecated("Use FromJson on the raw format class directly")]] static URawFormatValue* ConvertToRawFormat(UObject* Outer, const TSharedPtr& JsonValue); }; diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValue.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValue.h index c83dd049ee..f85ed9da12 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValue.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValue.h @@ -6,4 +6,11 @@ UCLASS(Abstract, BlueprintType) class SML_API URawFormatValue : public UObject { GENERATED_BODY() + +public: + /** Converts this object into a JSON value */ + virtual TSharedPtr ToJson() const { + checkf(false, TEXT("ToJson not implemented")); + return NULL; + } }; diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h index 649853d910..09abbb67fb 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h @@ -1,8 +1,11 @@ #pragma once +#include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Configuration/RawFileFormat/RawFormatValue.h" #include "Configuration/RawFileFormat/RawFormatValueNumber.h" #include "Configuration/RawFileFormat/RawFormatValueString.h" #include "Templates/SubclassOf.h" +#include "SatisfactoryModLoader.h" #include "RawFormatValueArray.generated.h" /** Describes raw array value */ @@ -85,6 +88,12 @@ class SML_API URawFormatValueArray : public URawFormatValue { /** Returns underlying array object reference. Reference is valid as long as this object is valid. */ FORCEINLINE const TArray& GetUnderlyingArrayRef() const { return Values; } + + virtual TSharedPtr ToJson() const override; + + /** Creates a new URawFormatValueArray from the given JSON value */ + static URawFormatValueArray* FromJson(UObject* Outer, const TSharedPtr& JsonValue); + private: /** Private to ensure that added objects have valid outer */ UPROPERTY() @@ -108,3 +117,22 @@ FORCEINLINE void URawFormatValueArray::AddValue(URawFormatValue* ValueClass) { checkf(ValueClass && ValueClass->GetOuter() == this, TEXT("Cannot add URawFormatValue residuing inside another outer object (should be URawFormatValueArray)")); Values.Add(ValueClass); } + +FORCEINLINE TSharedPtr URawFormatValueArray::ToJson() const { + TArray> OutJsonArray; + for (const URawFormatValue* ChildValue : Values) { + OutJsonArray.Add(ChildValue->ToJson()); + } + return MakeShareable(new FJsonValueArray(OutJsonArray)); +} + +FORCEINLINE URawFormatValueArray* URawFormatValueArray::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueArray* Array = NewObject(Outer); + for (const TSharedPtr& ChildValue : JsonValue->AsArray()) { + // TODO: Base child property deserialization on the child config property. + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Deserializing JSON array value for property with fallback implementation.")); + #pragma warning(suppress : 4996) + Array->AddValue(FJsonRawFormatConverter::ConvertToRawFormat(Array, ChildValue)); + } + return Array; +} \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueBool.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueBool.h index d012c18b49..5b39ec1497 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueBool.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueBool.h @@ -10,4 +10,19 @@ class SML_API URawFormatValueBool : public URawFormatValue { /** Actual boolean value stored */ UPROPERTY(BlueprintReadWrite) bool Value; + + virtual TSharedPtr ToJson() const override; + + /** Creates a new URawFormatValueBool from the given JSON value */ + static URawFormatValueBool* FromJson(UObject* Outer, const TSharedPtr& JsonValue); }; + +FORCEINLINE TSharedPtr URawFormatValueBool::ToJson() const { + return MakeShareable(new FJsonValueBoolean(Value)); +} + +FORCEINLINE URawFormatValueBool* URawFormatValueBool::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueBool* Boolean = NewObject(Outer); + Boolean->Value = JsonValue->AsBool(); + return Boolean; +} \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueNumber.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueNumber.h index ef44cbbef9..77c96ef850 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueNumber.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueNumber.h @@ -26,6 +26,11 @@ class SML_API URawFormatValueNumber : public URawFormatValue { /** Updates raw value to specified 32-bit signed integer */ UFUNCTION(BlueprintCallable) void SetValueInt(int32 NewValue); + + virtual TSharedPtr ToJson() const override; + + /** Creates a new URawFormatValueNumber from the given JSON value */ + static URawFormatValueNumber* FromJson(UObject* Outer, const TSharedPtr& JsonValue); }; FORCEINLINE void URawFormatValueNumber::SetValueFloat(float NewValue) { @@ -35,3 +40,13 @@ FORCEINLINE void URawFormatValueNumber::SetValueFloat(float NewValue) { FORCEINLINE void URawFormatValueNumber::SetValueInt(int32 NewValue) { this->Value = NewValue; } + +FORCEINLINE TSharedPtr URawFormatValueNumber::ToJson() const { + return MakeShareable(new FJsonValueNumber(Value)); +} + +FORCEINLINE URawFormatValueNumber* URawFormatValueNumber::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueNumber* Number = NewObject(Outer); + Number->Value = JsonValue->AsNumber(); + return Number; +} \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h index ee6a7a5bc0..48d1efe9de 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h @@ -1,6 +1,9 @@ #pragma once #include "Templates/SubclassOf.h" +#include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Configuration/RawFileFormat/RawFormatValueArray.h" +#include "SatisfactoryModLoader.h" #include "RawFormatValueObject.generated.h" /** Describes raw map (also known as object) value */ @@ -87,6 +90,11 @@ class SML_API URawFormatValueObject : public URawFormatValue { FORCEINLINE T* AddNewValue(const FString& Key) { return Cast(AddNewValue(Key, T::StaticClass())); } + + virtual TSharedPtr ToJson() const override; + + /** Creates a new URawFormatValueObject from the given JSON value */ + static URawFormatValueObject* FromJson(UObject* Outer, const TSharedPtr& JsonValue); }; FORCEINLINE void URawFormatValueObject::SetString(const FString& Key, const FString& Value) { @@ -106,3 +114,22 @@ FORCEINLINE void URawFormatValueObject::AddValue(const FString& Key, URawFormatV checkf(ValueClass && ValueClass->GetOuter() == this, TEXT("Cannot add URawFormatValue residuing inside another outer object (should be URawFormatValueArray)")); Values.Add(Key, ValueClass); }; + +FORCEINLINE TSharedPtr URawFormatValueObject::ToJson() const { + TSharedPtr JsonObject = MakeShareable(new FJsonObject()); + for (TPair Pair : Values) { + JsonObject->SetField(Pair.Key, Pair.Value->ToJson()); + } + return MakeShareable(new FJsonValueObject(JsonObject)); +} + +FORCEINLINE URawFormatValueObject* URawFormatValueObject::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueObject* Object = NewObject(Outer); + for (const TPair>& Pair : JsonValue->AsObject()->Values) { + // TODO: Base child property deserialization on the child config property. + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Deserializing JSON value for property %s with fallback implementation."), *Pair.Key); + #pragma warning(suppress : 4996) + Object->AddValue(Pair.Key, FJsonRawFormatConverter::ConvertToRawFormat(Object, Pair.Value)); + } + return Object; +} \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueString.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueString.h index f641839926..8c421166f9 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueString.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueString.h @@ -10,4 +10,18 @@ class SML_API URawFormatValueString : public URawFormatValue { /** Value of this raw value as string */ UPROPERTY(BlueprintReadWrite) FString Value; + + virtual TSharedPtr ToJson() const override; + + static URawFormatValueString* FromJson(UObject* Outer, const TSharedPtr& JsonValue); }; + +FORCEINLINE TSharedPtr URawFormatValueString::ToJson() const { + return MakeShareable(new FJsonValueString(Value)); +} + +FORCEINLINE URawFormatValueString* URawFormatValueString::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueString* String = NewObject(Outer); + String->Value = JsonValue->AsString(); + return String; +} \ No newline at end of file From 1e8621cd33b85211ffe58bcf9d851a0bbd034ee8 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sat, 6 Jun 2026 21:06:50 +1200 Subject: [PATCH 2/4] feat: add `GetChildProperty` to `UConfigPropertyArray` and `UConfigPropertySection` --- .../Properties/ConfigPropertyArray.cpp | 6 +++++- .../Properties/ConfigPropertySection.cpp | 6 +++++- .../Configuration/ConfigValueArrayInterface.h | 17 +++++++++++++++++ .../Configuration/ConfigValueObjectInterface.h | 17 +++++++++++++++++ .../Properties/ConfigPropertyArray.h | 11 +++++++++-- .../Properties/ConfigPropertySection.h | 11 +++++++++-- 6 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 Mods/SML/Source/SML/Public/Configuration/ConfigValueArrayInterface.h create mode 100644 Mods/SML/Source/SML/Public/Configuration/ConfigValueObjectInterface.h diff --git a/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyArray.cpp b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyArray.cpp index 69eef24ca1..8b794c3f08 100644 --- a/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyArray.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyArray.cpp @@ -215,4 +215,8 @@ FConfigVariableDescriptor UConfigPropertyArray::CreatePropertyDescriptor_Impleme return UConfigVariableLibrary::MakeConfigVariableArray(DefaultValue->CreatePropertyDescriptor(Context, OuterPath)); } -#undef LOCTEXT_NAMESPACE \ No newline at end of file +UConfigProperty* UConfigPropertyArray::GetChildProperty_Implementation(const int32 PropertyIndex) { + return Values[PropertyIndex]; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertySection.cpp b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertySection.cpp index ec18243908..89f585d9bf 100644 --- a/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertySection.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertySection.cpp @@ -162,4 +162,8 @@ FConfigVariableDescriptor UConfigPropertySection::CreatePropertyDescriptor_Imple return UConfigVariableLibrary::MakeConfigVariableGeneratedStruct(GeneratedStruct); } -#undef LOCTEXT_NAMESPACE \ No newline at end of file +UConfigProperty* UConfigPropertySection::GetChildProperty_Implementation(const FString& PropertyName) { + return SectionProperties.FindRef(PropertyName); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Mods/SML/Source/SML/Public/Configuration/ConfigValueArrayInterface.h b/Mods/SML/Source/SML/Public/Configuration/ConfigValueArrayInterface.h new file mode 100644 index 0000000000..36b62846f8 --- /dev/null +++ b/Mods/SML/Source/SML/Public/Configuration/ConfigValueArrayInterface.h @@ -0,0 +1,17 @@ +#pragma once +#include "CoreMinimal.h" +#include "Configuration/ConfigProperty.h" +#include "ConfigValueArrayInterface.generated.h" + +UINTERFACE(Blueprintable, BlueprintType) +class SML_API UConfigValueArrayInterface : public UInterface { + GENERATED_BODY() +}; + +class SML_API IConfigValueArrayInterface { + GENERATED_BODY() +public: + /** Returns the child property of this property at the specified index */ + UFUNCTION(BlueprintNativeEvent) + UConfigProperty* GetChildProperty(const int32 PropertyIndex); +}; diff --git a/Mods/SML/Source/SML/Public/Configuration/ConfigValueObjectInterface.h b/Mods/SML/Source/SML/Public/Configuration/ConfigValueObjectInterface.h new file mode 100644 index 0000000000..3f3c16735f --- /dev/null +++ b/Mods/SML/Source/SML/Public/Configuration/ConfigValueObjectInterface.h @@ -0,0 +1,17 @@ +#pragma once +#include "CoreMinimal.h" +#include "Configuration/ConfigProperty.h" +#include "ConfigValueObjectInterface.generated.h" + +UINTERFACE(Blueprintable, BlueprintType) +class SML_API UConfigValueObjectInterface : public UInterface { + GENERATED_BODY() +}; + +class SML_API IConfigValueObjectInterface { + GENERATED_BODY() +public: + /** Returns the child property of this property with the specified key */ + UFUNCTION(BlueprintNativeEvent) + UConfigProperty* GetChildProperty(const FString& PropertyKey); +}; diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h index 46072619d0..c79da9f6de 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h @@ -1,11 +1,12 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/ConfigValueArrayInterface.h" #include "Configuration/ConfigValueDirtyHandlerInterface.h" #include "ConfigPropertyArray.generated.h" /** Describes array configuration property with single nested element type */ UCLASS() -class SML_API UConfigPropertyArray : public UConfigProperty, public IConfigValueDirtyHandlerInterface { +class SML_API UConfigPropertyArray : public UConfigProperty, public IConfigValueDirtyHandlerInterface, public IConfigValueArrayInterface { GENERATED_BODY() public: /** Defines the "template" default value used for allocating other values in the array */ @@ -62,4 +63,10 @@ class SML_API UConfigPropertyArray : public UConfigProperty, public IConfigValue //Begin IConfigValueDirtyHandlerInterface virtual void HandleMarkDirty_Implementation() override; //End IConfigValueDirtyHandlerInterface -}; \ No newline at end of file + + //Begin IConfigPropertyArrayInterface + /** Returns the child property of this property at the specified index */ + UFUNCTION(BlueprintCallable, BlueprintPure, meta = (DisplayName = "Get Child By Index", CompactNodeTitle = ".", BlueprintAutocast), Category = "SML | Configuration") + virtual UConfigProperty* GetChildProperty_Implementation(const int32 PropertyIndex) override; + //End IConfigPropertyArrayInterface +}; diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h index 8c97bf4483..da72ed9838 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h @@ -1,11 +1,12 @@ #pragma once #include "Configuration/ConfigProperty.h" #include "Configuration/ConfigValueDirtyHandlerInterface.h" +#include "Configuration/ConfigValueObjectInterface.h" #include "ConfigPropertySection.generated.h" /** Describes a single configuration section with nested properties */ UCLASS() -class SML_API UConfigPropertySection : public UConfigProperty, public IConfigValueDirtyHandlerInterface { +class SML_API UConfigPropertySection : public UConfigProperty, public IConfigValueDirtyHandlerInterface, public IConfigValueObjectInterface { GENERATED_BODY() public: /** @@ -42,4 +43,10 @@ class SML_API UConfigPropertySection : public UConfigProperty, public IConfigVal //Begin IConfigValueDirtyHandlerInterface virtual void HandleMarkDirty_Implementation() override; //End IConfigValueDirtyHandlerInterface -}; \ No newline at end of file + + //Begin IConfigPropertyObjectInterface + /** Returns the child property of this property with the specified key */ + UFUNCTION(BlueprintCallable, BlueprintPure, meta = (DisplayName = "Get Child By Key", CompactNodeTitle = ".", BlueprintAutocast), Category = "SML | Configuration") + virtual UConfigProperty* GetChildProperty_Implementation(const FString& PropertyKey) override; + //End IConfigPropertyObjectInterface +}; From 5d18c951a32767b5bba83e361387fbdfb1b5819f Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Thu, 4 Jun 2026 21:41:05 +1200 Subject: [PATCH 3/4] refactor: UConfigPropertys are now directly given the json value from which they should deserialize For `URawFormatValue::FromJson` of values capable of having children, if the `UConfigProperty` is avaliable, that `UConfigProperty` is now used to perform the deserialize of the child value. --- .../SML/Private/Configuration/ConfigManager.cpp | 3 +-- .../SML/Public/Configuration/ConfigProperty.h | 15 +++++++++++++++ .../Properties/ConfigPropertyArray.h | 5 +++++ .../Properties/ConfigPropertyBool.h | 5 +++++ .../Properties/ConfigPropertyClass.h | 5 +++++ .../Properties/ConfigPropertyFloat.h | 5 +++++ .../Properties/ConfigPropertyInteger.h | 5 +++++ .../Properties/ConfigPropertySection.h | 5 +++++ .../Properties/ConfigPropertyString.h | 5 +++++ .../RawFileFormat/RawFormatValueArray.h | 16 ++++++++++++++-- .../RawFileFormat/RawFormatValueObject.h | 11 ++++++++++- 11 files changed, 75 insertions(+), 5 deletions(-) diff --git a/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp b/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp index de4848267d..4215ff2a88 100644 --- a/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/ConfigManager.cpp @@ -96,8 +96,7 @@ void UConfigManager::LoadConfigurationInternal(const FConfigId& ConfigId, URootC //Convert JSON tree into the raw value tree and feed it to root section value const TSharedRef RootValue = MakeShareable(new FJsonValueObject(JsonObject)); - URawFormatValue* RawFormatValue = URawFormatValueObject::FromJson(this, RootValue); - RootConfigValueHolder->GetWrappedValue()->Deserialize(RawFormatValue); + RootConfigValueHolder->GetWrappedValue()->DeserializeFromJson(RootValue); UE_LOG(LogConfigManager, Display, TEXT("Successfully loaded configuration from %s"), *ConfigurationFilePath); diff --git a/Mods/SML/Source/SML/Public/Configuration/ConfigProperty.h b/Mods/SML/Source/SML/Public/Configuration/ConfigProperty.h index 68061c255d..25c4de9a00 100644 --- a/Mods/SML/Source/SML/Public/Configuration/ConfigProperty.h +++ b/Mods/SML/Source/SML/Public/Configuration/ConfigProperty.h @@ -3,7 +3,9 @@ #include "FGGameMode.h" #include "UObject/Object.h" #include "Configuration/CodeGeneration/ConfigVariableDescriptor.h" +#include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Reflection/BlueprintReflectedObject.h" +#include "SatisfactoryModLoader.h" #include "ConfigProperty.generated.h" class URawFormatValue; @@ -59,6 +61,19 @@ class SML_API UConfigProperty : public UObject { UFUNCTION(BlueprintCallable, BlueprintNativeEvent) void Deserialize(const URawFormatValue* Value); + /** Deserializes passed json value into this property state */ + void DeserializeFromJson(const TSharedPtr& JsonValue) { + Deserialize(CreateRawFormatValue(this, JsonValue)); + } + + /** Creates a raw format value from the passed json value */ + virtual URawFormatValue* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) { + // This is a fallback. Derived classes should create a specific raw format value based on the expected type. + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Creating raw format value for property %s with fallback implementation."), *GetName()); + #pragma warning(suppress : 4996) + return FJsonRawFormatConverter::ConvertToRawFormat(Outer, JsonValue); + } + /** Marks this property directly, forcing file system synchronization to happen afterwards */ UFUNCTION(BlueprintCallable) virtual void MarkDirty(); diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h index c79da9f6de..608187a04c 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyArray.h @@ -2,6 +2,7 @@ #include "Configuration/ConfigProperty.h" #include "Configuration/ConfigValueArrayInterface.h" #include "Configuration/ConfigValueDirtyHandlerInterface.h" +#include "Configuration/RawFileFormat/RawFormatValueArray.h" #include "ConfigPropertyArray.generated.h" /** Describes array configuration property with single nested element type */ @@ -58,6 +59,10 @@ class SML_API UConfigPropertyArray : public UConfigProperty, public IConfigValue virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueArray* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueArray::FromJson(Outer, JsonValue); + } //End UConfigProperty //Begin IConfigValueDirtyHandlerInterface diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyBool.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyBool.h index d1fc487ecd..e19ddbe41d 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyBool.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyBool.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/RawFormatValueBool.h" #include "ConfigPropertyBool.generated.h" UCLASS() @@ -32,5 +33,9 @@ class SML_API UConfigPropertyBool : public UConfigProperty { virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueBool* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueBool::FromJson(Outer, JsonValue); + } //End UConfigProperty }; \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyClass.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyClass.h index 710cbdf5f5..b3ad0a2fda 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyClass.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyClass.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/RawFormatValueString.h" #include "ConfigPropertyClass.generated.h" UCLASS() @@ -60,5 +61,9 @@ class SML_API UConfigPropertyClass : public UConfigProperty { virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueString* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueString::FromJson(Outer, JsonValue); + } //End UConfigProperty }; \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyFloat.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyFloat.h index 31bc281c61..859d3ac7e9 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyFloat.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyFloat.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/RawFormatValueNumber.h" #include "ConfigPropertyFloat.generated.h" UCLASS() @@ -32,5 +33,9 @@ class SML_API UConfigPropertyFloat : public UConfigProperty { virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueNumber* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueNumber::FromJson(Outer, JsonValue); + } //End UConfigProperty }; \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyInteger.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyInteger.h index 7b690e1965..5604286f2e 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyInteger.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyInteger.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/RawFormatValueNumber.h" #include "ConfigPropertyInteger.generated.h" UCLASS() @@ -32,5 +33,9 @@ class SML_API UConfigPropertyInteger : public UConfigProperty { virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueNumber* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueNumber::FromJson(Outer, JsonValue); + } //End UConfigProperty }; diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h index da72ed9838..c85d424690 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertySection.h @@ -2,6 +2,7 @@ #include "Configuration/ConfigProperty.h" #include "Configuration/ConfigValueDirtyHandlerInterface.h" #include "Configuration/ConfigValueObjectInterface.h" +#include "Configuration/RawFileFormat/RawFormatValueObject.h" #include "ConfigPropertySection.generated.h" /** Describes a single configuration section with nested properties */ @@ -38,6 +39,10 @@ class SML_API UConfigPropertySection : public UConfigProperty, public IConfigVal virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueObject* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueObject::FromJson(Outer, JsonValue); + } //End UConfigProperty //Begin IConfigValueDirtyHandlerInterface diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyString.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyString.h index 9873aaad97..b896ed56ff 100644 --- a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyString.h +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyString.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/RawFileFormat/RawFormatValueString.h" #include "ConfigPropertyString.generated.h" UCLASS() @@ -32,5 +33,9 @@ class SML_API UConfigPropertyString : public UConfigProperty { virtual bool ResetToDefault_Implementation() override; virtual bool IsSetToDefaultValue_Implementation() const override; virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueString* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueString::FromJson(Outer, JsonValue); + } //End UConfigProperty }; \ No newline at end of file diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h index 09abbb67fb..614ddd81bc 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueArray.h @@ -1,5 +1,6 @@ #pragma once #include "Configuration/ConfigProperty.h" +#include "Configuration/ConfigValueArrayInterface.h" #include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Configuration/RawFileFormat/RawFormatValue.h" #include "Configuration/RawFileFormat/RawFormatValueNumber.h" @@ -128,8 +129,19 @@ FORCEINLINE TSharedPtr URawFormatValueArray::ToJson() const { FORCEINLINE URawFormatValueArray* URawFormatValueArray::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { URawFormatValueArray* Array = NewObject(Outer); - for (const TSharedPtr& ChildValue : JsonValue->AsArray()) { - // TODO: Base child property deserialization on the child config property. + const TArray>& JsonArray = JsonValue->AsArray(); + const int32 ChildNum = JsonArray.Num(); + for (int32 ChildIndex = 0; ChildIndex < ChildNum; ChildIndex++) { + const TSharedPtr& ChildValue = JsonArray[ChildIndex]; + UConfigProperty* Owner = Cast(Outer); + if (IsValid(Owner) && Owner->Implements()) { + UConfigProperty* ChildProperty = IConfigValueArrayInterface::Execute_GetChildProperty(Owner, ChildIndex); + if (IsValid(ChildProperty)) { + Array->AddValue(ChildProperty->CreateRawFormatValue(Array, ChildValue)); + continue; + } + } + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Deserializing JSON array value for property with fallback implementation.")); #pragma warning(suppress : 4996) Array->AddValue(FJsonRawFormatConverter::ConvertToRawFormat(Array, ChildValue)); diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h index 48d1efe9de..64c61824b1 100644 --- a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueObject.h @@ -1,6 +1,7 @@ #pragma once #include "Templates/SubclassOf.h" #include "Configuration/ConfigProperty.h" +#include "Configuration/ConfigValueObjectInterface.h" #include "Configuration/RawFileFormat/Json/JsonRawFormatConverter.h" #include "Configuration/RawFileFormat/RawFormatValueArray.h" #include "SatisfactoryModLoader.h" @@ -126,7 +127,15 @@ FORCEINLINE TSharedPtr URawFormatValueObject::ToJson() const { FORCEINLINE URawFormatValueObject* URawFormatValueObject::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { URawFormatValueObject* Object = NewObject(Outer); for (const TPair>& Pair : JsonValue->AsObject()->Values) { - // TODO: Base child property deserialization on the child config property. + UConfigProperty* Owner = Cast(Outer); + if (IsValid(Owner) && Owner->Implements()) { + UConfigProperty* ChildProperty = IConfigValueObjectInterface::Execute_GetChildProperty(Owner, Pair.Key); + if (IsValid(ChildProperty)) { + Object->AddValue(Pair.Key, ChildProperty->CreateRawFormatValue(Object, Pair.Value)); + continue; + } + } + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Deserializing JSON value for property %s with fallback implementation."), *Pair.Key); #pragma warning(suppress : 4996) Object->AddValue(Pair.Key, FJsonRawFormatConverter::ConvertToRawFormat(Object, Pair.Value)); From 3ce03b7b836fb61a9406a2404cd132bd8362cff4 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Thu, 4 Jun 2026 22:12:56 +1200 Subject: [PATCH 4/4] feat: add new config property for storing raw values --- .../BP_ConfigPropertyRaw.uasset | Bin 0 -> 16197 bytes .../ConfigVariableDescriptor.cpp | 4 + .../CodeGeneration/ConfigVariableLibrary.cpp | 6 ++ .../Properties/ConfigPropertyRaw.cpp | 81 ++++++++++++++++++ .../Properties/WidgetExtension/CP_Raw.cpp | 1 + .../Json/JsonRawFormatConverter.cpp | 4 + .../CodeGeneration/ConfigVariableDescriptor.h | 5 +- .../CodeGeneration/ConfigVariableLibrary.h | 4 + .../Properties/ConfigPropertyRaw.h | 47 ++++++++++ .../Properties/WidgetExtension/CP_Raw.h | 9 ++ .../RawFileFormat/RawFormatValueRawJson.h | 32 +++++++ 11 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 Mods/SML/Content/Interface/UI/Menu/Mods/ConfigProperties/BP_ConfigPropertyRaw.uasset mode change 100644 => 100755 Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableDescriptor.cpp mode change 100644 => 100755 Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableLibrary.cpp create mode 100755 Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyRaw.cpp create mode 100644 Mods/SML/Source/SML/Private/Configuration/Properties/WidgetExtension/CP_Raw.cpp mode change 100644 => 100755 Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableDescriptor.h mode change 100644 => 100755 Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableLibrary.h create mode 100755 Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyRaw.h create mode 100644 Mods/SML/Source/SML/Public/Configuration/Properties/WidgetExtension/CP_Raw.h create mode 100755 Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueRawJson.h diff --git a/Mods/SML/Content/Interface/UI/Menu/Mods/ConfigProperties/BP_ConfigPropertyRaw.uasset b/Mods/SML/Content/Interface/UI/Menu/Mods/ConfigProperties/BP_ConfigPropertyRaw.uasset new file mode 100644 index 0000000000000000000000000000000000000000..41046698c8bc5f9888ee2e3f14f5cb608a2eea95 GIT binary patch literal 16197 zcmeHO33OCdn!crBkwpR7qy>t|mH=4^ghe5#N`*j3LMn+Egixt^l@wI!74=>vgce1` zg{FJD>2?~=!KKB+jE8n+5L^dahp|0&+dZPK&S9Dsoo;jn+`4fY7nb?IyHveODwTrJ zZO=J#lehi%zyE&!d*6Mx4&9#p!2g^(cW&*aj19Vku`lUL|7_gTn|{1~v^)28nY(RZ_^xgLI}{WrtzKl!_v*9<4v!b5B3e!b*)|37YJPu#pA zduj&3?i@RQ?bd4FqsLw!z4zZ=Iyv+(!ESwXbKs{X)$e_Zy;o228r=)!QET%p}}fw(dKAqV%3m2mdyIcgaCl&UE0>k?USwnOhMu zwTR#2)pF}Aa+hnNXzp^|XXHBckU!8;6Vbz3#0+RgZfQ+Z0<5#v(?K*CTTMqHS*kx> zrw(Rp5?$vxi}L1{6qXb?id`l7rF3$Z7L^v470j7iT$=B25sD}N)Xab$V(0#J`TO4jxKeBJcsr{!%~z+_L?bPl zd%YH{)%*tg{y*Hf0Q5?OQ7s$^gv|12z{d^`7zba(q3%w@)Y=-fhyl8{nwQN;XjIo3 z*4U8YKYV*A8tHm4CfTrzecu@cV6q_l=-w+H;B1mqHaXa1Z%n!aZJTSg4bebEGp^So zL0_#F)IB~{_tEH8=oSu7FzAYgyiJaXM&_o#zdqn=(afe=&5TAu4IWaAg}?XRwZk~F zskP{lPPa~>A8KJEhfjEAAmDmin-((J%U3=7AOsTqAsX?(jP{r^d+r$2NFmJxt1@4} z)FXl$+gta$*_=bvF!eTSZEq(uxZ%W$U>q@#AA)eY-O*MJh+9r6tAcV z1rd+M|FPhO0RV~ce9Gp056Pu0644{vW9In0ulf;0+o*ZjO(#!}gDvn7H8mF4d3-M? zxY3MwTtQEZ!Jb{=%7ij5@_-q$%GZB?>`Um ziN-hBkO`N(3VSTq+M2aUm8VT(-<^2iNkqH=)p$rf^7x6(3lRwd7}xsdC!bjar&1D* z1~rOe3a)mI`!1Zh-2*xx8q@8zQv;VG@j)|gfY%<)_^ATa=*CL+;;OqZu>fvh5!Z(r zk~Nwb?3uH>g0NndPOun`%dX%i$H2QnLgxqd#tJdaW=MHY~fD_%z$|{?Z4!e5N1!D9Pk_{)l(d_AlPfjRt6h)&F(^2U!omro?y{}oj7`v z6Sh&+l(*P{@mKQUOTp@wm$NymPubDmW3UjVxnP-(&CJ+2a0Rb8kD*>T#>nL&s)sK9 z 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 RKUTaVBaseObjectClass = NewBaseObjectClass; } +void FConfigVariableDescriptor::SetupAsRawJsonValue() { + this->VariableType = EConfigVariableType::ECVT_RawJsonValue; +} + UScriptStruct* FConfigVariableDescriptor::GetCustomStructType() const { if (VariableType == EConfigVariableType::ECVT_CustomStruct) return CustomStructType; diff --git a/Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableLibrary.cpp b/Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableLibrary.cpp old mode 100644 new mode 100755 index e45337c25d..9a36460cdd --- a/Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableLibrary.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/CodeGeneration/ConfigVariableLibrary.cpp @@ -49,3 +49,9 @@ FConfigVariableDescriptor UConfigVariableLibrary::MakeConfigVariableMap(const FC VariableDescriptor.SetupAsMap(KeyType, ValueType); return VariableDescriptor; } + +FConfigVariableDescriptor UConfigVariableLibrary::MakeConfigVariableRawJsonValue() { + FConfigVariableDescriptor VariableDescriptor{}; + VariableDescriptor.SetupAsRawJsonValue(); + return VariableDescriptor; +} \ No newline at end of file diff --git a/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyRaw.cpp b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyRaw.cpp new file mode 100755 index 0000000000..c2efb192fa --- /dev/null +++ b/Mods/SML/Source/SML/Private/Configuration/Properties/ConfigPropertyRaw.cpp @@ -0,0 +1,81 @@ +#include "Configuration/Properties/ConfigPropertyRaw.h" +#include "Configuration/CodeGeneration/ConfigVariableDescriptor.h" +#include "Configuration/CodeGeneration/ConfigVariableLibrary.h" +#include "Configuration/RawFileFormat/RawFormatValueRawJson.h" +#include "Reflection/BlueprintReflectedObject.h" + +void UConfigPropertyRaw::SetValue(TSharedPtr NewValue) { + Value = NewValue.ToSharedRef(); +} + +void UConfigPropertyRaw::SetValue(TSharedPtr NewValue) { + Value = MakeShared(NewValue); +} + +FString UConfigPropertyRaw::DescribeValue_Implementation() const { + return TEXT("[raw]"); +} + +URawFormatValue* UConfigPropertyRaw::Serialize_Implementation(UObject* Outer) const { + URawFormatValueRawJson* JsonValue = NewObject(Outer); + JsonValue->Value = Value; + return JsonValue; +} + +void UConfigPropertyRaw::Deserialize_Implementation(const URawFormatValue* RawValue) { + const URawFormatValueRawJson* JsonValue = Cast(RawValue); + Value = JsonValue->Value; +} + +void UConfigPropertyRaw::FillConfigStruct_Implementation( + const FReflectedObject& ReflectedObject, const FString& VariableName) const { + checkf(false, TEXT("UConfigPropertyRaw::FillConfigStruct_Implementation: not supported")); +} + +bool UConfigPropertyRaw::ResetToDefault_Implementation() { + return false; +} + +bool UConfigPropertyRaw::IsSetToDefaultValue_Implementation() const { + return false; +} + +FString UConfigPropertyRaw::GetDefaultValueAsString_Implementation() const { + return TEXT(""); +} + +FConfigVariableDescriptor UConfigPropertyRaw::CreatePropertyDescriptor_Implementation( + UConfigGenerationContext* Context, const FString& OuterPath) const { + return UConfigVariableLibrary::MakeConfigVariablePrimitive(EConfigVariableType::ECVT_RawJsonValue); +} + +void UConfigPropertyRaw::PostInitProperties() { + Super::PostInitProperties(); + + bHidden = 1; + bAllowUserReset = false; + bRequiresWorldReload = 0; +} + +#if WITH_EDITOR +bool UConfigPropertyRaw::CanEditChange(const FProperty* InProperty) const { + auto Name = InProperty->GetFName(); + if (Name == GET_MEMBER_NAME_CHECKED(UConfigPropertyRaw, bHidden)) { + return false; + } + if (Name == GET_MEMBER_NAME_CHECKED(UConfigPropertyRaw, bAllowUserReset)) { + return false; + } + if (Name == GET_MEMBER_NAME_CHECKED(UConfigPropertyRaw, bRequiresWorldReload)) { + return false; + } + if (Name == GET_MEMBER_NAME_CHECKED(UConfigPropertyRaw, DisplayName)) { + return false; + } + if (Name == GET_MEMBER_NAME_CHECKED(UConfigPropertyRaw, Tooltip)) { + return false; + } + + return Super::CanEditChange(InProperty); +} +#endif diff --git a/Mods/SML/Source/SML/Private/Configuration/Properties/WidgetExtension/CP_Raw.cpp b/Mods/SML/Source/SML/Private/Configuration/Properties/WidgetExtension/CP_Raw.cpp new file mode 100644 index 0000000000..cea54093e0 --- /dev/null +++ b/Mods/SML/Source/SML/Private/Configuration/Properties/WidgetExtension/CP_Raw.cpp @@ -0,0 +1 @@ +#include "Configuration/Properties/WidgetExtension/CP_Raw.h" diff --git a/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp b/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp index eda50ef44b..46eee4049d 100755 --- a/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp +++ b/Mods/SML/Source/SML/Private/Configuration/RawFileFormat/Json/JsonRawFormatConverter.cpp @@ -3,6 +3,7 @@ #include "Configuration/RawFileFormat/RawFormatValueBool.h" #include "Configuration/RawFileFormat/RawFormatValueNumber.h" #include "Configuration/RawFileFormat/RawFormatValueObject.h" +#include "Configuration/RawFileFormat/RawFormatValueRawJson.h" #include "Configuration/RawFileFormat/RawFormatValueString.h" #include "Dom/JsonObject.h" @@ -22,6 +23,9 @@ TSharedPtr FJsonRawFormatConverter::ConvertToJson(const URawFormatVa if (const URawFormatValueObject* Object = Cast(RawFormatValue)) { return Object->ToJson(); } + if (const URawFormatValueRawJson* RawJson = Cast(RawFormatValue)) { + return RawJson->ToJson(); + } checkf(false, TEXT("Unreachable code")); return NULL; } diff --git a/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableDescriptor.h b/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableDescriptor.h old mode 100644 new mode 100755 index 7477e770a8..4a4c8bbc37 --- a/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableDescriptor.h +++ b/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableDescriptor.h @@ -16,7 +16,8 @@ enum class EConfigVariableType : uint8 { ECVT_Object UMETA(DisplayName = "Object"), ECVT_Class UMETA(DisplayName = "Class"), ECVT_CustomStruct UMETA(DisplayName = "Custom Structure"), - ECVT_ConfigGeneratedStruct UMETA(DisplayName = "Config Generated Struct (delayed)") + ECVT_ConfigGeneratedStruct UMETA(DisplayName = "Config Generated Struct (delayed)"), + ECVT_RawJsonValue UMETA(DisplayName = "Raw Json Value") }; /** Describes variable generated by the config property and associated metadata */ @@ -45,6 +46,8 @@ struct SML_API FConfigVariableDescriptor { void SetupAsClass(UClass* BaseClassType); + void SetupAsRawJsonValue(); + /** Type of the generated variable. Decides which of the settings below are applied */ FORCEINLINE EConfigVariableType GetVariableType() const { return VariableType; } diff --git a/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableLibrary.h b/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableLibrary.h old mode 100644 new mode 100755 index e6b340e364..3527ad2702 --- a/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableLibrary.h +++ b/Mods/SML/Source/SML/Public/Configuration/CodeGeneration/ConfigVariableLibrary.h @@ -68,6 +68,10 @@ class SML_API UConfigVariableLibrary : public UBlueprintFunctionLibrary { UFUNCTION(BlueprintPure, Category="ConfigVariables", meta=(DisplayName = "Make Config Variable (Map)", Keywords="construct build", NativeMakeFunc)) static FConfigVariableDescriptor MakeConfigVariableMap(const FConfigVariableDescriptor& KeyType, const FConfigVariableDescriptor& ValueType); + /** Creates new instance of raw json value config variable */ + UFUNCTION(BlueprintPure, Category="ConfigVariables", meta=(DisplayName = "Make Config Variable (Raw Json Value)", Keywords="construct build", NativeMakeFunc)) + static FConfigVariableDescriptor MakeConfigVariableRawJsonValue(); + DECLARE_FUNCTION(execMakeConfigVariableStruct) { const FDynamicStructInfo StructInfo = FReflectionHelper::CheckStructParameter(Context, Stack); P_FINISH; diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyRaw.h b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyRaw.h new file mode 100755 index 0000000000..6c8dcd2895 --- /dev/null +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/ConfigPropertyRaw.h @@ -0,0 +1,47 @@ +#pragma once +#include "Configuration/ConfigProperty.h" +#include "Configuration/ConfigValueDirtyHandlerInterface.h" +#include "Configuration/RawFileFormat/RawFormatValueRawJson.h" +#include "ConfigPropertyRaw.generated.h" + +/** + * Describes a raw configuration property not designed to be edited by the player. + * + * Note: Changes to this property's value will need to be made through C++ code. + * Blueprint editing of this property is not supported. + */ +UCLASS() +class SML_API UConfigPropertyRaw : public UConfigProperty { + GENERATED_BODY() +public: + TSharedRef Value = MakeShared(); + + void SetValue(TSharedPtr NewValue); + void SetValue(TSharedPtr NewValue); + + // Begin UConfigProperty +public: + virtual FString DescribeValue_Implementation() const override; + virtual URawFormatValue* Serialize_Implementation(UObject* Outer) const override; + virtual void Deserialize_Implementation(const URawFormatValue* Value) override; + virtual FConfigVariableDescriptor CreatePropertyDescriptor_Implementation( UConfigGenerationContext* Context, const FString& OuterPath) const override; + virtual void FillConfigStruct_Implementation(const FReflectedObject& ReflectedObject, const FString& VariableName) const override; + virtual bool ResetToDefault_Implementation() override; + virtual bool IsSetToDefaultValue_Implementation() const override; + virtual FString GetDefaultValueAsString_Implementation() const override; + + virtual URawFormatValueRawJson* CreateRawFormatValue(UObject* Outer, const TSharedPtr& JsonValue) override { + return URawFormatValueRawJson::FromJson(Outer, JsonValue); + } + // End UConfigProperty + + // Begin UObject +protected: + virtual void PostInitProperties() override; + +public: +#if WITH_EDITOR + virtual bool CanEditChange(const FProperty* InProperty) const override; +#endif + // End UObject +}; diff --git a/Mods/SML/Source/SML/Public/Configuration/Properties/WidgetExtension/CP_Raw.h b/Mods/SML/Source/SML/Public/Configuration/Properties/WidgetExtension/CP_Raw.h new file mode 100644 index 0000000000..d21edef65a --- /dev/null +++ b/Mods/SML/Source/SML/Public/Configuration/Properties/WidgetExtension/CP_Raw.h @@ -0,0 +1,9 @@ +#pragma once +#include "Configuration/Properties/ConfigPropertyRaw.h" +#include "CP_Raw.generated.h" + +UCLASS(EditInlineNew, Abstract) +class SML_API UCP_Raw : public UConfigPropertyRaw { + GENERATED_BODY() +public: +}; diff --git a/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueRawJson.h b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueRawJson.h new file mode 100755 index 0000000000..04436858cb --- /dev/null +++ b/Mods/SML/Source/SML/Public/Configuration/RawFileFormat/RawFormatValueRawJson.h @@ -0,0 +1,32 @@ +#pragma once +#include "Configuration/RawFileFormat/RawFormatValue.h" +#include "CoreMinimal.h" +#include "RawFormatValueRawJson.generated.h" + +/** + * Holds a raw JSON value. + * + * Note: Changes to this value will need to be made through C++ code. + * Blueprint editing of this value is not supported. + */ +UCLASS() +class SML_API URawFormatValueRawJson : public URawFormatValue { + GENERATED_BODY() +public: + TSharedRef Value = MakeShared(); + + virtual TSharedPtr ToJson() const override; + + /** Creates a new URawFormatValueRawJson from the given JSON value */ + static URawFormatValueRawJson* FromJson(UObject* Outer, const TSharedPtr& JsonValue); +}; + +FORCEINLINE TSharedPtr URawFormatValueRawJson::ToJson() const { + return Value.ToSharedPtr(); +} + +FORCEINLINE URawFormatValueRawJson* URawFormatValueRawJson::FromJson(UObject* Outer, const TSharedPtr& JsonValue) { + URawFormatValueRawJson* JsonValueWrapper = NewObject(Outer); + JsonValueWrapper->Value = JsonValue.ToSharedRef(); + return JsonValueWrapper; +} \ No newline at end of file