2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StateTree.h"
2022-04-06 10:04:05 -04:00
# include "StateTreeLinker.h"
# include "StateTreeNodeBase.h"
2021-09-28 13:33:17 -04:00
2022-02-24 08:19:23 -05:00
bool UStateTree : : IsReadyToRun ( ) const
2021-09-28 13:33:17 -04:00
{
2022-02-24 08:19:23 -05:00
// Valid tree must have at least one state and valid instance data.
return States . Num ( ) > 0 & & InstanceDataDefaultValue . IsValid ( ) ;
2021-09-28 13:33:17 -04:00
}
# if WITH_EDITOR
2022-04-05 09:44:28 -04:00
void UStateTree : : ResetCompiled ( )
2021-09-28 13:33:17 -04:00
{
States . Reset ( ) ;
Transitions . Reset ( ) ;
2022-04-12 15:55:39 -04:00
Schema = nullptr ;
Parameters . Reset ( ) ;
2022-02-24 08:19:23 -05:00
Nodes . Reset ( ) ;
2021-11-12 05:48:11 -05:00
Instances . Reset ( ) ;
2021-11-24 04:26:12 -05:00
InstanceObjects . Reset ( ) ;
2021-11-12 05:48:11 -05:00
ExternalDataDescs . Reset ( ) ;
2022-05-05 15:58:09 -04:00
NamedExternalDataDescs . Reset ( ) ;
2021-09-28 13:33:17 -04:00
PropertyBindings . Reset ( ) ;
2021-11-03 07:01:08 -04:00
2021-11-12 05:48:11 -05:00
NumDataViews = 0 ;
ExternalDataBaseIndex = 0 ;
2022-02-24 08:19:23 -05:00
InstanceDataDefaultValue . Reset ( ) ;
2021-09-28 13:33:17 -04:00
}
void UStateTree : : GetAssetRegistryTags ( TArray < FAssetRegistryTag > & OutTags ) const
{
static const FName SchemaTag ( TEXT ( " Schema " ) ) ;
const FString SchemaClassName = Schema ? Schema - > GetClass ( ) - > GetName ( ) : TEXT ( " " ) ;
OutTags . Add ( FAssetRegistryTag ( SchemaTag , SchemaClassName , FAssetRegistryTag : : TT_Alphabetical ) ) ;
Super : : GetAssetRegistryTags ( OutTags ) ;
}
# endif // WITH_EDITOR
void UStateTree : : PostLoad ( )
{
Super : : PostLoad ( ) ;
2022-03-28 04:48:50 -04:00
2022-04-06 10:04:05 -04:00
if ( ! Link ( ) )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s failed to link. Asset will not be usable at runtime. " ) , * GetName ( ) ) ;
}
2021-09-28 13:33:17 -04:00
}
2022-03-23 08:06:00 -04:00
void UStateTree : : Serialize ( FStructuredArchiveRecord Record )
{
Super : : Serialize ( Record ) ;
// We need to link and rebind property bindings each time a BP is compiled,
// because property bindings may get invalid, and instance data potentially needs refreshed.
if ( Record . GetUnderlyingArchive ( ) . IsModifyingWeakAndStrongReferences ( ) )
{
2022-04-06 10:04:05 -04:00
if ( ! Link ( ) )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s failed to link. Asset will not be usable at runtime. " ) , * GetName ( ) ) ;
}
2022-03-23 08:06:00 -04:00
}
}
2022-04-06 10:04:05 -04:00
bool UStateTree : : Link ( )
2021-10-27 06:10:12 -04:00
{
2022-04-06 10:04:05 -04:00
// Initialize the instance data default value.
// This data will be used to allocate runtime instance on all StateTree users.
InstanceDataDefaultValue . Reset ( ) ;
ExternalDataDescs . Reset ( ) ;
NumDataViews = 0 ;
ExternalDataBaseIndex = 0 ;
2022-04-28 03:54:07 -04:00
// Update property bag structs before resolving binding.
TArrayView < FStateTreeBindableStructDesc > SourceStructs = PropertyBindings . GetSourceStructs ( ) ;
TArrayView < FStateTreePropCopyBatch > CopyBatches = PropertyBindings . GetCopyBatches ( ) ;
2022-05-05 12:02:47 -04:00
if ( DefaultParametersDataViewIndex ! = INDEX_NONE )
{
SourceStructs [ DefaultParametersDataViewIndex ] . Struct = Parameters . GetPropertyBagStruct ( ) ;
}
2022-04-28 03:54:07 -04:00
for ( const FCompactStateTreeState & State : States )
{
if ( State . Type = = EStateTreeStateType : : Subtree )
{
2022-05-05 08:44:57 -04:00
if ( State . ParameterInstanceIndex = = MAX_uint16
| | State . ParameterDataViewIndex = = MAX_uint16 )
2022-04-28 03:54:07 -04:00
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s: Data for state '%s' is malformed. Please recompile the StateTree asset. " ) , * GetName ( ) , * State . Name . ToString ( ) ) ;
return false ;
}
2021-10-27 06:10:12 -04:00
2022-04-28 03:54:07 -04:00
// Subtree is a bind source, update bag struct.
const FCompactStateTreeParameters & Params = Instances [ State . ParameterInstanceIndex ] . GetMutable < FCompactStateTreeParameters > ( ) ;
FStateTreeBindableStructDesc & Desc = SourceStructs [ State . ParameterDataViewIndex ] ;
Desc . Struct = Params . Parameters . GetPropertyBagStruct ( ) ;
}
else if ( State . Type = = EStateTreeStateType : : Linked & & State . LinkedState . IsValid ( ) )
{
const FCompactStateTreeState & LinkedState = States [ State . LinkedState . Index ] ;
2022-05-05 08:44:57 -04:00
if ( State . ParameterInstanceIndex = = MAX_uint16
| | LinkedState . ParameterInstanceIndex = = MAX_uint16 )
2022-04-28 03:54:07 -04:00
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s: Data for state '%s' is malformed. Please recompile the StateTree asset. " ) , * GetName ( ) , * State . Name . ToString ( ) ) ;
return false ;
}
const FCompactStateTreeParameters & Params = Instances [ State . ParameterInstanceIndex ] . GetMutable < FCompactStateTreeParameters > ( ) ;
// Check that the bag in linked state matches.
const FCompactStateTreeParameters & LinkedStateParams = Instances [ LinkedState . ParameterInstanceIndex ] . GetMutable < FCompactStateTreeParameters > ( ) ;
if ( LinkedStateParams . Parameters . GetPropertyBagStruct ( ) ! = Params . Parameters . GetPropertyBagStruct ( ) )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s: The parameters on state '%s' does not match the linked state parameters in state '%s'. Please recompile the StateTree asset. " ) , * GetName ( ) , * State . Name . ToString ( ) , * LinkedState . Name . ToString ( ) ) ;
return false ;
}
FStateTreePropCopyBatch & Batch = CopyBatches [ Params . BindingsBatch . Index ] ;
Batch . TargetStruct . Struct = Params . Parameters . GetPropertyBagStruct ( ) ;
}
}
2022-04-06 10:04:05 -04:00
// Resolves property paths used by bindings a store property pointers
if ( ! PropertyBindings . ResolvePaths ( ) )
{
return false ;
}
// Resolves nodes references to other StateTree data
FStateTreeLinker Linker ( Schema ) ;
Linker . SetExternalDataBaseIndex ( PropertyBindings . GetSourceStructNum ( ) ) ;
2021-11-03 07:01:08 -04:00
2022-02-24 08:19:23 -05:00
for ( FInstancedStruct & Node : Nodes )
2021-10-27 06:10:12 -04:00
{
2022-02-24 08:19:23 -05:00
if ( FStateTreeNodeBase * NodePtr = Node . GetMutablePtr < FStateTreeNodeBase > ( ) )
2021-10-27 06:10:12 -04:00
{
2022-02-24 08:19:23 -05:00
Linker . SetCurrentInstanceDataType ( NodePtr - > GetInstanceDataType ( ) , NodePtr - > DataViewIndex ) ;
2022-04-06 10:04:05 -04:00
const bool bLinkSucceeded = NodePtr - > Link ( Linker ) ;
if ( ! bLinkSucceeded | | Linker . GetStatus ( ) = = EStateTreeLinkerStatus : : Failed )
{
UE_LOG ( LogStateTree , Error , TEXT ( " %s: node '%s' failed to resolve its references. " ) , * GetName ( ) , * NodePtr - > StaticStruct ( ) - > GetName ( ) ) ;
return false ;
}
2021-11-12 05:48:11 -05:00
}
2021-10-27 06:10:12 -04:00
}
2022-04-06 10:04:05 -04:00
// Link succeeded, setup tree to be ready to run
ExternalDataBaseIndex = PropertyBindings . GetSourceStructNum ( ) ;
2021-11-12 05:48:11 -05:00
ExternalDataDescs = Linker . GetExternalDataDescs ( ) ;
NumDataViews = ExternalDataBaseIndex + ExternalDataDescs . Num ( ) ;
2022-02-24 08:19:23 -05:00
if ( Instances . Num ( ) > 0 )
2022-03-28 04:48:50 -04:00
{
2022-03-23 08:06:00 -04:00
InstanceDataDefaultValue . Initialize ( * this , Instances , InstanceObjects ) ;
2021-09-28 13:33:17 -04:00
}
2022-04-06 10:04:05 -04:00
return true ;
2021-09-28 13:33:17 -04:00
}