diff --git a/Config/FilterPlugin.ini b/Config/FilterPlugin.ini new file mode 100644 index 0000000..ccebca2 --- /dev/null +++ b/Config/FilterPlugin.ini @@ -0,0 +1,8 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll diff --git a/Source/JsonSerialization/Private/JsonSerialization.cpp b/Source/JsonSerialization/Private/JsonSerialization.cpp index 5e537bf..c5b424e 100644 --- a/Source/JsonSerialization/Private/JsonSerialization.cpp +++ b/Source/JsonSerialization/Private/JsonSerialization.cpp @@ -18,34 +18,86 @@ void FJsonSerializationModule::ShutdownModule() // we call this function before unloading the module. } -template -static TArray> SerializePropertyAsJsonArray(const T* Data, FArrayProperty* Property, TSet& TraversedObjects) +// The two serialization functions depend on each other. I don't think you can forward declare template functions +// so they're both in this struct +template +struct FUObjectSerializer { - const uint8* PropData = Property->ContainerPtrToValuePtr(Data); - FScriptArrayHelper Helper(Property, PropData); - TArray> ValueArray; + static TArray> SerializePropertyAsJsonArray(const T* Data, FArrayProperty* Property, TSet& TraversedObjects) + { + const uint8* PropData = Property->ContainerPtrToValuePtr(Data); + FScriptArrayHelper Helper(Property, PropData); + TArray> ValueArray; + + for (int32 i = 0, n = Helper.Num(); i < n; ++i) + { + const uint8* InnerPropData = Helper.GetRawPtr(i); + if (FArrayProperty* ArrayProperty = CastField(Property->Inner)) // Array + { + TArray> InnerArray = FUObjectSerializer::SerializePropertyAsJsonArray(InnerPropData, ArrayProperty, TraversedObjects); + ValueArray.Emplace(new FJsonValueArray(InnerArray)); + } + else if (FStructProperty* StructProperty = CastField(Property->Inner)) // Struct + { + TSharedPtr StructObject = MakeShareable(new FJsonObject); + const uint8* StructPropData = StructProperty->ContainerPtrToValuePtr(InnerPropData); + for (TFieldIterator PropertyItr(StructProperty->Struct); PropertyItr; ++PropertyItr) + { + FUObjectSerializer::SerializePropertyAsJsonObjectField((void*)StructPropData, StructObject, *PropertyItr, TraversedObjects); + } + ValueArray.Emplace(new FJsonValueObject(StructObject)); + } + else if (FObjectProperty* ObjectProperty = CastField(Property->Inner)) // Object + { + const UObject* SubObject = ObjectProperty->GetObjectPropertyValue_InContainer(InnerPropData); + if (SubObject->IsValidLowLevel() && !TraversedObjects.Contains(SubObject)) + { + TraversedObjects.Add(SubObject); + TSharedPtr JsonSubObject = MakeShared(); + for (TFieldIterator PropertyItr(SubObject->GetClass()); PropertyItr; ++PropertyItr) + { + SerializePropertyAsJsonObjectField(SubObject, JsonSubObject, *PropertyItr, TraversedObjects); + } + ValueArray.Emplace(new FJsonValueObject(JsonSubObject)); + } + } + else + { + TSharedPtr JsonValue; + const uint8* InnerInnerPropData = Property->Inner->ContainerPtrToValuePtr(InnerPropData); + ValueArray.Emplace(FJsonObjectConverter::UPropertyToJsonValue(Property->Inner, InnerInnerPropData)); + } + } + return ValueArray; + } - for (int32 i = 0, n = Helper.Num(); i < n; ++i) + static void SerializePropertyAsJsonObjectField(const T* Data, TSharedPtr OuterObject, FProperty* Property, TSet& TraversedObjects) { - const uint8* InnerPropData = Helper.GetRawPtr(i); - if (FArrayProperty* ArrayProperty = CastField(Property->Inner)) // Array + if (Property->GetName() == "UberGraphFrame" + || Property->HasAnyPropertyFlags(CPF_Transient)) { - TArray> InnerArray = SerializePropertyAsJsonArray(InnerPropData, ArrayProperty, TraversedObjects); - ValueArray.Emplace(new FJsonValueArray(InnerArray)); + // Don't include "UberGraphFrame" or any transient properties + return; } - else if (FStructProperty* StructProperty = CastField(Property->Inner)) // Struct + + if (FArrayProperty* ArrayProperty = CastField(Property)) // Array + { + TArray> Values = SerializePropertyAsJsonArray(Data, ArrayProperty, TraversedObjects); + OuterObject->SetArrayField(Property->GetAuthoredName(), Values); + } + else if (FStructProperty* StructProperty = CastField(Property)) // Struct { TSharedPtr StructObject = MakeShareable(new FJsonObject); - const uint8* StructPropData = StructProperty->ContainerPtrToValuePtr(InnerPropData); + const uint8* PropData = Property->ContainerPtrToValuePtr(Data); for (TFieldIterator PropertyItr(StructProperty->Struct); PropertyItr; ++PropertyItr) { - SerializePropertyAsJsonObjectField((void*)StructPropData, StructObject, *PropertyItr, TraversedObjects); + FUObjectSerializer::SerializePropertyAsJsonObjectField((void*)PropData, StructObject, *PropertyItr, TraversedObjects); } - ValueArray.Emplace(new FJsonValueObject(StructObject)); + OuterObject->SetObjectField(Property->GetAuthoredName(), StructObject); } - else if (FObjectProperty* ObjectProperty = CastField(Property->Inner)) // Object + else if (FObjectProperty* ObjectProperty = CastField(Property)) // Object { - const UObject* SubObject = ObjectProperty->GetObjectPropertyValue_InContainer(InnerPropData); + const UObject* SubObject = ObjectProperty->GetObjectPropertyValue_InContainer(Data); if (SubObject->IsValidLowLevel() && !TraversedObjects.Contains(SubObject)) { TraversedObjects.Add(SubObject); @@ -54,65 +106,17 @@ static TArray> SerializePropertyAsJsonArray(const T* Data { SerializePropertyAsJsonObjectField(SubObject, JsonSubObject, *PropertyItr, TraversedObjects); } - ValueArray.Emplace(new FJsonValueObject(JsonSubObject)); + OuterObject->SetObjectField(Property->GetAuthoredName(), JsonSubObject); } } else { TSharedPtr JsonValue; - const uint8* InnerInnerPropData = Property->Inner->ContainerPtrToValuePtr(InnerPropData); - ValueArray.Emplace(FJsonObjectConverter::UPropertyToJsonValue(Property->Inner, InnerInnerPropData)); - } - } - return ValueArray; -} - -template -static void SerializePropertyAsJsonObjectField(const T* Data, TSharedPtr OuterObject, FProperty* Property, TSet& TraversedObjects) -{ - if (Property->GetName() == "UberGraphFrame" - || Property->HasAnyPropertyFlags(CPF_Transient)) - { - // Don't include "UberGraphFrame" or any transient properties - return; - } - - if (FArrayProperty* ArrayProperty = CastField(Property)) // Array - { - TArray> Values = SerializePropertyAsJsonArray(Data, ArrayProperty, TraversedObjects); - OuterObject->SetArrayField(Property->GetAuthoredName(), Values); - } - else if (FStructProperty* StructProperty = CastField(Property)) // Struct - { - TSharedRef StructObject = MakeShareable(new FJsonObject); - const uint8* PropData = Property->ContainerPtrToValuePtr(Data); - for (TFieldIterator PropertyItr(StructProperty->Struct); PropertyItr; ++PropertyItr) - { - SerializePropertyAsJsonObjectField((void*)PropData, StructObject, *PropertyItr, TraversedObjects); + const uint8* PropData = Property->ContainerPtrToValuePtr(Data); + OuterObject->SetField(Property->GetAuthoredName(), FJsonObjectConverter::UPropertyToJsonValue(Property, PropData)); } - OuterObject->SetObjectField(Property->GetAuthoredName(), StructObject.ToSharedPtr()); } - else if (FObjectProperty* ObjectProperty = CastField(Property)) // Object - { - const UObject* SubObject = ObjectProperty->GetObjectPropertyValue_InContainer(Data); - if (SubObject->IsValidLowLevel() && !TraversedObjects.Contains(SubObject)) - { - TraversedObjects.Add(SubObject); - TSharedPtr JsonSubObject = MakeShared(); - for (TFieldIterator PropertyItr(SubObject->GetClass()); PropertyItr; ++PropertyItr) - { - SerializePropertyAsJsonObjectField(SubObject, JsonSubObject, *PropertyItr, TraversedObjects); - } - OuterObject->SetObjectField(Property->GetAuthoredName(), JsonSubObject); - } - } - else - { - TSharedPtr JsonValue; - const uint8* PropData = Property->ContainerPtrToValuePtr(Data); - OuterObject->SetField(Property->GetAuthoredName(), FJsonObjectConverter::UPropertyToJsonValue(Property, PropData)); - } -} +}; TSharedPtr FJsonSerializationModule::SerializeUObjectToJson(const UObject* Object) { @@ -123,7 +127,7 @@ TSharedPtr FJsonSerializationModule::SerializeUObjectToJson(const U for (TFieldIterator PropertyItr(Object->GetClass()); PropertyItr; ++PropertyItr) { - SerializePropertyAsJsonObjectField(Object, JsonObject, *PropertyItr, TraversedObjects); + FUObjectSerializer::SerializePropertyAsJsonObjectField(Object, JsonObject, *PropertyItr, TraversedObjects); } return JsonObject; diff --git a/Source/JsonSerialization/Public/JsonSerialization.h b/Source/JsonSerialization/Public/JsonSerialization.h index 01963f3..7ee12bb 100644 --- a/Source/JsonSerialization/Public/JsonSerialization.h +++ b/Source/JsonSerialization/Public/JsonSerialization.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Dom/JsonObject.h" #include "Modules/ModuleManager.h" class JSONSERIALIZATION_API FJsonSerializationModule : public IModuleInterface diff --git a/Source/JsonSerialization/Public/JsonSerializationBlueprintFunctionLibrary.h b/Source/JsonSerialization/Public/JsonSerializationBlueprintFunctionLibrary.h index fd80468..c9419b3 100644 --- a/Source/JsonSerialization/Public/JsonSerializationBlueprintFunctionLibrary.h +++ b/Source/JsonSerialization/Public/JsonSerializationBlueprintFunctionLibrary.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" +#include "JsonObjectWrapper.h" #include "JsonSerializationBlueprintFunctionLibrary.generated.h" /** @@ -16,5 +17,5 @@ class JSONSERIALIZATION_API UJsonSerializationBlueprintFunctionLibrary : public public: UFUNCTION(BlueprintPure, Category = "Json Serialization") - static struct FJsonObjectWrapper ObjectToJson(const UObject* Object); + static FJsonObjectWrapper ObjectToJson(const UObject* Object); };