2022-06-27 16:24:02 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Bindings/MVVMCompiledBindingLibraryCompiler.h"
# include "Bindings/MVVMBindingHelper.h"
2023-06-16 12:57:13 -04:00
# include "Engine/Blueprint.h"
2022-06-27 16:24:02 -04:00
# include "Engine/Engine.h"
2023-06-16 12:57:13 -04:00
# include "Kismet2/BlueprintEditorUtils.h"
2023-02-14 12:07:02 -05:00
# include "MVVMDeveloperProjectSettings.h"
2022-06-27 16:24:02 -04:00
# include "MVVMSubsystem.h"
2023-01-12 01:48:34 -05:00
# include "Misc/TVariantMeta.h"
2023-01-13 01:54:07 -05:00
# include <limits> // IWYU pragma: keep
2022-06-27 16:24:02 -04:00
2022-10-06 20:08:12 -04:00
# define LOCTEXT_NAMESPACE "CompiledBindingLibraryCompiler"
2022-06-27 16:24:02 -04:00
namespace UE : : MVVM : : Private
{
static const FName NAME_BlueprintGetter = " BlueprintGetter " ;
/** */
struct FRawFieldId
{
2023-03-22 13:07:37 -04:00
const UClass * NotifyFieldValueChangedClass ;
2022-06-27 16:24:02 -04:00
UE : : FieldNotification : : FFieldId FieldId ;
int32 LoadedFieldIdIndex = INDEX_NONE ;
FCompiledBindingLibraryCompiler : : FFieldIdHandle IdHandle ;
FMVVMVCompiledFieldId CompiledFieldId ;
} ;
/** */
struct FRawField
{
FMVVMConstFieldVariant Field ;
bool bPropertyIsObjectProperty = false ; // either the FProperty or the return value of the UFunction
bool bPropertyIsStructProperty = false ;
int32 LoadedPropertyOrFunctionIndex = INDEX_NONE ;
public :
bool IsSameField ( const FRawField & Other ) const
{
return Field = = Other . Field ;
}
} ;
/** */
struct FRawFieldPath
{
TArray < int32 > RawFieldIndexes ;
bool bIsReadable = false ;
bool bIsWritable = false ;
FCompiledBindingLibraryCompiler : : FFieldPathHandle PathHandle ;
FMVVMVCompiledFieldPath CompiledFieldPath ;
public :
bool IsSameFieldPath ( const FRawFieldPath & Other ) const
{
return Other . RawFieldIndexes = = RawFieldIndexes ;
}
} ;
/** */
struct FRawBinding
{
2023-03-22 13:07:37 -04:00
FCompiledBindingLibraryCompiler : : FFieldPathHandle SourcePathHandle ;
2022-06-27 16:24:02 -04:00
FCompiledBindingLibraryCompiler : : FFieldPathHandle DestinationPathHandle ;
FCompiledBindingLibraryCompiler : : FFieldPathHandle ConversionFunctionPathHandle ;
FCompiledBindingLibraryCompiler : : FBindingHandle BindingHandle ;
FMVVMVCompiledBinding CompiledBinding ;
2023-05-26 11:58:47 -04:00
int32 BindingCount = 1 ;
2023-03-22 13:07:37 -04:00
bool bIsConversionFunctionComplex = false ;
2022-06-27 16:24:02 -04:00
public :
bool IsSameBinding ( const FRawBinding & Binding ) const
{
2023-03-22 13:07:37 -04:00
return Binding . SourcePathHandle = = SourcePathHandle
2022-06-27 16:24:02 -04:00
& & Binding . DestinationPathHandle = = DestinationPathHandle
& & Binding . ConversionFunctionPathHandle = = ConversionFunctionPathHandle ;
}
} ;
/** */
class FCompiledBindingLibraryCompilerImpl
{
public :
TArray < FRawFieldId > FieldIds ;
TArray < FRawField > Fields ;
TArray < FRawFieldPath > FieldPaths ;
TArray < FRawBinding > Bindings ;
bool bCompiled = false ;
public :
int32 AddUniqueField ( FMVVMConstFieldVariant InFieldVariant )
{
int32 FoundFieldPath = Fields . IndexOfByPredicate ( [ InFieldVariant ] ( const Private : : FRawField & Other )
{
return Other . Field = = InFieldVariant ;
} ) ;
if ( FoundFieldPath = = INDEX_NONE )
{
FRawField RawField ;
RawField . Field = InFieldVariant ;
check ( ! InFieldVariant . IsEmpty ( ) ) ;
const FProperty * FieldProperty = InFieldVariant . IsProperty ( ) ? InFieldVariant . GetProperty ( ) : BindingHelper : : GetReturnProperty ( InFieldVariant . GetFunction ( ) ) ;
// FieldProperty can be null if it's a setter function
RawField . bPropertyIsObjectProperty = CastField < FObjectPropertyBase > ( FieldProperty ) ! = nullptr ;
RawField . bPropertyIsStructProperty = CastField < FStructProperty > ( FieldProperty ) ! = nullptr ;
FoundFieldPath = Fields . Add ( RawField ) ;
}
return FoundFieldPath ;
}
} ;
2023-06-16 12:57:13 -04:00
/** */
//FMVVMConstFieldVariant GetMostUpToDate(FMVVMConstFieldVariant Field)
//{
// if (Field.IsValid())
// {
// UClass* Class = Cast<UClass>(Field.GetOwner());
// if (!Class)
// {
// return Field;
// }
// if (Field.IsProperty())
// {
// return FMVVMConstFieldVariant(FBlueprintEditorUtils::GetMostUpToDateProperty(Field.GetProperty()));
// }
// else if (Field.IsFunction())
// {
// return FMVVMConstFieldVariant(FBlueprintEditorUtils::GetMostUpToDateFunction(Field.GetFunction()));
// }
// }
// return Field;
//}
/** */
const UStruct * GetSavedGeneratedStruct ( FMVVMConstFieldVariant Field )
{
const UStruct * Result = Field . GetOwner ( ) ;
const UClass * Class = Cast < UClass > ( Result ) ;
if ( ! Class | | Class - > HasAnyClassFlags ( CLASS_Native ) | | Class - > bCooked | | ! Field . IsValid ( ) )
{
return Result ;
}
const UBlueprint * Blueprint = Cast < const UBlueprint > ( Class - > ClassGeneratedBy ) ;
if ( ! Blueprint )
{
return Result ;
}
ensure ( Blueprint - > GeneratedClass ) ;
return Blueprint - > GeneratedClass ;
}
/** */
const UClass * GetSavedGeneratedStruct ( const UClass * Class )
{
if ( ! Class | | Class - > HasAnyClassFlags ( CLASS_Native ) | | Class - > bCooked )
{
return Class ;
}
UBlueprint * Blueprint = Cast < UBlueprint > ( Class - > ClassGeneratedBy ) ;
if ( ! Blueprint )
{
return Class ;
}
ensure ( Blueprint - > GeneratedClass ) ;
return Blueprint - > GeneratedClass ;
}
2022-06-27 16:24:02 -04:00
} //namespace
namespace UE : : MVVM
{
int32 FCompiledBindingLibraryCompiler : : FBindingHandle : : IdGenerator = 0 ;
int32 FCompiledBindingLibraryCompiler : : FFieldPathHandle : : IdGenerator = 0 ;
int32 FCompiledBindingLibraryCompiler : : FFieldIdHandle : : IdGenerator = 0 ;
/**
*
*/
FCompiledBindingLibraryCompiler : : FCompiledBindingLibraryCompiler ( )
: Impl ( MakePimpl < Private : : FCompiledBindingLibraryCompilerImpl > ( ) )
{
}
2023-06-16 12:57:13 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldIdHandle , FText > FCompiledBindingLibraryCompiler : : AddFieldId ( const UClass * InSourceClass , FName FieldId )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
2023-06-16 12:57:13 -04:00
const UClass * SourceClass = FBlueprintEditorUtils : : GetMostUpToDateClass ( InSourceClass ) ;
2022-06-27 16:24:02 -04:00
if ( FieldId . IsNone ( ) )
{
2023-07-19 15:03:01 -04:00
return MakeError ( LOCTEXT ( " FieldNotDefined " , " The Field does not have the specifier FieldNotify and cannot be used as a binding source. You may want to use the 'One Time' binding mode. " ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( ! SourceClass - > ImplementsInterface ( UNotifyFieldValueChanged : : StaticClass ( ) ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " ClassDoesNotImplementInterface " , " '{0}' doesn't implement the NotifyFieldValueChanged interface. " )
, SourceClass - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
const TScriptInterface < INotifyFieldValueChanged > ScriptObject = SourceClass - > GetDefaultObject ( ) ;
if ( ensure ( ScriptObject . GetInterface ( ) ) )
{
UE : : FieldNotification : : FFieldId FoundFieldId = ScriptObject - > GetFieldNotificationDescriptor ( ) . GetField ( SourceClass , FieldId ) ;
if ( ! FoundFieldId . IsValid ( ) )
{
2023-08-02 08:36:00 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FieldNotifyNotSupported " , " The FieldNotify '{0}' is not supported by '{1}'. " )
2022-10-06 20:08:12 -04:00
, FText : : FromName ( FieldId )
, SourceClass - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
int32 FoundFieldIdIndex = Impl - > FieldIds . IndexOfByPredicate ( [ FoundFieldId , SourceClass ] ( const Private : : FRawFieldId & Other )
{
2023-03-22 13:07:37 -04:00
return Other . FieldId = = FoundFieldId & & Other . NotifyFieldValueChangedClass = = SourceClass ;
2022-06-27 16:24:02 -04:00
} ) ;
if ( FoundFieldIdIndex = = INDEX_NONE )
{
Private : : FRawFieldId RawFieldId ;
2023-03-22 13:07:37 -04:00
RawFieldId . NotifyFieldValueChangedClass = SourceClass ;
2022-06-27 16:24:02 -04:00
RawFieldId . FieldId = FoundFieldId ;
RawFieldId . IdHandle = FFieldIdHandle : : MakeHandle ( ) ;
FoundFieldIdIndex = Impl - > FieldIds . Add ( MoveTemp ( RawFieldId ) ) ;
}
return MakeValue ( Impl - > FieldIds [ FoundFieldIdIndex ] . IdHandle ) ;
}
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " UnexpectedCaseInAddFieldId " , " Unexpected case with AddFieldId. " ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FText > FCompiledBindingLibraryCompiler : : AddFieldPath ( TArrayView < const FMVVMConstFieldVariant > InFieldPath , bool bInRead )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
2022-07-13 13:52:41 -04:00
return AddFieldPathImpl ( InFieldPath , bInRead ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FText > FCompiledBindingLibraryCompiler : : AddFieldPathImpl ( TArrayView < const FMVVMConstFieldVariant > InFieldPath , bool bInRead )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
2022-10-06 20:08:12 -04:00
auto ValidateContainer = [ ] ( const FProperty * Property , bool bShouldBeInsideContainer , bool bIsObjectOrScriptStruct ) - > FText
2022-06-27 16:24:02 -04:00
{
const UStruct * OwnerStruct = Property - > GetOwnerStruct ( ) ;
if ( OwnerStruct = = nullptr )
{
2022-10-06 20:08:12 -04:00
return FText : : Format ( LOCTEXT ( " FieldHasInvalidOwner " , " The field {0} has an invalid owner struct. " ) , Property - > GetDisplayNameText ( ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( bShouldBeInsideContainer )
{
if ( ! Cast < UScriptStruct > ( OwnerStruct ) & & ! Cast < UClass > ( OwnerStruct ) )
{
2022-10-06 20:08:12 -04:00
return FText : : Format ( LOCTEXT ( " FieldDoesNotHaveValidOwnerForPath " , " The field {0} doesn't have a valid owner for that path. " ) , Property - > GetDisplayNameText ( ) ) ;
2022-06-27 16:24:02 -04:00
}
}
if ( bIsObjectOrScriptStruct )
{
if ( const FObjectPropertyBase * ObjectProperty = CastField < const FObjectPropertyBase > ( Property ) )
{
2022-10-06 20:08:12 -04:00
return FText : : GetEmpty ( ) ;
2022-06-27 16:24:02 -04:00
}
else if ( const FStructProperty * StructProperty = CastField < const FStructProperty > ( Property ) )
{
if ( StructProperty - > HasGetter ( ) | | Property - > HasMetaData ( Private : : NAME_BlueprintGetter ) )
{
2022-10-06 20:08:12 -04:00
return FText : : Format ( LOCTEXT ( " GetterNotSupported " , " Property {0} has getter accessor. Accessor not supported on FStructProperty since it would create a temporary structure and we would not able to return a valid container from that structure. " ) , StructProperty - > GetDisplayNameText ( ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
return FText : : GetEmpty ( ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
return FText : : Format ( LOCTEXT ( " FieldCanOnlyBeObjectOrStruct " , " Field can only be object properties or struct properties. {0} is a {1} " ) , Property - > GetDisplayNameText ( ) , Property - > GetClass ( ) - > GetDisplayNameText ( ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
return FText : : GetEmpty ( ) ;
2022-06-27 16:24:02 -04:00
} ;
TArray < int32 > RawFieldIndexes ;
RawFieldIndexes . Reserve ( InFieldPath . Num ( ) ) ;
for ( int32 Index = 0 ; Index < InFieldPath . Num ( ) ; + + Index )
{
2023-06-16 12:57:13 -04:00
// Make sure the FieldVariant is not from a skeletalclass
2022-06-27 16:24:02 -04:00
FMVVMConstFieldVariant FieldVariant = InFieldPath [ Index ] ;
2023-06-16 12:57:13 -04:00
if ( ! FieldVariant . IsValid ( ) )
{
return MakeError ( FText : : Format ( LOCTEXT ( " FieldDoesNotHaveValidOwner " , " The field {0} doesn't have a valid owner. " ) , FText : : FromName ( InFieldPath [ Index ] . GetName ( ) ) ) ) ;
}
2022-06-27 16:24:02 -04:00
const bool bIsLast = Index = = InFieldPath . Num ( ) - 1 ;
if ( FieldVariant . IsProperty ( ) )
{
// They must all be readable except the last item if we are writing to the property.
if ( bIsLast & & ! bInRead )
{
if ( ! BindingHelper : : IsValidForDestinationBinding ( FieldVariant . GetProperty ( ) ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " PropertyNotWritableAtRuntime " , " Property '{0}' is not writable at runtime. " ) , FieldVariant . GetProperty ( ) - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
}
else if ( ! BindingHelper : : IsValidForSourceBinding ( FieldVariant . GetProperty ( ) ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " PropertyNotReadableAtRuntime " , " Property '{0}' is not readable at runtime. " ) , FieldVariant . GetProperty ( ) - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
FText ValidatedStr = ValidateContainer ( FieldVariant . GetProperty ( ) , true , ! bIsLast ) ;
2022-06-27 16:24:02 -04:00
if ( ! ValidatedStr . IsEmpty ( ) )
{
return MakeError ( ValidatedStr ) ;
}
2023-02-17 15:28:46 -05:00
if ( ! GetDefault < UMVVMDeveloperProjectSettings > ( ) - > IsPropertyAllowed ( FieldVariant . GetProperty ( ) ) )
{
return MakeError ( LOCTEXT ( " PropertyNotAllow " , " A property is not allowed. " ) ) ;
}
2023-02-14 12:07:02 -05:00
2022-06-27 16:24:02 -04:00
RawFieldIndexes . Add ( Impl - > AddUniqueField ( FieldVariant ) ) ;
}
else if ( FieldVariant . IsFunction ( ) )
{
if ( bIsLast & & ! bInRead )
{
if ( ! BindingHelper : : IsValidForDestinationBinding ( FieldVariant . GetFunction ( ) ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FunctionNotWritableAtRuntime " , " Function '{0}' is not writable at runtime. " ) , FieldVariant . GetFunction ( ) - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
}
else if ( ! BindingHelper : : IsValidForSourceBinding ( FieldVariant . GetFunction ( ) ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FunctionNotReadableAtRuntime " , " Function '{0}' is not readable at runtime. " ) , FieldVariant . GetFunction ( ) - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
2023-02-17 15:28:46 -05:00
if ( ! GetDefault < UMVVMDeveloperProjectSettings > ( ) - > IsFunctionAllowed ( FieldVariant . GetFunction ( ) ) )
{
return MakeError ( LOCTEXT ( " FunctionNotAllow " , " A function is not allowed. " ) ) ;
}
2023-02-14 12:07:02 -05:00
2022-06-27 16:24:02 -04:00
if ( bIsLast & & ! bInRead )
{
const FProperty * FirstProperty = BindingHelper : : GetFirstArgumentProperty ( FieldVariant . GetFunction ( ) ) ;
ValidateContainer ( FirstProperty , false , bIsLast ) ;
RawFieldIndexes . Add ( Impl - > AddUniqueField ( FieldVariant ) ) ;
}
else
{
const FProperty * ReturnProperty = BindingHelper : : GetReturnProperty ( FieldVariant . GetFunction ( ) ) ;
ValidateContainer ( ReturnProperty , false , bIsLast ) ;
RawFieldIndexes . Add ( Impl - > AddUniqueField ( FieldVariant ) ) ;
}
}
else
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " InvalidFieldInPath " , " There is an invalid field in the field path. " ) ) ;
2022-06-27 16:24:02 -04:00
}
}
int32 FoundFieldPath = Impl - > FieldPaths . IndexOfByPredicate ( [ & RawFieldIndexes ] ( const Private : : FRawFieldPath & Other )
{
return Other . RawFieldIndexes = = RawFieldIndexes ;
} ) ;
if ( FoundFieldPath ! = INDEX_NONE )
{
Impl - > FieldPaths [ FoundFieldPath ] . bIsReadable = Impl - > FieldPaths [ FoundFieldPath ] . bIsReadable | | bInRead ;
Impl - > FieldPaths [ FoundFieldPath ] . bIsWritable = Impl - > FieldPaths [ FoundFieldPath ] . bIsWritable | | ! bInRead ;
return MakeValue ( Impl - > FieldPaths [ FoundFieldPath ] . PathHandle ) ;
}
Private : : FRawFieldPath RawFieldPath ;
RawFieldPath . RawFieldIndexes = RawFieldIndexes ;
RawFieldPath . PathHandle = FFieldPathHandle : : MakeHandle ( ) ;
RawFieldPath . bIsReadable = bInRead ;
RawFieldPath . bIsWritable = ! bInRead ;
FoundFieldPath = Impl - > FieldPaths . Add ( MoveTemp ( RawFieldPath ) ) ;
return MakeValue ( Impl - > FieldPaths [ FoundFieldPath ] . PathHandle ) ;
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FText > FCompiledBindingLibraryCompiler : : AddObjectFieldPath ( TArrayView < const UE : : MVVM : : FMVVMConstFieldVariant > FieldPath , UClass * ExpectedType , bool bInRead )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
check ( ExpectedType ) ;
2022-07-13 13:52:41 -04:00
if ( FieldPath . Num ( ) = = 0 )
2022-06-27 16:24:02 -04:00
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FieldDoesNotReturnType " , " The field does not return a '{0}'. " ) , ExpectedType - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
2023-06-16 12:57:13 -04:00
UE : : MVVM : : FMVVMConstFieldVariant Last = FieldPath . Last ( ) ;
2022-06-27 16:24:02 -04:00
const FObjectPropertyBase * ObjectPropertyBase = nullptr ;
2023-06-16 12:57:13 -04:00
if ( Last . IsProperty ( ) )
2022-06-27 16:24:02 -04:00
{
2023-06-16 12:57:13 -04:00
ObjectPropertyBase = CastField < const FObjectPropertyBase > ( Last . GetProperty ( ) ) ;
2022-06-27 16:24:02 -04:00
}
2023-06-16 12:57:13 -04:00
else if ( Last . IsFunction ( ) )
2022-06-27 16:24:02 -04:00
{
2023-06-16 12:57:13 -04:00
ObjectPropertyBase = CastField < const FObjectPropertyBase > ( BindingHelper : : GetReturnProperty ( Last . GetFunction ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( ObjectPropertyBase = = nullptr )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FieldDoesNotReturnType " , " The field does not return a '{0}'. " ) , ExpectedType - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( ObjectPropertyBase - > PropertyClass = = nullptr | | ! ExpectedType - > IsChildOf ( ObjectPropertyBase - > PropertyClass ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FieldDoesNotReturnType " , " The field does not return a '{0}'. " ) , ExpectedType - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-07-13 13:52:41 -04:00
return AddFieldPathImpl ( FieldPath , bInRead ) ;
2022-06-27 16:24:02 -04:00
}
2023-06-16 12:57:13 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FText > FCompiledBindingLibraryCompiler : : AddConversionFunctionFieldPath ( const UClass * InSourceClass , const UFunction * InFunction )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
2023-06-16 12:57:13 -04:00
const UClass * SourceClass = FBlueprintEditorUtils : : GetMostUpToDateClass ( InSourceClass ) ;
const UFunction * Function = FBlueprintEditorUtils : : GetMostUpToDateFunction ( InFunction ) ;
2023-07-26 13:51:11 -04:00
// Transient Conversion function are only added to generated class and not to the skeletal class.
bool bTransientConversionFunction = false ;
if ( Function = = nullptr & & InFunction & & InFunction - > GetTypedOuter < UClass > ( ) = = InSourceClass )
{
Function = InFunction ;
bTransientConversionFunction = true ;
}
2022-06-27 16:24:02 -04:00
if ( SourceClass = = nullptr )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " SourceClassInvalid " , " The source class is invalid. " ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( Function = = nullptr )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " FunctionPathEmpty " , " The function path is empty. " ) ) ;
2022-06-27 16:24:02 -04:00
}
2022-08-24 13:14:51 -04:00
const bool bIsSimpleFunction = BindingHelper : : IsValidForSimpleRuntimeConversion ( Function ) ;
const bool bIsComplexFunction = BindingHelper : : IsValidForComplexRuntimeConversion ( Function ) ;
if ( ! bIsSimpleFunction & & ! bIsComplexFunction )
2022-06-27 16:24:02 -04:00
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FunctionCannotBeUsedAsConversionFunction " , " Function {0} cannot be used as a runtime conversion function. " ) , Function - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( ! Function - > HasAllFunctionFlags ( FUNC_Static ) )
{
2023-07-26 13:51:11 -04:00
if ( ! SourceClass - > IsChildOf ( Function - > GetOuterUClass ( ) ) & & ! bTransientConversionFunction )
2022-06-27 16:24:02 -04:00
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " FunctionHasInvalidSelf " , " Function {0} is going to be executed with an invalid self. " ) , Function - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
}
TArray < int32 > RawFieldIndexes ;
RawFieldIndexes . Add ( Impl - > AddUniqueField ( FMVVMConstFieldVariant ( Function ) ) ) ;
const int32 FoundFieldPath = Impl - > FieldPaths . IndexOfByPredicate ( [ & RawFieldIndexes ] ( const Private : : FRawFieldPath & Other )
{
return Other . RawFieldIndexes = = RawFieldIndexes ;
} ) ;
if ( FoundFieldPath ! = INDEX_NONE )
{
return MakeValue ( Impl - > FieldPaths [ FoundFieldPath ] . PathHandle ) ;
}
Private : : FRawFieldPath RawFieldPath ;
RawFieldPath . RawFieldIndexes = MoveTemp ( RawFieldIndexes ) ;
RawFieldPath . PathHandle = FFieldPathHandle : : MakeHandle ( ) ;
RawFieldPath . bIsReadable = false ;
RawFieldPath . bIsWritable = false ;
const int32 NewFieldPathIndex = Impl - > FieldPaths . Add ( MoveTemp ( RawFieldPath ) ) ;
return MakeValue ( Impl - > FieldPaths [ NewFieldPathIndex ] . PathHandle ) ;
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FBindingHandle , FText > FCompiledBindingLibraryCompiler : : AddBinding ( FFieldPathHandle InSourceHandle , FFieldPathHandle InDestinationHandle )
2022-06-27 16:24:02 -04:00
{
2023-03-22 13:07:37 -04:00
return AddBindingImpl ( InSourceHandle , InDestinationHandle , FFieldPathHandle ( ) , false ) ;
2022-06-27 16:24:02 -04:00
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FBindingHandle , FText > FCompiledBindingLibraryCompiler : : AddBinding ( FFieldPathHandle InSourceHandle , FFieldPathHandle InDestinationHandle , FFieldPathHandle InConversionFunctionHandle )
2022-06-27 16:24:02 -04:00
{
2023-03-22 13:07:37 -04:00
return AddBindingImpl ( InSourceHandle , InDestinationHandle , InConversionFunctionHandle , false ) ;
2022-06-27 16:24:02 -04:00
}
2023-03-22 13:07:37 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FBindingHandle , FText > FCompiledBindingLibraryCompiler : : AddComplexBinding ( FFieldPathHandle InDestinationHandle , FFieldPathHandle InConversionFunctionHandle )
{
return AddBindingImpl ( FFieldPathHandle ( ) , InDestinationHandle , InConversionFunctionHandle , true ) ;
}
TValueOrError < FCompiledBindingLibraryCompiler : : FBindingHandle , FText > FCompiledBindingLibraryCompiler : : AddBindingImpl ( FFieldPathHandle InSourceHandle , FFieldPathHandle InDestinationHandle , FFieldPathHandle InConversionFunctionHandle , bool bInIsComplexBinding )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
UMVVMSubsystem : : FConstDirectionalBindingArgs DirectionBindingArgs ;
2023-03-22 13:07:37 -04:00
// Complex Conversion function do not have input arguments.
if ( ! bInIsComplexBinding )
2022-06-27 16:24:02 -04:00
{
2023-03-22 13:07:37 -04:00
const int32 FoundSourceFieldPath = Impl - > FieldPaths . IndexOfByPredicate ( [ InSourceHandle ] ( const Private : : FRawFieldPath & Other )
2022-06-27 16:24:02 -04:00
{
2023-03-22 13:07:37 -04:00
return Other . PathHandle = = InSourceHandle ;
2022-06-27 16:24:02 -04:00
} ) ;
if ( FoundSourceFieldPath = = INDEX_NONE )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " SourceHandleInvalid " , " The source handle is invalid. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawFieldPath & SourceRawFieldPath = Impl - > FieldPaths [ FoundSourceFieldPath ] ;
if ( ! SourceRawFieldPath . bIsReadable )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " SourceHandleNotReadable " , " The source handle was not constructed as a readable path. " ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( SourceRawFieldPath . RawFieldIndexes . Num ( ) = = 0 )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " SourceHandleNotRegistered " , " The source handle was not registered correctly. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawField & RawField = Impl - > Fields [ SourceRawFieldPath . RawFieldIndexes . Last ( ) ] ;
if ( RawField . Field . IsEmpty ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " SourceHandleNotRegistered " , " The source handle was not registered correctly. " ) ) ;
2022-06-27 16:24:02 -04:00
}
DirectionBindingArgs . SourceBinding = RawField . Field ;
}
{
const int32 FoundDestinationFieldPath = Impl - > FieldPaths . IndexOfByPredicate ( [ InDestinationHandle ] ( const Private : : FRawFieldPath & Other )
{
return Other . PathHandle = = InDestinationHandle ;
} ) ;
if ( FoundDestinationFieldPath = = INDEX_NONE )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " DestinationHandleInvalid " , " The destination handle is invalid. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawFieldPath & DestinationRawFieldPath = Impl - > FieldPaths [ FoundDestinationFieldPath ] ;
if ( ! DestinationRawFieldPath . bIsWritable )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " DestinationHandleNotWritable " , " The destination handle was not constructed as a writable path. " ) ) ;
2022-06-27 16:24:02 -04:00
}
if ( DestinationRawFieldPath . RawFieldIndexes . Num ( ) = = 0 )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " DestinationHandleNotRegistered " , " The destination handle was not registered correctly. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawField & RawField = Impl - > Fields [ DestinationRawFieldPath . RawFieldIndexes . Last ( ) ] ;
if ( RawField . Field . IsEmpty ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " DestinationHandleNotRegistered " , " The destination handle was not registered correctly. " ) ) ;
2022-06-27 16:24:02 -04:00
}
DirectionBindingArgs . DestinationBinding = RawField . Field ;
}
if ( InConversionFunctionHandle . IsValid ( ) )
{
const int32 FoundFunctionFieldPath = Impl - > FieldPaths . IndexOfByPredicate ( [ InConversionFunctionHandle ] ( const Private : : FRawFieldPath & Other )
{
return Other . PathHandle = = InConversionFunctionHandle ;
} ) ;
if ( FoundFunctionFieldPath = = INDEX_NONE )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " FunctionHandleInvalid " , " The function handle is invalid. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawFieldPath & ConversionFunctinRawFieldPath = Impl - > FieldPaths [ FoundFunctionFieldPath ] ;
if ( ConversionFunctinRawFieldPath . RawFieldIndexes . Num ( ) = = 0 )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " FunctionHandleNotRegistered " , " The function handle was not registered as a function. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Private : : FRawField & RawField = Impl - > Fields [ ConversionFunctinRawFieldPath . RawFieldIndexes . Last ( ) ] ;
if ( ! RawField . Field . IsFunction ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " FunctionHandleNotRegistered " , " The function handle was not registered as a function. " ) ) ;
2022-06-27 16:24:02 -04:00
}
DirectionBindingArgs . ConversionFunction = RawField . Field . GetFunction ( ) ;
}
2022-10-06 20:08:12 -04:00
TValueOrError < bool , FText > IsValidBinding = GEngine - > GetEngineSubsystem < UMVVMSubsystem > ( ) - > IsBindingValid ( DirectionBindingArgs ) ;
2022-06-27 16:24:02 -04:00
if ( IsValidBinding . HasError ( ) )
{
return MakeError ( IsValidBinding . StealError ( ) ) ;
}
Private : : FRawBinding NewBinding ;
2023-03-22 13:07:37 -04:00
NewBinding . SourcePathHandle = InSourceHandle ;
2022-06-27 16:24:02 -04:00
NewBinding . DestinationPathHandle = InDestinationHandle ;
NewBinding . ConversionFunctionPathHandle = InConversionFunctionHandle ;
2023-03-22 13:07:37 -04:00
NewBinding . bIsConversionFunctionComplex = bInIsComplexBinding ;
2023-03-16 13:02:33 -04:00
const int32 FoundSameBindingIndex = Impl - > Bindings . IndexOfByPredicate ( [ & NewBinding ] ( const Private : : FRawBinding & Binding )
2022-06-27 16:24:02 -04:00
{
return NewBinding . IsSameBinding ( Binding ) ;
} ) ;
2023-03-22 13:07:37 -04:00
if ( FoundSameBindingIndex ! = INDEX_NONE )
{
2023-04-13 10:55:58 -04:00
if ( ! bInIsComplexBinding )
{
return MakeError ( LOCTEXT ( " BindingAlreadyAdded " , " The binding already exist. " ) ) ;
}
else
{
2023-05-26 11:58:47 -04:00
+ + Impl - > Bindings [ FoundSameBindingIndex ] . BindingCount ;
2023-04-13 10:55:58 -04:00
return MakeValue ( Impl - > Bindings [ FoundSameBindingIndex ] . BindingHandle ) ;
}
2023-03-22 13:07:37 -04:00
}
else
2022-06-27 16:24:02 -04:00
{
FCompiledBindingLibraryCompiler : : FBindingHandle ResultBindingHandle = FBindingHandle : : MakeHandle ( ) ;
NewBinding . BindingHandle = ResultBindingHandle ;
Impl - > Bindings . Add ( MoveTemp ( NewBinding ) ) ;
return MakeValue ( ResultBindingHandle ) ;
}
}
2022-10-06 20:08:12 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FCompileResult , FText > FCompiledBindingLibraryCompiler : : Compile ( )
2022-06-27 16:24:02 -04:00
{
Impl - > bCompiled = false ;
struct FCompiledClassInfo
{
TArray < int32 > RawFieldIndex ;
TArray < int32 > RawFieldIdIndex ;
} ;
2023-06-16 12:57:13 -04:00
// create the list of UClass. Uses the Generated class, not the SkeletalClass.
2022-06-27 16:24:02 -04:00
TMap < const UStruct * , FCompiledClassInfo > MapOfFieldInClass ;
{
for ( int32 Index = 0 ; Index < Impl - > Fields . Num ( ) ; + + Index )
{
const Private : : FRawField & RawField = Impl - > Fields [ Index ] ;
check ( ! RawField . Field . IsEmpty ( ) ) ;
2023-06-16 12:57:13 -04:00
const UStruct * FinalOwner = Private : : GetSavedGeneratedStruct ( RawField . Field ) ;
check ( FinalOwner ) ;
FCompiledClassInfo & ClassInfo = MapOfFieldInClass . FindOrAdd ( FinalOwner ) ;
2022-06-27 16:24:02 -04:00
2023-06-16 12:57:13 -04:00
// Test if the Field is there more than one
2022-06-27 16:24:02 -04:00
{
FMVVMConstFieldVariant FieldToTest = RawField . Field ;
const TArray < Private : : FRawField > & ListOfFields = Impl - > Fields ;
const bool bContains = ClassInfo . RawFieldIndex . ContainsByPredicate ( [ FieldToTest , & ListOfFields ] ( int32 OtherIndex )
{
return ListOfFields [ OtherIndex ] . Field = = FieldToTest ;
} ) ;
check ( ! bContains ) ;
}
ClassInfo . RawFieldIndex . Add ( Index ) ;
}
}
{
for ( int32 Index = 0 ; Index < Impl - > FieldIds . Num ( ) ; + + Index )
{
const Private : : FRawFieldId & RawFieldId = Impl - > FieldIds [ Index ] ;
check ( RawFieldId . FieldId . IsValid ( ) ) ;
2022-12-12 13:37:17 -05:00
check ( RawFieldId . NotifyFieldValueChangedClass ) ;
2022-06-27 16:24:02 -04:00
2023-06-16 12:57:13 -04:00
FCompiledClassInfo & ClassInfo = MapOfFieldInClass . FindOrAdd ( Private : : GetSavedGeneratedStruct ( RawFieldId . NotifyFieldValueChangedClass ) ) ;
2022-06-27 16:24:02 -04:00
// Test if the Field is not there more than one
{
UE : : FieldNotification : : FFieldId FieldIdToTest = RawFieldId . FieldId ;
const TArray < Private : : FRawFieldId > & ListOfFieldIds = Impl - > FieldIds ;
const bool bContains = ClassInfo . RawFieldIdIndex . ContainsByPredicate ( [ FieldIdToTest , & ListOfFieldIds ] ( int32 OtherIndex )
{
return ListOfFieldIds [ OtherIndex ] . FieldId = = FieldIdToTest ;
} ) ;
check ( ! bContains ) ;
}
ClassInfo . RawFieldIdIndex . Add ( Index ) ;
}
}
// Todo optimize that list to group common type. ie UWidget::ToolTip == UProgressBar::ToolTip. We can merge UWidget in UProgressBar.
2023-06-16 12:57:13 -04:00
//Algo: for each class entry
// if: a class is child of another class in the list (ProgressBar is child of Widget all property inside Widget are also in ProgressBar)
// then: merge the 2 and restart the algo
2022-06-27 16:24:02 -04:00
FCompileResult Result ;
// Create FMVVMCompiledBindingLibrary::CompiledFields and FMVVMCompiledBindingLibrary::CompiledFieldNames
int32 TotalNumberOfProperties = 0 ;
int32 TotalNumberOfFunctions = 0 ;
int32 TotalNumberOfFieldIds = 0 ;
for ( TPair < const UStruct * , FCompiledClassInfo > & StructCompiledFields : MapOfFieldInClass )
{
FMVVMVCompiledFields CompiledFields ;
2023-06-16 12:57:13 -04:00
CompiledFields . ClassOrScriptStruct = StructCompiledFields . Key ; // The generated class not the skeletal class
2022-06-27 16:24:02 -04:00
check ( StructCompiledFields . Key ) ;
TArray < FName > PropertyNames ;
TArray < FName > FunctionNames ;
TArray < FName > FieldIdNames ;
for ( const int32 FieldIndex : StructCompiledFields . Value . RawFieldIndex )
{
check ( Impl - > Fields . IsValidIndex ( FieldIndex ) ) ;
Private : : FRawField & RawField = Impl - > Fields [ FieldIndex ] ;
const FMVVMConstFieldVariant & Field = RawField . Field ;
if ( Field . IsProperty ( ) )
{
2023-06-16 12:57:13 -04:00
// N.B. no need to translate from skeletal to generated, we only use the the name or the index.
2022-06-27 16:24:02 -04:00
Result . Library . LoadedProperties . Add ( const_cast < FProperty * > ( Field . GetProperty ( ) ) ) ;
PropertyNames . Add ( Field . GetName ( ) ) ;
RawField . LoadedPropertyOrFunctionIndex = TotalNumberOfProperties ;
+ + TotalNumberOfProperties ;
}
else
{
check ( Field . IsFunction ( ) ) ;
2023-06-16 12:57:13 -04:00
// N.B. no need to translate from skeletal to generated, we only use the the name or the index.
2022-06-27 16:24:02 -04:00
Result . Library . LoadedFunctions . Add ( const_cast < UFunction * > ( Field . GetFunction ( ) ) ) ;
FunctionNames . Add ( Field . GetName ( ) ) ;
RawField . LoadedPropertyOrFunctionIndex = TotalNumberOfFunctions ;
+ + TotalNumberOfFunctions ;
}
}
for ( const int32 FieldIdIndex : StructCompiledFields . Value . RawFieldIdIndex )
{
check ( Impl - > FieldIds . IsValidIndex ( FieldIdIndex ) ) ;
Private : : FRawFieldId & RawFieldId = Impl - > FieldIds [ FieldIdIndex ] ;
Result . Library . LoadedFieldIds . Add ( RawFieldId . FieldId ) ;
FieldIdNames . Add ( RawFieldId . FieldId . GetName ( ) ) ;
RawFieldId . LoadedFieldIdIndex = TotalNumberOfFieldIds ;
+ + TotalNumberOfFieldIds ;
}
if ( PropertyNames . Num ( ) > std : : numeric_limits < FMVVMVCompiledBinding : : IndexType > : : max ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " TooManyPropertiesBound " , " There are too many properties bound to struct '{0}' " ) , StructCompiledFields . Key - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
CompiledFields . NumberOfProperties = static_cast < int16 > ( PropertyNames . Num ( ) ) ;
if ( FunctionNames . Num ( ) > std : : numeric_limits < FMVVMVCompiledBinding : : IndexType > : : max ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " TooManyFunctionsBound " , " There are too many functions bound to struct '{0}' " ) , StructCompiledFields . Key - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
CompiledFields . NumberOfFunctions = static_cast < int16 > ( FunctionNames . Num ( ) ) ;
if ( FieldIdNames . Num ( ) > std : : numeric_limits < FMVVMVCompiledBinding : : IndexType > : : max ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( FText : : Format ( LOCTEXT ( " TooManyFieldIdsBound " , " There are too many field IDs bound to struct '{0}' " ) , StructCompiledFields . Key - > GetDisplayNameText ( ) ) ) ;
2022-06-27 16:24:02 -04:00
}
CompiledFields . NumberOfFieldIds = static_cast < int16 > ( FieldIdNames . Num ( ) ) ;
int32 LibraryStartIndex = Result . Library . CompiledFieldNames . Num ( ) ;
if ( LibraryStartIndex > std : : numeric_limits < FMVVMVCompiledBinding : : IndexType > : : max ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " TooManyPropertiesAndFunctionsBound " , " There are too many properties and functions bound in the library. " ) ) ;
2022-06-27 16:24:02 -04:00
}
CompiledFields . LibraryStartIndex = static_cast < int16 > ( LibraryStartIndex ) ;
Result . Library . CompiledFieldNames . Append ( PropertyNames ) ;
PropertyNames . Reset ( ) ;
Result . Library . CompiledFieldNames . Append ( FunctionNames ) ;
FunctionNames . Reset ( ) ;
Result . Library . CompiledFieldNames . Append ( FieldIdNames ) ;
FieldIdNames . Reset ( ) ;
if ( Result . Library . CompiledFieldNames . Num ( ) > std : : numeric_limits < FMVVMVCompiledBinding : : IndexType > : : max ( ) )
{
2022-10-06 20:08:12 -04:00
return MakeError ( LOCTEXT ( " TooManyPropertiesBoundInLibrary " , " There are too many properties bound in the library. " ) ) ;
2022-06-27 16:24:02 -04:00
}
Result . Library . CompiledFields . Add ( CompiledFields ) ;
check ( Result . Library . LoadedProperties . Num ( ) + Result . Library . LoadedFunctions . Num ( ) + Result . Library . LoadedFieldIds . Num ( ) = = Result . Library . CompiledFieldNames . Num ( ) ) ;
check ( Result . Library . LoadedProperties . Num ( ) = = TotalNumberOfProperties ) ;
check ( Result . Library . LoadedFunctions . Num ( ) = = TotalNumberOfFunctions ) ;
check ( Result . Library . LoadedFieldIds . Num ( ) = = TotalNumberOfFieldIds ) ;
}
// Create FMVVMCompiledBindingLibrary::FieldPaths
for ( Private : : FRawFieldPath & FieldPath : Impl - > FieldPaths )
{
FieldPath . CompiledFieldPath . CompiledBindingLibraryId = Result . Library . CompiledBindingLibraryId ;
FieldPath . CompiledFieldPath . StartIndex = INDEX_NONE ;
FieldPath . CompiledFieldPath . Num = FieldPath . RawFieldIndexes . Num ( ) ;
if ( FieldPath . RawFieldIndexes . Num ( ) )
{
FieldPath . CompiledFieldPath . StartIndex = Result . Library . FieldPaths . Num ( ) ;
for ( const int32 RawFieldIndex : FieldPath . RawFieldIndexes )
{
const Private : : FRawField & RawField = Impl - > Fields [ RawFieldIndex ] ;
check ( ! RawField . Field . IsEmpty ( ) ) ;
FMVVMCompiledLoadedPropertyOrFunctionIndex FieldIndex ;
FieldIndex . Index = RawField . LoadedPropertyOrFunctionIndex ;
FieldIndex . bIsObjectProperty = RawField . bPropertyIsObjectProperty ;
FieldIndex . bIsScriptStructProperty = RawField . bPropertyIsStructProperty ;
FieldIndex . bIsProperty = RawField . Field . IsProperty ( ) ;
Result . Library . FieldPaths . Add ( FieldIndex ) ;
if ( FieldIndex . bIsProperty )
{
check ( Result . Library . LoadedProperties . IsValidIndex ( FieldIndex . Index ) ) ;
}
else
{
check ( Result . Library . LoadedFunctions . IsValidIndex ( FieldIndex . Index ) ) ;
}
}
}
Result . FieldPaths . Add ( FieldPath . PathHandle , FieldPath . CompiledFieldPath ) ;
}
// Create FieldId
for ( Private : : FRawFieldId & FieldId : Impl - > FieldIds )
{
FieldId . CompiledFieldId . CompiledBindingLibraryId = Result . Library . CompiledBindingLibraryId ;
FieldId . CompiledFieldId . FieldIdIndex = FieldId . LoadedFieldIdIndex ;
Result . FieldIds . Add ( FieldId . IdHandle , FieldId . CompiledFieldId ) ;
}
auto GetCompiledFieldPath = [ this ] ( const FFieldPathHandle Handle )
{
const Private : : FRawFieldPath * FoundBinding = Impl - > FieldPaths . FindByPredicate ( [ Handle ] ( const Private : : FRawFieldPath & Other )
{
return Other . PathHandle = = Handle ;
} ) ;
if ( FoundBinding )
{
return FoundBinding - > CompiledFieldPath ;
}
return FMVVMVCompiledFieldPath ( ) ;
} ;
// Create the requested FMVVMVCompiledBinding
for ( Private : : FRawBinding & Binding : Impl - > Bindings )
{
Binding . CompiledBinding . CompiledBindingLibraryId = Result . Library . CompiledBindingLibraryId ;
check ( Binding . CompiledBinding . CompiledBindingLibraryId . IsValid ( ) ) ;
2023-03-22 13:07:37 -04:00
Binding . CompiledBinding . SourceFieldPath = GetCompiledFieldPath ( Binding . SourcePathHandle ) ;
check ( Binding . bIsConversionFunctionComplex | | Binding . CompiledBinding . SourceFieldPath . IsValid ( ) ) ;
2022-06-27 16:24:02 -04:00
Binding . CompiledBinding . DestinationFieldPath = GetCompiledFieldPath ( Binding . DestinationPathHandle ) ;
check ( Binding . CompiledBinding . DestinationFieldPath . IsValid ( ) ) ;
Binding . CompiledBinding . ConversionFunctionFieldPath = GetCompiledFieldPath ( Binding . ConversionFunctionPathHandle ) ;
2023-03-22 13:07:37 -04:00
Binding . CompiledBinding . Flags = 0 ;
Binding . CompiledBinding . Flags | = ( Binding . ConversionFunctionPathHandle . IsValid ( ) ) ? ( uint8 ) FMVVMVCompiledBinding : : EFlags : : HasConversionFunction : 0 ;
Binding . CompiledBinding . Flags | = ( Binding . bIsConversionFunctionComplex ) ? ( uint8 ) FMVVMVCompiledBinding : : EFlags : : IsConversionFunctionComplex : 0 ;
2023-05-26 11:58:47 -04:00
Binding . CompiledBinding . Flags | = Binding . BindingCount > 1 ? ( uint8 ) FMVVMVCompiledBinding : : EFlags : : IsShared : 0 ;
2023-03-22 13:07:37 -04:00
2022-06-27 16:24:02 -04:00
Result . Bindings . Add ( Binding . BindingHandle , Binding . CompiledBinding ) ;
}
Result . Library . LoadedProperties . Reset ( ) ;
Result . Library . LoadedFunctions . Reset ( ) ;
Result . Library . LoadedFieldIds . Reset ( ) ;
Impl - > bCompiled = true ;
return MakeValue ( MoveTemp ( Result ) ) ;
}
} //namespace
2022-10-06 20:08:12 -04:00
# undef LOCTEXT_NAMESPACE