2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StateTreePropertyBindingCompiler.h"
# include "IPropertyAccessEditor.h"
# include "PropertyPathHelpers.h"
2022-05-31 04:51:18 -04:00
# include "StateTreeCompiler.h"
2023-01-25 02:42:36 -05:00
# include "StateTreeCompilerLog.h"
2023-01-19 00:48:07 -05:00
# include "StateTreeEditorPropertyBindings.h"
2023-02-10 07:22:48 -05:00
# include "Misc/EnumerateRange.h"
2024-01-11 04:24:45 -05:00
# include "StateTreePropertyBindings.h"
# include "StateTreePropertyRef.h"
# include "StateTreePropertyRefHelpers.h"
# include "StateTreePropertyHelpers.h"
2021-09-28 13:33:17 -04:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(StateTreePropertyBindingCompiler)
2021-10-29 04:33:21 -04:00
bool FStateTreePropertyBindingCompiler : : Init ( FStateTreePropertyBindings & InPropertyBindings , FStateTreeCompilerLog & InLog )
2021-09-28 13:33:17 -04:00
{
2021-10-29 04:33:21 -04:00
Log = & InLog ;
2021-09-28 13:33:17 -04:00
PropertyBindings = & InPropertyBindings ;
PropertyBindings - > Reset ( ) ;
2023-11-22 04:08:33 -05:00
2021-09-28 13:33:17 -04:00
SourceStructs . Reset ( ) ;
2023-11-22 04:08:33 -05:00
2021-09-28 13:33:17 -04:00
return true ;
}
2023-02-10 07:22:48 -05:00
bool FStateTreePropertyBindingCompiler : : CompileBatch ( const FStateTreeBindableStructDesc & TargetStruct , TConstArrayView < FStateTreePropertyPathBinding > BatchPropertyBindings , int32 & OutBatchIndex )
2021-09-28 13:33:17 -04:00
{
2021-10-29 04:33:21 -04:00
check ( Log ) ;
2021-09-28 13:33:17 -04:00
check ( PropertyBindings ) ;
OutBatchIndex = INDEX_NONE ;
StoreSourceStructs ( ) ;
2022-05-31 04:51:18 -04:00
2023-02-17 04:00:32 -05:00
struct FSortedBinding
{
FStateTreePropertyPathBinding Binding ;
TArray < FStateTreePropertyPathIndirection > TargetIndirections ;
} ;
TArray < FSortedBinding > NewBindings ;
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
for ( const FStateTreePropertyPathBinding & Binding : BatchPropertyBindings )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
if ( Binding . GetTargetPath ( ) . GetStructID ( ) ! = TargetStruct . ID )
2021-09-28 13:33:17 -04:00
{
continue ;
}
// Source must be in the source array
2023-11-22 04:08:33 -05:00
const FStateTreeBindableStructDesc * SourceStruct = GetSourceStructDescByID ( Binding . GetSourcePath ( ) . GetStructID ( ) ) ;
if ( ! SourceStruct )
2021-09-28 13:33:17 -04:00
{
2021-10-29 04:33:21 -04:00
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
TEXT ( " Could not find a binding source. " ) ) ;
2021-09-28 13:33:17 -04:00
return false ;
}
2023-02-10 07:22:48 -05:00
FString Error ;
TArray < FStateTreePropertyPathIndirection > SourceIndirections ;
TArray < FStateTreePropertyPathIndirection > TargetIndirections ;
2023-11-22 04:08:33 -05:00
if ( ! Binding . GetSourcePath ( ) . ResolveIndirections ( SourceStruct - > Struct , SourceIndirections , & Error ) )
2023-02-10 07:22:48 -05:00
{
2023-11-22 04:08:33 -05:00
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct , TEXT ( " Resolving path in %s: %s " ) , * SourceStruct - > ToString ( ) , * Error ) ;
2023-02-10 07:22:48 -05:00
return false ;
}
2021-09-28 13:33:17 -04:00
2023-02-10 07:22:48 -05:00
if ( ! Binding . GetTargetPath ( ) . ResolveIndirections ( TargetStruct . Struct , TargetIndirections , & Error ) )
{
2023-06-26 06:34:49 -04:00
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct , TEXT ( " Resolving path in %s: %s " ) , * TargetStruct . ToString ( ) , * Error ) ;
2023-02-10 07:22:48 -05:00
return false ;
}
2022-05-31 04:51:18 -04:00
2023-02-10 07:22:48 -05:00
FStateTreePropertyCopy DummyCopy ;
2023-11-22 04:08:33 -05:00
FStateTreePropertyPathIndirection LastSourceIndirection = ! SourceIndirections . IsEmpty ( ) ? SourceIndirections . Last ( ) : FStateTreePropertyPathIndirection ( SourceStruct - > Struct ) ;
2023-02-10 07:22:48 -05:00
FStateTreePropertyPathIndirection LastTargetIndirection = ! TargetIndirections . IsEmpty ( ) ? TargetIndirections . Last ( ) : FStateTreePropertyPathIndirection ( TargetStruct . Struct ) ;
2023-06-26 06:34:49 -04:00
if ( ! PropertyBindings - > ResolveCopyType ( LastSourceIndirection , LastTargetIndirection , DummyCopy ) )
2021-09-28 13:33:17 -04:00
{
2021-10-29 04:33:21 -04:00
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
2023-06-26 06:34:49 -04:00
TEXT ( " Cannot copy properties between %s and %s, properties are incompatible. " ) ,
2023-11-22 04:08:33 -05:00
* UE : : StateTree : : GetDescAndPathAsString ( * SourceStruct , Binding . GetSourcePath ( ) ) ,
2023-06-26 06:34:49 -04:00
* UE : : StateTree : : GetDescAndPathAsString ( TargetStruct , Binding . GetTargetPath ( ) ) ) ;
2022-05-31 04:51:18 -04:00
return false ;
}
2023-02-17 04:00:32 -05:00
FSortedBinding & NewBinding = NewBindings . AddDefaulted_GetRef ( ) ;
2023-11-22 04:08:33 -05:00
NewBinding . Binding = FStateTreePropertyPathBinding ( SourceStruct - > DataHandle , Binding . GetSourcePath ( ) , Binding . GetTargetPath ( ) ) ;
2023-02-17 04:00:32 -05:00
NewBinding . TargetIndirections = TargetIndirections ;
2021-09-28 13:33:17 -04:00
}
2023-02-17 04:00:32 -05:00
if ( ! NewBindings . IsEmpty ( ) )
2021-09-28 13:33:17 -04:00
{
2023-02-17 04:00:32 -05:00
// Sort bindings base on copy target memory layout.
NewBindings . StableSort ( [ ] ( const FSortedBinding & A , const FSortedBinding & B )
{
const int32 MaxSegments = FMath : : Min ( A . TargetIndirections . Num ( ) , B . TargetIndirections . Num ( ) ) ;
for ( int32 Index = 0 ; Index < MaxSegments ; Index + + )
{
// If property A is in struct before B, copy A first.
if ( A . TargetIndirections [ Index ] . GetPropertyOffset ( ) < B . TargetIndirections [ Index ] . GetPropertyOffset ( ) )
{
return true ;
}
// If A and B points to the same property, choose the one that points to an earlier array item.
// Note: this assumes that INDEX_NONE = -1, which means that binding directly to an array comes before an array access,
// and non-array access will compare equal (both INDEX_NONE).
if ( A . TargetIndirections [ Index ] . GetPropertyOffset ( ) = = B . TargetIndirections [ Index ] . GetPropertyOffset ( )
& & A . TargetIndirections [ Index ] . GetArrayIndex ( ) < B . TargetIndirections [ Index ] . GetArrayIndex ( ) )
{
return true ;
}
}
// We get here if the common path is the same, shorter path wins.
return A . TargetIndirections . Num ( ) < = B . TargetIndirections . Num ( ) ;
} ) ;
// Store bindings batch.
const int32 BindingsBegin = PropertyBindings - > PropertyPathBindings . Num ( ) ;
for ( const FSortedBinding & NewBinding : NewBindings )
{
PropertyBindings - > PropertyPathBindings . Add ( NewBinding . Binding ) ;
}
const int32 BindingsEnd = PropertyBindings - > PropertyPathBindings . Num ( ) ;
2023-02-10 07:22:48 -05:00
FStateTreePropertyCopyBatch & Batch = PropertyBindings - > CopyBatches . AddDefaulted_GetRef ( ) ;
2021-09-28 13:33:17 -04:00
Batch . TargetStruct = TargetStruct ;
2022-12-02 10:07:29 -05:00
Batch . BindingsBegin = IntCastChecked < uint16 > ( BindingsBegin ) ;
Batch . BindingsEnd = IntCastChecked < uint16 > ( BindingsEnd ) ;
2021-09-28 13:33:17 -04:00
OutBatchIndex = PropertyBindings - > CopyBatches . Num ( ) - 1 ;
}
return true ;
}
2024-02-14 09:04:52 -05:00
bool FStateTreePropertyBindingCompiler : : CompileReferences ( const FStateTreeBindableStructDesc & TargetStruct , TConstArrayView < FStateTreePropertyPathBinding > PropertyReferenceBindings , FStateTreeDataView InstanceDataView , const TMap < FGuid , const FStateTreeDataView > & IDToStructValue )
2024-01-11 04:24:45 -05:00
{
for ( const FStateTreePropertyPathBinding & Binding : PropertyReferenceBindings )
{
if ( Binding . GetTargetPath ( ) . GetStructID ( ) ! = TargetStruct . ID )
{
continue ;
}
// Source must be in the source array/
const FStateTreeBindableStructDesc * SourceStruct = GetSourceStructDescByID ( Binding . GetSourcePath ( ) . GetStructID ( ) ) ;
if ( ! SourceStruct )
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
TEXT ( " Could not find a binding source. " ) ) ;
return false ;
}
2024-02-14 09:04:52 -05:00
const FStateTreeDataView * SourceDataView = IDToStructValue . Find ( Binding . GetSourcePath ( ) . GetStructID ( ) ) ;
if ( ! SourceDataView )
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
TEXT ( " Could not find a binding source data view. " ) ) ;
return false ;
}
2024-01-11 04:24:45 -05:00
FString Error ;
TArray < FStateTreePropertyPathIndirection > SourceIndirections ;
2024-02-14 09:04:52 -05:00
if ( ! Binding . GetSourcePath ( ) . ResolveIndirectionsWithValue ( * SourceDataView , SourceIndirections , & Error ) )
2024-01-11 04:24:45 -05:00
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct , TEXT ( " Resolving path in %s: %s " ) , * SourceStruct - > ToString ( ) , * Error ) ;
return false ;
}
if ( ! UE : : StateTree : : PropertyRefHelpers : : IsPropertyAccessibleForPropertyRef ( SourceIndirections , * SourceStruct ) )
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
TEXT ( " %s cannot reference non-output %s " ) ,
* UE : : StateTree : : GetDescAndPathAsString ( TargetStruct , Binding . GetTargetPath ( ) ) ,
* UE : : StateTree : : GetDescAndPathAsString ( * SourceStruct , Binding . GetSourcePath ( ) ) ) ;
return false ;
}
2024-02-14 09:04:52 -05:00
TArray < FStateTreePropertyPathIndirection > TargetIndirections ;
if ( ! Binding . GetTargetPath ( ) . ResolveIndirectionsWithValue ( InstanceDataView , TargetIndirections , & Error ) )
2024-01-11 04:24:45 -05:00
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct , TEXT ( " Resolving path in %s: %s " ) , * TargetStruct . ToString ( ) , * Error ) ;
return false ;
}
2024-02-14 09:04:52 -05:00
FStateTreePropertyPathIndirection & TargetLeafIndirection = TargetIndirections . Last ( ) ;
FStateTreePropertyRef * PropertyRef = reinterpret_cast < FStateTreePropertyRef * > ( const_cast < uint8 * > ( TargetLeafIndirection . GetPropertyAddress ( ) ) ) ;
check ( PropertyRef ) ;
FStateTreePropertyPathIndirection & SourceLeafIndirection = SourceIndirections . Last ( ) ;
if ( ! UE : : StateTree : : PropertyRefHelpers : : IsPropertyRefCompatibleWithProperty ( * TargetLeafIndirection . GetProperty ( ) , * SourceLeafIndirection . GetProperty ( ) , PropertyRef , SourceLeafIndirection . GetPropertyAddress ( ) ) )
2024-01-11 04:24:45 -05:00
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct ,
TEXT ( " %s cannot reference %s, types are incompatible. " ) ,
* UE : : StateTree : : GetDescAndPathAsString ( TargetStruct , Binding . GetTargetPath ( ) ) ,
* UE : : StateTree : : GetDescAndPathAsString ( * SourceStruct , Binding . GetSourcePath ( ) ) ) ;
return false ;
}
FStateTreeIndex16 ReferenceIndex ;
// Reuse the index if another PropertyRef already references the same property.
{
int32 IndexOfAlreadyExisting = PropertyBindings - > PropertyReferencePaths . IndexOfByPredicate ( [ & Binding ] ( const FStateTreePropertyRefPath & RefPath )
{
return RefPath . GetSourcePath ( ) = = Binding . GetSourcePath ( ) ;
} ) ;
if ( IndexOfAlreadyExisting ! = INDEX_NONE )
{
ReferenceIndex = FStateTreeIndex16 ( IndexOfAlreadyExisting ) ;
}
}
if ( ! ReferenceIndex . IsValid ( ) )
{
2024-02-14 09:04:52 -05:00
// If referencing another non global or subtree parameter PropertyRef, reuse it's index.
if ( UE : : StateTree : : PropertyRefHelpers : : IsPropertyRef ( * SourceIndirections . Last ( ) . GetProperty ( ) )
& & SourceStruct - > DataHandle . GetSource ( ) ! = EStateTreeDataSourceType : : GlobalParameterData
& & SourceStruct - > DataHandle . GetSource ( ) ! = EStateTreeDataSourceType : : SubtreeParameterData )
2024-01-11 04:24:45 -05:00
{
const FCompiledReference * ReferencedReference = CompiledReferences . FindByPredicate ( [ & Binding ] ( const FCompiledReference & CompiledReference )
{
return CompiledReference . Path = = Binding . GetSourcePath ( ) ;
} ) ;
if ( ReferencedReference )
{
ReferenceIndex = ReferencedReference - > Index ;
}
else
{
if ( ! UE : : StateTree : : PropertyHelpers : : HasOptionalMetadata ( * TargetLeafIndirection . GetProperty ( ) ) )
{
Log - > Reportf ( EMessageSeverity : : Error , TargetStruct , TEXT ( " Referenced %s is not bound " ) , * UE : : StateTree : : GetDescAndPathAsString ( * SourceStruct , Binding . GetSourcePath ( ) ) ) ;
return false ;
}
return true ;
}
}
}
if ( ! ReferenceIndex . IsValid ( ) )
{
ReferenceIndex = FStateTreeIndex16 ( PropertyBindings - > PropertyReferencePaths . Num ( ) ) ;
PropertyBindings - > PropertyReferencePaths . Emplace ( SourceStruct - > DataHandle , Binding . GetSourcePath ( ) ) ;
}
// Store index in instance data.
2024-02-14 09:04:52 -05:00
PropertyRef - > RefAccessIndex = ReferenceIndex ;
2024-01-11 04:24:45 -05:00
FCompiledReference & CompiledReference = CompiledReferences . AddDefaulted_GetRef ( ) ;
CompiledReference . Path = Binding . GetTargetPath ( ) ;
CompiledReference . Index = ReferenceIndex ;
}
return true ;
}
2021-09-28 13:33:17 -04:00
void FStateTreePropertyBindingCompiler : : Finalize ( )
{
StoreSourceStructs ( ) ;
}
int32 FStateTreePropertyBindingCompiler : : AddSourceStruct ( const FStateTreeBindableStructDesc & SourceStruct )
{
2023-06-26 06:34:49 -04:00
const FStateTreeBindableStructDesc * ExistingStruct = SourceStructs . FindByPredicate ( [ & SourceStruct ] ( const FStateTreeBindableStructDesc & Struct ) { return ( Struct . ID = = SourceStruct . ID ) ; } ) ;
if ( ExistingStruct )
2023-02-09 04:23:32 -05:00
{
2023-06-27 14:01:11 -04:00
UE_LOG ( LogStateTree , Error , TEXT ( " %s already exists as %s using ID '%s' " ) ,
* SourceStruct . ToString ( ) , * ExistingStruct - > ToString ( ) , * ExistingStruct - > ID . ToString ( ) ) ;
2023-02-09 04:23:32 -05:00
}
2023-11-22 04:08:33 -05:00
UE_CLOG ( ! SourceStruct . DataHandle . IsValid ( ) , LogStateTree , Error , TEXT ( " %s does not have a valid data handle. " ) , * SourceStruct . ToString ( ) ) ;
2021-09-28 13:33:17 -04:00
SourceStructs . Add ( SourceStruct ) ;
return SourceStructs . Num ( ) - 1 ;
}
int32 FStateTreePropertyBindingCompiler : : GetSourceStructIndexByID ( const FGuid & ID ) const
{
return SourceStructs . IndexOfByPredicate ( [ ID ] ( const FStateTreeBindableStructDesc & Structs ) { return ( Structs . ID = = ID ) ; } ) ;
}
2023-02-10 07:22:48 -05:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2021-09-28 13:33:17 -04:00
bool FStateTreePropertyBindingCompiler : : ResolvePropertyPath ( const FStateTreeBindableStructDesc & InStructDesc , const FStateTreeEditorPropertyPath & InPath ,
2021-10-29 04:33:21 -04:00
TArray < FStateTreePropertySegment > & OutSegments , const FProperty * & OutLeafProperty , int32 & OutLeafArrayIndex ,
FStateTreeCompilerLog * InLog , const FStateTreeBindableStructDesc * InLogContextStruct )
2021-09-28 13:33:17 -04:00
{
if ( ! InPath . IsValid ( ) )
{
2021-10-29 04:33:21 -04:00
if ( InLog ! = nullptr & & InLogContextStruct ! = nullptr )
{
InLog - > Reportf ( EMessageSeverity : : Error , * InLogContextStruct ,
TEXT ( " Invalid path '%s:%s'. " ) ,
* InStructDesc . Name . ToString ( ) , * InPath . ToString ( ) ) ;
}
2021-09-28 13:33:17 -04:00
return false ;
}
2022-04-14 06:28:13 -04:00
// If the path is empty, we're pointing directly at the source struct.
if ( InPath . Path . Num ( ) = = 0 )
{
OutLeafProperty = nullptr ;
OutLeafArrayIndex = INDEX_NONE ;
return true ;
}
2021-09-28 13:33:17 -04:00
const UStruct * CurrentStruct = InStructDesc . Struct ;
2021-10-29 04:33:21 -04:00
const FProperty * LeafProperty = nullptr ;
2021-09-28 13:33:17 -04:00
int32 LeafArrayIndex = INDEX_NONE ;
2022-04-14 06:28:13 -04:00
bool bResult = true ;
2021-09-28 13:33:17 -04:00
for ( int32 SegmentIndex = 0 ; SegmentIndex < InPath . Path . Num ( ) ; SegmentIndex + + )
{
const FString & SegmentString = InPath . Path [ SegmentIndex ] ;
const TCHAR * PropertyNamePtr = nullptr ;
int32 PropertyNameLength = 0 ;
int32 ArrayIndex = INDEX_NONE ;
PropertyPathHelpers : : FindFieldNameAndArrayIndex ( SegmentString . Len ( ) , * SegmentString , PropertyNameLength , & PropertyNamePtr , ArrayIndex ) ;
ensure ( PropertyNamePtr ! = nullptr ) ;
FString PropertyNameString ( PropertyNameLength , PropertyNamePtr ) ;
2021-10-29 04:33:21 -04:00
const FName PropertyName = FName ( * PropertyNameString , FNAME_Find ) ;
2021-09-28 13:33:17 -04:00
const bool bFinalSegment = SegmentIndex = = ( InPath . Path . Num ( ) - 1 ) ;
if ( CurrentStruct = = nullptr )
{
2021-10-29 04:33:21 -04:00
if ( InLog ! = nullptr & & InLogContextStruct ! = nullptr )
{
InLog - > Reportf ( EMessageSeverity : : Error , * InLogContextStruct ,
TEXT ( " Malformed path '%s:%s'. " ) ,
* InStructDesc . Name . ToString ( ) , * InPath . ToString ( SegmentIndex , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
2021-09-28 13:33:17 -04:00
bResult = false ;
break ;
}
2021-10-29 04:33:21 -04:00
const FProperty * Property = CurrentStruct - > FindPropertyByName ( PropertyName ) ;
2021-09-28 13:33:17 -04:00
if ( Property = = nullptr )
{
// TODO: use core redirects to fix up the name.
2021-10-29 04:33:21 -04:00
if ( InLog ! = nullptr & & InLogContextStruct ! = nullptr )
{
InLog - > Reportf ( EMessageSeverity : : Error , * InLogContextStruct ,
TEXT ( " Malformed path '%s:%s', could not find property '%s%s.%s'. " ) ,
* InStructDesc . Name . ToString ( ) , * InPath . ToString ( SegmentIndex , TEXT ( " < " ) , TEXT ( " > " ) ) ,
CurrentStruct - > GetPrefixCPP ( ) , * CurrentStruct - > GetName ( ) , * PropertyName . ToString ( ) ) ;
}
2021-09-28 13:33:17 -04:00
bResult = false ;
break ;
}
2022-05-31 04:51:18 -04:00
if ( const auto Validation = UE : : StateTree : : Compiler : : IsValidIndex16 ( ArrayIndex ) ; Validation . DidFail ( ) )
{
if ( InLog ! = nullptr )
{
Validation . Log ( * InLog , TEXT ( " ArrayIndex " ) , InStructDesc ) ;
}
return false ;
}
2021-09-28 13:33:17 -04:00
FStateTreePropertySegment & Segment = OutSegments . AddDefaulted_GetRef ( ) ;
Segment . Name = PropertyName ;
2022-05-31 04:51:18 -04:00
Segment . ArrayIndex = FStateTreeIndex16 ( ArrayIndex ) ;
2021-09-28 13:33:17 -04:00
// Check to see if it is an array access first
2021-10-29 04:33:21 -04:00
const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( Property ) ;
2021-09-28 13:33:17 -04:00
if ( ArrayProperty ! = nullptr & & ArrayIndex ! = INDEX_NONE )
{
// It is an array, now check to see if this is an array of structures
2021-10-29 04:33:21 -04:00
if ( const FStructProperty * ArrayOfStructsProperty = CastField < FStructProperty > ( ArrayProperty - > Inner ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : IndexArray ;
CurrentStruct = ArrayOfStructsProperty - > Struct ;
}
// if it's not an array of structs, maybe it's an array of objects
2021-10-29 04:33:21 -04:00
else if ( const FObjectPropertyBase * ArrayOfObjectsProperty = CastField < FObjectPropertyBase > ( ArrayProperty - > Inner ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : IndexArray ;
CurrentStruct = ArrayOfObjectsProperty - > PropertyClass ;
if ( ! bFinalSegment )
{
// Object arrays need an object dereference adding if non-leaf
FStateTreePropertySegment & ExtraSegment = OutSegments . AddDefaulted_GetRef ( ) ;
2022-05-31 04:51:18 -04:00
ExtraSegment . ArrayIndex = FStateTreeIndex16 ( 0 ) ;
2021-09-28 13:33:17 -04:00
ExtraSegment . Type = EStateTreePropertyAccessType : : Object ;
2021-10-29 04:33:21 -04:00
const FProperty * InnerProperty = ArrayProperty - > Inner ;
if ( const FObjectProperty * ObjectProperty = CastField < FObjectProperty > ( InnerProperty ) )
2021-09-28 13:33:17 -04:00
{
ExtraSegment . Type = EStateTreePropertyAccessType : : Object ;
}
2021-10-29 04:33:21 -04:00
else if ( const FWeakObjectProperty * WeakObjectProperty = CastField < FWeakObjectProperty > ( InnerProperty ) )
2021-09-28 13:33:17 -04:00
{
ExtraSegment . Type = EStateTreePropertyAccessType : : WeakObject ;
}
2021-10-29 04:33:21 -04:00
else if ( const FSoftObjectProperty * SoftObjectProperty = CastField < FSoftObjectProperty > ( InnerProperty ) )
2021-09-28 13:33:17 -04:00
{
ExtraSegment . Type = EStateTreePropertyAccessType : : SoftObject ;
}
}
}
else
{
Segment . Type = EStateTreePropertyAccessType : : IndexArray ;
2022-05-31 04:51:18 -04:00
Segment . ArrayIndex = FStateTreeIndex16 ( ArrayIndex ) ;
2021-09-28 13:33:17 -04:00
CurrentStruct = nullptr ;
}
}
// Leaf segments all get treated the same, plain, array, struct or object. Copy type is figured out separately.
else if ( bFinalSegment )
{
Segment . Type = EStateTreePropertyAccessType : : Offset ;
CurrentStruct = nullptr ;
}
// Check to see if this is a simple structure (eg. not an array of structures)
2021-10-29 04:33:21 -04:00
else if ( const FStructProperty * StructProperty = CastField < FStructProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : Offset ;
CurrentStruct = StructProperty - > Struct ;
}
// Check to see if this is a simple object (eg. not an array of objects)
2021-10-29 04:33:21 -04:00
else if ( const FObjectProperty * ObjectProperty = CastField < FObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : Object ;
CurrentStruct = ObjectProperty - > PropertyClass ;
}
// Check to see if this is a simple weak object property (eg. not an array of weak objects).
2021-10-29 04:33:21 -04:00
else if ( const FWeakObjectProperty * WeakObjectProperty = CastField < FWeakObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : WeakObject ;
CurrentStruct = WeakObjectProperty - > PropertyClass ;
}
// Check to see if this is a simple soft object property (eg. not an array of soft objects).
2021-10-29 04:33:21 -04:00
else if ( const FSoftObjectProperty * SoftObjectProperty = CastField < FSoftObjectProperty > ( Property ) )
2021-09-28 13:33:17 -04:00
{
Segment . Type = EStateTreePropertyAccessType : : SoftObject ;
CurrentStruct = SoftObjectProperty - > PropertyClass ;
}
else
{
2021-10-29 04:33:21 -04:00
if ( InLog ! = nullptr & & InLogContextStruct ! = nullptr )
{
InLog - > Reportf ( EMessageSeverity : : Error , * InLogContextStruct ,
TEXT ( " Unsupported segment %s in path '%s:%s'. " ) ,
* InStructDesc . Name . ToString ( ) , * InPath . ToString ( SegmentIndex , TEXT ( " < " ) , TEXT ( " > " ) ) ,
* Property - > GetCPPType ( ) , * InStructDesc . Name . ToString ( ) , * InPath . ToString ( SegmentIndex , TEXT ( " < " ) , TEXT ( " > " ) ) ) ;
}
2021-09-28 13:33:17 -04:00
bResult = false ;
break ;
}
if ( bFinalSegment )
{
LeafProperty = Property ;
LeafArrayIndex = ArrayIndex ;
}
}
if ( ! bResult )
{
return false ;
}
OutLeafProperty = LeafProperty ;
OutLeafArrayIndex = LeafArrayIndex ;
return true ;
}
2022-09-09 07:14:47 -04:00
EPropertyAccessCompatibility FStateTreePropertyBindingCompiler : : GetPropertyCompatibility ( const FProperty * FromProperty , const FProperty * ToProperty )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
const EStateTreePropertyAccessCompatibility Result = FStateTreePropertyBindings : : GetPropertyCompatibility ( FromProperty , ToProperty ) ;
if ( Result = = EStateTreePropertyAccessCompatibility : : Compatible )
2021-09-28 13:33:17 -04:00
{
return EPropertyAccessCompatibility : : Compatible ;
}
2023-02-10 07:22:48 -05:00
if ( Result = = EStateTreePropertyAccessCompatibility : : Promotable )
2021-09-28 13:33:17 -04:00
{
2023-02-10 07:22:48 -05:00
return EPropertyAccessCompatibility : : Promotable ;
2021-09-28 13:33:17 -04:00
}
return EPropertyAccessCompatibility : : Incompatible ;
}
2023-02-10 07:22:48 -05:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2021-09-28 13:33:17 -04:00
void FStateTreePropertyBindingCompiler : : StoreSourceStructs ( )
{
// Check that existing structs are compatible
check ( PropertyBindings - > SourceStructs . Num ( ) < = SourceStructs . Num ( ) ) ;
for ( int32 i = 0 ; i < PropertyBindings - > SourceStructs . Num ( ) ; i + + )
{
check ( PropertyBindings - > SourceStructs [ i ] = = SourceStructs [ i ] ) ;
}
// Add new
if ( SourceStructs . Num ( ) > PropertyBindings - > SourceStructs . Num ( ) )
{
for ( int32 i = PropertyBindings - > SourceStructs . Num ( ) ; i < SourceStructs . Num ( ) ; i + + )
{
PropertyBindings - > SourceStructs . Add ( SourceStructs [ i ] ) ;
}
}
}