2022-02-21 02:04:58 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2021-11-24 04:26:12 -05:00
2022-09-01 09:06:53 -04:00
# include "Blueprint/StateTreeNodeBlueprintBase.h"
2021-11-24 04:26:12 -05:00
# include "AIController.h"
# include "StateTreeExecutionContext.h"
2022-09-01 09:06:53 -04:00
# include "VisualLogger/VisualLogger.h"
2024-02-14 09:04:52 -05:00
# include "StateTreePropertyRef.h"
# include "StateTreePropertyRefHelpers.h"
2021-11-24 04:26:12 -05:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(StateTreeNodeBlueprintBase)
2024-04-19 05:44:13 -04:00
# define LOCTEXT_NAMESPACE "StateTree"
# if WITH_EDITOR
FGuid UStateTreeNodeBlueprintBase : : CachedNodeID ;
const IStateTreeBindingLookup * UStateTreeNodeBlueprintBase : : CachedBindingLookup = nullptr ;
# endif
2022-09-01 09:06:53 -04:00
UWorld * UStateTreeNodeBlueprintBase : : GetWorld ( ) const
2021-11-24 04:26:12 -05:00
{
2022-12-02 05:18:07 -05:00
// The items are duplicated as the State Tree execution context as outer, so this should be essentially the same as GetWorld() on StateTree context.
2021-11-24 04:26:12 -05:00
// The CDO is used by the BP editor to check for certain functionality, make it return nullptr so that the GetWorld() passes as overridden.
if ( ! HasAnyFlags ( RF_ClassDefaultObject ) )
{
2022-12-05 09:16:37 -05:00
if ( CachedOwner ! = nullptr )
2022-12-02 05:18:07 -05:00
{
2022-12-05 09:16:37 -05:00
return CachedOwner - > GetWorld ( ) ;
2022-12-02 05:18:07 -05:00
}
2021-11-24 04:26:12 -05:00
if ( UObject * Outer = GetOuter ( ) )
{
return Outer - > GetWorld ( ) ;
}
}
return nullptr ;
}
2022-09-01 09:06:53 -04:00
AActor * UStateTreeNodeBlueprintBase : : GetOwnerActor ( const FStateTreeExecutionContext & Context ) const
2021-11-24 04:26:12 -05:00
{
if ( const AAIController * Controller = Cast < AAIController > ( Context . GetOwner ( ) ) )
{
return Controller - > GetPawn ( ) ;
}
return Cast < AActor > ( Context . GetOwner ( ) ) ;
}
2023-01-23 12:48:04 -05:00
void UStateTreeNodeBlueprintBase : : SetCachedInstanceDataFromContext ( const FStateTreeExecutionContext & Context ) const
2022-09-01 09:06:53 -04:00
{
2023-01-23 12:48:04 -05:00
if ( FStateTreeInstanceData * InstanceData = Context . GetMutableInstanceData ( ) )
{
2024-02-14 09:04:52 -05:00
WeakInstanceStorage = InstanceData - > GetWeakMutableStorage ( ) ;
2023-01-23 12:48:04 -05:00
}
CachedState = Context . GetCurrentlyProcessedState ( ) ;
2022-12-05 09:16:37 -05:00
CachedOwner = Context . GetOwner ( ) ;
2024-02-14 09:04:52 -05:00
const FStateTreeExecutionFrame * CurrentlyProcessedFrame = Context . GetCurrentlyProcessedFrame ( ) ;
check ( CurrentlyProcessedFrame ) ;
CachedFrameStateTree = CurrentlyProcessedFrame - > StateTree ;
CachedFrameRootState = CurrentlyProcessedFrame - > RootState ;
2022-12-05 09:16:37 -05:00
}
2023-01-23 12:48:04 -05:00
void UStateTreeNodeBlueprintBase : : ClearCachedInstanceData ( ) const
2022-12-05 09:16:37 -05:00
{
2024-02-14 09:04:52 -05:00
WeakInstanceStorage = nullptr ;
2023-01-23 12:48:04 -05:00
CachedState = FStateTreeStateHandle : : Invalid ;
2022-12-05 09:16:37 -05:00
CachedOwner = nullptr ;
2024-02-14 09:04:52 -05:00
CachedFrameStateTree = nullptr ;
CachedFrameRootState = FStateTreeStateHandle : : Invalid ;
}
void * UStateTreeNodeBlueprintBase : : GetMutablePtrToProperty ( const FStateTreeBlueprintPropertyRef & PropertyRef , FProperty * & OutSourceProperty ) const
{
TSharedPtr < FStateTreeInstanceStorage > InstanceStorage = WeakInstanceStorage . Pin ( ) ;
if ( InstanceStorage = = nullptr )
{
UE_VLOG_UELOG ( this , LogStateTree , Error , TEXT ( " Trying to GetMutablePtrToProperty while node is not active. " ) ) ;
return nullptr ;
}
check ( CachedFrameStateTree & & CachedFrameRootState . IsValid ( ) ) ;
TConstArrayView < FStateTreeExecutionFrame > ActiveFrames = InstanceStorage - > GetExecutionState ( ) . ActiveFrames ;
const FStateTreeExecutionFrame * CurrentParentFrame = nullptr ;
2024-02-29 03:19:31 -05:00
const FStateTreeExecutionFrame * CurrentFrame = FStateTreeExecutionContext : : FindFrame ( CachedFrameStateTree , CachedFrameRootState , ActiveFrames , CurrentParentFrame ) ;
check ( CurrentFrame ) ;
2024-02-14 09:04:52 -05:00
const FProperty * SourceProperty = nullptr ;
2024-02-29 03:19:31 -05:00
void * PropertyAddress = UE : : StateTree : : PropertyRefHelpers : : GetMutablePtrToProperty < void > ( PropertyRef , * InstanceStorage , * CurrentFrame , CurrentParentFrame , & SourceProperty ) ;
2024-02-14 09:04:52 -05:00
if ( PropertyAddress & & UE : : StateTree : : PropertyRefHelpers : : IsBlueprintPropertyRefCompatibleWithProperty ( * SourceProperty , & PropertyRef ) )
{
OutSourceProperty = const_cast < FProperty * > ( SourceProperty ) ;
return PropertyAddress ;
}
OutSourceProperty = nullptr ;
return nullptr ;
2022-12-05 09:16:37 -05:00
}
void UStateTreeNodeBlueprintBase : : SendEvent ( const FStateTreeEvent & Event )
{
2024-02-14 09:04:52 -05:00
TSharedPtr < FStateTreeInstanceStorage > InstanceStorage = WeakInstanceStorage . Pin ( ) ;
2023-01-23 12:48:04 -05:00
if ( InstanceStorage = = nullptr | | CachedOwner = = nullptr )
2022-12-05 09:16:37 -05:00
{
UE_VLOG_UELOG ( this , LogStateTree , Error , TEXT ( " Trying to call SendEvent() while node is not active. Use SendEvent() on UStateTreeComponent instead for sending signals externally. " ) ) ;
return ;
}
2023-01-23 12:48:04 -05:00
InstanceStorage - > GetMutableEventQueue ( ) . SendEvent ( CachedOwner , Event . Tag , Event . Payload , Event . Origin ) ;
2022-09-01 09:06:53 -04:00
}
2022-09-28 01:06:15 -04:00
2023-01-23 12:48:04 -05:00
void UStateTreeNodeBlueprintBase : : RequestTransition ( const FStateTreeStateLink & TargetState , const EStateTreeTransitionPriority Priority )
{
2024-02-14 09:04:52 -05:00
TSharedPtr < FStateTreeInstanceStorage > InstanceStorage = WeakInstanceStorage . Pin ( ) ;
2023-01-23 12:48:04 -05:00
if ( InstanceStorage = = nullptr | | CachedOwner = = nullptr )
{
UE_VLOG_UELOG ( this , LogStateTree , Error , TEXT ( " Trying to call SendEvent() while node is not active. Use SendEvent() on UStateTreeComponent instead for sending signals externally. " ) ) ;
return ;
}
FStateTreeTransitionRequest Request ;
Request . SourceState = CachedState ;
Request . TargetState = TargetState . StateHandle ;
Request . Priority = Priority ;
InstanceStorage - > AddTransitionRequest ( CachedOwner , Request ) ;
}
2024-02-14 09:04:52 -05:00
bool UStateTreeNodeBlueprintBase : : IsPropertyRefValid ( const FStateTreeBlueprintPropertyRef & PropertyRef ) const
{
FProperty * SourceProperty = nullptr ;
return GetMutablePtrToProperty ( PropertyRef , SourceProperty ) ! = nullptr ;
}
DEFINE_FUNCTION ( UStateTreeNodeBlueprintBase : : execGetPropertyReference )
{
P_GET_STRUCT_REF ( FStateTreeBlueprintPropertyRef , PropertyRef ) ;
Stack . StepCompiledIn < FProperty > ( nullptr ) ;
P_FINISH ;
FProperty * SourceProperty = nullptr ;
if ( void * PropertyAddress = P_THIS - > GetMutablePtrToProperty ( PropertyRef , SourceProperty ) )
{
Stack . MostRecentPropertyAddress = reinterpret_cast < uint8 * > ( PropertyAddress ) ;
Stack . MostRecentProperty = const_cast < FProperty * > ( SourceProperty ) ;
if ( RESULT_PARAM )
{
Stack . MostRecentProperty - > CopyCompleteValueToScriptVM ( RESULT_PARAM , Stack . MostRecentPropertyAddress ) ;
}
}
else
{
Stack . MostRecentPropertyAddress = nullptr ;
Stack . MostRecentProperty = nullptr ;
}
}
2024-04-19 05:44:13 -04:00
# if WITH_EDITOR
FText UStateTreeNodeBlueprintBase : : GetDescription ( const FGuid & ID , FStateTreeDataView InstanceDataView , const IStateTreeBindingLookup & BindingLookup , EStateTreeNodeFormatting Formatting ) const
{
FText Result ;
const FGuid OldCachedNodeID = CachedNodeID ;
const IStateTreeBindingLookup * OldCachedBindingLookup = CachedBindingLookup ;
CachedNodeID = ID ;
CachedBindingLookup = & BindingLookup ;
Result = Description ;
if ( Result . IsEmpty ( ) )
{
Result = ReceiveGetDescription ( Formatting ) ;
}
if ( Result . IsEmpty ( ) )
{
Result = GetClass ( ) - > GetDisplayNameText ( ) ;
}
CachedNodeID = OldCachedNodeID ;
CachedBindingLookup = OldCachedBindingLookup ;
return Result ;
}
# endif
FText UStateTreeNodeBlueprintBase : : GetPropertyDescriptionByPropertyName ( FName PropertyName ) const
{
FText Result ;
# if WITH_EDITOR
// Try property binding first
if ( CachedBindingLookup )
{
const FStateTreePropertyPath Path ( CachedNodeID , PropertyName ) ;
Result = CachedBindingLookup - > GetBindingSourceDisplayName ( Path ) ;
}
// No binding, get the value.
if ( Result . IsEmpty ( ) )
{
if ( const FProperty * Property = GetClass ( ) - > FindPropertyByName ( PropertyName ) )
{
FString Value ;
Property - > ExportText_InContainer ( 0 , Value , this , this , nullptr , PPF_PropertyWindow | PPF_BlueprintDebugView ) ;
Result = FText : : FromString ( Value ) ;
}
}
# endif
return Result ;
}
# undef LOCTEXT_NAMESPACE