From cea8c715b56db8b0cd81a7b35a1dbca498294448 Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Sat, 4 Nov 2023 19:35:20 +0300 Subject: [PATCH 1/7] #46 Added getting of integer UPROPERTY of UCLASS --- Config/DefaultGame.ini | 2 +- Source/Cloud9/Game/Cloud9DeveloperSettings.h | 19 ++-- Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp | 93 ++++++++++++++++++++ Source/Cloud9/Tools/Cloud9ToolsLibrary.h | 2 + 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index 6fbf2c699..fb05f57a3 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -13,6 +13,6 @@ InsertPack = (PackSource="StarterContent.upack",PackName="StarterContent") [/Script/Cloud9.Cloud9DeveloperSettings] bIsDrawHitCursorLine=False bIsDrawDeprojectedCursorLine=False -bIsShowMouseCursor=False +bIsShowMouseCursor=True NetGraph=1 diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.h b/Source/Cloud9/Game/Cloud9DeveloperSettings.h index 3fd6d84a4..41182fae8 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.h +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "Cloud9/Cloud9.h" +#include "Cloud9/Tools/Cloud9ToolsLibrary.h" #include "Cloud9DeveloperSettings.generated.h" UCLASS(Config=Game, defaultconfig, meta = (DisplayName="Save Game Settings")) @@ -16,14 +17,16 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings static auto bIsLoaded = false; static const auto Settings = GetDefault(); - if (!bIsLoaded) - { - UE_LOG(LogCloud9, Display, TEXT("IsDrawHitCursorLine: %d"), Settings->bIsShowMouseCursor); - UE_LOG(LogCloud9, Display, TEXT("IsDrawDeprojectedCursorLine: %d"), Settings->bIsDrawDeprojectedCursorLine); - UE_LOG(LogCloud9, Display, TEXT("IsShowMouseCursor: %d"), Settings->bIsShowMouseCursor); - UE_LOG(LogCloud9, Display, TEXT("NetGraph: %d"), Settings->NetGraph); - bIsLoaded = true; - } + // if (!bIsLoaded) + // { + UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ToolsLibrary::UObjectToString(Settings)); + + // UE_LOG(LogCloud9, Display, TEXT("IsDrawHitCursorLine: %d"), Settings->bIsShowMouseCursor); + // UE_LOG(LogCloud9, Display, TEXT("IsDrawDeprojectedCursorLine: %d"), Settings->bIsDrawDeprojectedCursorLine); + // UE_LOG(LogCloud9, Display, TEXT("IsShowMouseCursor: %d"), Settings->bIsShowMouseCursor); + // UE_LOG(LogCloud9, Display, TEXT("NetGraph: %d"), Settings->NetGraph); + // bIsLoaded = true; + // } return Settings; } diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp index 50e62eadd..24f2df33b 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp @@ -1,4 +1,6 @@ #include "Cloud9ToolsLibrary.h" + +#include "Cloud9/Cloud9.h" #include "Cloud9/Game/Cloud9GameMode.h" void UCloud9ToolsLibrary::SetCollisionComplexity(UStaticMesh* StaticMesh, uint8 CollisionTraceFlag) @@ -99,3 +101,94 @@ FVector UCloud9ToolsLibrary::VInterpTo( ClampLerp(Current.Z, Dist.Z, Alpha.Z, Target.Z), }; } + +template +class FPropertyToString +{ +public: + using TCppType = typename TType::TCppType; + using TGetter = TFunction; + + FPropertyToString(const UObject* Container, const FProperty* ToConvert) + { + static_assert(TIsDerivedFrom::Value, "Type should be inherited from FProperty"); + Object = Container; + Property = ToConvert; + } + + FPropertyToString& UseGetter(TGetter NewGetter) + { + Getter = NewGetter; + return *this; + } + + TOptional Convert() + { + if (const auto TypedProperty = CastField(Property)) + { + const auto Name = Property->GetFName(); + const auto TypeName = Property->GetCPPType(); + const auto ActualGetter = Getter.Get(&FPropertyToString::DefaultGetter); + const auto Value = ActualGetter(Object, TypedProperty); + return FString::Printf(TEXT("\t%s: %s = %s\n"), *Name.ToString(), *TypeName, *LexToString(Value)); + } + + return {}; + } + + bool AppendTo(FString& String) + { + if (const auto Converted = Convert(); Converted.IsSet()) + { + String += Converted.GetValue(); + return true; + } + + return false; + } + +private: + static TCppType DefaultGetter(const UObject* Object, const TType* Property) + { + if constexpr (!TIsSame::Value) + { + const auto ValuePtr = Property->template ContainerPtrToValuePtr(Object); + return TType::GetPropertyValue(ValuePtr); + } + + UE_LOG(LogCloud9, Fatal, TEXT("Default getter not exists for FBoolProperty")) + return false; + } + + const UObject* Object; + const FProperty* Property; + TOptional Getter; +}; + + +FString UCloud9ToolsLibrary::UObjectToString(const UObject* Object) +{ + FString String; + const auto Class = Object->GetClass(); + + String += FString::Printf(TEXT("class %s {\n"), *Class->GetName()); + for (TFieldIterator PropertyIterator(Class); PropertyIterator; ++PropertyIterator) + { + const auto Property = *PropertyIterator; + + FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property).AppendTo(String) + || FPropertyToString(Object, Property) + .UseGetter([](auto Object, auto Property) { return true; }) + .AppendTo(String); + } + String += FString::Printf(TEXT("}")); + + return String; +} diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.h b/Source/Cloud9/Tools/Cloud9ToolsLibrary.h index c4a3e3361..a8fe747c0 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.h +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.h @@ -67,4 +67,6 @@ class CLOUD9_API UCloud9ToolsLibrary : public UBlueprintFunctionLibrary const FVector Target, float DeltaTime, const FVector InterpSpeed); + + static FString UObjectToString(const UObject* Object); }; From 09ee48b0dc1d6c07d86d8f797d7791c3fe4b1e61 Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Sun, 5 Nov 2023 13:38:19 +0300 Subject: [PATCH 2/7] #46 Refactored getting UPROPERTY value using template spec. --- Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp | 98 +++++++--------------- 1 file changed, 30 insertions(+), 68 deletions(-) diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp index 24f2df33b..750daa15c 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp @@ -103,68 +103,31 @@ FVector UCloud9ToolsLibrary::VInterpTo( } template -class FPropertyToString +typename TType::TCppType UPropertyGetValue(const UObject* Object, const TType* Property) { -public: - using TCppType = typename TType::TCppType; - using TGetter = TFunction; + const auto Ptr = Property->template ContainerPtrToValuePtr(Object); + return TType::GetPropertyValue(Ptr); +} - FPropertyToString(const UObject* Container, const FProperty* ToConvert) - { - static_assert(TIsDerivedFrom::Value, "Type should be inherited from FProperty"); - Object = Container; - Property = ToConvert; - } - - FPropertyToString& UseGetter(TGetter NewGetter) - { - Getter = NewGetter; - return *this; - } - - TOptional Convert() - { - if (const auto TypedProperty = CastField(Property)) - { - const auto Name = Property->GetFName(); - const auto TypeName = Property->GetCPPType(); - const auto ActualGetter = Getter.Get(&FPropertyToString::DefaultGetter); - const auto Value = ActualGetter(Object, TypedProperty); - return FString::Printf(TEXT("\t%s: %s = %s\n"), *Name.ToString(), *TypeName, *LexToString(Value)); - } - - return {}; - } - - bool AppendTo(FString& String) - { - if (const auto Converted = Convert(); Converted.IsSet()) - { - String += Converted.GetValue(); - return true; - } - - return false; - } +template <> +bool UPropertyGetValue(const UObject* Object, const FBoolProperty* Property) +{ + return false; +} -private: - static TCppType DefaultGetter(const UObject* Object, const TType* Property) +template +typename TType::TCppType UPropertyAppendTo(FString& String, const UObject* Object, const FProperty* Property) +{ + if (const auto TypedProperty = CastField(Property)) { - if constexpr (!TIsSame::Value) - { - const auto ValuePtr = Property->template ContainerPtrToValuePtr(Object); - return TType::GetPropertyValue(ValuePtr); - } - - UE_LOG(LogCloud9, Fatal, TEXT("Default getter not exists for FBoolProperty")) - return false; + const auto Name = Property->GetFName(); + const auto TypeName = Property->GetCPPType(); + const auto Value = UPropertyGetValue(Object, TypedProperty); + String += FString::Printf(TEXT("\t%s: %s = %s\n"), *Name.ToString(), *TypeName, *LexToString(Value)); + return true; } - - const UObject* Object; - const FProperty* Property; - TOptional Getter; -}; - + return false; +} FString UCloud9ToolsLibrary::UObjectToString(const UObject* Object) { @@ -176,17 +139,16 @@ FString UCloud9ToolsLibrary::UObjectToString(const UObject* Object) { const auto Property = *PropertyIterator; - FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property).AppendTo(String) - || FPropertyToString(Object, Property) - .UseGetter([](auto Object, auto Property) { return true; }) - .AppendTo(String); + UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + || UPropertyAppendTo(String, Object, Property) + ; } String += FString::Printf(TEXT("}")); From f2382a90904c131dc66a9f18a5fec53588d343da Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Sun, 5 Nov 2023 13:45:15 +0300 Subject: [PATCH 3/7] #46 Added get value for bool variable --- Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp index 750daa15c..083a6a27b 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp @@ -112,7 +112,7 @@ typename TType::TCppType UPropertyGetValue(const UObject* Object, const TType* P template <> bool UPropertyGetValue(const UObject* Object, const FBoolProperty* Property) { - return false; + return Property->GetPropertyValue_InContainer(Object); } template From ec2a9afa69c163d126cb67786fbb589bc0d7fcc0 Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Sun, 5 Nov 2023 17:30:33 +0300 Subject: [PATCH 4/7] #46 Separated Tools and Reflection library --- Config/DefaultGame.ini | 3 +- Source/Cloud9/Cloud9.h | 3 + .../Cloud9/Game/Cloud9DeveloperSettings.cpp | 28 ++++ Source/Cloud9/Game/Cloud9DeveloperSettings.h | 38 +++-- .../Cloud9/Tools/Cloud9ReflectionLibrary.cpp | 139 ++++++++++++++++++ Source/Cloud9/Tools/Cloud9ReflectionLibrary.h | 53 +++++++ Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp | 106 +++++-------- Source/Cloud9/Tools/Cloud9ToolsLibrary.h | 26 +++- 8 files changed, 305 insertions(+), 91 deletions(-) create mode 100644 Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp create mode 100644 Source/Cloud9/Tools/Cloud9ReflectionLibrary.h diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index fb05f57a3..55f4e898e 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -13,6 +13,7 @@ InsertPack = (PackSource="StarterContent.upack",PackName="StarterContent") [/Script/Cloud9.Cloud9DeveloperSettings] bIsDrawHitCursorLine=False bIsDrawDeprojectedCursorLine=False -bIsShowMouseCursor=True +bIsShowMouseCursor=False NetGraph=1 +UnUsedEnum=Everything diff --git a/Source/Cloud9/Cloud9.h b/Source/Cloud9/Cloud9.h index b9135291b..8f4e3a927 100644 --- a/Source/Cloud9/Cloud9.h +++ b/Source/Cloud9/Cloud9.h @@ -5,3 +5,6 @@ #include "CoreMinimal.h" DECLARE_LOG_CATEGORY_EXTERN(LogCloud9, Log, All); + +#define let const auto +#define var auto \ No newline at end of file diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp index 9da0ec927..d18b078ee 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp @@ -1 +1,29 @@ #include "Cloud9DeveloperSettings.h" + +#include "Cloud9/Cloud9.h" +#include "Cloud9/Tools/Cloud9ReflectionLibrary.h" + +const UCloud9DeveloperSettings* UCloud9DeveloperSettings::GetCloud9DeveloperSettings() +{ + static var bIsInitialized = false; + static let Settings = GetDefault(); + + if (!bIsInitialized) + { + Cast(Settings)->Log(); + bIsInitialized = true; + } + + return Settings; +} + +void UCloud9DeveloperSettings::Save() +{ + UpdateDefaultConfigFile(); + Log(); +} + +void UCloud9DeveloperSettings::Log() const +{ + UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ReflectionLibrary::UObjectToString(this)); +} diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.h b/Source/Cloud9/Game/Cloud9DeveloperSettings.h index 41182fae8..ef427c892 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.h +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.h @@ -1,10 +1,17 @@ #pragma once #include "CoreMinimal.h" -#include "Cloud9/Cloud9.h" -#include "Cloud9/Tools/Cloud9ToolsLibrary.h" #include "Cloud9DeveloperSettings.generated.h" +UENUM() +enum class EUnUsedEnum : int32 +{ + Special = 0, + Anything = 1, + Everything = 2, + Whatever = 3, +}; + UCLASS(Config=Game, defaultconfig, meta = (DisplayName="Save Game Settings")) class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings { @@ -12,27 +19,13 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings public: UFUNCTION(BlueprintCallable, Category=Settings) - static const UCloud9DeveloperSettings* GetCloud9DeveloperSettings() - { - static auto bIsLoaded = false; - static const auto Settings = GetDefault(); - - // if (!bIsLoaded) - // { - UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ToolsLibrary::UObjectToString(Settings)); - - // UE_LOG(LogCloud9, Display, TEXT("IsDrawHitCursorLine: %d"), Settings->bIsShowMouseCursor); - // UE_LOG(LogCloud9, Display, TEXT("IsDrawDeprojectedCursorLine: %d"), Settings->bIsDrawDeprojectedCursorLine); - // UE_LOG(LogCloud9, Display, TEXT("IsShowMouseCursor: %d"), Settings->bIsShowMouseCursor); - // UE_LOG(LogCloud9, Display, TEXT("NetGraph: %d"), Settings->NetGraph); - // bIsLoaded = true; - // } - - return Settings; - } + static const UCloud9DeveloperSettings* GetCloud9DeveloperSettings(); UFUNCTION(BlueprintCallable) - void Save() { UpdateDefaultConfigFile(); } + void Save(); + + UFUNCTION(BlueprintCallable) + void Log() const; // Debug @@ -47,4 +40,7 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = "Debug") int NetGraph; + + UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = "Debug") + EUnUsedEnum UnUsedEnum; }; diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp new file mode 100644 index 000000000..252f27aad --- /dev/null +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp @@ -0,0 +1,139 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "Cloud9ReflectionLibrary.h" + +#include "Cloud9/Cloud9.h" + +auto LexToString(const FText& Text) { return *Text.ToString(); } + +template +TResult UCloud9ReflectionLibrary::UPropertyGetValue(const UObject* Object, const TType* Property) +{ + let Ptr = Property->template ContainerPtrToValuePtr(Object); + return TType::GetPropertyValue(Ptr); +} + +template <> +bool UCloud9ReflectionLibrary::UPropertyGetValue(const UObject* Object, const FBoolProperty* Property) +{ + return Property->GetPropertyValue_InContainer(Object); +} + +template +FString UCloud9ReflectionLibrary::FormatProperty(const FProperty* Property, TValue Value) +{ + let Name = Property->GetFName(); + let TypeName = Property->GetCPPType(); + return FString::Printf(TEXT("%s: %s = %s"), *Name.ToString(), *TypeName, *LexToString(Value)); +} + +template +TOptional UCloud9ReflectionLibrary::UPropertyConvert(const UObject* Object, const FProperty* Property) +{ + if (let TypedProperty = CastField(Property)) + { + let Value = UPropertyGetValue(Object, TypedProperty); + return FormatProperty(Property, Value); + } + return {}; +} + +template <> +TOptional UCloud9ReflectionLibrary::UPropertyConvert( + const UObject* Object, + const FProperty* Property) +{ + if (let TypedProperty = CastField(Property)) + { + let UnderlyingProperty = TypedProperty->GetUnderlyingProperty(); + let Ptr = Property->ContainerPtrToValuePtr(Object); + let Index = UnderlyingProperty->GetSignedIntPropertyValue(Ptr); + let Enum = TypedProperty->GetEnum(); + let Value = Enum->GetNameByIndex(Index); + return FormatProperty(Property, Value); + } + return {}; +} + +template +bool UCloud9ReflectionLibrary::UPropertyAppendTo( + FTextBuilder& Builder, + const UObject* Object, + const FProperty* Property) +{ + if (let String = UPropertyConvert(Object, Property)) + { + Builder.AppendLine(*String); + return true; + } + return false; +} + +FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object) +{ + FTextBuilder Builder; + let Class = Object->GetClass(); + + Builder.AppendLine(FString::Printf(TEXT("class %s {"), *Class->GetName())); + Builder.Indent(); + + for (TFieldIterator PropertyIterator(Class); PropertyIterator; ++PropertyIterator) + { + let Property = *PropertyIterator; + + UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property); + } + + Builder.Unindent(); + Builder.AppendLine(FString{"}"}); + + let Text = Builder.ToText(); + + return Text.ToString(); +} diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h new file mode 100644 index 000000000..4a474ce32 --- /dev/null +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h @@ -0,0 +1,53 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Cloud9ReflectionLibrary.generated.h" + +/** + * Class to work with UE4 UPROPERTY/UCLASS reflection for debugging. + */ +UCLASS() +class CLOUD9_API UCloud9ReflectionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + template + static TResult UPropertyGetValue(const UObject* Object, const TType* Property); + + template + static FString FormatProperty(const FProperty* Property, TValue Value); + + template + static TOptional UPropertyConvert(const UObject* Object, const FProperty* Property); + + template + static bool UPropertyAppendTo(FTextBuilder& Builder, const UObject* Object, const FProperty* Property); + + UFUNCTION(BlueprintCallable) + static FString UObjectToString(const UObject* Object); +}; diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp index 083a6a27b..c0d22e01d 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.cpp @@ -1,8 +1,32 @@ -#include "Cloud9ToolsLibrary.h" +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "Cloud9ToolsLibrary.h" #include "Cloud9/Cloud9.h" #include "Cloud9/Game/Cloud9GameMode.h" + void UCloud9ToolsLibrary::SetCollisionComplexity(UStaticMesh* StaticMesh, uint8 CollisionTraceFlag) { StaticMesh->GetBodySetup()->CollisionTraceFlag = static_cast(CollisionTraceFlag); @@ -10,9 +34,9 @@ void UCloud9ToolsLibrary::SetCollisionComplexity(UStaticMesh* StaticMesh, uint8 float UCloud9ToolsLibrary::CalculateCollisionVolumeScale(UStaticMesh* StaticMesh) { - const auto Scale = FVector{1.0f, 1.0f, 1.0f}; - const auto BoundingBoxVolume = StaticMesh->GetBoundingBox().GetVolume(); - const auto SimpleCollisionVolume = StaticMesh->GetBodySetup()->AggGeom.GetVolume(Scale); + let Scale = FVector{1.0f, 1.0f, 1.0f}; + let BoundingBoxVolume = StaticMesh->GetBoundingBox().GetVolume(); + let SimpleCollisionVolume = StaticMesh->GetBodySetup()->AggGeom.GetVolume(Scale); return SimpleCollisionVolume / BoundingBoxVolume; } @@ -20,7 +44,7 @@ UWorld* UCloud9ToolsLibrary::GetWorld() { return GEngine->GameViewport->GetWorld ACloud9GameMode* UCloud9ToolsLibrary::GetGameMode() { - const auto MyWorld = GetWorld(); + let MyWorld = GetWorld(); return Cast(UGameplayStatics::GetGameMode(MyWorld)); } @@ -29,21 +53,20 @@ ACloud9GameMode* UCloud9ToolsLibrary::GetGameMode() */ FBox UCloud9ToolsLibrary::GetAccurateReferencePoseBounds(const USkeletalMesh* Mesh) { - auto Box = FBox(ForceInitToZero); + var Box = FBox(ForceInitToZero); if (!Mesh || !Mesh->GetPhysicsAsset()) { return {}; } - for (const auto BodySetups : Mesh->GetPhysicsAsset()->SkeletalBodySetups) + for (let BodySetups : Mesh->GetPhysicsAsset()->SkeletalBodySetups) { - const FReferenceSkeleton& RefSkeleton = Mesh->GetSkeleton()->GetReferenceSkeleton(); - auto ComponentSpaceBoneTransform = FTransform::Identity; + let& RefSkeleton = Mesh->GetSkeleton()->GetReferenceSkeleton(); + var ComponentSpaceBoneTransform = FTransform::Identity; - auto BoneIndex = RefSkeleton.FindBoneIndex(BodySetups->BoneName); + var BoneIndex = RefSkeleton.FindBoneIndex(BodySetups->BoneName); while (BoneIndex != INDEX_NONE) { - const FTransform& BoneLocalTM = RefSkeleton.GetRefBonePose()[BoneIndex]; + let& BoneLocalTM = RefSkeleton.GetRefBonePose()[BoneIndex]; ComponentSpaceBoneTransform = ComponentSpaceBoneTransform * BoneLocalTM; - BoneIndex = RefSkeleton.GetParentIndex(BoneIndex); } @@ -58,7 +81,7 @@ FBox UCloud9ToolsLibrary::GetAccurateReferencePoseBounds(const USkeletalMesh* Me */ void UCloud9ToolsLibrary::GetWidthHeightDepth(const FBox& Box, float& Width, float& Height, float& Depth) { - const auto Size = Box.GetExtent(); + let Size = Box.GetExtent(); Width = Size.Y; Height = Size.X; Depth = Size.Z; @@ -79,13 +102,13 @@ FVector UCloud9ToolsLibrary::VInterpTo( float DeltaTime, const FVector InterpSpeed) { - const auto ClampLerp = [](auto Current, auto Dist, auto Alpha, auto Target) + let ClampLerp = [](auto Current, auto Dist, auto Alpha, auto Target) { return Alpha <= 0.0f ? Target : Current + Dist * FMath::Clamp(Alpha, 0.0f, 1.0f); }; // Distance to reach - const auto Dist = Target - Current; + let Dist = Target - Current; // If distance is too small, just set the desired location if (Dist.SizeSquared() < KINDA_SMALL_NUMBER) @@ -93,7 +116,7 @@ FVector UCloud9ToolsLibrary::VInterpTo( return Target; } - const auto Alpha = DeltaTime * InterpSpeed; + let Alpha = DeltaTime * InterpSpeed; return { ClampLerp(Current.X, Dist.X, Alpha.X, Target.X), @@ -102,55 +125,4 @@ FVector UCloud9ToolsLibrary::VInterpTo( }; } -template -typename TType::TCppType UPropertyGetValue(const UObject* Object, const TType* Property) -{ - const auto Ptr = Property->template ContainerPtrToValuePtr(Object); - return TType::GetPropertyValue(Ptr); -} - -template <> -bool UPropertyGetValue(const UObject* Object, const FBoolProperty* Property) -{ - return Property->GetPropertyValue_InContainer(Object); -} - -template -typename TType::TCppType UPropertyAppendTo(FString& String, const UObject* Object, const FProperty* Property) -{ - if (const auto TypedProperty = CastField(Property)) - { - const auto Name = Property->GetFName(); - const auto TypeName = Property->GetCPPType(); - const auto Value = UPropertyGetValue(Object, TypedProperty); - String += FString::Printf(TEXT("\t%s: %s = %s\n"), *Name.ToString(), *TypeName, *LexToString(Value)); - return true; - } - return false; -} - -FString UCloud9ToolsLibrary::UObjectToString(const UObject* Object) -{ - FString String; - const auto Class = Object->GetClass(); - String += FString::Printf(TEXT("class %s {\n"), *Class->GetName()); - for (TFieldIterator PropertyIterator(Class); PropertyIterator; ++PropertyIterator) - { - const auto Property = *PropertyIterator; - - UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - || UPropertyAppendTo(String, Object, Property) - ; - } - String += FString::Printf(TEXT("}")); - - return String; -} diff --git a/Source/Cloud9/Tools/Cloud9ToolsLibrary.h b/Source/Cloud9/Tools/Cloud9ToolsLibrary.h index a8fe747c0..1f5661217 100644 --- a/Source/Cloud9/Tools/Cloud9ToolsLibrary.h +++ b/Source/Cloud9/Tools/Cloud9ToolsLibrary.h @@ -1,4 +1,27 @@ -#pragma once +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" @@ -68,5 +91,4 @@ class CLOUD9_API UCloud9ToolsLibrary : public UBlueprintFunctionLibrary float DeltaTime, const FVector InterpSpeed); - static FString UObjectToString(const UObject* Object); }; From 567e7e589c3b2bffa8676beafbcc224163983579 Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Sun, 5 Nov 2023 20:55:53 +0300 Subject: [PATCH 5/7] #46 Added USTRUCT to printer --- Config/DefaultGame.ini | 1 + .../Cloud9/Game/Cloud9DeveloperSettings.cpp | 4 +- Source/Cloud9/Game/Cloud9DeveloperSettings.h | 16 +++ .../Cloud9/Tools/Cloud9ReflectionLibrary.cpp | 108 ++++++++++-------- Source/Cloud9/Tools/Cloud9ReflectionLibrary.h | 14 ++- 5 files changed, 91 insertions(+), 52 deletions(-) diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index 55f4e898e..7fb50bced 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -16,4 +16,5 @@ bIsDrawDeprojectedCursorLine=False bIsShowMouseCursor=False NetGraph=1 UnUsedEnum=Everything +UnUsedStruct=(IntField0=3,FloatField1=0.000000) diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp index d18b078ee..03c585a44 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp @@ -10,6 +10,8 @@ const UCloud9DeveloperSettings* UCloud9DeveloperSettings::GetCloud9DeveloperSett if (!bIsInitialized) { + let X = FUnUsedStruct(); + let q = X.StaticStruct(); Cast(Settings)->Log(); bIsInitialized = true; } @@ -25,5 +27,5 @@ void UCloud9DeveloperSettings::Save() void UCloud9DeveloperSettings::Log() const { - UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ReflectionLibrary::UObjectToString(this)); + UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ReflectionLibrary::UObjectToString(this, GetClass())); } diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.h b/Source/Cloud9/Game/Cloud9DeveloperSettings.h index ef427c892..9576d4e4f 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.h +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.h @@ -3,6 +3,19 @@ #include "CoreMinimal.h" #include "Cloud9DeveloperSettings.generated.h" +USTRUCT(BlueprintType) +struct FUnUsedStruct +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + int IntField0 = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float FloatField1 = 0.0f; +}; + UENUM() enum class EUnUsedEnum : int32 { @@ -43,4 +56,7 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = "Debug") EUnUsedEnum UnUsedEnum; + + UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = "Debug") + FUnUsedStruct UnUsedStruct; }; diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp index 252f27aad..ee6d60350 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp @@ -27,29 +27,29 @@ auto LexToString(const FText& Text) { return *Text.ToString(); } +template +FString UCloud9ReflectionLibrary::FormatProperty(const FProperty* Property, TValue Value) +{ + let Name = Property->GetFName(); + let TypeName = Property->GetCPPType(); + return FString::Printf(TEXT("%s: %s = %s"), *Name.ToString(), *TypeName, *LexToString(Value)); +} + template -TResult UCloud9ReflectionLibrary::UPropertyGetValue(const UObject* Object, const TType* Property) +TResult UCloud9ReflectionLibrary::UPropertyGetValue(const void* Object, const TType* Property) { let Ptr = Property->template ContainerPtrToValuePtr(Object); return TType::GetPropertyValue(Ptr); } template <> -bool UCloud9ReflectionLibrary::UPropertyGetValue(const UObject* Object, const FBoolProperty* Property) +bool UCloud9ReflectionLibrary::UPropertyGetValue(const void* Object, const FBoolProperty* Property) { return Property->GetPropertyValue_InContainer(Object); } -template -FString UCloud9ReflectionLibrary::FormatProperty(const FProperty* Property, TValue Value) -{ - let Name = Property->GetFName(); - let TypeName = Property->GetCPPType(); - return FString::Printf(TEXT("%s: %s = %s"), *Name.ToString(), *TypeName, *LexToString(Value)); -} - template -TOptional UCloud9ReflectionLibrary::UPropertyConvert(const UObject* Object, const FProperty* Property) +TOptional UCloud9ReflectionLibrary::UPropertyConvert(const void* Object, const FProperty* Property) { if (let TypedProperty = CastField(Property)) { @@ -61,7 +61,7 @@ TOptional UCloud9ReflectionLibrary::UPropertyConvert(const UObject* Obj template <> TOptional UCloud9ReflectionLibrary::UPropertyConvert( - const UObject* Object, + const void* Object, const FProperty* Property) { if (let TypedProperty = CastField(Property)) @@ -76,10 +76,23 @@ TOptional UCloud9ReflectionLibrary::UPropertyConvert( return {}; } +template <> +TOptional UCloud9ReflectionLibrary::UPropertyConvert( + const void* Object, + const FProperty* Property) +{ + if (let TypedProperty = CastField(Property)) + { + let Ptr = TypedProperty->ContainerPtrToValuePtr(Object); + return UObjectToString(Ptr, TypedProperty->Struct); + } + return {}; +} + template bool UCloud9ReflectionLibrary::UPropertyAppendTo( FTextBuilder& Builder, - const UObject* Object, + const void* Object, const FProperty* Property) { if (let String = UPropertyConvert(Object, Property)) @@ -90,44 +103,49 @@ bool UCloud9ReflectionLibrary::UPropertyAppendTo( return false; } -FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object) +bool UCloud9ReflectionLibrary::UPropertyAppendTo( + FTextBuilder& Builder, + const void* Object, + const FProperty* Property) +{ + return UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + // || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property); +} + +FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object, const UStruct* Type) { FTextBuilder Builder; - let Class = Object->GetClass(); - Builder.AppendLine(FString::Printf(TEXT("class %s {"), *Class->GetName())); + Builder.AppendLine(FString::Printf(TEXT("class %s {"), *Type->GetName())); Builder.Indent(); - for (TFieldIterator PropertyIterator(Class); PropertyIterator; ++PropertyIterator) + for (TFieldIterator It(Type); It; ++It) { - let Property = *PropertyIterator; - - UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property); + UPropertyAppendTo(Builder, Object, *It); } Builder.Unindent(); diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h index 4a474ce32..6b31dd396 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h @@ -36,18 +36,20 @@ class CLOUD9_API UCloud9ReflectionLibrary : public UBlueprintFunctionLibrary GENERATED_BODY() public: - template - static TResult UPropertyGetValue(const UObject* Object, const TType* Property); - template static FString FormatProperty(const FProperty* Property, TValue Value); + template + static TResult UPropertyGetValue(const void* Object, const TType* Property); + template - static TOptional UPropertyConvert(const UObject* Object, const FProperty* Property); + static TOptional UPropertyConvert(const void* Object, const FProperty* Property); template - static bool UPropertyAppendTo(FTextBuilder& Builder, const UObject* Object, const FProperty* Property); + static bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property); + + static bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property); UFUNCTION(BlueprintCallable) - static FString UObjectToString(const UObject* Object); + static FString UObjectToString(const UObject* Object, const UStruct* Type); }; From b82d8ae690fc01707c224585b2610dede1e3087e Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Mon, 6 Nov 2023 12:55:36 +0300 Subject: [PATCH 6/7] #46 Fixed indents of nested struct --- Source/Cloud9/Cloud9.h | 48 +++++++++++- .../Cloud9/Game/Cloud9DeveloperSettings.cpp | 32 ++++++-- Source/Cloud9/Game/Cloud9DeveloperSettings.h | 25 ++++++- .../Cloud9/Tools/Cloud9ReflectionLibrary.cpp | 74 +++++++++---------- Source/Cloud9/Tools/Cloud9ReflectionLibrary.h | 9 +-- Source/Cloud9/Tools/Extensions/UObject.cpp | 31 ++++++++ Source/Cloud9/Tools/Extensions/UObject.h | 35 +++++++++ 7 files changed, 201 insertions(+), 53 deletions(-) create mode 100644 Source/Cloud9/Tools/Extensions/UObject.cpp create mode 100644 Source/Cloud9/Tools/Extensions/UObject.h diff --git a/Source/Cloud9/Cloud9.h b/Source/Cloud9/Cloud9.h index 8f4e3a927..80393fc3b 100644 --- a/Source/Cloud9/Cloud9.h +++ b/Source/Cloud9/Cloud9.h @@ -1,4 +1,25 @@ -// Copyright Epic Games, Inc. All Rights Reserved. +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. #pragma once @@ -7,4 +28,27 @@ DECLARE_LOG_CATEGORY_EXTERN(LogCloud9, Log, All); #define let const auto -#define var auto \ No newline at end of file +#define var auto + +template +class TOperator +{ +public: + template + constexpr friend auto operator|(const TValue* Value, const TFunction& Function) + { + return Function(Value); + } + + template + constexpr friend auto operator|(const TValue& Value, const TFunction& Function) + { + return Function(Value); + } + + template + constexpr friend auto operator|(TValue&& Value, const TFunction& Function) + { + return Function(Forward(Value)); + } +}; diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp index 03c585a44..64da32be6 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp @@ -1,7 +1,30 @@ -#include "Cloud9DeveloperSettings.h" +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "Cloud9DeveloperSettings.h" #include "Cloud9/Cloud9.h" -#include "Cloud9/Tools/Cloud9ReflectionLibrary.h" +#include "Cloud9/Tools/Extensions/UObject.h" const UCloud9DeveloperSettings* UCloud9DeveloperSettings::GetCloud9DeveloperSettings() { @@ -10,8 +33,6 @@ const UCloud9DeveloperSettings* UCloud9DeveloperSettings::GetCloud9DeveloperSett if (!bIsInitialized) { - let X = FUnUsedStruct(); - let q = X.StaticStruct(); Cast(Settings)->Log(); bIsInitialized = true; } @@ -27,5 +48,6 @@ void UCloud9DeveloperSettings::Save() void UCloud9DeveloperSettings::Log() const { - UE_LOG(LogCloud9, Display, TEXT("%s"), *UCloud9ReflectionLibrary::UObjectToString(this, GetClass())); + let String = this | EUObject::Stringify(); + UE_LOG(LogCloud9, Display, TEXT("%s"), *String); } diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.h b/Source/Cloud9/Game/Cloud9DeveloperSettings.h index 9576d4e4f..f75dd637d 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.h +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.h @@ -1,4 +1,27 @@ -#pragma once +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once #include "CoreMinimal.h" #include "Cloud9DeveloperSettings.generated.h" diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp index ee6d60350..3f23c9576 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp @@ -28,7 +28,7 @@ auto LexToString(const FText& Text) { return *Text.ToString(); } template -FString UCloud9ReflectionLibrary::FormatProperty(const FProperty* Property, TValue Value) +FString FormatProperty(const FProperty* Property, TValue Value) { let Name = Property->GetFName(); let TypeName = Property->GetCPPType(); @@ -49,18 +49,24 @@ bool UCloud9ReflectionLibrary::UPropertyGetValue(const void* Object, const FBool } template -TOptional UCloud9ReflectionLibrary::UPropertyConvert(const void* Object, const FProperty* Property) +bool UCloud9ReflectionLibrary::UPropertyAppendTo( + FTextBuilder& Builder, + const void* Object, + const FProperty* Property) { if (let TypedProperty = CastField(Property)) { let Value = UPropertyGetValue(Object, TypedProperty); - return FormatProperty(Property, Value); + let String = FormatProperty(Property, Value); + Builder.AppendLine(String); + return true; } - return {}; + return false; } template <> -TOptional UCloud9ReflectionLibrary::UPropertyConvert( +bool UCloud9ReflectionLibrary::UPropertyAppendTo( + FTextBuilder& Builder, const void* Object, const FProperty* Property) { @@ -71,44 +77,44 @@ TOptional UCloud9ReflectionLibrary::UPropertyConvert( let Index = UnderlyingProperty->GetSignedIntPropertyValue(Ptr); let Enum = TypedProperty->GetEnum(); let Value = Enum->GetNameByIndex(Index); - return FormatProperty(Property, Value); + let String = FormatProperty(Property, Value); + Builder.AppendLine(String); + return true; } - return {}; + return false; } template <> -TOptional UCloud9ReflectionLibrary::UPropertyConvert( +bool UCloud9ReflectionLibrary::UPropertyAppendTo( + FTextBuilder& Builder, const void* Object, const FProperty* Property) { if (let TypedProperty = CastField(Property)) { let Ptr = TypedProperty->ContainerPtrToValuePtr(Object); - return UObjectToString(Ptr, TypedProperty->Struct); - } - return {}; -} - -template -bool UCloud9ReflectionLibrary::UPropertyAppendTo( - FTextBuilder& Builder, - const void* Object, - const FProperty* Property) -{ - if (let String = UPropertyConvert(Object, Property)) - { - Builder.AppendLine(*String); + UObjectAppendTo(Builder, Ptr, TypedProperty->Struct); return true; } return false; } -bool UCloud9ReflectionLibrary::UPropertyAppendTo( +void UCloud9ReflectionLibrary::UObjectAppendTo( FTextBuilder& Builder, const void* Object, - const FProperty* Property) + const UStruct* Type) { - return UPropertyAppendTo(Builder, Object, Property) + let TypeClass = Type->GetClass(); + let Header = FString::Printf(TEXT("%s %s {"), + *TypeClass->GetName(), *Type->GetName()); + + Builder.AppendLine(Header); + Builder.Indent(); + + for (TFieldIterator It(Type); It; ++It) + { + let Property = *It; + UPropertyAppendTo(Builder, Object, Property) || UPropertyAppendTo(Builder, Object, Property) || UPropertyAppendTo(Builder, Object, Property) || UPropertyAppendTo(Builder, Object, Property) @@ -134,24 +140,16 @@ bool UCloud9ReflectionLibrary::UPropertyAppendTo( // || UPropertyAppendTo(Builder, Object, Property) || UPropertyAppendTo(Builder, Object, Property) || UPropertyAppendTo(Builder, Object, Property); -} - -FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object, const UStruct* Type) -{ - FTextBuilder Builder; - - Builder.AppendLine(FString::Printf(TEXT("class %s {"), *Type->GetName())); - Builder.Indent(); - - for (TFieldIterator It(Type); It; ++It) - { - UPropertyAppendTo(Builder, Object, *It); } Builder.Unindent(); Builder.AppendLine(FString{"}"}); +} +FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object, const UStruct* Type) +{ + FTextBuilder Builder; + UObjectAppendTo(Builder, Object, Type); let Text = Builder.ToText(); - return Text.ToString(); } diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h index 6b31dd396..53be6e5d6 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h @@ -36,20 +36,15 @@ class CLOUD9_API UCloud9ReflectionLibrary : public UBlueprintFunctionLibrary GENERATED_BODY() public: - template - static FString FormatProperty(const FProperty* Property, TValue Value); - template static TResult UPropertyGetValue(const void* Object, const TType* Property); - template - static TOptional UPropertyConvert(const void* Object, const FProperty* Property); - template static bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property); - static bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property); + static void UObjectAppendTo(FTextBuilder& Builder, const void* Object, const UStruct* Type); UFUNCTION(BlueprintCallable) static FString UObjectToString(const UObject* Object, const UStruct* Type); }; + diff --git a/Source/Cloud9/Tools/Extensions/UObject.cpp b/Source/Cloud9/Tools/Extensions/UObject.cpp new file mode 100644 index 000000000..75e74c4c5 --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/UObject.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "UObject.h" + +#include "Cloud9/Tools/Cloud9ReflectionLibrary.h" + +FString EUObject::Stringify::operator()(const UObject* Object) const +{ + return UCloud9ReflectionLibrary::UObjectToString(Object, Object->GetClass()); +} diff --git a/Source/Cloud9/Tools/Extensions/UObject.h b/Source/Cloud9/Tools/Extensions/UObject.h new file mode 100644 index 000000000..c6b070f3e --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/UObject.h @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "Cloud9/Cloud9.h" + +namespace EUObject +{ + struct Stringify : TOperator + { + public: + FString operator()(const UObject* Object) const; + }; +} From 11e8e3d03bbf6daa51ed86f7c0e35ca635616dee Mon Sep 17 00:00:00 2001 From: Alexei Gladkikh Date: Mon, 6 Nov 2023 15:15:01 +0300 Subject: [PATCH 7/7] #46 Refactored to extensions --- Source/Cloud9/Cloud9.h | 4 +- .../Cloud9/Tools/Cloud9ReflectionLibrary.cpp | 130 +------------- Source/Cloud9/Tools/Cloud9ReflectionLibrary.h | 8 - .../Cloud9/Tools/Extensions/FTextBuilder.cpp | 158 ++++++++++++++++++ Source/Cloud9/Tools/Extensions/FTextBuilder.h | 58 +++++++ 5 files changed, 224 insertions(+), 134 deletions(-) create mode 100644 Source/Cloud9/Tools/Extensions/FTextBuilder.cpp create mode 100644 Source/Cloud9/Tools/Extensions/FTextBuilder.h diff --git a/Source/Cloud9/Cloud9.h b/Source/Cloud9/Cloud9.h index 80393fc3b..41e9fffd3 100644 --- a/Source/Cloud9/Cloud9.h +++ b/Source/Cloud9/Cloud9.h @@ -41,7 +41,7 @@ class TOperator } template - constexpr friend auto operator|(const TValue& Value, const TFunction& Function) + constexpr friend auto operator|(TValue& Value, const TFunction& Function) { return Function(Value); } @@ -49,6 +49,6 @@ class TOperator template constexpr friend auto operator|(TValue&& Value, const TFunction& Function) { - return Function(Forward(Value)); + return Function(Value); } }; diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp index 3f23c9576..f1c4c391c 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.cpp @@ -24,132 +24,14 @@ #include "Cloud9ReflectionLibrary.h" #include "Cloud9/Cloud9.h" - -auto LexToString(const FText& Text) { return *Text.ToString(); } - -template -FString FormatProperty(const FProperty* Property, TValue Value) -{ - let Name = Property->GetFName(); - let TypeName = Property->GetCPPType(); - return FString::Printf(TEXT("%s: %s = %s"), *Name.ToString(), *TypeName, *LexToString(Value)); -} - -template -TResult UCloud9ReflectionLibrary::UPropertyGetValue(const void* Object, const TType* Property) -{ - let Ptr = Property->template ContainerPtrToValuePtr(Object); - return TType::GetPropertyValue(Ptr); -} - -template <> -bool UCloud9ReflectionLibrary::UPropertyGetValue(const void* Object, const FBoolProperty* Property) -{ - return Property->GetPropertyValue_InContainer(Object); -} - -template -bool UCloud9ReflectionLibrary::UPropertyAppendTo( - FTextBuilder& Builder, - const void* Object, - const FProperty* Property) -{ - if (let TypedProperty = CastField(Property)) - { - let Value = UPropertyGetValue(Object, TypedProperty); - let String = FormatProperty(Property, Value); - Builder.AppendLine(String); - return true; - } - return false; -} - -template <> -bool UCloud9ReflectionLibrary::UPropertyAppendTo( - FTextBuilder& Builder, - const void* Object, - const FProperty* Property) -{ - if (let TypedProperty = CastField(Property)) - { - let UnderlyingProperty = TypedProperty->GetUnderlyingProperty(); - let Ptr = Property->ContainerPtrToValuePtr(Object); - let Index = UnderlyingProperty->GetSignedIntPropertyValue(Ptr); - let Enum = TypedProperty->GetEnum(); - let Value = Enum->GetNameByIndex(Index); - let String = FormatProperty(Property, Value); - Builder.AppendLine(String); - return true; - } - return false; -} - -template <> -bool UCloud9ReflectionLibrary::UPropertyAppendTo( - FTextBuilder& Builder, - const void* Object, - const FProperty* Property) -{ - if (let TypedProperty = CastField(Property)) - { - let Ptr = TypedProperty->ContainerPtrToValuePtr(Object); - UObjectAppendTo(Builder, Ptr, TypedProperty->Struct); - return true; - } - return false; -} - -void UCloud9ReflectionLibrary::UObjectAppendTo( - FTextBuilder& Builder, - const void* Object, - const UStruct* Type) -{ - let TypeClass = Type->GetClass(); - let Header = FString::Printf(TEXT("%s %s {"), - *TypeClass->GetName(), *Type->GetName()); - - Builder.AppendLine(Header); - Builder.Indent(); - - for (TFieldIterator It(Type); It; ++It) - { - let Property = *It; - UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - // || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property) - || UPropertyAppendTo(Builder, Object, Property); - } - - Builder.Unindent(); - Builder.AppendLine(FString{"}"}); -} +#include "Extensions/FTextBuilder.h" FString UCloud9ReflectionLibrary::UObjectToString(const UObject* Object, const UStruct* Type) { - FTextBuilder Builder; - UObjectAppendTo(Builder, Object, Type); - let Text = Builder.ToText(); + using namespace EFTextBuilder; + + let Text = FTextBuilder() + | AppendObject(Object, Type) + | ToText(); return Text.ToString(); } diff --git a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h index 53be6e5d6..afd29a744 100644 --- a/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h +++ b/Source/Cloud9/Tools/Cloud9ReflectionLibrary.h @@ -36,14 +36,6 @@ class CLOUD9_API UCloud9ReflectionLibrary : public UBlueprintFunctionLibrary GENERATED_BODY() public: - template - static TResult UPropertyGetValue(const void* Object, const TType* Property); - - template - static bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property); - - static void UObjectAppendTo(FTextBuilder& Builder, const void* Object, const UStruct* Type); - UFUNCTION(BlueprintCallable) static FString UObjectToString(const UObject* Object, const UStruct* Type); }; diff --git a/Source/Cloud9/Tools/Extensions/FTextBuilder.cpp b/Source/Cloud9/Tools/Extensions/FTextBuilder.cpp new file mode 100644 index 000000000..dc09c5adb --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/FTextBuilder.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "FTextBuilder.h" + +auto LexToString(const FText& Text) { return *Text.ToString(); } + +namespace EFTextBuilder +{ + template + TResult UPropertyGetValue(const void* Object, const TType* Property) + { + let Ptr = Property->template ContainerPtrToValuePtr(Object); + return TType::GetPropertyValue(Ptr); + } + + template <> + bool UPropertyGetValue(const void* Object, const FBoolProperty* Property) + { + return Property->GetPropertyValue_InContainer(Object); + } + + template + FString Format(const FProperty* Property, TValue Value) + { + let Name = Property->GetFName(); + let TypeName = Property->GetCPPType(); + return FString::Printf(TEXT("%s: %s = %s"), *Name.ToString(), *TypeName, *LexToString(Value)); + } + + template + bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property) + { + if (let TypedProperty = CastField(Property)) + { + let Value = UPropertyGetValue(Object, TypedProperty); + let String = Format(Property, Value); + Builder.AppendLine(String); + return true; + } + return false; + } + + template <> + bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property) + { + if (let TypedProperty = CastField(Property)) + { + let UnderlyingProperty = TypedProperty->GetUnderlyingProperty(); + let Ptr = Property->ContainerPtrToValuePtr(Object); + let Index = UnderlyingProperty->GetSignedIntPropertyValue(Ptr); + let Enum = TypedProperty->GetEnum(); + let Value = Enum->GetNameByIndex(Index); + let String = Format(Property, Value); + Builder.AppendLine(String); + return true; + } + return false; + } + + template <> + bool UPropertyAppendTo(FTextBuilder& Builder, const void* Object, const FProperty* Property) + { + if (let TypedProperty = CastField(Property)) + { + let Ptr = TypedProperty->ContainerPtrToValuePtr(Object); + Builder | AppendObject(Ptr, TypedProperty->Struct); + return true; + } + return false; + } + + template + bool UPropertyNotSupported(FTextBuilder& Builder, const void* Object, const FProperty* Property) + { + if (let TypedProperty = CastField(Property)) + { + let String = Format(Property, TEXT("")); + Builder.AppendLine(String); + return true; + } + return false; + } + + FTextBuilder& AppendProperty::operator()(FTextBuilder& Builder) const + { + UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyNotSupported(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property) + || UPropertyAppendTo(Builder, Object, Property); + return Builder; + } + + FTextBuilder& AppendObject::operator()(FTextBuilder& Builder) const + { + let TypeClass = Type->GetClass(); + let Header = FString::Printf(TEXT("%s %s {"), *TypeClass->GetName(), *Type->GetName()); + + Builder.AppendLine(Header); + Builder.Indent(); + + for (TFieldIterator It(Type); It; ++It) + { + Builder | AppendProperty(Object, *It); + } + + Builder.Unindent(); + Builder.AppendLine(FString{"}"}); + + return Builder; + } + + FText ToText::operator()(const FTextBuilder& Builder) const { return Builder.ToText(); } +} diff --git a/Source/Cloud9/Tools/Extensions/FTextBuilder.h b/Source/Cloud9/Tools/Extensions/FTextBuilder.h new file mode 100644 index 000000000..59670fc0d --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/FTextBuilder.h @@ -0,0 +1,58 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "Cloud9/Cloud9.h" + +namespace EFTextBuilder +{ + struct AppendObject : TOperator + { + AppendObject(const UObject* Object, const UStruct* Type) + : Object(Object), Type(Type) { } + + FTextBuilder& operator()(FTextBuilder& Builder) const; + + private: + const UObject* Object; + const UStruct* Type; + }; + + struct AppendProperty : TOperator + { + AppendProperty(const UObject* Object, const FProperty* Property) + : Object(Object), Property(Property) { } + + FTextBuilder& operator()(FTextBuilder& Builder) const; + + private: + const UObject* Object; + const FProperty* Property; + }; + + struct ToText : TOperator + { + FText operator()(const FTextBuilder& Builder) const; + }; +}