2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StateTreePropertyBindings.h"
2023-01-19 00:48:07 -05:00
# include "UObject/EnumProperty.h"
2023-02-10 07:22:48 -05:00
# include "Misc/EnumerateRange.h"
# include "PropertyPathHelpers.h"
2021-09-28 13:33:17 -04:00
2023-06-21 10:27:51 -04:00
# if WITH_EDITOR
# include "UObject/CoreRedirects.h"
# include "UObject/Package.h"
# include "Engine/BlueprintGeneratedClass.h"
# include "Engine/UserDefinedStruct.h"
# include "Kismet2/StructureEditorUtils.h"
# endif
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(StateTreePropertyBindings)
2023-06-26 06:36:04 -04:00
namespace UE : : StateTree
{
FString GetDescAndPathAsString ( const FStateTreeBindableStructDesc & Desc , const FStateTreePropertyPath & Path )
{
FStringBuilderBase Result ;
Result + = Desc . ToString ( ) ;
if ( ! Path . IsPathEmpty ( ) )
{
Result + = TEXT ( " " ) ;
Result + = Path . ToString ( ) ;
}
return Result . ToString ( ) ;
}
} // UE::StateTree
2023-02-10 07:22:48 -05:00
namespace UE : : StateTree : : Private
{
# if WITH_EDITORONLY_DATA
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FStateTreePropertyPath ConvertEditorPath ( const FStateTreeEditorPropertyPath & InEditorPath )
{
FStateTreePropertyPath Path ;
Path . SetStructID ( InEditorPath . StructID ) ;
for ( const FString & Segment : InEditorPath . Path )
{
const TCHAR * PropertyNamePtr = nullptr ;
int32 PropertyNameLength = 0 ;
int32 ArrayIndex = INDEX_NONE ;
PropertyPathHelpers : : FindFieldNameAndArrayIndex ( Segment . Len ( ) , * Segment , PropertyNameLength , & PropertyNamePtr , ArrayIndex ) ;
FString PropertyNameString ( PropertyNameLength , PropertyNamePtr ) ;
const FName PropertyName ( * PropertyNameString , FNAME_Find ) ;
Path . AddPathSegment ( PropertyName , ArrayIndex ) ;
}
return Path ;
}
FStateTreeEditorPropertyPath ConvertEditorPath ( const FStateTreePropertyPath & InPath )
{
FStateTreeEditorPropertyPath Path ;
Path . StructID = InPath . GetStructID ( ) ;
for ( const FStateTreePropertyPathSegment & Segment : InPath . GetSegments ( ) )
{
if ( Segment . GetArrayIndex ( ) ! = INDEX_NONE )
{
Path . Path . Add ( FString : : Printf ( TEXT ( " %s[%d] " ) , * Segment . GetName ( ) . ToString ( ) , Segment . GetArrayIndex ( ) ) ) ;
}
else
{
Path . Path . Add ( Segment . GetName ( ) . ToString ( ) ) ;
}
}
return Path ;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
# endif // WITH_EDITORONLY_DATA
2023-06-26 06:36:04 -04:00
} // UE::StateTree::Private
2023-02-10 07:22:48 -05:00
2023-06-26 06:36:04 -04:00
//----------------------------------------------------------------//
// FStateTreeBindableStructDesc
//----------------------------------------------------------------//
FString FStateTreeBindableStructDesc : : ToString ( ) const
{
FStringBuilderBase Result ;
Result + = UEnum : : GetDisplayValueAsText ( DataSource ) . ToString ( ) ;
Result + = TEXT ( " ' " ) ;
Result + = Name . ToString ( ) ;
Result + = TEXT ( " ' " ) ;
return Result . ToString ( ) ;
}
2023-02-10 07:22:48 -05:00
//----------------------------------------------------------------//
// FStateTreePropertyPathBinding
//----------------------------------------------------------------//
void FStateTreePropertyPathBinding : : PostSerialize ( const FArchive & Ar )
{
# if WITH_EDITORONLY_DATA
PRAGMA_DISABLE_DEPRECATION_WARNINGS
if ( SourcePath_DEPRECATED . IsValid ( ) )
{
SourcePropertyPath = UE : : StateTree : : Private : : ConvertEditorPath ( SourcePath_DEPRECATED ) ;
SourcePath_DEPRECATED . StructID = FGuid ( ) ;
SourcePath_DEPRECATED . Path . Reset ( ) ;
}
if ( TargetPath_DEPRECATED . IsValid ( ) )
{
TargetPropertyPath = UE : : StateTree : : Private : : ConvertEditorPath ( TargetPath_DEPRECATED ) ;
TargetPath_DEPRECATED . StructID = FGuid ( ) ;
TargetPath_DEPRECATED . Path . Reset ( ) ;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
# endif // WITH_EDITORONLY_DATA
}
2021-09-28 13:33:17 -04:00
//----------------------------------------------------------------//
// FStateTreePropertyBindings
//----------------------------------------------------------------//
void FStateTreePropertyBindings : : Reset ( )
{
SourceStructs . Reset ( ) ;
CopyBatches . Reset ( ) ;
2023-02-10 07:22:48 -05:00
PropertyPathBindings . Reset ( ) ;
2021-09-28 13:33:17 -04:00
PropertyCopies . Reset ( ) ;
PropertyIndirections . Reset ( ) ;
2023-02-10 07:22:48 -05:00
2021-09-28 13:33:17 -04:00
bBindingsResolved = false ;
}
bool FStateTreePropertyBindings : : ResolvePaths ( )
{
PropertyIndirections . Reset ( ) ;
2023-02-10 07:22:48 -05:00
PropertyCopies . SetNum ( PropertyPathBindings . Num ( ) ) ;
2021-09-28 13:33:17 -04:00
bBindingsResolved = true ;
bool bResult = true ;
2023-02-10 07:22:48 -05:00
for ( const FStateTreePropertyCopyBatch & Batch : CopyBatches )
2021-09-28 13:33:17 -04:00
{
for ( int32 i = Batch . BindingsBegin ; i ! = Batch . BindingsEnd ; i + + )
{
2023-02-10 07:22:48 -05:00
const FStateTreePropertyPathBinding & Binding = PropertyPathBindings [ i ] ;
FStateTreePropertyCopy & Copy = PropertyCopies [ i ] ;
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
if ( ! Binding . GetCompiledSourceStructIndex ( ) . IsValid ( ) )
{
2023-02-10 10:44:54 -05:00
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: Invalid source struct for property binding %s. " ) , __FUNCTION__ , * Binding . GetSourcePath ( ) . ToString ( ) ) ;
2023-02-10 07:22:48 -05:00
bResult = false ;
continue ;
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
Copy . SourceStructIndex = Binding . GetCompiledSourceStructIndex ( ) ;
const UStruct * SourceStruct = SourceStructs [ Copy . SourceStructIndex . Get ( ) ] . Struct ;
2021-09-28 13:33:17 -04:00
const UStruct * TargetStruct = Batch . TargetStruct . Struct ;
if ( ! SourceStruct | | ! TargetStruct )
{
2022-04-28 03:54:07 -04:00
Copy . Type = EStateTreePropertyCopyType : : None ;
2021-09-28 13:33:17 -04:00
bBindingsResolved = false ;
2022-04-28 03:54:07 -04:00
bResult = false ;
continue ;
2021-09-28 13:33:17 -04:00
}
// Resolve paths and validate the copy. Stops on first failure.
bool bSuccess = true ;
2023-02-10 07:22:48 -05:00
FStateTreePropertyPathIndirection SourceLeafIndirection ;
FStateTreePropertyPathIndirection TargetLeafIndirection ;
bSuccess = bSuccess & & ResolvePath ( SourceStruct , Binding . GetSourcePath ( ) , Copy . SourceIndirection , SourceLeafIndirection ) ;
bSuccess = bSuccess & & ResolvePath ( TargetStruct , Binding . GetTargetPath ( ) , Copy . TargetIndirection , TargetLeafIndirection ) ;
2023-06-26 06:36:04 -04:00
bSuccess = bSuccess & & ResolveCopyType ( SourceLeafIndirection , TargetLeafIndirection , Copy ) ;
2023-02-10 07:22:48 -05:00
if ( ! bSuccess )
2021-09-28 13:33:17 -04:00
{
// Resolving or validating failed, make the copy a nop.
Copy . Type = EStateTreePropertyCopyType : : None ;
bResult = false ;
}
}
}
return bResult ;
}
2023-02-10 07:22:48 -05:00
bool FStateTreePropertyBindings : : ResolvePath ( const UStruct * Struct , const FStateTreePropertyPath & Path , FStateTreePropertyIndirection & OutFirstIndirection , FStateTreePropertyPathIndirection & OutLeafIndirection )
2021-09-28 13:33:17 -04:00
{
if ( ! Struct )
2023-02-10 07:22:48 -05:00
{
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: '%s' Invalid source struct. " ) , __FUNCTION__ , * Path . ToString ( ) ) ;
2021-09-28 13:33:17 -04:00
return false ;
}
2023-02-10 07:22:48 -05:00
FString Error ;
TArray < FStateTreePropertyPathIndirection > PathIndirections ;
if ( ! Path . ResolveIndirections ( Struct , PathIndirections , & Error ) )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: %s " ) , __FUNCTION__ , * Error ) ;
return false ;
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
// Casts array index to FStateTreeIndex16 (clamping INDEX_NONE to 0) or returns false if out if index bounds.
auto CastArrayIndexToIndex16 = [ ] ( const int32 Index )
{
const int32 ClampedIndex = FMath : : Max ( 0 , Index ) ;
if ( ! FStateTreeIndex16 : : IsValidIndex ( ClampedIndex ) )
{
return FStateTreeIndex16 ( ) ;
}
return FStateTreeIndex16 ( ClampedIndex ) ;
} ;
TArray < FStateTreePropertyIndirection , TInlineAllocator < 16 > > TempIndirections ;
for ( FStateTreePropertyPathIndirection & PathIndirection : PathIndirections )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
FStateTreePropertyIndirection & Indirection = TempIndirections . AddDefaulted_GetRef ( ) ;
2021-09-28 13:33:17 -04:00
2023-05-10 15:14:21 -04:00
check ( PathIndirection . GetPropertyOffset ( ) > = MIN_uint16 & & PathIndirection . GetPropertyOffset ( ) < = MAX_uint16 ) ;
Indirection . Offset = static_cast < uint16 > ( PathIndirection . GetPropertyOffset ( ) ) ;
2023-02-10 07:22:48 -05:00
Indirection . Type = PathIndirection . GetAccessType ( ) ;
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
if ( Indirection . Type = = EStateTreePropertyAccessType : : IndexArray )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
if ( const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( PathIndirection . GetProperty ( ) ) )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
Indirection . ArrayProperty = ArrayProperty ;
Indirection . ArrayIndex = CastArrayIndexToIndex16 ( PathIndirection . GetArrayIndex ( ) ) ;
if ( ! Indirection . ArrayIndex . IsValid ( ) )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: Array index %d at %s, is too large. " ) ,
__FUNCTION__ , PathIndirection . GetArrayIndex ( ) , * Path . ToString ( PathIndirection . GetPathSegmentIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
return false ;
}
2021-09-28 13:33:17 -04:00
}
2023-02-10 07:22:48 -05:00
else
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: Expect property %s to be array property. " ) ,
__FUNCTION__ , * Path . ToString ( PathIndirection . GetPathSegmentIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
return false ;
2021-09-28 13:33:17 -04:00
}
}
2023-02-10 07:22:48 -05:00
else if ( Indirection . Type = = EStateTreePropertyAccessType : : StructInstance
| | Indirection . Type = = EStateTreePropertyAccessType : : ObjectInstance )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
if ( PathIndirection . GetInstanceStruct ( ) )
{
Indirection . InstanceStruct = PathIndirection . GetInstanceStruct ( ) ;
}
else
{
UE_LOG ( LogStateTree , Error , TEXT ( " %hs: Expect instanced property access %s to have instance type specified. " ) ,
__FUNCTION__ , * Path . ToString ( PathIndirection . GetPathSegmentIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
return false ;
}
2021-09-28 13:33:17 -04:00
}
}
2022-06-03 04:55:42 -04:00
if ( TempIndirections . Num ( ) > 0 )
2021-09-28 13:33:17 -04:00
{
2022-06-03 04:55:42 -04:00
for ( int32 Index = 0 ; Index < TempIndirections . Num ( ) ; Index + + )
2021-09-28 13:33:17 -04:00
{
2022-06-03 04:55:42 -04:00
FStateTreePropertyIndirection & Indirection = TempIndirections [ Index ] ;
2023-02-10 07:22:48 -05:00
if ( ( Index + 1 ) < TempIndirections . Num ( ) )
2021-09-28 13:33:17 -04:00
{
2022-06-03 04:55:42 -04:00
const FStateTreePropertyIndirection & NextIndirection = TempIndirections [ Index + 1 ] ;
2023-02-10 07:22:48 -05:00
if ( Indirection . Type = = EStateTreePropertyAccessType : : Offset
& & NextIndirection . Type = = EStateTreePropertyAccessType : : Offset )
2022-06-03 04:55:42 -04:00
{
2023-02-10 07:22:48 -05:00
// Collapse adjacent offset indirections
2022-06-03 04:55:42 -04:00
Indirection . Offset + = NextIndirection . Offset ;
TempIndirections . RemoveAt ( Index + 1 ) ;
Index - - ;
}
2023-02-10 07:22:48 -05:00
else if ( Indirection . Type = = EStateTreePropertyAccessType : : IndexArray
& & NextIndirection . Type = = EStateTreePropertyAccessType : : Offset
& & NextIndirection . Offset = = 0 )
{
// Remove empty offset after array indexing.
TempIndirections . RemoveAt ( Index + 1 ) ;
Index - - ;
}
else if ( Indirection . Type = = EStateTreePropertyAccessType : : StructInstance
& & NextIndirection . Type = = EStateTreePropertyAccessType : : Offset
& & NextIndirection . Offset = = 0 )
{
// Remove empty offset after struct indirection.
TempIndirections . RemoveAt ( Index + 1 ) ;
Index - - ;
}
else if ( ( Indirection . Type = = EStateTreePropertyAccessType : : Object
| | Indirection . Type = = EStateTreePropertyAccessType : : ObjectInstance )
& & NextIndirection . Type = = EStateTreePropertyAccessType : : Offset
& & NextIndirection . Offset = = 0 )
{
// Remove empty offset after object indirection.
TempIndirections . RemoveAt ( Index + 1 ) ;
Index - - ;
}
2021-09-28 13:33:17 -04:00
}
}
2022-06-03 04:55:42 -04:00
2023-02-10 07:22:48 -05:00
OutLeafIndirection = PathIndirections . Last ( ) ;
2022-06-03 04:55:42 -04:00
// Store indirections
OutFirstIndirection = TempIndirections [ 0 ] ;
FStateTreePropertyIndirection * PrevIndirection = & OutFirstIndirection ;
for ( int32 Index = 1 ; Index < TempIndirections . Num ( ) ; Index + + )
{
const int32 IndirectionIndex = PropertyIndirections . Num ( ) ;
2023-04-24 22:59:49 -04:00
PrevIndirection - > NextIndex = FStateTreeIndex16 ( IndirectionIndex ) ; // Set PrevIndirection before array add, as it can invalidate the pointer.
2022-06-03 04:55:42 -04:00
FStateTreePropertyIndirection & NewIndirection = PropertyIndirections . Add_GetRef ( TempIndirections [ Index ] ) ;
PrevIndirection = & NewIndirection ;
}
2021-09-28 13:33:17 -04:00
}
2022-06-03 04:55:42 -04:00
else
2022-05-31 04:51:18 -04:00
{
2022-06-03 04:55:42 -04:00
// Indirections can be empty in case we're directly binding to source structs.
// Zero offset will return the struct itself.
OutFirstIndirection . Offset = 0 ;
OutFirstIndirection . Type = EStateTreePropertyAccessType : : Offset ;
2023-02-10 07:22:48 -05:00
OutLeafIndirection = FStateTreePropertyPathIndirection ( Struct ) ;
2022-05-31 04:51:18 -04:00
}
2021-09-28 13:33:17 -04:00
return true ;
}
2023-06-26 06:36:04 -04:00
bool FStateTreePropertyBindings : : ResolveCopyType ( const FStateTreePropertyPathIndirection & SourceIndirection , const FStateTreePropertyPathIndirection & TargetIndirection , FStateTreePropertyCopy & OutCopy )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
// @todo: see if GetPropertyCompatibility() can be implemented as call to ResolveCopyType() instead so that we write this logic just once.
const FProperty * SourceProperty = SourceIndirection . GetProperty ( ) ;
const UStruct * SourceStruct = SourceIndirection . GetContainerStruct ( ) ;
const FProperty * TargetProperty = TargetIndirection . GetProperty ( ) ;
const UStruct * TargetStruct = TargetIndirection . GetContainerStruct ( ) ;
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
if ( ! SourceStruct | | ! TargetStruct )
2022-04-20 07:19:18 -04:00
{
return false ;
}
2023-06-26 06:36:04 -04:00
OutCopy . SourceLeafProperty = SourceProperty ;
OutCopy . TargetLeafProperty = TargetProperty ;
OutCopy . CopySize = 0 ;
OutCopy . Type = EStateTreePropertyCopyType : : None ;
2023-02-10 07:22:48 -05:00
2022-04-14 06:28:13 -04:00
if ( SourceProperty = = nullptr )
{
2023-02-10 07:22:48 -05:00
// Copy directly from the source struct, target must be.
if ( const FStructProperty * TargetStructProperty = CastField < FStructProperty > ( TargetProperty ) )
{
if ( TargetStructProperty - > Struct = = SourceStruct )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyStruct ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( const FObjectPropertyBase * TargetObjectProperty = CastField < FObjectPropertyBase > ( TargetProperty ) )
{
if ( SourceStruct - > IsChildOf ( TargetObjectProperty - > PropertyClass ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyObject ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
return false ;
2022-04-14 06:28:13 -04:00
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
// Handle FStateTreeStructRef
if ( const FStructProperty * TargetStructProperty = CastField < const FStructProperty > ( TargetProperty ) )
{
if ( TargetStructProperty - > Struct = = TBaseStructure < FStateTreeStructRef > : : Get ( ) )
{
if ( const FStructProperty * SourceStructProperty = CastField < const FStructProperty > ( SourceProperty ) )
{
// FStateTreeStructRef to FStateTreeStructRef is copied as usual.
if ( SourceStructProperty - > Struct ! = TBaseStructure < FStateTreeStructRef > : : Get ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : StructReference ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
}
}
const EStateTreePropertyAccessCompatibility Compatibility = FStateTreePropertyBindings : : GetPropertyCompatibility ( SourceProperty , TargetProperty ) ;
2021-09-28 13:33:17 -04:00
// Extract underlying types for enums
if ( const FEnumProperty * EnumPropertyA = CastField < const FEnumProperty > ( SourceProperty ) )
{
SourceProperty = EnumPropertyA - > GetUnderlyingProperty ( ) ;
}
if ( const FEnumProperty * EnumPropertyB = CastField < const FEnumProperty > ( TargetProperty ) )
{
TargetProperty = EnumPropertyB - > GetUnderlyingProperty ( ) ;
}
2023-02-10 07:22:48 -05:00
if ( Compatibility = = EStateTreePropertyAccessCompatibility : : Compatible )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
if ( CastField < FNameProperty > ( TargetProperty ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyName ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( CastField < FBoolProperty > ( TargetProperty ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyBool ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( CastField < FStructProperty > ( TargetProperty ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyStruct ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( CastField < FObjectPropertyBase > ( TargetProperty ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyObject ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( CastField < FArrayProperty > ( TargetProperty ) & & TargetProperty - > HasAnyPropertyFlags ( CPF_EditFixedSize ) )
{
// only apply array copying rules if the destination array is fixed size, otherwise it will be 'complex'
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyFixedArray ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > PropertyFlags & CPF_IsPlainOldData )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyPlain ;
OutCopy . CopySize = SourceProperty - > ElementSize * SourceProperty - > ArrayDim ;
2023-02-10 07:22:48 -05:00
return true ;
}
else
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : CopyComplex ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( Compatibility = = EStateTreePropertyAccessCompatibility : : Promotable )
2022-06-29 04:52:18 -04:00
{
2023-02-10 07:22:48 -05:00
if ( SourceProperty - > IsA < FBoolProperty > ( ) )
{
if ( TargetProperty - > IsA < FByteProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToByte ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FIntProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FUInt32Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToUInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FFloatProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToFloat ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FDoubleProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteBoolToDouble ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( SourceProperty - > IsA < FByteProperty > ( ) )
{
if ( TargetProperty - > IsA < FIntProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteByteToInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FUInt32Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteByteToUInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteByteToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FFloatProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteByteToFloat ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FDoubleProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteByteToDouble ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( SourceProperty - > IsA < FIntProperty > ( ) )
{
if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteInt32ToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FFloatProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteInt32ToFloat ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FDoubleProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteInt32ToDouble ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( SourceProperty - > IsA < FUInt32Property > ( ) )
{
if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteUInt32ToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FFloatProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteUInt32ToFloat ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FDoubleProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteUInt32ToDouble ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( SourceProperty - > IsA < FFloatProperty > ( ) )
{
if ( TargetProperty - > IsA < FIntProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteFloatToInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteFloatToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FDoubleProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : PromoteFloatToDouble ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
else if ( SourceProperty - > IsA < FDoubleProperty > ( ) )
{
if ( TargetProperty - > IsA < FIntProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : DemoteDoubleToInt32 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FInt64Property > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : DemoteDoubleToInt64 ;
2023-02-10 07:22:48 -05:00
return true ;
}
else if ( TargetProperty - > IsA < FFloatProperty > ( ) )
{
2023-06-26 06:36:04 -04:00
OutCopy . Type = EStateTreePropertyCopyType : : DemoteDoubleToFloat ;
2023-02-10 07:22:48 -05:00
return true ;
}
}
2022-06-29 04:52:18 -04:00
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
ensureMsgf ( false , TEXT ( " Couldnt determine property copy type (%s -> %s) " ) , * SourceProperty - > GetNameCPP ( ) , * TargetProperty - > GetNameCPP ( ) ) ;
return false ;
}
EStateTreePropertyAccessCompatibility FStateTreePropertyBindings : : GetPropertyCompatibility ( const FProperty * FromProperty , const FProperty * ToProperty )
{
if ( FromProperty = = ToProperty )
{
return EStateTreePropertyAccessCompatibility : : Compatible ;
}
if ( FromProperty = = nullptr | | ToProperty = = nullptr )
{
return EStateTreePropertyAccessCompatibility : : Incompatible ;
}
// Special case for object properties since InPropertyA->SameType(InPropertyB) requires both properties to be of the exact same class.
// In our case we want to be able to bind a source property if its class is a child of the target property class.
if ( FromProperty - > IsA < FObjectPropertyBase > ( ) & & ToProperty - > IsA < FObjectPropertyBase > ( ) )
{
const FObjectPropertyBase * SourceProperty = CastField < FObjectPropertyBase > ( FromProperty ) ;
const FObjectPropertyBase * TargetProperty = CastField < FObjectPropertyBase > ( ToProperty ) ;
return ( SourceProperty - > PropertyClass - > IsChildOf ( TargetProperty - > PropertyClass ) ) ? EStateTreePropertyAccessCompatibility : : Compatible : EStateTreePropertyAccessCompatibility : : Incompatible ;
}
// When copying to an enum property, expect FromProperty to be the same enum.
auto GetPropertyEnum = [ ] ( const FProperty * Property ) - > const UEnum *
{
if ( const FByteProperty * ByteProperty = CastField < FByteProperty > ( Property ) )
{
return ByteProperty - > GetIntPropertyEnum ( ) ;
}
if ( const FEnumProperty * EnumProperty = CastField < FEnumProperty > ( Property ) )
{
return EnumProperty - > GetEnum ( ) ;
}
return nullptr ;
} ;
if ( const UEnum * ToPropertyEnum = GetPropertyEnum ( ToProperty ) )
{
const UEnum * FromPropertyEnum = GetPropertyEnum ( FromProperty ) ;
return ( ToPropertyEnum = = FromPropertyEnum ) ? EStateTreePropertyAccessCompatibility : : Compatible : EStateTreePropertyAccessCompatibility : : Incompatible ;
}
// Allow source enums to be promoted to numbers.
if ( const FEnumProperty * EnumPropertyA = CastField < const FEnumProperty > ( FromProperty ) )
{
FromProperty = EnumPropertyA - > GetUnderlyingProperty ( ) ;
}
if ( FromProperty - > SameType ( ToProperty ) )
{
return EStateTreePropertyAccessCompatibility : : Compatible ;
}
else
{
// Not directly compatible, check for promotions
if ( FromProperty - > IsA < FBoolProperty > ( ) )
{
if ( ToProperty - > IsA < FByteProperty > ( )
| | ToProperty - > IsA < FIntProperty > ( )
| | ToProperty - > IsA < FUInt32Property > ( )
| | ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FFloatProperty > ( )
| | ToProperty - > IsA < FDoubleProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
else if ( FromProperty - > IsA < FByteProperty > ( ) )
{
if ( ToProperty - > IsA < FIntProperty > ( )
| | ToProperty - > IsA < FUInt32Property > ( )
| | ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FFloatProperty > ( )
| | ToProperty - > IsA < FDoubleProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
else if ( FromProperty - > IsA < FIntProperty > ( ) )
{
if ( ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FFloatProperty > ( )
| | ToProperty - > IsA < FDoubleProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
else if ( FromProperty - > IsA < FUInt32Property > ( ) )
{
if ( ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FFloatProperty > ( )
| | ToProperty - > IsA < FDoubleProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
else if ( FromProperty - > IsA < FFloatProperty > ( ) )
{
if ( ToProperty - > IsA < FIntProperty > ( )
| | ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FDoubleProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
else if ( FromProperty - > IsA < FDoubleProperty > ( ) )
{
if ( ToProperty - > IsA < FIntProperty > ( )
| | ToProperty - > IsA < FInt64Property > ( )
| | ToProperty - > IsA < FFloatProperty > ( ) )
{
return EStateTreePropertyAccessCompatibility : : Promotable ;
}
}
}
return EStateTreePropertyAccessCompatibility : : Incompatible ;
2021-09-28 13:33:17 -04:00
}
2022-05-31 04:51:18 -04:00
uint8 * FStateTreePropertyBindings : : GetAddress ( FStateTreeDataView InStructView , const FStateTreePropertyIndirection & FirstIndirection , const FProperty * LeafProperty ) const
2021-09-28 13:33:17 -04:00
{
uint8 * Address = InStructView . GetMutableMemory ( ) ;
2022-04-28 03:54:07 -04:00
if ( Address = = nullptr )
{
2023-02-10 07:22:48 -05:00
// Failed indirection, will be reported by caller.
2022-04-28 03:54:07 -04:00
return nullptr ;
}
2022-05-31 04:51:18 -04:00
const FStateTreePropertyIndirection * Indirection = & FirstIndirection ;
while ( Indirection ! = nullptr & & Address ! = nullptr )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
switch ( Indirection - > Type )
2021-09-28 13:33:17 -04:00
{
case EStateTreePropertyAccessType : : Offset :
{
2022-05-31 04:51:18 -04:00
Address = Address + Indirection - > Offset ;
2021-09-28 13:33:17 -04:00
break ;
}
case EStateTreePropertyAccessType : : Object :
{
2022-05-31 04:51:18 -04:00
UObject * Object = * reinterpret_cast < UObject * * > ( Address + Indirection - > Offset ) ;
2021-09-28 13:33:17 -04:00
Address = reinterpret_cast < uint8 * > ( Object ) ;
break ;
}
case EStateTreePropertyAccessType : : WeakObject :
{
2022-05-31 04:51:18 -04:00
TWeakObjectPtr < UObject > & WeakObjectPtr = * reinterpret_cast < TWeakObjectPtr < UObject > * > ( Address + Indirection - > Offset ) ;
2021-09-28 13:33:17 -04:00
UObject * Object = WeakObjectPtr . Get ( ) ;
Address = reinterpret_cast < uint8 * > ( Object ) ;
break ;
}
case EStateTreePropertyAccessType : : SoftObject :
{
2022-05-31 04:51:18 -04:00
FSoftObjectPtr & SoftObjectPtr = * reinterpret_cast < FSoftObjectPtr * > ( Address + Indirection - > Offset ) ;
2021-09-28 13:33:17 -04:00
UObject * Object = SoftObjectPtr . Get ( ) ;
Address = reinterpret_cast < uint8 * > ( Object ) ;
break ;
}
2023-02-10 07:22:48 -05:00
case EStateTreePropertyAccessType : : ObjectInstance :
{
check ( Indirection - > InstanceStruct ) ;
UObject * Object = * reinterpret_cast < UObject * * > ( Address + Indirection - > Offset ) ;
if ( Object
& & Object - > GetClass ( ) - > IsChildOf ( Indirection - > InstanceStruct ) )
{
Address = reinterpret_cast < uint8 * > ( Object ) ;
}
else
{
// Failed indirection, will be reported by caller.
return nullptr ;
}
break ;
}
case EStateTreePropertyAccessType : : StructInstance :
{
check ( Indirection - > InstanceStruct ) ;
FInstancedStruct & InstancedStruct = * reinterpret_cast < FInstancedStruct * > ( Address + Indirection - > Offset ) ;
const UScriptStruct * InstanceType = InstancedStruct . GetScriptStruct ( ) ;
if ( InstanceType ! = nullptr
& & InstanceType - > IsChildOf ( Indirection - > InstanceStruct ) )
{
Address = InstancedStruct . GetMutableMemory ( ) ;
}
else
{
// Failed indirection, will be reported by caller.
return nullptr ;
}
break ;
}
2021-09-28 13:33:17 -04:00
case EStateTreePropertyAccessType : : IndexArray :
{
2022-05-31 04:51:18 -04:00
check ( Indirection - > ArrayProperty ) ;
FScriptArrayHelper Helper ( Indirection - > ArrayProperty , Address + Indirection - > Offset ) ;
if ( Helper . IsValidIndex ( Indirection - > ArrayIndex . Get ( ) ) )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
Address = Helper . GetRawPtr ( Indirection - > ArrayIndex . Get ( ) ) ;
2021-09-28 13:33:17 -04:00
}
else
{
2023-02-10 07:22:48 -05:00
// Failed indirection, will be reported by caller.
return nullptr ;
2021-09-28 13:33:17 -04:00
}
break ;
}
default :
ensureMsgf ( false , TEXT ( " FStateTreePropertyBindings::GetAddress: Unhandled indirection type %s for '%s' " ) ,
2022-05-31 04:51:18 -04:00
* StaticEnum < EStateTreePropertyAccessType > ( ) - > GetValueAsString ( Indirection - > Type ) , * LeafProperty - > GetNameCPP ( ) ) ;
2021-09-28 13:33:17 -04:00
}
2022-05-31 04:51:18 -04:00
Indirection = Indirection - > NextIndex . IsValid ( ) ? & PropertyIndirections [ Indirection - > NextIndex . Get ( ) ] : nullptr ;
2021-09-28 13:33:17 -04:00
}
return Address ;
}
2023-02-10 07:22:48 -05:00
void FStateTreePropertyBindings : : PerformCopy ( const FStateTreePropertyCopy & Copy , uint8 * SourceAddress , uint8 * TargetAddress ) const
2021-09-28 13:33:17 -04:00
{
2022-04-14 06:28:13 -04:00
// Source property can be null
2021-09-28 13:33:17 -04:00
check ( SourceAddress ) ;
2022-05-31 04:51:18 -04:00
check ( Copy . TargetLeafProperty ) ;
2021-09-28 13:33:17 -04:00
check ( TargetAddress ) ;
switch ( Copy . Type )
{
case EStateTreePropertyCopyType : : CopyPlain :
FMemory : : Memcpy ( TargetAddress , SourceAddress , Copy . CopySize ) ;
break ;
case EStateTreePropertyCopyType : : CopyComplex :
2022-05-31 04:51:18 -04:00
Copy . TargetLeafProperty - > CopyCompleteValue ( TargetAddress , SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : CopyBool :
2022-05-31 04:51:18 -04:00
static_cast < const FBoolProperty * > ( Copy . TargetLeafProperty ) - > SetPropertyValue ( TargetAddress , static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : CopyStruct :
2022-04-14 06:28:13 -04:00
// If SourceProperty == nullptr (pointing to the struct source directly), the GetAddress() did the right thing and is pointing the the beginning of the struct.
2022-05-31 04:51:18 -04:00
static_cast < const FStructProperty * > ( Copy . TargetLeafProperty ) - > Struct - > CopyScriptStruct ( TargetAddress , SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : CopyObject :
2022-05-31 04:51:18 -04:00
if ( Copy . SourceLeafProperty = = nullptr )
2022-04-14 06:28:13 -04:00
{
// Source is pointing at object directly.
2022-05-31 04:51:18 -04:00
static_cast < const FObjectPropertyBase * > ( Copy . TargetLeafProperty ) - > SetObjectPropertyValue ( TargetAddress , ( UObject * ) SourceAddress ) ;
2022-04-14 06:28:13 -04:00
}
else
{
2022-05-31 04:51:18 -04:00
static_cast < const FObjectPropertyBase * > ( Copy . TargetLeafProperty ) - > SetObjectPropertyValue ( TargetAddress , static_cast < const FObjectPropertyBase * > ( Copy . SourceLeafProperty ) - > GetObjectPropertyValue ( SourceAddress ) ) ;
2022-04-14 06:28:13 -04:00
}
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : CopyName :
2022-05-31 04:51:18 -04:00
static_cast < const FNameProperty * > ( Copy . TargetLeafProperty ) - > SetPropertyValue ( TargetAddress , static_cast < const FNameProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : CopyFixedArray :
{
// Copy into fixed sized array (EditFixedSize). Resizable arrays are copied as Complex, and regular fixed sizes arrays via the regular copies (dim specifies array size).
2022-05-31 04:51:18 -04:00
const FArrayProperty * SourceArrayProperty = static_cast < const FArrayProperty * > ( Copy . SourceLeafProperty ) ;
const FArrayProperty * TargetArrayProperty = static_cast < const FArrayProperty * > ( Copy . TargetLeafProperty ) ;
2021-09-28 13:33:17 -04:00
FScriptArrayHelper SourceArrayHelper ( SourceArrayProperty , SourceAddress ) ;
FScriptArrayHelper TargetArrayHelper ( TargetArrayProperty , TargetAddress ) ;
const int32 MinSize = FMath : : Min ( SourceArrayHelper . Num ( ) , TargetArrayHelper . Num ( ) ) ;
for ( int32 ElementIndex = 0 ; ElementIndex < MinSize ; + + ElementIndex )
{
2022-04-14 06:28:13 -04:00
TargetArrayProperty - > Inner - > CopySingleValue ( TargetArrayHelper . GetRawPtr ( ElementIndex ) , SourceArrayHelper . GetRawPtr ( ElementIndex ) ) ;
2021-09-28 13:33:17 -04:00
}
break ;
}
2022-06-29 04:52:18 -04:00
case EStateTreePropertyCopyType : : StructReference :
{
const FStructProperty * SourceStructProperty = static_cast < const FStructProperty * > ( Copy . SourceLeafProperty ) ;
FStateTreeStructRef * Target = ( FStateTreeStructRef * ) TargetAddress ;
Target - > Set ( FStructView ( SourceStructProperty - > Struct , SourceAddress ) ) ;
break ;
}
2022-09-09 07:14:47 -04:00
// Bool promotions
2021-09-28 13:33:17 -04:00
case EStateTreePropertyCopyType : : PromoteBoolToByte :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < uint8 * > ( TargetAddress ) = ( uint8 ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : PromoteBoolToInt32 :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < int32 * > ( TargetAddress ) = ( int32 ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : PromoteBoolToUInt32 :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < uint32 * > ( TargetAddress ) = ( uint32 ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : PromoteBoolToInt64 :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : PromoteBoolToFloat :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
case EStateTreePropertyCopyType : : PromoteBoolToDouble :
2022-05-31 04:51:18 -04:00
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) static_cast < const FBoolProperty * > ( Copy . SourceLeafProperty ) - > GetPropertyValue ( SourceAddress ) ;
2021-09-28 13:33:17 -04:00
break ;
2022-09-09 07:14:47 -04:00
// Byte promotions
2021-09-28 13:33:17 -04:00
case EStateTreePropertyCopyType : : PromoteByteToInt32 :
* reinterpret_cast < int32 * > ( TargetAddress ) = ( int32 ) * reinterpret_cast < const uint8 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToUInt32 :
* reinterpret_cast < uint32 * > ( TargetAddress ) = ( uint32 ) * reinterpret_cast < const uint8 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToInt64 :
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) * reinterpret_cast < const uint8 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToFloat :
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) * reinterpret_cast < const uint8 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToDouble :
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) * reinterpret_cast < const uint8 * > ( SourceAddress ) ;
break ;
2022-09-09 07:14:47 -04:00
// Int32 promotions
2021-09-28 13:33:17 -04:00
case EStateTreePropertyCopyType : : PromoteInt32ToInt64 :
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) * reinterpret_cast < const int32 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteInt32ToFloat :
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) * reinterpret_cast < const int32 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteInt32ToDouble :
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) * reinterpret_cast < const int32 * > ( SourceAddress ) ;
break ;
2022-09-09 07:14:47 -04:00
// Uint32 promotions
2021-09-28 13:33:17 -04:00
case EStateTreePropertyCopyType : : PromoteUInt32ToInt64 :
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) * reinterpret_cast < const uint32 * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteUInt32ToFloat :
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) * reinterpret_cast < const uint32 * > ( SourceAddress ) ;
break ;
2022-09-09 07:14:47 -04:00
case EStateTreePropertyCopyType : : PromoteUInt32ToDouble :
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) * reinterpret_cast < const uint32 * > ( SourceAddress ) ;
break ;
// Float promotions
case EStateTreePropertyCopyType : : PromoteFloatToInt32 :
* reinterpret_cast < int32 * > ( TargetAddress ) = ( int32 ) * reinterpret_cast < const float * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteFloatToInt64 :
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) * reinterpret_cast < const float * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : PromoteFloatToDouble :
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) * reinterpret_cast < const float * > ( SourceAddress ) ;
break ;
// Double promotions
case EStateTreePropertyCopyType : : DemoteDoubleToInt32 :
* reinterpret_cast < int32 * > ( TargetAddress ) = ( int32 ) * reinterpret_cast < const double * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : DemoteDoubleToInt64 :
* reinterpret_cast < int64 * > ( TargetAddress ) = ( int64 ) * reinterpret_cast < const double * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : DemoteDoubleToFloat :
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) * reinterpret_cast < const double * > ( SourceAddress ) ;
break ;
2021-09-28 13:33:17 -04:00
default :
ensureMsgf ( false , TEXT ( " FStateTreePropertyBindings::PerformCopy: Unhandled copy type %s between '%s' and '%s' " ) ,
2022-05-31 04:51:18 -04:00
* StaticEnum < EStateTreePropertyCopyType > ( ) - > GetValueAsString ( Copy . Type ) , * Copy . SourceLeafProperty - > GetNameCPP ( ) , * Copy . TargetLeafProperty - > GetNameCPP ( ) ) ;
2021-09-28 13:33:17 -04:00
break ;
}
}
2022-05-31 04:51:18 -04:00
bool FStateTreePropertyBindings : : CopyTo ( TConstArrayView < FStateTreeDataView > SourceStructViews , const FStateTreeIndex16 TargetBatchIndex , FStateTreeDataView TargetStructView ) const
2021-09-28 13:33:17 -04:00
{
// This is made ensure so that the programmers have the change to catch it (it's usually programming error not to call ResolvePaths(), and it wont spam log for others.
if ( ! ensureMsgf ( bBindingsResolved , TEXT ( " Bindings must be resolved successfully before copying. See ResolvePaths() " ) ) )
{
2022-04-28 03:54:07 -04:00
return false ;
2021-09-28 13:33:17 -04:00
}
2022-05-31 04:51:18 -04:00
if ( TargetBatchIndex . IsValid ( ) = = false )
2021-09-28 13:33:17 -04:00
{
2022-04-28 03:54:07 -04:00
return false ;
2021-09-28 13:33:17 -04:00
}
2022-05-31 04:51:18 -04:00
check ( CopyBatches . IsValidIndex ( TargetBatchIndex . Get ( ) ) ) ;
2023-02-10 07:22:48 -05:00
const FStateTreePropertyCopyBatch & Batch = CopyBatches [ TargetBatchIndex . Get ( ) ] ;
2021-09-28 13:33:17 -04:00
check ( TargetStructView . IsValid ( ) ) ;
check ( TargetStructView . GetStruct ( ) = = Batch . TargetStruct . Struct ) ;
2022-04-28 03:54:07 -04:00
bool bResult = true ;
2021-09-28 13:33:17 -04:00
for ( int32 i = Batch . BindingsBegin ; i ! = Batch . BindingsEnd ; i + + )
{
2023-02-10 07:22:48 -05:00
const FStateTreePropertyCopy & Copy = PropertyCopies [ i ] ;
2021-09-28 13:33:17 -04:00
// Copies that fail to be resolved (i.e. property path does not resolve, types changed) will be marked as None, skip them.
if ( Copy . Type = = EStateTreePropertyCopyType : : None )
{
continue ;
}
2022-04-28 03:54:07 -04:00
2022-05-31 04:51:18 -04:00
const FStateTreeDataView SourceStructView = SourceStructViews [ Copy . SourceStructIndex . Get ( ) ] ;
2022-05-05 08:44:57 -04:00
if ( SourceStructView . IsValid ( ) )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
check ( SourceStructView . GetStruct ( ) = = SourceStructs [ Copy . SourceStructIndex . Get ( ) ] . Struct
| | ( SourceStructView . GetStruct ( ) & & SourceStructView . GetStruct ( ) - > IsChildOf ( SourceStructs [ Copy . SourceStructIndex . Get ( ) ] . Struct ) ) ) ;
2022-05-05 08:44:57 -04:00
2022-06-29 04:52:18 -04:00
uint8 * SourceAddress = GetAddress ( SourceStructView , Copy . SourceIndirection , Copy . SourceLeafProperty ) ;
2022-05-31 04:51:18 -04:00
uint8 * TargetAddress = GetAddress ( TargetStructView , Copy . TargetIndirection , Copy . TargetLeafProperty ) ;
2022-05-05 08:44:57 -04:00
2023-02-10 07:22:48 -05:00
if ( SourceAddress ! = nullptr & & TargetAddress ! = nullptr )
{
PerformCopy ( Copy , SourceAddress , TargetAddress ) ;
}
else
{
bResult = false ;
}
2021-09-28 13:33:17 -04:00
}
2022-04-28 03:54:07 -04:00
else
{
bResult = false ;
}
2021-09-28 13:33:17 -04:00
}
2022-04-28 03:54:07 -04:00
return bResult ;
2021-09-28 13:33:17 -04:00
}
2023-02-10 07:22:48 -05:00
void FStateTreePropertyBindings : : PerformResetObjects ( const FStateTreePropertyCopy & Copy , uint8 * TargetAddress ) const
2022-11-30 07:17:26 -05:00
{
// Source property can be null
check ( Copy . TargetLeafProperty ) ;
check ( TargetAddress ) ;
switch ( Copy . Type )
{
case EStateTreePropertyCopyType : : CopyComplex :
Copy . TargetLeafProperty - > InitializeValue ( TargetAddress ) ;
break ;
case EStateTreePropertyCopyType : : CopyStruct :
static_cast < const FStructProperty * > ( Copy . TargetLeafProperty ) - > Struct - > ClearScriptStruct ( TargetAddress ) ;
break ;
case EStateTreePropertyCopyType : : CopyObject :
static_cast < const FObjectPropertyBase * > ( Copy . TargetLeafProperty ) - > SetObjectPropertyValue ( TargetAddress , nullptr ) ;
break ;
case EStateTreePropertyCopyType : : CopyName :
break ;
case EStateTreePropertyCopyType : : CopyFixedArray :
{
// Copy into fixed sized array (EditFixedSize). Resizable arrays are copied as Complex, and regular fixed sizes arrays via the regular copies (dim specifies array size).
const FArrayProperty * TargetArrayProperty = static_cast < const FArrayProperty * > ( Copy . TargetLeafProperty ) ;
FScriptArrayHelper TargetArrayHelper ( TargetArrayProperty , TargetAddress ) ;
for ( int32 ElementIndex = 0 ; ElementIndex < TargetArrayHelper . Num ( ) ; + + ElementIndex )
{
TargetArrayProperty - > Inner - > InitializeValue ( TargetArrayHelper . GetRawPtr ( ElementIndex ) ) ;
}
break ;
}
default :
break ;
}
}
bool FStateTreePropertyBindings : : ResetObjects ( const FStateTreeIndex16 TargetBatchIndex , FStateTreeDataView TargetStructView ) const
{
// This is made ensure so that the programmers have the change to catch it (it's usually programming error not to call ResolvePaths(), and it wont spam log for others.
if ( ! ensureMsgf ( bBindingsResolved , TEXT ( " Bindings must be resolved successfully before copying. See ResolvePaths() " ) ) )
{
return false ;
}
if ( TargetBatchIndex . IsValid ( ) = = false )
{
return false ;
}
check ( CopyBatches . IsValidIndex ( TargetBatchIndex . Get ( ) ) ) ;
2023-02-10 07:22:48 -05:00
const FStateTreePropertyCopyBatch & Batch = CopyBatches [ TargetBatchIndex . Get ( ) ] ;
2022-11-30 07:17:26 -05:00
check ( TargetStructView . IsValid ( ) ) ;
check ( TargetStructView . GetStruct ( ) = = Batch . TargetStruct . Struct ) ;
bool bResult = true ;
for ( int32 i = Batch . BindingsBegin ; i ! = Batch . BindingsEnd ; i + + )
{
2023-02-10 07:22:48 -05:00
const FStateTreePropertyCopy & Copy = PropertyCopies [ i ] ;
2022-11-30 07:17:26 -05:00
// Copies that fail to be resolved (i.e. property path does not resolve, types changed) will be marked as None, skip them.
if ( Copy . Type = = EStateTreePropertyCopyType : : None )
{
continue ;
}
uint8 * TargetAddress = GetAddress ( TargetStructView , Copy . TargetIndirection , Copy . TargetLeafProperty ) ;
check ( TargetAddress ! = nullptr ) ;
PerformResetObjects ( Copy , TargetAddress ) ;
}
return bResult ;
}
2023-04-14 16:36:43 -04:00
bool FStateTreePropertyBindings : : ContainsAnyStruct ( const TSet < const UStruct * > & Structs )
{
for ( FStateTreeBindableStructDesc & SourceStruct : SourceStructs )
{
if ( Structs . Contains ( SourceStruct . Struct ) )
{
return true ;
}
}
for ( FStateTreePropertyCopyBatch & CopyBatch : CopyBatches )
{
if ( Structs . Contains ( CopyBatch . TargetStruct . Struct ) )
{
return true ;
}
}
auto PathContainsStruct = [ & Structs ] ( const FStateTreePropertyPath & PropertyPath )
{
for ( const FStateTreePropertyPathSegment & Segment : PropertyPath . GetSegments ( ) )
{
if ( Structs . Contains ( Segment . GetInstanceStruct ( ) ) )
{
return true ;
}
}
return false ;
} ;
for ( FStateTreePropertyPathBinding & PropertyPathBinding : PropertyPathBindings )
{
if ( PathContainsStruct ( PropertyPathBinding . GetSourcePath ( ) ) )
{
return true ;
}
if ( PathContainsStruct ( PropertyPathBinding . GetTargetPath ( ) ) )
{
return true ;
}
}
return false ;
}
2021-09-28 13:33:17 -04:00
void FStateTreePropertyBindings : : DebugPrintInternalLayout ( FString & OutString ) const
{
/** Array of expected source structs. */
OutString + = FString : : Printf ( TEXT ( " \n BindableStructDesc (%d) \n [ %-40s | %-40s ] \n " ) , SourceStructs . Num ( ) , TEXT ( " Type " ) , TEXT ( " Name " ) ) ;
for ( const FStateTreeBindableStructDesc & BindableStructDesc : SourceStructs )
{
OutString + = FString : : Printf ( TEXT ( " | %-40s | %-40s | \n " ) ,
BindableStructDesc . Struct ? * BindableStructDesc . Struct - > GetName ( ) : TEXT ( " null " ) ,
* BindableStructDesc . Name . ToString ( ) ) ;
}
/** Array of copy batches. */
OutString + = FString : : Printf ( TEXT ( " \n CopyBatches (%d) \n [ %-40s | %-40s | %-8s [%-3s:%-3s[ ] \n " ) , CopyBatches . Num ( ) ,
TEXT ( " Target Type " ) , TEXT ( " Target Name " ) , TEXT ( " Bindings " ) , TEXT ( " Beg " ) , TEXT ( " End " ) ) ;
2023-02-10 07:22:48 -05:00
for ( const FStateTreePropertyCopyBatch & CopyBatch : CopyBatches )
2021-09-28 13:33:17 -04:00
{
OutString + = FString : : Printf ( TEXT ( " | %-40s | %-40s | %8s [%3d:%-3d[ | \n " ) ,
CopyBatch . TargetStruct . Struct ? * CopyBatch . TargetStruct . Struct - > GetName ( ) : TEXT ( " null " ) ,
* CopyBatch . TargetStruct . Name . ToString ( ) ,
TEXT ( " " ) , CopyBatch . BindingsBegin , CopyBatch . BindingsEnd ) ;
}
/** Array of property bindings, resolved into arrays of copies before use. */
2023-02-10 07:22:48 -05:00
OutString + = FString : : Printf ( TEXT ( " \n PropertyPathBindings (%d) \n " ) , PropertyPathBindings . Num ( ) ) ;
for ( const FStateTreePropertyPathBinding & PropertyBinding : PropertyPathBindings )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
OutString + = FString : : Printf ( TEXT ( " \n Source: %s | Target: %s " ) ,
* PropertyBinding . GetSourcePath ( ) . ToString ( ) , * PropertyBinding . GetSourcePath ( ) . ToString ( ) ) ;
2021-09-28 13:33:17 -04:00
}
/** Array of property copies */
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " \n PropertyCopies (%d) \n [ %-7s | %-4s | %-4s | %-10s | %-7s | %-4s | %-4s | %-10s | %-7s | %-20s | %-4s ] \n " ) , PropertyCopies . Num ( ) ,
TEXT ( " Src Idx " ) , TEXT ( " Off. " ) , TEXT ( " Next " ) , TEXT ( " Type " ) ,
TEXT ( " Tgt Idx " ) , TEXT ( " Off. " ) , TEXT ( " Next " ) , TEXT ( " Type " ) ,
TEXT ( " Struct " ) , TEXT ( " Copy Type " ) , TEXT ( " Size " ) ) ;
2023-02-10 07:22:48 -05:00
for ( const FStateTreePropertyCopy & PropertyCopy : PropertyCopies )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " | %7d | %4d | %4d | %-10s | %7d | %4d | %4d | %-10s | %7d | %-20s | %4d | \n " ) ,
PropertyCopy . SourceIndirection . ArrayIndex . Get ( ) ,
PropertyCopy . SourceIndirection . Offset ,
PropertyCopy . SourceIndirection . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyCopy . SourceIndirection . Type ) . ToString ( ) ,
PropertyCopy . TargetIndirection . ArrayIndex . Get ( ) ,
PropertyCopy . TargetIndirection . Offset ,
PropertyCopy . TargetIndirection . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyCopy . TargetIndirection . Type ) . ToString ( ) ,
PropertyCopy . SourceStructIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyCopy . Type ) . ToString ( ) ,
2021-09-28 13:33:17 -04:00
PropertyCopy . CopySize ) ;
}
/** Array of property indirections, indexed by accesses*/
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " \n PropertyIndirections (%d) \n [ %-4s | %-4s | %-4s | %-10s ] \n " ) , PropertyIndirections . Num ( ) ,
TEXT ( " Idx " ) , TEXT ( " Off. " ) , TEXT ( " Next " ) , TEXT ( " Access Type " ) ) ;
2021-09-28 13:33:17 -04:00
for ( const FStateTreePropertyIndirection & PropertyIndirection : PropertyIndirections )
{
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " | %4d | %4d | %4d | %-10s | \n " ) ,
PropertyIndirection . ArrayIndex . Get ( ) ,
PropertyIndirection . Offset ,
PropertyIndirection . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyIndirection . Type ) . ToString ( ) ) ;
2021-09-28 13:33:17 -04:00
}
}
2023-02-10 07:22:48 -05:00
//----------------------------------------------------------------//
// FStateTreePropertyPath
//----------------------------------------------------------------//
bool FStateTreePropertyPath : : FromString ( const FString & InPath )
{
Segments . Reset ( ) ;
if ( InPath . IsEmpty ( ) )
{
return true ;
}
bool bResult = true ;
TArray < FString > PathSegments ;
InPath . ParseIntoArray ( PathSegments , TEXT ( " . " ) , /*InCullEmpty=*/ false ) ;
for ( const FString & Segment : PathSegments )
{
if ( Segment . IsEmpty ( ) )
{
bResult = false ;
break ;
}
int32 FirstBracket = INDEX_NONE ;
int32 LastBracket = INDEX_NONE ;
if ( Segment . FindChar ( TEXT ( ' [ ' ) , FirstBracket )
& & Segment . FindLastChar ( TEXT ( ' ] ' ) , LastBracket ) )
{
const int32 NameStringLength = FirstBracket ;
const int32 IndexStringLength = LastBracket - FirstBracket - 1 ;
if ( NameStringLength < 1
| | IndexStringLength < = 0 )
{
bResult = false ;
break ;
}
const FString NameString = Segment . Left ( FirstBracket ) ;
const FString IndexString = Segment . Mid ( FirstBracket + 1 , IndexStringLength ) ;
int32 ArrayIndex = INDEX_NONE ;
LexFromString ( ArrayIndex , * IndexString ) ;
if ( ArrayIndex < 0 )
{
bResult = false ;
break ;
}
AddPathSegment ( FName ( NameString ) , ArrayIndex ) ;
}
else
{
AddPathSegment ( FName ( Segment ) ) ;
}
}
if ( ! bResult )
{
Segments . Reset ( ) ;
}
return bResult ;
}
2023-06-21 10:27:51 -04:00
bool FStateTreePropertyPath : : UpdateSegments ( const UStruct * BaseStruct , FString * OutError )
{
return UpdateSegmentsFromValue ( FStateTreeDataView ( BaseStruct , nullptr ) , OutError ) ;
}
bool FStateTreePropertyPath : : UpdateSegmentsFromValue ( const FStateTreeDataView BaseValueView , FString * OutError )
2023-02-10 07:22:48 -05:00
{
TArray < FStateTreePropertyPathIndirection > Indirections ;
2023-06-21 10:27:51 -04:00
if ( ! ResolveIndirectionsWithValue ( BaseValueView , Indirections , OutError , /*bHandleRedirects*/ true ) )
2023-02-10 07:22:48 -05:00
{
return false ;
}
for ( FStateTreePropertyPathSegment & Segment : Segments )
{
Segment . SetInstanceStruct ( nullptr ) ;
}
for ( const FStateTreePropertyPathIndirection & Indirection : Indirections )
{
if ( Indirection . InstanceStruct ! = nullptr )
{
Segments [ Indirection . PathSegmentIndex ] . SetInstanceStruct ( Indirection . InstanceStruct ) ;
}
2023-06-21 10:27:51 -04:00
# if WITH_EDITORONLY_DATA
if ( ! Indirection . GetRedirectedName ( ) . IsNone ( ) )
{
Segments [ Indirection . PathSegmentIndex ] . SetName ( Indirection . GetRedirectedName ( ) ) ;
}
Segments [ Indirection . PathSegmentIndex ] . SetPropertyGuid ( Indirection . GetPropertyGuid ( ) ) ;
# endif
2023-02-10 07:22:48 -05:00
}
return true ;
}
FString FStateTreePropertyPath : : ToString ( const int32 HighlightedSegment , const TCHAR * HighlightPrefix , const TCHAR * HighlightPostfix , const bool bOutputInstances ) const
2021-09-28 13:33:17 -04:00
{
FString Result ;
2023-02-10 07:22:48 -05:00
for ( TEnumerateRef < const FStateTreePropertyPathSegment > Segment : EnumerateRange ( Segments ) )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
if ( Segment . GetIndex ( ) > 0 )
2021-09-28 13:33:17 -04:00
{
Result + = TEXT ( " . " ) ;
}
2023-02-10 07:22:48 -05:00
if ( Segment . GetIndex ( ) = = HighlightedSegment & & HighlightPrefix )
2021-09-28 13:33:17 -04:00
{
Result + = HighlightPrefix ;
}
2023-02-10 07:22:48 -05:00
if ( bOutputInstances & & Segment - > GetInstanceStruct ( ) )
{
Result + = FString : : Printf ( TEXT ( " (%s) " ) , * GetNameSafe ( Segment - > GetInstanceStruct ( ) ) ) ;
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
if ( Segment - > GetArrayIndex ( ) > = 0 )
{
Result + = FString : : Printf ( TEXT ( " %s[%d] " ) , * Segment - > GetName ( ) . ToString ( ) , Segment - > GetArrayIndex ( ) ) ;
}
else
{
Result + = Segment - > GetName ( ) . ToString ( ) ;
}
if ( Segment . GetIndex ( ) = = HighlightedSegment & & HighlightPostfix )
2021-09-28 13:33:17 -04:00
{
Result + = HighlightPostfix ;
}
}
return Result ;
}
2023-06-21 10:27:51 -04:00
bool FStateTreePropertyPath : : ResolveIndirections ( const UStruct * BaseStruct , TArray < FStateTreePropertyPathIndirection > & OutIndirections , FString * OutError , bool bHandleRedirects ) const
2023-02-10 07:22:48 -05:00
{
2023-06-21 10:27:51 -04:00
return ResolveIndirectionsWithValue ( FStateTreeDataView ( BaseStruct , nullptr ) , OutIndirections , OutError , bHandleRedirects ) ;
2023-02-10 07:22:48 -05:00
}
2023-06-21 10:27:51 -04:00
bool FStateTreePropertyPath : : ResolveIndirectionsWithValue ( const FStateTreeDataView BaseValueView , TArray < FStateTreePropertyPathIndirection > & OutIndirections , FString * OutError , bool bHandleRedirects ) const
2023-02-10 07:22:48 -05:00
{
OutIndirections . Reset ( ) ;
if ( OutError )
{
OutError - > Reset ( ) ;
}
// Nothing to do for an empty path.
if ( IsPathEmpty ( ) )
{
return true ;
}
const uint8 * CurrentAddress = BaseValueView . GetMemory ( ) ;
const UStruct * CurrentStruct = BaseValueView . GetStruct ( ) ;
const bool bWithValue = CurrentAddress ! = nullptr ;
for ( const TEnumerateRef < const FStateTreePropertyPathSegment > Segment : EnumerateRange ( Segments ) )
{
if ( CurrentStruct = = nullptr | | ( bWithValue & & CurrentAddress = = nullptr ) )
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Malformed path '%s'. " ) ,
* ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
const FProperty * Property = CurrentStruct - > FindPropertyByName ( Segment - > GetName ( ) ) ;
2023-06-21 10:27:51 -04:00
# if WITH_EDITORONLY_DATA
FName RedirectedName ;
FGuid PropertyGuid = Segment - > GetPropertyGuid ( ) ;
// Try to fix the path in editor.
if ( bHandleRedirects )
{
// Check if there's a core redirect for it.
if ( ! Property )
{
// Try to match by property ID (Blueprint or User Defined Struct).
if ( Segment - > GetPropertyGuid ( ) . IsValid ( ) )
{
if ( const UBlueprintGeneratedClass * BlueprintClass = Cast < UBlueprintGeneratedClass > ( CurrentStruct ) )
{
if ( const FName * Name = BlueprintClass - > PropertyGuids . FindKey ( Segment - > GetPropertyGuid ( ) ) )
{
RedirectedName = * Name ;
Property = CurrentStruct - > FindPropertyByName ( RedirectedName ) ;
}
}
else if ( const UUserDefinedStruct * UserDefinedStruct = Cast < UUserDefinedStruct > ( CurrentStruct ) )
{
if ( FProperty * FoundProperty = FStructureEditorUtils : : GetPropertyByGuid ( UserDefinedStruct , Segment - > GetPropertyGuid ( ) ) )
{
RedirectedName = FoundProperty - > GetFName ( ) ;
Property = FoundProperty ;
}
}
}
else
{
// Try core redirect
const FCoreRedirectObjectName OldPropertyName ( Segment - > GetName ( ) , CurrentStruct - > GetFName ( ) , * CurrentStruct - > GetOutermost ( ) - > GetPathName ( ) ) ;
const FCoreRedirectObjectName NewPropertyName = FCoreRedirects : : GetRedirectedName ( ECoreRedirectFlags : : Type_Property , OldPropertyName ) ;
if ( OldPropertyName ! = NewPropertyName )
{
// Cached the result for later use.
RedirectedName = NewPropertyName . ObjectName ;
Property = CurrentStruct - > FindPropertyByName ( RedirectedName ) ;
}
}
}
// Update PropertyGuid
if ( Property )
{
const FName PropertyName = ! RedirectedName . IsNone ( ) ? RedirectedName : Segment - > GetName ( ) ;
if ( const UBlueprintGeneratedClass * BlueprintClass = Cast < UBlueprintGeneratedClass > ( CurrentStruct ) )
{
if ( const FGuid * VarGuid = BlueprintClass - > PropertyGuids . Find ( PropertyName ) )
{
PropertyGuid = * VarGuid ;
}
}
else if ( const UUserDefinedStruct * UserDefinedStruct = Cast < UUserDefinedStruct > ( CurrentStruct ) )
{
// Parse Guid from UDS property name.
PropertyGuid = FStructureEditorUtils : : GetGuidFromPropertyName ( PropertyName ) ;
}
}
}
# endif // WITH_EDITORONLY_DATA
if ( ! Property )
2023-02-10 07:22:48 -05:00
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Malformed path '%s', could not find property '%s%s::%s'. " ) ,
* ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ,
CurrentStruct - > GetPrefixCPP ( ) , * CurrentStruct - > GetName ( ) , * Segment - > GetName ( ) . ToString ( ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( Property ) ;
int ArrayIndex = 0 ;
int32 Offset = 0 ;
if ( ArrayProperty & & Segment - > GetArrayIndex ( ) ! = INDEX_NONE )
{
FStateTreePropertyPathIndirection & Indirection = OutIndirections . AddDefaulted_GetRef ( ) ;
Indirection . Property = Property ;
Indirection . ContainerAddress = CurrentAddress ;
Indirection . ContainerStruct = CurrentStruct ;
Indirection . InstanceStruct = nullptr ;
Indirection . ArrayIndex = Segment - > GetArrayIndex ( ) ;
Indirection . PropertyOffset = ArrayProperty - > GetOffset_ForInternal ( ) ;
Indirection . PathSegmentIndex = Segment . GetIndex ( ) ;
2023-06-21 10:27:51 -04:00
Indirection . AccessType = EStateTreePropertyAccessType : : IndexArray ;
# if WITH_EDITORONLY_DATA
Indirection . RedirectedName = RedirectedName ;
Indirection . PropertyGuid = PropertyGuid ;
# endif
2023-02-10 07:22:48 -05:00
ArrayIndex = 0 ;
Offset = 0 ;
Property = ArrayProperty - > Inner ;
if ( bWithValue )
{
FScriptArrayHelper Helper ( ArrayProperty , CurrentAddress + ArrayProperty - > GetOffset_ForInternal ( ) ) ;
if ( ! Helper . IsValidIndex ( Segment - > GetArrayIndex ( ) ) )
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Index %d out of range (num elements %d) trying to access dynamic array '%s'. " ) ,
Segment - > GetArrayIndex ( ) , Helper . Num ( ) , * ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
CurrentAddress = Helper . GetRawPtr ( Segment - > GetArrayIndex ( ) ) ;
}
}
else
{
if ( Segment - > GetArrayIndex ( ) > Property - > ArrayDim )
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Index %d out of range %d trying to access static array '%s'. " ) ,
Segment - > GetArrayIndex ( ) , Property - > ArrayDim , * ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
ArrayIndex = FMath : : Max ( 0 , Segment - > GetArrayIndex ( ) ) ;
Offset = Property - > GetOffset_ForInternal ( ) + Property - > ElementSize * ArrayIndex ;
}
FStateTreePropertyPathIndirection & Indirection = OutIndirections . AddDefaulted_GetRef ( ) ;
Indirection . Property = Property ;
Indirection . ContainerAddress = CurrentAddress ;
Indirection . ContainerStruct = CurrentStruct ;
Indirection . ArrayIndex = ArrayIndex ;
Indirection . PropertyOffset = Offset ;
Indirection . PathSegmentIndex = Segment . GetIndex ( ) ;
Indirection . AccessType = EStateTreePropertyAccessType : : Offset ;
2023-06-21 10:27:51 -04:00
# if WITH_EDITORONLY_DATA
Indirection . RedirectedName = RedirectedName ;
Indirection . PropertyGuid = PropertyGuid ;
# endif
2023-02-10 07:22:48 -05:00
const bool bLastSegment = Segment . GetIndex ( ) = = ( Segments . Num ( ) - 1 ) ;
if ( ! bLastSegment )
{
if ( const FStructProperty * StructProperty = CastField < FStructProperty > ( Property ) )
{
if ( bWithValue )
{
if ( StructProperty - > Struct = = TBaseStructure < FInstancedStruct > : : Get ( ) )
{
const FInstancedStruct & InstancedStruct = * reinterpret_cast < const FInstancedStruct * > ( CurrentAddress + Offset ) ;
if ( ! InstancedStruct . IsValid ( ) )
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Expecting valid instanced struct value at path '%s'. " ) ,
* ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
const UScriptStruct * ValueInstanceStructType = InstancedStruct . GetScriptStruct ( ) ;
CurrentAddress = InstancedStruct . GetMemory ( ) ;
CurrentStruct = ValueInstanceStructType ;
Indirection . InstanceStruct = CurrentStruct ;
Indirection . AccessType = EStateTreePropertyAccessType : : StructInstance ;
}
else
{
CurrentAddress = CurrentAddress + Offset ;
CurrentStruct = StructProperty - > Struct ;
Indirection . AccessType = EStateTreePropertyAccessType : : Offset ;
}
}
else
{
if ( Segment - > GetInstanceStruct ( ) )
{
CurrentStruct = Segment - > GetInstanceStruct ( ) ;
Indirection . InstanceStruct = CurrentStruct ;
Indirection . AccessType = EStateTreePropertyAccessType : : StructInstance ;
}
else
{
CurrentStruct = StructProperty - > Struct ;
Indirection . AccessType = EStateTreePropertyAccessType : : Offset ;
}
}
}
else if ( const FObjectProperty * ObjectProperty = CastField < FObjectProperty > ( Property ) )
{
if ( bWithValue )
{
const UObject * Object = * reinterpret_cast < UObject * const * > ( CurrentAddress + Offset ) ;
CurrentAddress = reinterpret_cast < const uint8 * > ( Object ) ;
if ( Property - > HasAnyPropertyFlags ( CPF_PersistentInstance | CPF_InstancedReference ) )
{
if ( ! Object )
{
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Expecting valid instanced object value at path '%s'. " ) ,
* ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
CurrentStruct = Object - > GetClass ( ) ;
Indirection . InstanceStruct = CurrentStruct ;
Indirection . AccessType = EStateTreePropertyAccessType : : ObjectInstance ;
}
else
{
CurrentStruct = ObjectProperty - > PropertyClass ;
Indirection . AccessType = EStateTreePropertyAccessType : : Object ;
}
}
else
{
if ( Segment - > GetInstanceStruct ( ) )
{
CurrentStruct = Segment - > GetInstanceStruct ( ) ;
Indirection . InstanceStruct = CurrentStruct ;
Indirection . AccessType = EStateTreePropertyAccessType : : ObjectInstance ;
}
else
{
CurrentStruct = ObjectProperty - > PropertyClass ;
Indirection . AccessType = EStateTreePropertyAccessType : : Object ;
}
}
}
// Check to see if this is a simple weak object property (eg. not an array of weak objects).
else if ( const FWeakObjectProperty * WeakObjectProperty = CastField < FWeakObjectProperty > ( Property ) )
{
const TWeakObjectPtr < UObject > & WeakObjectPtr = * reinterpret_cast < const TWeakObjectPtr < UObject > * > ( CurrentAddress + Offset ) ;
const UObject * Object = WeakObjectPtr . Get ( ) ;
CurrentAddress = reinterpret_cast < const uint8 * > ( Object ) ;
CurrentStruct = WeakObjectProperty - > PropertyClass ;
Indirection . AccessType = EStateTreePropertyAccessType : : WeakObject ;
}
// Check to see if this is a simple soft object property (eg. not an array of soft objects).
else if ( const FSoftObjectProperty * SoftObjectProperty = CastField < FSoftObjectProperty > ( Property ) )
{
const FSoftObjectPtr & SoftObjectPtr = * reinterpret_cast < const FSoftObjectPtr * > ( CurrentAddress + Offset ) ;
const UObject * Object = SoftObjectPtr . Get ( ) ;
CurrentAddress = reinterpret_cast < const uint8 * > ( Object ) ;
CurrentStruct = SoftObjectProperty - > PropertyClass ;
Indirection . AccessType = EStateTreePropertyAccessType : : SoftObject ;
}
else
{
// We get here if we encounter a property type that is not supported for indirection (e.g. Map or Set).
if ( OutError )
{
* OutError = FString : : Printf ( TEXT ( " Unsupported property indirection type %s in path '%s'. " ) ,
* Property - > GetCPPType ( ) , * ToString ( Segment . GetIndex ( ) , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
OutIndirections . Reset ( ) ;
return false ;
}
}
}
return true ;
}
bool FStateTreePropertyPath : : operator = = ( const FStateTreePropertyPath & RHS ) const
{
# if WITH_EDITORONLY_DATA
if ( StructID ! = RHS . StructID )
{
return false ;
}
# endif // WITH_EDITORONLY_DATA
if ( Segments . Num ( ) ! = RHS . Segments . Num ( ) )
{
return false ;
}
for ( TEnumerateRef < const FStateTreePropertyPathSegment > Segment : EnumerateRange ( Segments ) )
{
if ( * Segment ! = RHS . Segments [ Segment . GetIndex ( ) ] )
{
return false ;
}
}
return true ;
}
2021-09-28 13:33:17 -04:00
//----------------------------------------------------------------//
// FStateTreeEditorPropertyPath
//----------------------------------------------------------------//
FString FStateTreeEditorPropertyPath : : ToString ( const int32 HighlightedSegment , const TCHAR * HighlightPrefix , const TCHAR * HighlightPostfix ) const
{
FString Result ;
for ( int32 i = 0 ; i < Path . Num ( ) ; i + + )
{
if ( i > 0 )
{
Result + = TEXT ( " . " ) ;
}
if ( i = = HighlightedSegment & & HighlightPrefix )
{
Result + = HighlightPrefix ;
}
Result + = Path [ i ] ;
if ( i = = HighlightedSegment & & HighlightPostfix )
{
Result + = HighlightPostfix ;
}
}
return Result ;
}
2023-02-10 07:22:48 -05:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2021-09-28 13:33:17 -04:00
bool FStateTreeEditorPropertyPath : : operator = = ( const FStateTreeEditorPropertyPath & RHS ) const
{
if ( StructID ! = RHS . StructID )
{
return false ;
}
if ( Path . Num ( ) ! = RHS . Path . Num ( ) )
{
return false ;
}
for ( int32 i = 0 ; i < Path . Num ( ) ; i + + )
{
if ( Path [ i ] ! = RHS . Path [ i ] )
{
return false ;
}
}
return true ;
}
2023-02-10 07:22:48 -05:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS