UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
PropertyPathHelpers.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
7#include "CoreMinimal.h"
8#include "CoreTypes.h"
9#include "HAL/PlatformCrt.h"
12#include "UObject/Class.h"
13#include "UObject/Field.h"
14#include "UObject/NameTypes.h"
15#include "UObject/Object.h"
17#include "UObject/ObjectPtr.h"
18#include "UObject/UnrealType.h"
19
20#include "PropertyPathHelpers.generated.h"
21
22class FArchive;
23template <typename FuncType> class TFunctionRef;
24
26USTRUCT()
87
93
95USTRUCT()
97{
99
100
102
104 PROPERTYPATH_API FCachedPropertyPath(const FString& Path);
105
108
111
114 PROPERTYPATH_API FCachedPropertyPath(const FPropertyChangedEvent& PropertyChangedEvent, const FEditPropertyChain& PropertyChain);
115
118
120 bool IsValid() const { return Segments.Num() > 0; }
121
123 PROPERTYPATH_API void MakeFromString(const FString& InPropertyPath);
124
127 PROPERTYPATH_API void MakeFromChangeEvent(const FPropertyChangedEvent& PropertyChangedEvent, const FEditPropertyChain& PropertyChain);
128
130 static PROPERTYPATH_API FCachedPropertyPath MakeUnresolvedCopy(const FCachedPropertyPath& ToCopy);
131
133 PROPERTYPATH_API FCachedPropertyPath MakeParentPath() const;
134
136 PROPERTYPATH_API int32 GetNumSegments() const;
137
144
149 PROPERTYPATH_API const FPropertyPathSegment& GetLastSegment() const;
150
156
158 PROPERTYPATH_API void SetCanSafelyUsedCachedAddress(bool bInCanSafelyUsedCachedAddress) const;
159
161 PROPERTYPATH_API void SetCachedLastContainer(void* InContainer, int32 InIndex) const;
162
164 PROPERTYPATH_API void* GetCachedLastContainerInPath() const;
165
167 PROPERTYPATH_API int32 GetCachedLastContainerInPathIndex() const;
168
170 PROPERTYPATH_API void ResolveLeaf(void* InAddress) const;
171
173 PROPERTYPATH_API void ResolveLeaf(UFunction* InFunction) const;
174
180 PROPERTYPATH_API bool IsResolved() const;
181
187 PROPERTYPATH_API bool IsFullyResolved() const;
188
190 PROPERTYPATH_API void* GetCachedAddress() const;
191
193 PROPERTYPATH_API UFunction* GetCachedFunction() const;
194
197
199 PROPERTYPATH_API void ToEditPropertyChain(FEditPropertyChain& OutPropertyChain) const;
200
202 PROPERTYPATH_API FString ToString() const;
203
205 PROPERTYPATH_API bool operator==(const FString& Other) const;
206
208 PROPERTYPATH_API bool Equals(const FString& Other) const;
209
211 PROPERTYPATH_API void* GetCachedContainer() const;
212
214 PROPERTYPATH_API void SetCachedContainer(void* InContainer) const;
215
217 PROPERTYPATH_API void RemoveFromEnd(int32 InNumSegments = 1);
218
220 PROPERTYPATH_API void RemoveFromStart(int32 InNumSegments = 1);
221
223 PROPERTYPATH_API FProperty* GetFProperty() const;
224private:
226 UPROPERTY()
228
230 mutable void* CachedAddress;
231
233 UPROPERTY()
234 mutable TObjectPtr<UFunction> CachedFunction;
235
237 mutable void* CachedContainer;
238
240 mutable void* CachedLastContainerInPath;
241
243 mutable int32 CachedLastContainerInPathIndex;
244
246 mutable bool bCanSafelyUsedCachedAddress;
247};
248
251{
252 struct FPropertyPathResolver;
253 struct FPropertyStructView;
254 template<typename T> struct FInternalGetterResolver;
255 template<typename T> struct FInternalSetterResolver;
256
257 PROPERTYPATH_API bool ResolvePropertyPath(UObject* InContainer, const FString& InPropertyPath, FPropertyPathResolver& InResolver);
258 PROPERTYPATH_API bool ResolvePropertyPath(UObject* InContainer, const FCachedPropertyPath& InPropertyPath, FPropertyPathResolver& InResolver);
259 PROPERTYPATH_API bool ResolvePropertyPath(void* InContainer, UStruct* InStruct, const FString& InPropertyPath, FPropertyPathResolver& InResolver);
260 PROPERTYPATH_API bool ResolvePropertyPath(void* InContainer, UStruct* InStruct, const FCachedPropertyPath& InPropertyPath, FPropertyPathResolver& InResolver);
261 template<typename T, typename ContainerType> bool GetValueFast(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, T& OutValue, FProperty*& OutProperty);
262 template<typename T, typename ContainerType> bool SetValueFast(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const T& InValue);
263}
264
266namespace PropertyPathHelpers
267{
276
286
296
307
316
326
334 PROPERTYPATH_API bool SetPropertyValueFromString(UObject* InContainer, const FString& InPropertyPath, const FString& InValue, uint32 PPF_Flags = PPF_None);
335
344
353 PROPERTYPATH_API bool SetPropertyValueFromString(void* InContainer, UStruct* InStruct, const FString& InPropertyPath, const FString& InValue, uint32 PPF_Flags = PPF_None);
354
364
374 template<typename T>
375 bool GetPropertyValueFast(UObject* InContainer, const FCachedPropertyPath& InPropertyPath, T& OutValue)
376 {
379 }
380
391 template<typename T>
392 bool GetPropertyValueFast(UObject* InContainer, const FCachedPropertyPath& InPropertyPath, T& OutValue, FProperty*& OutProperty)
393 {
395 check(InContainer == InPropertyPath.GetCachedContainer());
396 check(InPropertyPath.IsResolved());
397
398 return PropertyPathHelpersInternal::GetValueFast<T>(InContainer, InPropertyPath, OutValue, OutProperty);
399 }
400
413 template<typename T>
415 {
417
418 if(InPropertyPath.IsFullyResolved())
419 {
421 }
422 else
423 {
424 PropertyPathHelpersInternal::FInternalGetterResolver<T> Resolver(OutValue, OutProperty);
426 }
427 }
428
440 template<typename T>
442 {
446 }
447
460 template<typename T>
462 {
465 }
466
478 template<typename T>
480 {
483 }
484
493 template<typename T>
494 bool SetPropertyValueFast(UObject* InContainer, const FCachedPropertyPath& InPropertyPath, const T& InValue)
495 {
497 check(InContainer == InPropertyPath.GetCachedContainer());
498 check(InPropertyPath.IsResolved());
499
500 return PropertyPathHelpersInternal::SetValueFast<T>(InContainer, InPropertyPath, InValue);
501 }
502
514 template<typename T>
516 {
518
519 if(InPropertyPath.IsFullyResolved())
520 {
522 }
523 else
524 {
525 PropertyPathHelpersInternal::FInternalSetterResolver<T> Resolver(InValue);
527 }
528 }
529
541 template<typename T>
542 bool SetPropertyValue(UObject* InContainer, const FString& InPropertyPath, const T& InValue)
543 {
546 }
547
561
575
584
596
606
615
624}
625
628{
630 struct FPropertyPathResolver
631 {
633 virtual ~FPropertyPathResolver() {}
634
641 virtual bool Resolve(void* InContainer, const FCachedPropertyPath& InPropertyPath) = 0;
643 };
644
646 struct FPropertyStructView
647 {
648 explicit FPropertyStructView(const UScriptStruct* InScriptStruct, const uint8* InMemory)
649 : ScriptStruct(InScriptStruct)
651 {
652 }
653
654 const UScriptStruct* ScriptStruct;
655 const uint8* Memory;
656 };
657
659 template<typename DerivedType>
660 struct TPropertyPathResolver : public FPropertyPathResolver
661 {
662 virtual bool Resolve(void* InContainer, const FCachedPropertyPath& InPropertyPath) override
663 {
664 return static_cast<DerivedType*>(this)->template Resolve_Impl<void>(InContainer, InPropertyPath);
665 }
666
667 virtual bool Resolve(UObject* InContainer, const FCachedPropertyPath& InPropertyPath) override
668 {
669 return static_cast<DerivedType*>(this)->template Resolve_Impl<UObject>(InContainer, InPropertyPath);
670 }
671 };
672
675
678
685
687 template<typename T, typename ContainerType>
688 struct FCallGetterFunctionHelper
689 {
690 static bool CallGetterFunction(ContainerType* InContainer, UFunction* InFunction, T& OutValue)
691 {
692 // Cant call UFunctions on non-UObject containers
693 return false;
694 }
695 };
696
698 template<typename T>
699 struct FCallGetterFunctionHelper<T, UObject>
700 {
701 static bool CallGetterFunction(UObject* InContainer, UFunction* InFunction, T& OutValue)
702 {
703 // We only support calling functions that return a single value and take no parameters.
704 if ( InFunction->NumParms == 1 )
705 {
706 // Find the pointer to the only param
707 FProperty* ReturnProperty = nullptr;
708 for (TFieldIterator<FProperty> It(InFunction); It; ++It)
709 {
710 if (It->PropertyFlags & CPF_Parm)
711 {
712 ReturnProperty = *It;
713 break;
714 }
715 }
716
717 // Verify there's a return property.
718 if ( ReturnProperty && ReturnProperty->PropertyFlags & (CPF_ReturnParm | CPF_OutParm) )
719 {
720 // Verify that the cpp type matches a known property type.
722 {
723 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
724 if ( PropertySizesMatch<T>(ReturnProperty) && !InContainer->IsUnreachable() )
725 {
726 InContainer->ProcessEvent(InFunction, &OutValue);
727 return true;
728 }
729 }
730 }
731 }
732
733 return false;
734 }
735 };
736
738 template<typename T, typename ContainerType>
739 struct FGetValueHelper
740 {
741 static bool GetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, T& OutValue, FProperty*& OutProperty)
742 {
743 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
744 int32 ArrayIndex = LastSegment.GetArrayIndex();
746
747 // Verify that the cpp type matches a known property type.
749 {
750 ArrayIndex = ArrayIndex == INDEX_NONE ? 0 : ArrayIndex;
752 {
753 if (Property->HasGetter())
754 {
755 Property->CallGetter(InContainer, &OutValue);
756 }
757 else if (void* Address = Property->ContainerPtrToValuePtr<T>(InContainer, ArrayIndex))
758 {
759 InPropertyPath.ResolveLeaf(Address);
761 }
763 return true;
764 }
765 }
766
767 return false;
768 }
769 };
770
772 template<typename T, typename ContainerType, int32 N>
773 struct FGetValueHelper<T[N], ContainerType>
774 {
775 static bool GetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, T(&OutValue)[N], FProperty*& OutProperty)
776 {
777 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
779
780 // Verify that the cpp type matches a known property type.
782 {
783 if ( PropertySizesMatch<T>(Property) && Property->ArrayDim == N )
784 {
785 if(void* Address = Property->ContainerPtrToValuePtr<T>(InContainer))
786 {
787 InPropertyPath.ResolveLeaf(Address);
788 Property->CopyCompleteValue(&OutValue, Address);
790 return true;
791 }
792 }
793 }
794
795 return true;
796 }
797 };
798
800 template<typename ContainerType>
801 struct FGetValueHelper<bool, ContainerType>
802 {
803 static bool GetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, bool& OutValue, FProperty*& OutProperty)
804 {
805 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
806 int32 ArrayIndex = LastSegment.GetArrayIndex();
808
809 // Verify that the cpp type matches a known property type.
811 {
812 ArrayIndex = ArrayIndex == INDEX_NONE ? 0 : ArrayIndex;
814 {
815 if(void* Address = Property->ContainerPtrToValuePtr<bool>(InContainer, ArrayIndex))
816 {
817 InPropertyPath.ResolveLeaf(Address);
819 OutValue = BoolProperty->GetPropertyValue(Address);
821 return true;
822 }
823 }
824 }
825
826 return false;
827 }
828 };
829
838 template<typename T, typename ContainerType>
840 {
841 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
842 int32 ArrayIndex = LastSegment.GetArrayIndex();
843 FFieldVariant Field = LastSegment.GetField();
844
845 // We're on the final property in the path, it may be an array property, so check that first.
847 {
848 // if it's an array property, we need to see if we parsed an index as part of the segment
849 // as a user may have baked the index directly into the property path.
850 if(ArrayIndex != INDEX_NONE)
851 {
852 // Property is an array property, so make sure we have a valid index specified
854 if ( ArrayHelper.IsValidIndex(ArrayIndex) )
855 {
856 // Verify that the cpp type matches a known property type.
858 {
859 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
860 if ( PropertySizesMatch<T>(ArrayProp->Inner) )
861 {
862 if(void* Address = static_cast<void*>(ArrayHelper.GetRawPtr(ArrayIndex)))
863 {
864 InPropertyPath.ResolveLeaf(Address);
865 ArrayProp->Inner->CopySingleValue(&OutValue, Address);
866 OutProperty = ArrayProp->Inner;
867 return true;
868 }
869 }
870 }
871 }
872 }
873 else
874 {
875 // No index, so assume we want the array property itself
877 {
879 {
880 if(void* Address = ArrayProp->ContainerPtrToValuePtr<T>(InContainer))
881 {
882 InPropertyPath.ResolveLeaf(Address);
883 ArrayProp->CopySingleValue(&OutValue, Address);
885 return true;
886 }
887 }
888 }
889 }
890 }
891 else if(UFunction* Function = Field.Get<UFunction>())
892 {
893 InPropertyPath.ResolveLeaf(Function);
894 return FCallGetterFunctionHelper<T, ContainerType>::CallGetterFunction(InContainer, Function, OutValue);
895 }
896 else if(FProperty* Property = Field.Get<FProperty>())
897 {
898 return FGetValueHelper<T, ContainerType>::GetValue(InContainer, InPropertyPath, OutValue, OutProperty);
899 }
900
901 return false;
902 }
903
904 template<typename T>
905 struct FInternalGetterResolver : public TPropertyPathResolver<FInternalGetterResolver<T>>
906 {
907 FInternalGetterResolver(T& InValue, FProperty*& InOutProperty)
908 : Value(InValue)
910 {
911 }
912
913 template<typename ContainerType>
914 bool Resolve_Impl(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath)
915 {
916 return GetValue<T>(InContainer, InPropertyPath, Property, Value);
917 }
918
919 T& Value;
921 };
922
924 template<typename T, typename ContainerType>
925 struct FCallSetterFunctionHelper
926 {
927 static bool CallSetterFunction(ContainerType* InContainer, UFunction* InFunction, const T& InValue)
928 {
929 // Cant call UFunctions on non-UObject containers
930 return false;
931 }
932 };
933
935 template<typename T>
936 struct FCallSetterFunctionHelper<T, UObject>
937 {
938 static bool CallSetterFunction(UObject* InContainer, UFunction* InFunction, const T& InValue)
939 {
940 // We only support calling functions that take a single value and return no parameters
941 if ( InFunction->NumParms == 1 && InFunction->GetReturnProperty() == nullptr )
942 {
943 // Verify there's a return property.
945 {
946 if constexpr (std::is_same<FPropertyStructView, T>::value)
947 {
948 const FPropertyStructView& InStuctView = static_cast<const FPropertyStructView&>(InValue);
949
950 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
951 if (ParamProperty->GetElementSize() == InStuctView.ScriptStruct->GetStructureSize() && !InContainer->IsUnreachable())
952 {
953 InContainer->ProcessEvent(InFunction, const_cast<uint8*>(InStuctView.Memory));
954 return true;
955 }
956 }
957 // Verify that the cpp type matches a known property type.
959 {
960 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
961 if ( PropertySizesMatch<T>(ParamProperty) && !InContainer->IsUnreachable() )
962 {
963 InContainer->ProcessEvent(InFunction, const_cast<T*>(&InValue));
964 return true;
965 }
966 }
967 }
968 }
969 else
970 {
971 //LOG ERROR
972 }
973
974 return false;
975 }
976 };
977
979 template<typename T, typename ContainerType>
980 struct FSetValueHelper
981 {
982 static bool SetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const T& InValue)
983 {
984 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
985 int32 ArrayIndex = LastSegment.GetArrayIndex();
987
988 if constexpr (std::is_same<FPropertyStructView, T>::value)
989 {
990 const FPropertyStructView& InStuctView = static_cast<const FPropertyStructView&>(InValue);
991
992 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
993 ArrayIndex = ArrayIndex == INDEX_NONE ? 0 : ArrayIndex;
994 if ( Property->GetElementSize() == InStuctView.ScriptStruct->GetStructureSize() && ArrayIndex < Property->ArrayDim)
995 {
996 if (Property->HasSetter())
997 {
998 Property->CallSetter(InContainer, InStuctView.Memory);
999 }
1000 else if (void* Address = Property->ContainerPtrToValuePtr<void>(InContainer, ArrayIndex))
1001 {
1002 InPropertyPath.ResolveLeaf(Address);
1003 Property->CopySingleValue(Address, InStuctView.Memory);
1005 }
1006 return true;
1007 }
1008 }
1009 // Verify that the cpp type matches a known property type.
1011 {
1012 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1013 ArrayIndex = ArrayIndex == INDEX_NONE ? 0 : ArrayIndex;
1015 {
1016 if (Property->HasSetter())
1017 {
1018 Property->CallSetter(InContainer, &InValue);
1019 }
1020 else if (void* Address = Property->ContainerPtrToValuePtr<T>(InContainer, ArrayIndex))
1021 {
1022 InPropertyPath.ResolveLeaf(Address);
1023 Property->CopySingleValue(Address, &InValue);
1025 }
1026 return true;
1027 }
1028 }
1029
1030 return false;
1031 }
1032 };
1033
1035 template<typename T, typename ContainerType, int32 N>
1036 struct FSetValueHelper<T[N], ContainerType>
1037 {
1038 static bool SetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const T(&InValue)[N])
1039 {
1040 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1042
1043 // Verify that the cpp type matches a known property type.
1045 {
1046 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1047 if ( PropertySizesMatch<T>(Property) && Property->ArrayDim == N )
1048 {
1049 if(void* Address = Property->ContainerPtrToValuePtr<T>(InContainer))
1050 {
1051 InPropertyPath.ResolveLeaf(Address);
1052 Property->CopyCompleteValue(Address, &InValue);
1053 return true;
1054 }
1055 }
1056 }
1057
1058 return false;
1059 }
1060 };
1061
1063 template<typename ContainerType>
1064 struct FSetValueHelper<bool, ContainerType>
1065 {
1066 static bool SetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const bool& InValue)
1067 {
1068 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1069 int32 ArrayIndex = LastSegment.GetArrayIndex();
1071
1072 // Verify that the cpp type matches a known property type.
1074 {
1075 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1076 ArrayIndex = ArrayIndex == INDEX_NONE ? 0 : ArrayIndex;
1078 {
1079 if(void* Address = Property->ContainerPtrToValuePtr<bool>(InContainer, ArrayIndex))
1080 {
1081 InPropertyPath.ResolveLeaf(Address);
1082
1083 if (Property->HasSetter())
1084 {
1085 // Setter should be specialized to handle masking
1086 Property->CallSetter(InContainer, &InValue);
1087 }
1088 else
1089 {
1091 BoolProperty->SetPropertyValue(InPropertyPath.GetCachedAddress(), InValue);
1093 }
1094 return true;
1095 }
1096 }
1097 }
1098
1099 return false;
1100 }
1101 };
1102
1111 template<typename T, typename ContainerType>
1112 bool SetValue(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const T& InValue)
1113 {
1114 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1115 int32 ArrayIndex = LastSegment.GetArrayIndex();
1116 FFieldVariant Field = LastSegment.GetField();
1117
1118 // We're on the final property in the path, it may be an array property, so check that first.
1120 {
1121 // if it's an array property, we need to see if we parsed an index as part of the segment
1122 // as a user may have baked the index directly into the property path.
1123 if(ArrayIndex != INDEX_NONE)
1124 {
1125 // Property is an array property, so make sure we have a valid index specified
1127 if ( ArrayHelper.IsValidIndex(ArrayIndex) )
1128 {
1129 if constexpr (std::is_same<FPropertyStructView, T>::value)
1130 {
1131 const FPropertyStructView& InStuctView = static_cast<const FPropertyStructView&>(InValue);
1132
1133 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1134 if (ArrayProp->Inner->GetElementSize() == InStuctView.ScriptStruct->GetStructureSize())
1135 {
1136 if (void* Address = static_cast<void*>(ArrayHelper.GetRawPtr(ArrayIndex)))
1137 {
1138 InPropertyPath.ResolveLeaf(Address);
1139 ArrayProp->Inner->CopySingleValue(Address, InStuctView.Memory);
1140 return true;
1141 }
1142 }
1143 }
1144 else
1145 {
1146 // Verify that the cpp type matches a known property type.
1148 {
1149 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1150 if (PropertySizesMatch<T>(ArrayProp->Inner))
1151 {
1152 if (void* Address = static_cast<void*>(ArrayHelper.GetRawPtr(ArrayIndex)))
1153 {
1154 InPropertyPath.ResolveLeaf(Address);
1155 ArrayProp->Inner->CopySingleValue(Address, &InValue);
1156 return true;
1157 }
1158 }
1159 }
1160 }
1161 }
1162 }
1163 else
1164 {
1165 // No index, so assume we want the array property itself
1166 // Verify that the cpp type matches a known property type.
1167 if constexpr (!std::is_same<FPropertyStructView, T>::value)
1168 {
1170 {
1171 // Ensure that the element sizes are the same, prevents the user from doing something terribly wrong.
1173 {
1174 if (void* Address = ArrayProp->ContainerPtrToValuePtr<T>(InContainer))
1175 {
1176 InPropertyPath.ResolveLeaf(Address);
1177 ArrayProp->CopySingleValue(Address, &InValue);
1178 return true;
1179 }
1180 }
1181 }
1182 }
1183 }
1184 }
1185 else if(UFunction* Function = Field.Get<UFunction>())
1186 {
1187 InPropertyPath.ResolveLeaf(Function);
1188 return FCallSetterFunctionHelper<T, ContainerType>::CallSetterFunction(InContainer, Function, InValue);
1189 }
1190 else if(FProperty* Property = Field.Get<FProperty>())
1191 {
1192 return FSetValueHelper<T, ContainerType>::SetValue(InContainer, InPropertyPath, InValue);
1193 }
1194
1195 return false;
1196 }
1197
1198 template<typename T>
1199 struct FInternalSetterResolver : public TPropertyPathResolver<FInternalSetterResolver<T>>
1200 {
1201 FInternalSetterResolver(const T& InValueToSet)
1203 {
1204 }
1205
1206 template<typename ContainerType>
1207 bool Resolve_Impl(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath)
1208 {
1209 return SetValue<T>(InContainer, InPropertyPath, Value);
1210 }
1211
1212 const T& Value;
1213 };
1214
1223
1233
1241 PROPERTYPATH_API bool ResolvePropertyPath(UObject* InContainer, const FString& InPropertyPath, FPropertyPathResolver& InResolver);
1242
1251 PROPERTYPATH_API bool ResolvePropertyPath(void* InContainer, UStruct* InStruct, const FString& InPropertyPath, FPropertyPathResolver& InResolver);
1252
1254 template<typename T>
1255 struct FGetValueFastHelper
1256 {
1258 {
1259 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1260 OutProperty = CastFieldChecked<FProperty>(LastSegment.GetField().ToField());
1262 if ( ArrayProp && LastSegment.GetArrayIndex() != INDEX_NONE )
1263 {
1265 {
1266 ArrayProp->Inner->CopySingleValue(&OutValue, InPropertyPath.GetCachedAddress());
1267 return true;
1268 }
1269 }
1271 {
1272 if (OutProperty->HasGetter())
1273 {
1274 OutProperty->CallGetter(InPropertyPath.GetCachedContainer(), &OutValue);
1275 }
1276 else
1277 {
1279 }
1280 return true;
1281 }
1282 return false;
1283 }
1284 };
1285
1287 template<typename T, int32 N>
1288 struct FGetValueFastHelper<T[N]>
1289 {
1291 {
1292 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1293 OutProperty = CastFieldChecked<FProperty>(LastSegment.GetField().ToField());
1295 {
1296 OutProperty->CopyCompleteValue(&OutValue, InPropertyPath.GetCachedAddress());
1297 return true;
1298 }
1299 return false;
1300 }
1301 };
1302
1311 template<typename T, typename ContainerType>
1312 bool GetValueFast(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, T& OutValue, FProperty*& OutProperty)
1313 {
1314 if(InPropertyPath.GetCachedFunction())
1315 {
1316 return FCallGetterFunctionHelper<T, ContainerType>::CallGetterFunction(InContainer, InPropertyPath.GetCachedFunction(), OutValue);
1317 }
1318 else if(InPropertyPath.GetCachedAddress())
1319 {
1320 return FGetValueFastHelper<T>::GetValue(InPropertyPath, OutValue, OutProperty);
1321 }
1322
1323 return false;
1324 }
1325
1327 template<typename T>
1328 struct FSetValueFastHelper
1329 {
1330 static bool SetValue(const FCachedPropertyPath& InPropertyPath, const T& InValue)
1331 {
1332 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1335
1336 const void* Value = nullptr;
1337 if constexpr (std::is_same<FPropertyStructView, T>::value)
1338 {
1339 const FPropertyStructView& InStuctView = static_cast<const FPropertyStructView&>(InValue);
1340 Value = static_cast<const void*>(InStuctView.Memory);
1341 }
1342 else
1343 {
1344 Value = &InValue;
1345 }
1346
1348 {
1349 if constexpr (!std::is_same<FPropertyStructView, T>::value)
1350 {
1352 {
1353 return false;
1354 }
1355 }
1356
1357 return true;
1358 };
1359
1360 if ( ArrayProp && LastSegment.GetArrayIndex() != INDEX_NONE )
1361 {
1362 if (!IsPropertyCompatible(ArrayProp->Inner))
1363 {
1364 return false;
1365 }
1366
1367 ArrayProp->Inner->CopySingleValue(InPropertyPath.GetCachedAddress(), Value);
1368 return true;
1369 }
1370 else
1371 {
1373 {
1374 return false;
1375 }
1376
1377 if (Property->HasSetter())
1378 {
1379 Property->CallSetter(InPropertyPath.GetCachedContainer(), Value);
1380 }
1381 else
1382 {
1383 Property->CopySingleValue(InPropertyPath.GetCachedAddress(), Value);
1385 }
1386 return true;
1387 }
1388 }
1389 };
1390
1392 template<typename T, int32 N>
1393 struct FSetValueFastHelper<T[N]>
1394 {
1395 static bool SetValue(const FCachedPropertyPath& InPropertyPath, const T(&InValue)[N])
1396 {
1397 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1400 {
1401 Property->CopyCompleteValue(InPropertyPath.GetCachedAddress(), &InValue);
1402 return true;
1403 }
1404 return false;
1405 }
1406 };
1407
1409 template<>
1410 struct FSetValueFastHelper<bool>
1411 {
1412 static bool SetValue(const FCachedPropertyPath& InPropertyPath, const bool& InValue)
1413 {
1414 const FPropertyPathSegment& LastSegment = InPropertyPath.GetLastSegment();
1417 if ( ArrayProp && LastSegment.GetArrayIndex() != INDEX_NONE )
1418 {
1420 {
1421 ArrayProp->Inner->CopySingleValue(InPropertyPath.GetCachedAddress(), &InValue);
1422 return true;
1423 }
1424 }
1426 {
1427 if (Property->HasSetter())
1428 {
1429 // Setter should be specialized to handle masking
1430 Property->CallSetter(InPropertyPath.GetCachedContainer(), &InValue);
1431 }
1432 else
1433 {
1435 BoolProperty->SetPropertyValue(InPropertyPath.GetCachedAddress(), InValue);
1437 }
1438 return true;
1439 }
1440 return false;
1441 }
1442 };
1443
1451 template<typename T, typename ContainerType>
1452 bool SetValueFast(ContainerType* InContainer, const FCachedPropertyPath& InPropertyPath, const T& InValue)
1453 {
1454 if(InPropertyPath.GetCachedFunction())
1455 {
1456 return FCallSetterFunctionHelper<T, ContainerType>::CallSetterFunction(InContainer, InPropertyPath.GetCachedFunction(), InValue);
1457 }
1458 else if(InPropertyPath.GetCachedAddress())
1459 {
1460 return FSetValueFastHelper<T>::SetValue(InPropertyPath, InValue);
1461 }
1462
1463 return false;
1464 }
1465}
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
const bool
Definition NetworkReplayStreaming.h:178
#define UPROPERTY(...)
UObject definition macros.
Definition ObjectMacros.h:744
@ CPF_Parm
Function/When call parameter.
Definition ObjectMacros.h:426
@ CPF_OutParm
Value is copied out after function call.
Definition ObjectMacros.h:427
@ CPF_ReturnParm
Return value.
Definition ObjectMacros.h:429
#define GENERATED_BODY(...)
Definition ObjectMacros.h:765
#define USTRUCT(...)
Definition ObjectMacros.h:746
@ PPF_None
Definition PropertyPortFlags.h:15
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
Definition UnrealType.h:3702
Definition UnrealType.h:2543
Definition UnrealType.h:6738
Definition Field.h:353
Definition NameTypes.h:617
Definition UnrealType.h:174
Definition UnrealType.h:4564
Definition UnrealType.h:4175
Definition Array.h:670
Definition UnrealType.h:7083
Definition AssetRegistryState.h:50
Definition Class.h:2476
Definition Object.h:95
virtual COREUOBJECT_API void ProcessEvent(UFunction *Function, void *Parms)
Definition ScriptCore.cpp:2015
Definition Class.h:1720
Definition Class.h:480
IAnalyticsPropertyStore::EStatusCode SetValue(TGetter &&GetterFn, TSetter &&SetterFn, const T &ProposedValue, TCompare &&ConditionFn)
Definition AnalyticsPropertyStore.cpp:34
uint32 Type
Definition UnrealType.h:6835
T::FDataType GetValue(const UBlackboardComponent &Blackboard, const FName &Name, FBlackboard::FKey &InOutCachedKey, const typename T::FDataType &DefaultValue)
Definition ValueOrBBKey.h:51
Definition FieldSystemNoiseAlgo.cpp:6
Definition PropertyPathHelpers.cpp:10
void CallParentSetters(const FCachedPropertyPath &InPropertyPath)
Definition PropertyPathHelpers.cpp:523
FProperty * GetFirstParamProperty(UFunction *InFunction)
Definition PropertyPathHelpers.cpp:511
void CallParentGetters(void *OutValue, const FCachedPropertyPath &InPropertyPath, const void *InPropertyAddress)
Definition PropertyPathHelpers.cpp:586
bool ResolvePropertyPath(UObject *InContainer, const FString &InPropertyPath, FPropertyPathResolver &InResolver)
Definition PropertyPathHelpers.cpp:479
Definition PropertyPathHelpers.cpp:1090
bool PerformArrayOperation(UObject *InContainer, const FString &InPropertyPath, TFunctionRef< bool(FScriptArrayHelper &, int32)> InOperation)
Definition PropertyPathHelpers.cpp:1301
void FindFieldNameAndArrayIndex(int32 InCount, const TCHAR *InString, int32 &OutCount, const TCHAR **OutPropertyName, int32 &OutArrayIndex)
Definition PropertyPathHelpers.cpp:1091
bool CopyPropertyValue(UObject *InContainer, const FCachedPropertyPath &InDestPropertyPath, const FCachedPropertyPath &InSrcPropertyPath)
Definition PropertyPathHelpers.cpp:1248
bool SetPropertyValueFromString(UObject *InContainer, const FString &InPropertyPath, const FString &InValue, uint32 PPF_Flags)
Definition PropertyPathHelpers.cpp:1202
bool GetPropertyValueAsString(UObject *InContainer, const FString &InPropertyPath, FString &OutValue, uint32 PPF_Flags)
Definition PropertyPathHelpers.cpp:1114
bool SetPropertyValue(UObject *InContainer, const FCachedPropertyPath &InPropertyPath, const UScriptStruct *InScriptStruct, const uint8 *InValue)
Definition PropertyPathHelpers.cpp:1236
bool CopyPropertyValueFast(UObject *InContainer, const FCachedPropertyPath &InDestPropertyPath, const FCachedPropertyPath &InSrcPropertyPath)
Definition PropertyPathHelpers.cpp:1273
EPropertyBagResult GetPropertyValue(const FPropertyBagPropertyDesc *Desc, const void *Address, T &OutValue)
Definition PropertyBag.cpp:761
Definition PropertyPathHelpers.h:97
PROPERTYPATH_API ~FCachedPropertyPath()
bool IsValid() const
Definition PropertyPathHelpers.h:120
Definition UnrealType.h:7001
Definition UnrealType.h:6865
Definition PropertyPathHelpers.h:28
PROPERTYPATH_API int32 GetArrayIndex() const
Definition PropertyPathHelpers.cpp:725
Definition ObjectPtr.h:488
Definition StructOpsTypeTraits.h:11
Definition StructOpsTypeTraits.h:46