2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StateTreeTest.h"
# include "AITestsCommon.h"
# include "StateTreeEditorData.h"
# include "StateTreeState.h"
2022-04-05 09:44:28 -04:00
# include "StateTreeCompiler.h"
2021-09-28 13:33:17 -04:00
# include "Conditions/StateTreeCondition_Common.h"
# include "StateTree.h"
# include "StateTreeTestTypes.h"
# include "StateTreeExecutionContext.h"
2021-11-17 18:06:10 -05:00
# include "Engine/World.h"
2021-09-28 13:33:17 -04:00
# define LOCTEXT_NAMESPACE "AITestSuite_StateTreeTest"
PRAGMA_DISABLE_OPTIMIZATION
namespace UE : : StateTree : : Tests
{
2021-11-17 18:06:10 -05:00
UStateTree & NewStateTree ( UObject * Outer = GetTransientPackage ( ) )
2021-09-28 13:33:17 -04:00
{
2021-11-17 18:06:10 -05:00
UStateTree * StateTree = NewObject < UStateTree > ( Outer ) ;
2021-09-28 13:33:17 -04:00
check ( StateTree ) ;
UStateTreeEditorData * EditorData = NewObject < UStateTreeEditorData > ( StateTree ) ;
check ( EditorData ) ;
StateTree - > EditorData = EditorData ;
2022-04-12 15:55:39 -04:00
EditorData - > Schema = NewObject < UStateTreeTestSchema > ( ) ;
2021-09-28 13:33:17 -04:00
return * StateTree ;
}
2022-04-05 03:20:57 -04:00
2021-09-28 13:33:17 -04:00
}
struct FStateTreeTest_MakeAndBakeStateTree : FAITestBase
{
virtual bool InstantTest ( ) override
{
2021-11-17 18:06:10 -05:00
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
2021-09-28 13:33:17 -04:00
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & StateA = Root . AddChildState ( FName ( TEXT ( " A " ) ) ) ;
UStateTreeState & StateB = Root . AddChildState ( FName ( TEXT ( " B " ) ) ) ;
// Root
2022-05-16 05:13:27 -04:00
auto & EvalA = EditorData . AddEvaluator < FTestEval_A > ( ) ;
2021-10-21 04:08:20 -04:00
2021-09-28 13:33:17 -04:00
// State A
2021-11-12 05:48:11 -05:00
auto & TaskB1 = StateA . AddTask < FTestTask_B > ( ) ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( EvalA . ID , TEXT ( " IntA " ) ) , FStateTreeEditorPropertyPath ( TaskB1 . ID , TEXT ( " IntB " ) ) ) ;
2021-09-28 13:33:17 -04:00
2021-11-12 05:48:11 -05:00
auto & IntCond = StateA . AddEnterCondition < FStateTreeCondition_CompareInt > ( EGenericAICheck : : Less ) ;
IntCond . GetInstance ( ) . Right = 2 ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( EvalA . ID , TEXT ( " IntA " ) ) , FStateTreeEditorPropertyPath ( IntCond . ID , TEXT ( " Left " ) ) ) ;
2021-09-28 13:33:17 -04:00
2021-10-21 04:08:20 -04:00
StateA . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & StateB ) ;
2021-09-28 13:33:17 -04:00
// State B
2021-11-12 05:48:11 -05:00
auto & TaskB2 = StateB . AddTask < FTestTask_B > ( ) ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( EvalA . ID , TEXT ( " bBoolA " ) ) , FStateTreeEditorPropertyPath ( TaskB2 . ID , TEXT ( " bBoolB " ) ) ) ;
2021-09-28 13:33:17 -04:00
2021-10-21 04:08:20 -04:00
FStateTreeTransition & Trans = StateB . AddTransition ( EStateTreeTransitionEvent : : OnCondition , EStateTreeTransitionType : : GotoState , & Root ) ;
2021-11-12 05:48:11 -05:00
auto & TransFloatCond = Trans . AddCondition < FStateTreeCondition_CompareFloat > ( EGenericAICheck : : Less ) ;
TransFloatCond . GetInstance ( ) . Right = 13.0f ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( EvalA . ID , TEXT ( " FloatA " ) ) , FStateTreeEditorPropertyPath ( TransFloatCond . ID , TEXT ( " Left " ) ) ) ;
2021-09-28 13:33:17 -04:00
2021-10-21 04:08:20 -04:00
StateB . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : Succeeded ) ;
2021-09-28 13:33:17 -04:00
2021-10-29 04:33:21 -04:00
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
const bool bResult = Compiler . Compile ( StateTree ) ;
2021-09-28 13:33:17 -04:00
2022-04-05 09:44:28 -04:00
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2021-09-28 13:33:17 -04:00
return true ;
}
} ;
2021-12-09 05:26:00 -05:00
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_MakeAndBakeStateTree , " System.StateTree.MakeAndBakeStateTree " ) ;
2021-09-28 13:33:17 -04:00
2021-11-12 05:48:11 -05:00
#if 0
// @todo: fix this test
2021-09-28 13:33:17 -04:00
struct FStateTreeTest_WanderLoop : FAITestBase
{
virtual bool InstantTest ( ) override
{
2021-11-17 18:06:10 -05:00
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
2021-09-28 13:33:17 -04:00
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & Wander = Root . AddChildState ( FName ( TEXT ( " Wander " ) ) ) ;
UStateTreeState & UseSmartObjectOnLane = Wander . AddChildState ( FName ( TEXT ( " UseSmartObjectOnLane " ) ) ) ;
UStateTreeState & WalkAlongLane = Wander . AddChildState ( FName ( TEXT ( " WalkAlongLane " ) ) ) ;
UStateTreeState & StandOnLane = Wander . AddChildState ( FName ( TEXT ( " StandOnLane " ) ) ) ;
UStateTreeState & WalkToSO = UseSmartObjectOnLane . AddChildState ( FName ( TEXT ( " WalkToSO " ) ) ) ;
UStateTreeState & UseSO = UseSmartObjectOnLane . AddChildState ( FName ( TEXT ( " UseSO " ) ) ) ;
// - Root
// \- Wander
2021-11-12 05:48:11 -05:00
auto & WanderEval = Wander . AddEvaluator < FTestEval_Wander > ( FName ( TEXT ( " WanderEval " ) ) ) ;
auto & SmartObjectEval = Wander . AddEvaluator < FTestEval_SmartObjectSensor > ( ) ;
2021-09-28 13:33:17 -04:00
// |- UseSmartObjectOnLane
2021-11-12 05:48:11 -05:00
auto & ReserveSOTask = UseSmartObjectOnLane . AddTask < FTestTask_ReserveSmartObject > ( FName ( TEXT ( " ReserveSOTask " ) ) ) ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( SmartObjectEval . ID , TEXT ( " PotentialSmartObjects " ) ) , FStateTreeEditorPropertyPath ( ReserveSOTask . ID , TEXT ( " PotentialSmartObjects " ) ) ) ;
auto & ReserveHasSmartObjects = UseSmartObjectOnLane . AddEnterCondition < FStateTreeCondition_CompareBool > ( ) ;
ReserveHasSmartObjects . GetInstance ( ) . bRight = true ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( SmartObjectEval . ID , TEXT ( " bHasSmartObjects " ) ) , FStateTreeEditorPropertyPath ( ReserveHasSmartObjects . ID , TEXT ( " bLeft " ) ) ) ;
2021-09-28 13:33:17 -04:00
UseSmartObjectOnLane . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & Wander ) ; // This catches child states too
// | |- WalkToSO
2021-11-12 05:48:11 -05:00
auto & MoveToSOTask = WalkToSO . AddTask < FTestTask_MoveTo > ( FName ( TEXT ( " MoveToSOTask " ) ) ) ;
MoveToSOTask . GetItem ( ) . TicksToCompletion = 2 ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( ReserveSOTask . ID , TEXT ( " ReservedSmartObjectLocation " ) ) , FStateTreeEditorPropertyPath ( MoveToSOTask . ID , TEXT ( " MoveLocation " ) ) ) ;
2021-09-28 13:33:17 -04:00
WalkToSO . AddTransition ( EStateTreeTransitionEvent : : OnSucceeded , EStateTreeTransitionType : : NextState ) ;
// | \- UseSO
2021-11-12 05:48:11 -05:00
auto & UseSOTask = UseSO . AddTask < FTestTask_UseSmartObject > ( FName ( TEXT ( " UseSOTask " ) ) ) ;
UseSOTask . GetItem ( ) . TicksToCompletion = 2 ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( ReserveSOTask . ID , TEXT ( " ReservedSmartObject " ) ) , FStateTreeEditorPropertyPath ( UseSOTask . ID , TEXT ( " SmartObject " ) ) ) ;
2021-09-28 13:33:17 -04:00
// UseSO uses UseSmartObjectOnLane completed transition.
// |- Walk Along Lane
2021-11-12 05:48:11 -05:00
auto & MoveAlongLaneTask = WalkAlongLane . AddTask < FTestTask_MoveTo > ( FName ( TEXT ( " MoveAlongLaneTask " ) ) ) ;
MoveAlongLaneTask . GetItem ( ) . TicksToCompletion = 2 ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( WanderEval . ID , TEXT ( " WanderLocation " ) ) , FStateTreeEditorPropertyPath ( MoveAlongLaneTask . ID , TEXT ( " MoveLocation " ) ) ) ;
auto & MoveHasWanderLoc = WalkAlongLane . AddEnterCondition < FStateTreeCondition_CompareBool > ( ) ;
MoveHasWanderLoc . GetInstance ( ) . bRight = true ;
EditorData . AddPropertyBinding ( FStateTreeEditorPropertyPath ( WanderEval . ID , TEXT ( " bHasWanderLocation " ) ) , FStateTreeEditorPropertyPath ( MoveHasWanderLoc . ID , TEXT ( " bLeft " ) ) ) ;
2021-09-28 13:33:17 -04:00
WalkAlongLane . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & Wander ) ;
// \- StandOnLane
2021-11-12 05:48:11 -05:00
auto & StandTask = StandOnLane . AddTask < FTestTask_Stand > ( FName ( TEXT ( " StandTask " ) ) ) ;
StandTask . GetItem ( ) . TicksToCompletion = 2 ;
2021-09-28 13:33:17 -04:00
StandOnLane . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & Wander ) ;
2021-10-29 04:33:21 -04:00
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
bool bResult = Compiler . Compile ( StateTree ) ;
2021-09-28 13:33:17 -04:00
2022-04-05 09:44:28 -04:00
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2021-09-28 13:33:17 -04:00
EStateTreeRunStatus Status = EStateTreeRunStatus : : Unset ;
FTestStateTreeExecutionContext Exec ;
const bool bInitSucceeded = Exec . Init ( StateTree , StateTree , EStateTreeStorage : : Internal ) ;
AITEST_TRUE ( " StateTree should init " , bInitSucceeded ) ;
const FString TickStr ( TEXT ( " Tick " ) ) ;
const FString EnterStateStr ( TEXT ( " EnterState " ) ) ;
const FString ExitStateStr ( TEXT ( " ExitState " ) ) ;
const FString ReserveFailedStr ( TEXT ( " ReserveFailed " ) ) ;
Exec . Start ( ) ;
// No SOs on first tick, we should stand.
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
// Stand completed, SO sensor should have found SOs, Expect Move to SO
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree MoveToSOTask should enter state, and tick " , Exec . Expect ( MoveToSOTask . GetName ( ) , EnterStateStr ) . Then ( MoveToSOTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree MoveToSOTask should tick " , Exec . Expect ( MoveToSOTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
// Use SO
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree UseSOTask should enter state, and tick " , Exec . Expect ( UseSOTask . GetName ( ) , EnterStateStr ) . Then ( UseSOTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree UseSOTask should tick " , Exec . Expect ( UseSOTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
// SO done, should select Wander>UseSmartObjectOnLane>WalkToSO.
// The next SO on the sensor is invalid, we try to reserve invalid SO, fail, then fallback to select Stand.
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree ReserveSOTask should fail enter state " , Exec . Expect ( ReserveSOTask . GetName ( ) , EnterStateStr ) . Then ( ReserveSOTask . GetName ( ) , ReserveFailedStr ) ) ;
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
// We should end up in stand again because of the failed cool down on SO sensor.
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree StandTask should tick " , Exec . Expect ( StandTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
// After stand is done we should have new SO ready to use.
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree MoveToSOTask should enter state, and tick " , Exec . Expect ( MoveToSOTask . GetName ( ) , EnterStateStr ) . Then ( MoveToSOTask . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
Exec . LogClear ( ) ;
return true ;
}
} ;
2021-12-09 05:26:00 -05:00
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_WanderLoop , " System.StateTree.WanderLoop " ) ;
2021-11-12 05:48:11 -05:00
# endif
2021-09-28 13:33:17 -04:00
struct FStateTreeTest_Sequence : FAITestBase
{
virtual bool InstantTest ( ) override
{
2021-11-17 18:06:10 -05:00
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
2021-09-28 13:33:17 -04:00
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & State1 = Root . AddChildState ( FName ( TEXT ( " State1 " ) ) ) ;
UStateTreeState & State2 = Root . AddChildState ( FName ( TEXT ( " State2 " ) ) ) ;
2021-11-12 05:48:11 -05:00
auto & Task1 = State1 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task1 " ) ) ) ;
2021-09-28 13:33:17 -04:00
State1 . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : NextState ) ;
2021-11-12 05:48:11 -05:00
auto & Task2 = State2 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task2 " ) ) ) ;
2021-09-28 13:33:17 -04:00
State2 . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : Succeeded ) ;
2021-10-29 04:33:21 -04:00
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
const bool bResult = Compiler . Compile ( StateTree ) ;
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2021-09-28 13:33:17 -04:00
EStateTreeRunStatus Status = EStateTreeRunStatus : : Unset ;
FTestStateTreeExecutionContext Exec ;
const bool bInitSucceeded = Exec . Init ( StateTree , StateTree , EStateTreeStorage : : Internal ) ;
AITEST_TRUE ( " StateTree should init " , bInitSucceeded ) ;
const FString TickStr ( TEXT ( " Tick " ) ) ;
const FString EnterStateStr ( TEXT ( " EnterState " ) ) ;
const FString ExitStateStr ( TEXT ( " ExitState " ) ) ;
2021-11-22 12:11:19 -05:00
Status = Exec . Start ( ) ;
AITEST_TRUE ( " StateTree Task1 should enter state " , Exec . Expect ( Task1 . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree Task1 should not tick " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) ) ;
Exec . LogClear ( ) ;
2021-09-28 13:33:17 -04:00
Status = Exec . Tick ( 0.1f ) ;
2021-11-22 12:11:19 -05:00
AITEST_TRUE ( " StateTree Task1 should tick, and exit state " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) . Then ( Task1 . GetName ( ) , ExitStateStr ) ) ;
AITEST_TRUE ( " StateTree Task2 should enter state " , Exec . Expect ( Task2 . GetName ( ) , EnterStateStr ) ) ;
2021-11-12 05:48:11 -05:00
AITEST_FALSE ( " StateTree Task2 should not tick " , Exec . Expect ( Task2 . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
2021-11-22 12:11:19 -05:00
AITEST_TRUE ( " StateTree Task2 should tick, and exit state " , Exec . Expect ( Task2 . GetName ( ) , TickStr ) . Then ( Task2 . GetName ( ) , ExitStateStr ) ) ;
2021-11-12 05:48:11 -05:00
AITEST_FALSE ( " StateTree Task1 should not tick " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
AITEST_TRUE ( " StateTree should be completed " , Status = = EStateTreeRunStatus : : Succeeded ) ;
2021-11-22 12:11:19 -05:00
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
AITEST_FALSE ( " StateTree Task1 should not tick " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) ) ;
AITEST_FALSE ( " StateTree Task2 should not tick " , Exec . Expect ( Task2 . GetName ( ) , TickStr ) ) ;
Exec . LogClear ( ) ;
2021-09-28 13:33:17 -04:00
return true ;
}
} ;
2021-12-09 05:26:00 -05:00
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_Sequence , " System.StateTree.Sequence " ) ;
2021-09-28 13:33:17 -04:00
struct FStateTreeTest_Select : FAITestBase
{
virtual bool InstantTest ( ) override
{
2021-11-17 18:06:10 -05:00
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
2021-09-28 13:33:17 -04:00
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & State1 = Root . AddChildState ( FName ( TEXT ( " State1 " ) ) ) ;
UStateTreeState & State1A = State1 . AddChildState ( FName ( TEXT ( " State1A " ) ) ) ;
2021-11-12 05:48:11 -05:00
auto & TaskRoot = Root . AddTask < FTestTask_Stand > ( FName ( TEXT ( " TaskRoot " ) ) ) ;
TaskRoot . GetItem ( ) . TicksToCompletion = 2 ;
2021-09-28 13:33:17 -04:00
2021-11-12 05:48:11 -05:00
auto & Task1 = State1 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task1 " ) ) ) ;
Task1 . GetItem ( ) . TicksToCompletion = 2 ;
2021-09-28 13:33:17 -04:00
2021-11-12 05:48:11 -05:00
auto & Task1A = State1A . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task1A " ) ) ) ;
Task1A . GetItem ( ) . TicksToCompletion = 2 ;
2021-09-28 13:33:17 -04:00
State1A . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & State1 ) ;
2021-10-29 04:33:21 -04:00
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
const bool bResult = Compiler . Compile ( StateTree ) ;
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2021-09-28 13:33:17 -04:00
EStateTreeRunStatus Status = EStateTreeRunStatus : : Unset ;
FTestStateTreeExecutionContext Exec ;
const bool bInitSucceeded = Exec . Init ( StateTree , StateTree , EStateTreeStorage : : Internal ) ;
AITEST_TRUE ( " StateTree should init " , bInitSucceeded ) ;
const FString TickStr ( TEXT ( " Tick " ) ) ;
const FString EnterStateStr ( TEXT ( " EnterState " ) ) ;
const FString ExitStateStr ( TEXT ( " ExitState " ) ) ;
2021-11-22 12:11:19 -05:00
// Start and enter state
Status = Exec . Start ( ) ;
AITEST_TRUE ( " StateTree TaskRoot should enter state " , Exec . Expect ( TaskRoot . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task1 should enter state " , Exec . Expect ( Task1 . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task1A should enter state " , Exec . Expect ( Task1A . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree TaskRoot should not tick " , Exec . Expect ( TaskRoot . GetName ( ) , TickStr ) ) ;
AITEST_FALSE ( " StateTree Task1 should not tick " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) ) ;
AITEST_FALSE ( " StateTree Task1A should not tick " , Exec . Expect ( Task1A . GetName ( ) , TickStr ) ) ;
2021-09-28 13:33:17 -04:00
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
Exec . LogClear ( ) ;
// Regular tick
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_TRUE ( " StateTree tasks should update in order " , Exec . Expect ( TaskRoot . GetName ( ) , TickStr ) . Then ( Task1 . GetName ( ) , TickStr ) . Then ( Task1A . GetName ( ) , TickStr ) ) ;
AITEST_FALSE ( " StateTree TaskRoot should not EnterState " , Exec . Expect ( TaskRoot . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree Task1 should not EnterState " , Exec . Expect ( Task1 . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree Task1A should not EnterState " , Exec . Expect ( Task1A . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree TaskRoot should not ExitState " , Exec . Expect ( TaskRoot . GetName ( ) , ExitStateStr ) ) ;
AITEST_FALSE ( " StateTree Task1 should not ExitState " , Exec . Expect ( Task1 . GetName ( ) , ExitStateStr ) ) ;
AITEST_FALSE ( " StateTree Task1A should not ExitState " , Exec . Expect ( Task1A . GetName ( ) , ExitStateStr ) ) ;
2021-09-28 13:33:17 -04:00
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
Exec . LogClear ( ) ;
// Partial reselect, Root should not get EnterState
Status = Exec . Tick ( 0.1f ) ;
2021-11-12 05:48:11 -05:00
AITEST_FALSE ( " StateTree TaskRoot should not enter state " , Exec . Expect ( TaskRoot . GetName ( ) , EnterStateStr ) ) ;
2021-11-22 12:11:19 -05:00
AITEST_TRUE ( " StateTree Task1 should tick, exit state, and enter state " , Exec . Expect ( Task1 . GetName ( ) , TickStr ) . Then ( Task1 . GetName ( ) , ExitStateStr ) . Then ( Task1 . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task1A should tick, exit state, and enter state " , Exec . Expect ( Task1A . GetName ( ) , TickStr ) . Then ( Task1A . GetName ( ) , ExitStateStr ) . Then ( Task1A . GetName ( ) , EnterStateStr ) ) ;
2021-09-28 13:33:17 -04:00
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
Exec . LogClear ( ) ;
return true ;
}
} ;
2021-12-09 05:26:00 -05:00
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_Select , " System.StateTree.Select " ) ;
struct FStateTreeTest_FailEnterState : FAITestBase
{
virtual bool InstantTest ( ) override
{
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & State1 = Root . AddChildState ( FName ( TEXT ( " State1 " ) ) ) ;
UStateTreeState & State1A = State1 . AddChildState ( FName ( TEXT ( " State1A " ) ) ) ;
auto & TaskRoot = Root . AddTask < FTestTask_Stand > ( FName ( TEXT ( " TaskRoot " ) ) ) ;
auto & Task1 = State1 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task1 " ) ) ) ;
auto & Task2 = State1 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task2 " ) ) ) ;
Task2 . GetItem ( ) . EnterStateResult = EStateTreeRunStatus : : Failed ;
auto & Task3 = State1 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task3 " ) ) ) ;
auto & Task1A = State1A . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task1A " ) ) ) ;
State1A . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & State1 ) ;
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
const bool bResult = Compiler . Compile ( StateTree ) ;
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2021-12-09 05:26:00 -05:00
EStateTreeRunStatus Status = EStateTreeRunStatus : : Unset ;
FTestStateTreeExecutionContext Exec ;
const bool bInitSucceeded = Exec . Init ( StateTree , StateTree , EStateTreeStorage : : Internal ) ;
AITEST_TRUE ( " StateTree should init " , bInitSucceeded ) ;
const FString TickStr ( TEXT ( " Tick " ) ) ;
const FString EnterStateStr ( TEXT ( " EnterState " ) ) ;
const FString ExitStateStr ( TEXT ( " ExitState " ) ) ;
const FString StateCompletedStr ( TEXT ( " StateCompleted " ) ) ;
// Start and enter state
Status = Exec . Start ( ) ;
AITEST_TRUE ( " StateTree TaskRoot should enter state " , Exec . Expect ( TaskRoot . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task1 should enter state " , Exec . Expect ( Task1 . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task2 should enter state " , Exec . Expect ( Task2 . GetName ( ) , EnterStateStr ) ) ;
AITEST_FALSE ( " StateTree Task3 should not enter state " , Exec . Expect ( Task3 . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Should execute StateCompleted in reverse order " , Exec . Expect ( Task2 . GetName ( ) , StateCompletedStr ) . Then ( Task1 . GetName ( ) , StateCompletedStr ) . Then ( TaskRoot . GetName ( ) , StateCompletedStr ) ) ;
AITEST_FALSE ( " StateTree Task3 should not state complete " , Exec . Expect ( Task3 . GetName ( ) , StateCompletedStr ) ) ;
AITEST_TRUE ( " StateTree exec status should be failed " , Exec . GetLastTickStatus ( ) = = EStateTreeRunStatus : : Failed ) ;
Exec . LogClear ( ) ;
// Stop and exit state
Status = Exec . Stop ( ) ;
AITEST_TRUE ( " StateTree TaskRoot should exit state " , Exec . Expect ( TaskRoot . GetName ( ) , ExitStateStr ) ) ;
AITEST_TRUE ( " StateTree Task1 should exit state " , Exec . Expect ( Task1 . GetName ( ) , ExitStateStr ) ) ;
AITEST_TRUE ( " StateTree Task2 should exit state " , Exec . Expect ( Task2 . GetName ( ) , ExitStateStr ) ) ;
AITEST_FALSE ( " StateTree Task3 should not exit state " , Exec . Expect ( Task3 . GetName ( ) , ExitStateStr ) ) ;
Exec . LogClear ( ) ;
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_FailEnterState , " System.StateTree.FailEnterState " ) ;
2021-09-28 13:33:17 -04:00
2022-04-05 03:20:57 -04:00
struct FStateTreeTest_SubTree : FAITestBase
{
virtual bool InstantTest ( ) override
{
UStateTree & StateTree = UE : : StateTree : : Tests : : NewStateTree ( & GetWorld ( ) ) ;
UStateTreeEditorData & EditorData = * Cast < UStateTreeEditorData > ( StateTree . EditorData ) ;
UStateTreeState & Root = EditorData . AddSubTree ( FName ( TEXT ( " Root " ) ) ) ;
UStateTreeState & State1 = Root . AddChildState ( FName ( TEXT ( " State1 " ) ) , EStateTreeStateType : : Linked ) ;
UStateTreeState & State2 = Root . AddChildState ( FName ( TEXT ( " State2 " ) ) ) ;
UStateTreeState & State3 = Root . AddChildState ( FName ( TEXT ( " State3 " ) ) ) ;
UStateTreeState & State3A = State3 . AddChildState ( FName ( TEXT ( " State3A " ) ) ) ;
UStateTreeState & State3B = State3 . AddChildState ( FName ( TEXT ( " State3B " ) ) ) ;
State1 . LinkedState . Set ( & State3 ) ;
auto & Task2 = State2 . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task2 " ) ) ) ;
auto & Task3A = State3A . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task3A " ) ) ) ;
State3A . AddTransition ( EStateTreeTransitionEvent : : OnCompleted , EStateTreeTransitionType : : GotoState , & State3B ) ;
auto & Task3B = State3B . AddTask < FTestTask_Stand > ( FName ( TEXT ( " Task3B " ) ) ) ;
FStateTreeCompilerLog Log ;
2022-04-05 09:44:28 -04:00
FStateTreeCompiler Compiler ( Log ) ;
const bool bResult = Compiler . Compile ( StateTree ) ;
AITEST_TRUE ( " StateTree should get compiled " , bResult ) ;
2022-04-05 03:20:57 -04:00
EStateTreeRunStatus Status = EStateTreeRunStatus : : Unset ;
FTestStateTreeExecutionContext Exec ;
const bool bInitSucceeded = Exec . Init ( StateTree , StateTree , EStateTreeStorage : : Internal ) ;
AITEST_TRUE ( " StateTree should init " , bInitSucceeded ) ;
const FString TickStr ( TEXT ( " Tick " ) ) ;
const FString EnterStateStr ( TEXT ( " EnterState " ) ) ;
const FString ExitStateStr ( TEXT ( " ExitState " ) ) ;
const FString StateCompletedStr ( TEXT ( " StateCompleted " ) ) ;
// Start and enter state
Status = Exec . Start ( ) ;
AITEST_TRUE ( " StateTree Active States should be in Root/State1/State3/State3A " , Exec . ExpectInActiveStates ( Root . Name , State1 . Name , State3 . Name , State3A . Name ) ) ;
AITEST_TRUE ( " StateTree Task2 should enter state " , ! Exec . Expect ( Task2 . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree Task3A should enter state " , Exec . Expect ( Task3A . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
Exec . LogClear ( ) ;
Status = Exec . Tick ( 0.1f ) ;
AITEST_TRUE ( " StateTree Active States should be in Root/State1/State3/State3B " , Exec . ExpectInActiveStates ( Root . Name , State1 . Name , State3 . Name , State3B . Name ) ) ;
AITEST_TRUE ( " StateTree Task3B should enter state " , Exec . Expect ( Task3B . GetName ( ) , EnterStateStr ) ) ;
AITEST_TRUE ( " StateTree should be running " , Status = = EStateTreeRunStatus : : Running ) ;
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FStateTreeTest_SubTree , " System.StateTree.SubTree " ) ;
2021-09-28 13:33:17 -04:00
PRAGMA_ENABLE_OPTIMIZATION
# undef LOCTEXT_NAMESPACE