2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StateTreePropertyBindings.h"
# include "StateTreeTypes.h"
//----------------------------------------------------------------//
// FStateTreePropertyBindings
//----------------------------------------------------------------//
void FStateTreePropertyBindings : : Reset ( )
{
SourceStructs . Reset ( ) ;
CopyBatches . Reset ( ) ;
PropertyBindings . Reset ( ) ;
PropertySegments . Reset ( ) ;
PropertyCopies . Reset ( ) ;
PropertyIndirections . Reset ( ) ;
bBindingsResolved = false ;
}
bool FStateTreePropertyBindings : : ResolvePaths ( )
{
PropertyIndirections . Reset ( ) ;
PropertyCopies . SetNum ( PropertyBindings . Num ( ) ) ;
bBindingsResolved = true ;
bool bResult = true ;
for ( const FStateTreePropCopyBatch & Batch : CopyBatches )
{
for ( int32 i = Batch . BindingsBegin ; i ! = Batch . BindingsEnd ; i + + )
{
const FStateTreePropertyBinding & Binding = PropertyBindings [ i ] ;
FStateTreePropCopy & Copy = PropertyCopies [ i ] ;
Copy . SourceStructIndex = Binding . SourceStructIndex ;
Copy . Type = Binding . CopyType ;
2022-05-31 04:51:18 -04:00
const UStruct * SourceStruct = SourceStructs [ Binding . 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 ;
2022-05-31 04:51:18 -04:00
bSuccess = bSuccess & & ResolvePath ( SourceStruct , Binding . SourcePath , Copy . SourceIndirection , Copy . SourceLeafProperty ) ;
bSuccess = bSuccess & & ResolvePath ( TargetStruct , Binding . TargetPath , Copy . TargetIndirection , Copy . TargetLeafProperty ) ;
2021-09-28 13:33:17 -04:00
bSuccess = bSuccess & & ValidateCopy ( Copy ) ;
if ( ! bSuccess )
{
// Resolving or validating failed, make the copy a nop.
Copy . Type = EStateTreePropertyCopyType : : None ;
bResult = false ;
}
}
}
return bResult ;
}
2022-05-31 04:51:18 -04:00
bool FStateTreePropertyBindings : : ResolvePath ( const UStruct * Struct , const FStateTreePropertySegment & FirstPathSegment , FStateTreePropertyIndirection & OutFirstIndirection , const FProperty * & OutLeafProperty )
2021-09-28 13:33:17 -04:00
{
if ( ! Struct )
{
2022-05-31 04:51:18 -04:00
UE_LOG ( LogStateTree , Error , TEXT ( " %s: '%s' Invalid source struct. " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , * GetPathAsString ( FirstPathSegment ) ) ;
2021-09-28 13:33:17 -04:00
return false ;
}
const UStruct * CurrentStruct = Struct ;
2022-05-31 04:51:18 -04:00
const FProperty * LeafProperty = nullptr ;
TArray < FStateTreePropertyIndirection , TInlineAllocator < 16 > > TempIndirections ;
const FStateTreePropertySegment * Segment = & FirstPathSegment ;
2021-09-28 13:33:17 -04:00
2022-06-03 04:55:42 -04:00
while ( Segment ! = nullptr & & ! Segment - > IsEmpty ( ) )
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
2022-05-31 04:51:18 -04:00
const bool bFinalSegment = Segment - > NextIndex . IsValid ( ) = = false ; ;
2021-09-28 13:33:17 -04:00
if ( ! ensure ( CurrentStruct ) )
{
2022-05-31 04:51:18 -04:00
UE_LOG ( LogStateTree , Error , TEXT ( " %s: '%s' Invalid struct. " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , * GetPathAsString ( FirstPathSegment , Segment , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
2021-09-28 13:33:17 -04:00
return false ;
}
2022-05-31 04:51:18 -04:00
FProperty * Property = CurrentStruct - > FindPropertyByName ( Segment - > Name ) ;
2021-09-28 13:33:17 -04:00
if ( ! Property )
{
// TODO: use core redirects to fix up the name.
UE_LOG ( LogStateTree , Error , TEXT ( " %s: Malformed path '%s', could not to find property '%s%s.%s'. " ) ,
2022-05-31 04:51:18 -04:00
ANSI_TO_TCHAR ( __FUNCTION__ ) , * GetPathAsString ( FirstPathSegment , Segment , TEXT ( " < " ) , TEXT ( " > " ) ) ,
CurrentStruct - > GetPrefixCPP ( ) , * CurrentStruct - > GetName ( ) , * Segment - > Name . ToString ( ) ) ;
2021-09-28 13:33:17 -04:00
return false ;
}
2022-05-31 04:51:18 -04:00
Indirection . ArrayIndex = FStateTreeIndex16 ( Segment - > ArrayIndex . IsValid ( ) ? Segment - > ArrayIndex . Get ( ) : 0 ) ;
Indirection . Type = Segment - > Type ;
Indirection . Offset = Property - > GetOffset_ForInternal ( ) + Property - > ElementSize * Indirection . ArrayIndex . Get ( ) ;
2021-09-28 13:33:17 -04:00
// Check to see if it is an array access first.
2022-05-31 04:51:18 -04:00
if ( const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
if ( const FStructProperty * ArrayOfStructsProperty = CastField < FStructProperty > ( ArrayProperty - > Inner ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = ArrayOfStructsProperty - > Struct ;
}
2022-05-31 04:51:18 -04:00
else if ( const FObjectPropertyBase * ArrayOfObjectsProperty = CastField < FObjectPropertyBase > ( ArrayProperty - > Inner ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = ArrayOfObjectsProperty - > PropertyClass ;
}
Indirection . ArrayProperty = ArrayProperty ;
}
// Leaf segments all get treated the same, plain, struct or object
else if ( bFinalSegment )
{
CurrentStruct = nullptr ;
}
// Check to see if this is a simple structure (eg. not an array of structures)
2022-05-31 04:51:18 -04:00
else if ( const FStructProperty * StructProperty = CastField < FStructProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = StructProperty - > Struct ;
}
// Check to see if this is a simple object (eg. not an array of objects)
2022-05-31 04:51:18 -04:00
else if ( const FObjectProperty * ObjectProperty = CastField < FObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = ObjectProperty - > PropertyClass ;
}
// Check to see if this is a simple weak object property (eg. not an array of weak objects).
2022-05-31 04:51:18 -04:00
else if ( const FWeakObjectProperty * WeakObjectProperty = CastField < FWeakObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = WeakObjectProperty - > PropertyClass ;
}
// Check to see if this is a simple soft object property (eg. not an array of soft objects).
2022-05-31 04:51:18 -04:00
else if ( const FSoftObjectProperty * SoftObjectProperty = CastField < FSoftObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
CurrentStruct = SoftObjectProperty - > PropertyClass ;
}
else
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s: Unsupported segment %s in path '%s'. " ) ,
2022-05-31 04:51:18 -04:00
ANSI_TO_TCHAR ( __FUNCTION__ ) , * Property - > GetCPPType ( ) , * GetPathAsString ( FirstPathSegment , Segment , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
2021-09-28 13:33:17 -04:00
}
if ( bFinalSegment )
{
LeafProperty = Property ;
}
2022-05-31 04:51:18 -04:00
Segment = Segment - > NextIndex . IsValid ( ) ? & PropertySegments [ Segment - > NextIndex . Get ( ) ] : nullptr ;
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
// Collapse adjacent offset indirections
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 ] ;
if ( Indirection . Type = = EStateTreePropertyAccessType : : Offset & & ( 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 ] ;
if ( NextIndirection . Type = = EStateTreePropertyAccessType : : Offset )
{
Indirection . Offset + = NextIndirection . Offset ;
TempIndirections . RemoveAt ( Index + 1 ) ;
Index - - ;
}
2021-09-28 13:33:17 -04:00
}
}
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 ( ) ;
FStateTreePropertyIndirection & NewIndirection = PropertyIndirections . Add_GetRef ( TempIndirections [ Index ] ) ;
PrevIndirection - > NextIndex = FStateTreeIndex16 ( IndirectionIndex ) ;
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 ;
2022-05-31 04:51:18 -04:00
}
OutLeafProperty = LeafProperty ;
2021-09-28 13:33:17 -04:00
return true ;
}
bool FStateTreePropertyBindings : : ValidateCopy ( FStateTreePropCopy & Copy ) const
{
2022-05-31 04:51:18 -04:00
const FProperty * SourceProperty = Copy . SourceLeafProperty ;
const FProperty * TargetProperty = Copy . TargetLeafProperty ;
2021-09-28 13:33:17 -04:00
2022-04-20 07:19:18 -04:00
if ( ! TargetProperty )
{
return false ;
}
// If source property is nullptr, we're binding directly to the source.
2022-04-14 06:28:13 -04:00
if ( SourceProperty = = nullptr )
{
return TargetProperty - > IsA < FStructProperty > ( ) | | TargetProperty - > IsA < FObjectPropertyBase > ( ) ;
}
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 ( ) ;
}
bool bResult = true ;
switch ( Copy . Type )
{
case EStateTreePropertyCopyType : : CopyPlain :
2022-05-31 04:51:18 -04:00
Copy . CopySize = SourceProperty - > ElementSize * SourceProperty - > ArrayDim ;
2021-09-28 13:33:17 -04:00
bResult = ( SourceProperty - > PropertyFlags & CPF_IsPlainOldData ) ! = 0 & & ( TargetProperty - > PropertyFlags & CPF_IsPlainOldData ) ! = 0 ;
break ;
case EStateTreePropertyCopyType : : CopyComplex :
bResult = true ;
break ;
case EStateTreePropertyCopyType : : CopyBool :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FBoolProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : CopyStruct :
bResult = SourceProperty - > IsA < FStructProperty > ( ) & & TargetProperty - > IsA < FStructProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : CopyObject :
bResult = SourceProperty - > IsA < FObjectPropertyBase > ( ) & & TargetProperty - > IsA < FObjectPropertyBase > ( ) ;
break ;
case EStateTreePropertyCopyType : : CopyName :
bResult = SourceProperty - > IsA < FNameProperty > ( ) & & TargetProperty - > IsA < FNameProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : CopyFixedArray :
bResult = SourceProperty - > IsA < FArrayProperty > ( ) & & TargetProperty - > IsA < FArrayProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToByte :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FByteProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToInt32 :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FIntProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToUInt32 :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FUInt32Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToInt64 :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FInt64Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToFloat :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FFloatProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteBoolToDouble :
bResult = SourceProperty - > IsA < FBoolProperty > ( ) & & TargetProperty - > IsA < FDoubleProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToInt32 :
bResult = SourceProperty - > IsA < FByteProperty > ( ) & & TargetProperty - > IsA < FIntProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToUInt32 :
bResult = SourceProperty - > IsA < FByteProperty > ( ) & & TargetProperty - > IsA < FUInt32Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToInt64 :
bResult = SourceProperty - > IsA < FByteProperty > ( ) & & TargetProperty - > IsA < FInt64Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToFloat :
bResult = SourceProperty - > IsA < FByteProperty > ( ) & & TargetProperty - > IsA < FFloatProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteByteToDouble :
bResult = SourceProperty - > IsA < FByteProperty > ( ) & & TargetProperty - > IsA < FDoubleProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteInt32ToInt64 :
bResult = SourceProperty - > IsA < FIntProperty > ( ) & & TargetProperty - > IsA < FInt64Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteInt32ToFloat :
bResult = SourceProperty - > IsA < FIntProperty > ( ) & & TargetProperty - > IsA < FFloatProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteInt32ToDouble :
bResult = SourceProperty - > IsA < FIntProperty > ( ) & & TargetProperty - > IsA < FDoubleProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteFloatToDouble :
bResult = SourceProperty - > IsA < FFloatProperty > ( ) & & TargetProperty - > IsA < FDoubleProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : DemoteDoubleToFloat :
bResult = SourceProperty - > IsA < FDoubleProperty > ( ) & & TargetProperty - > IsA < FFloatProperty > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteUInt32ToInt64 :
bResult = SourceProperty - > IsA < FUInt32Property > ( ) & & TargetProperty - > IsA < FInt64Property > ( ) ;
break ;
case EStateTreePropertyCopyType : : PromoteUInt32ToFloat :
bResult = SourceProperty - > IsA < FUInt32Property > ( ) & & TargetProperty - > IsA < FFloatProperty > ( ) ;
break ;
default :
UE_LOG ( LogStateTree , Error , TEXT ( " FStateTreePropertyBindings::ValidateCopy: Unhandled copy type %s between '%s' and '%s' " ) ,
* StaticEnum < EStateTreePropertyCopyType > ( ) - > GetValueAsString ( Copy . Type ) , * SourceProperty - > GetNameCPP ( ) , * TargetProperty - > GetNameCPP ( ) ) ;
bResult = false ;
break ;
}
UE_CLOG ( ! bResult , LogStateTree , Error , TEXT ( " FStateTreePropertyBindings::ValidateCopy: Failed to validate copy type %s between '%s' and '%s' " ) ,
* StaticEnum < EStateTreePropertyCopyType > ( ) - > GetValueAsString ( Copy . Type ) , * SourceProperty - > GetNameCPP ( ) , * TargetProperty - > GetNameCPP ( ) ) ;
return bResult ;
}
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 )
{
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 ;
}
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
{
2022-05-31 04:51:18 -04:00
Address = reinterpret_cast < uint8 * > ( Helper . GetRawPtr ( Indirection - > ArrayIndex . Get ( ) ) ) ;
2021-09-28 13:33:17 -04:00
}
else
{
Address = nullptr ;
}
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 ;
}
2022-05-31 04:51:18 -04:00
void FStateTreePropertyBindings : : PerformCopy ( const FStateTreePropCopy & Copy , const 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 ;
}
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 ;
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 ;
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 ;
case EStateTreePropertyCopyType : : PromoteFloatToDouble :
* reinterpret_cast < double * > ( TargetAddress ) = ( double ) * reinterpret_cast < const float * > ( SourceAddress ) ;
break ;
case EStateTreePropertyCopyType : : DemoteDoubleToFloat :
* reinterpret_cast < float * > ( TargetAddress ) = ( float ) * reinterpret_cast < const double * > ( SourceAddress ) ;
break ;
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 ;
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 ( ) ) ) ;
const FStateTreePropCopyBatch & 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 + + )
{
const FStateTreePropCopy & Copy = PropertyCopies [ i ] ;
// 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-05-31 04:51:18 -04:00
const uint8 * SourceAddress = GetAddress ( SourceStructView , Copy . SourceIndirection , Copy . SourceLeafProperty ) ;
uint8 * TargetAddress = GetAddress ( TargetStructView , Copy . TargetIndirection , Copy . TargetLeafProperty ) ;
2022-05-05 08:44:57 -04:00
check ( SourceAddress ! = nullptr & & TargetAddress ! = nullptr ) ;
2022-05-31 04:51:18 -04:00
PerformCopy ( Copy , SourceAddress , TargetAddress ) ;
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
}
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 " ) ) ;
for ( const FStateTreePropCopyBatch & CopyBatch : CopyBatches )
{
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. */
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " \n PropertyBindings (%d) \n [ %-20s | %-4s | %-4s | %-10s | %-20s | %-4s | %-7s | %-20s | %-7s | %-20s ] \n " ) ,
PropertyBindings . Num ( ) ,
TEXT ( " Source Name " ) , TEXT ( " Arr# " ) , TEXT ( " Next " ) , TEXT ( " Access " ) ,
TEXT ( " Target Name " ) , TEXT ( " Arr# " ) , TEXT ( " Next " ) , TEXT ( " Access " ) ,
TEXT ( " Struct# " ) , TEXT ( " Copy Type " ) ) ;
2021-09-28 13:33:17 -04:00
for ( const FStateTreePropertyBinding & PropertyBinding : PropertyBindings )
{
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " | %-20s | %4d | %4d | %-10s | %-20s | %4d | %4d | %-10s | %7d | %-20s | \n " ) ,
* PropertyBinding . SourcePath . Name . ToString ( ) ,
PropertyBinding . SourcePath . ArrayIndex . Get ( ) ,
PropertyBinding . SourcePath . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyBinding . TargetPath . Type ) . ToString ( ) ,
* PropertyBinding . TargetPath . Name . ToString ( ) ,
PropertyBinding . TargetPath . ArrayIndex . Get ( ) ,
PropertyBinding . TargetPath . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertyBinding . TargetPath . Type ) . ToString ( ) ,
PropertyBinding . SourceStructIndex . Get ( ) ,
* UEnum : : GetValueAsString ( PropertyBinding . CopyType ) ) ;
2021-09-28 13:33:17 -04:00
}
/** Array of property segments, indexed by property paths. */
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " \n PropertySegments (%d) \n [ %-20s | %4s | %4s | %-10s ] \n " ) , PropertySegments . Num ( ) ,
TEXT ( " Name " ) , TEXT ( " Arr# " ) , TEXT ( " Next " ) , TEXT ( " Access " ) ) ;
2021-09-28 13:33:17 -04:00
for ( const FStateTreePropertySegment & PropertySegment : PropertySegments )
{
2022-05-31 04:51:18 -04:00
OutString + = FString : : Printf ( TEXT ( " | %-20s | %4d | %4d | %-10s | \n " ) ,
2021-09-28 13:33:17 -04:00
* PropertySegment . Name . ToString ( ) ,
2022-05-31 04:51:18 -04:00
PropertySegment . ArrayIndex . Get ( ) ,
PropertySegment . NextIndex . Get ( ) ,
* UEnum : : GetDisplayValueAsText ( PropertySegment . Type ) . 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 " ) ) ;
2021-09-28 13:33:17 -04:00
for ( const FStateTreePropCopy & PropertyCopy : PropertyCopies )
{
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
}
}
2022-05-31 04:51:18 -04:00
FString FStateTreePropertyBindings : : GetPathAsString ( const FStateTreePropertySegment & FirstPathSegment , const FStateTreePropertySegment * HighlightedSegment , const TCHAR * HighlightPrefix , const TCHAR * HighlightPostfix )
2021-09-28 13:33:17 -04:00
{
FString Result ;
2022-05-31 04:51:18 -04:00
const FStateTreePropertySegment * Segment = & FirstPathSegment ;
while ( Segment ! = nullptr )
2021-09-28 13:33:17 -04:00
{
2022-05-31 04:51:18 -04:00
if ( ! Result . IsEmpty ( ) )
2021-09-28 13:33:17 -04:00
{
Result + = TEXT ( " . " ) ;
}
2022-05-31 04:51:18 -04:00
if ( Segment = = HighlightedSegment & & HighlightPrefix )
2021-09-28 13:33:17 -04:00
{
Result + = HighlightPrefix ;
}
2022-05-31 04:51:18 -04:00
Result + = Segment - > Name . ToString ( ) ;
2021-09-28 13:33:17 -04:00
2022-05-31 04:51:18 -04:00
if ( Segment = = HighlightedSegment & & HighlightPostfix )
2021-09-28 13:33:17 -04:00
{
Result + = HighlightPostfix ;
}
2022-05-31 04:51:18 -04:00
Segment = Segment - > NextIndex . IsValid ( ) ? & PropertySegments [ Segment - > NextIndex . Get ( ) ] : nullptr ;
2021-09-28 13:33:17 -04:00
}
return Result ;
}
//----------------------------------------------------------------//
// 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 ;
}
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 ;
}