2022-03-08 10:30:07 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2022-08-12 10:47:11 -04:00
# include "MassEntityManager.h"
2022-03-08 10:30:07 -05:00
# include "MassProcessingTypes.h"
# include "MassEntityTestTypes.h"
# include "MassEntityTypes.h"
# include "MassEntityView.h"
2024-04-17 02:32:35 -04:00
# include "MassExecutionContext.h"
2022-03-08 10:30:07 -05:00
# include "Algo/Sort.h"
# include "Algo/RandomShuffle.h"
# define LOCTEXT_NAMESPACE "MassTest"
2023-01-20 10:29:35 -05:00
UE_DISABLE_OPTIMIZATION_SHIP
2022-03-08 10:30:07 -05:00
//----------------------------------------------------------------------//
// tests
//----------------------------------------------------------------------//
namespace FMassCommandsTest
{
2022-03-23 11:58:55 -04:00
# if WITH_MASSENTITY_DEBUG
2022-03-08 10:30:07 -05:00
struct FCommands_FragmentInstanceList : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
const int32 Count = 5 ;
TArray < FMassEntityHandle > IntEntities ;
TArray < FMassEntityHandle > FloatEntities ;
2022-08-12 07:56:27 -04:00
EntityManager - > BatchCreateEntities ( IntsArchetype , Count , IntEntities ) ;
EntityManager - > BatchCreateEntities ( FloatsArchetype , Count , FloatEntities ) ;
2022-03-08 10:30:07 -05:00
for ( int i = 0 ; i < Count ; + + i )
{
2022-11-17 10:22:33 -05:00
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddFragmentInstances > ( IntEntities [ i ] , FTestFragment_Int ( i ) , FTestFragment_Float ( ( float ) i ) ) ;
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddFragmentInstances > ( FloatEntities [ i ] , FTestFragment_Int ( i ) , FTestFragment_Float ( ( float ) i ) ) ;
2022-03-08 10:30:07 -05:00
}
2022-08-12 07:56:27 -04:00
EntityManager - > FlushCommands ( ) ;
2022-03-08 10:30:07 -05:00
auto TestEntities = [ this ] ( const TArray < FMassEntityHandle > & Entities ) - > bool {
// all entities should have ended up in the same archetype, FloatsIntsArchetype
for ( int i = 0 ; i < Entities . Num ( ) ; + + i )
{
2022-08-12 07:56:27 -04:00
AITEST_EQUAL ( TEXT ( " All entities should have ended up in the same archetype " ) , EntityManager - > GetArchetypeForEntity ( Entities [ i ] ) , FloatsIntsArchetype ) ;
2022-03-08 10:30:07 -05:00
FMassEntityView View ( FloatsIntsArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Int > ( ) . Value , i ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Float > ( ) . Value , float ( i ) ) ;
}
return true ;
} ;
if ( ! TestEntities ( IntEntities ) | | ! TestEntities ( FloatEntities ) )
{
return false ;
}
//AITEST_EQUAL(TEXT("All entities should have ended up in the same archetype"), EntitySubsystem->GetArchetypeForEntity(FloatEntities[i]), FloatsIntsArchetype);
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_FragmentInstanceList , " System.Mass.Commands.FragmentInstanceList " ) ;
struct FCommands_FragmentMemoryCleanup : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
const UScriptStruct * ArrayFragmentTypes [ ] = {
FTestFragment_Array : : StaticStruct ( ) ,
FTestFragment_Int : : StaticStruct ( )
} ;
2022-08-12 07:56:27 -04:00
const FMassArchetypeHandle ArrayArchetype = EntityManager - > CreateArchetype ( MakeArrayView ( ArrayFragmentTypes , 1 ) ) ;
const FMassArchetypeHandle ArrayIntArchetype = EntityManager - > CreateArchetype ( MakeArrayView ( ArrayFragmentTypes , 2 ) ) ;
const int32 EntitiesPerChunk = EntityManager - > DebugGetArchetypeEntitiesCountPerChunk ( ArrayArchetype ) ;
2024-03-21 09:44:11 -04:00
const int32 Count = static_cast < int32 > ( static_cast < float > ( EntitiesPerChunk ) * 2.5f ) ;
2022-03-08 10:30:07 -05:00
TArray < FMassEntityHandle > Entities ;
2022-08-12 07:56:27 -04:00
EntityManager - > BatchCreateEntities ( ArrayArchetype , Count , Entities ) ;
2022-03-08 10:30:07 -05:00
2022-08-12 07:56:27 -04:00
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( ArrayArchetype ) , Entities . Num ( ) ) ;
2022-03-08 10:30:07 -05:00
TArray < int32 > EntitiesModified ;
for ( int i = 0 ; i < Count ; + + i )
{
if ( FMath : : FRand ( ) < 0.2 )
{
FTestFragment_Array A ;
A . Value . Add ( i ) ;
2022-08-12 07:56:27 -04:00
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddFragmentInstances > ( Entities [ i ] , A ) ;
EntityManager - > Defer ( ) . AddFragment < FTestFragment_Int > ( Entities [ i ] ) ;
2022-03-08 10:30:07 -05:00
EntitiesModified . Add ( i ) ;
}
}
2022-08-12 07:56:27 -04:00
EntityManager - > FlushCommands ( ) ;
2022-03-08 10:30:07 -05:00
for ( int32 i : EntitiesModified )
{
FMassEntityView View ( ArrayIntArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Array > ( ) . Value . Num ( ) , 1 ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Array > ( ) . Value [ 0 ] , i ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_FragmentMemoryCleanup , " System.Mass.Commands.MemoryManagement " ) ;
// @todo add "add-then remove some to make holes in chunks-then add again" test
struct FCommands_BuildEntitiesWithFragments : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
2022-08-12 07:56:27 -04:00
const int32 EntitiesPerChunk = EntityManager - > DebugGetArchetypeEntitiesCountPerChunk ( FloatsIntsArchetype ) ;
2024-03-21 09:44:11 -04:00
const int32 Count = static_cast < int32 > ( static_cast < float > ( EntitiesPerChunk ) * 2.5f ) ;
2022-03-08 10:30:07 -05:00
TArray < FMassEntityHandle > Entities ;
for ( int i = 0 ; i < Count ; + + i )
{
2022-08-12 07:56:27 -04:00
Entities . Add ( EntityManager - > ReserveEntity ( ) ) ;
2022-11-17 10:22:33 -05:00
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddFragmentInstances > ( Entities . Last ( ) , FTestFragment_Int ( i ) , FTestFragment_Float ( ( float ) i ) ) ;
2022-03-08 10:30:07 -05:00
}
2022-08-12 07:56:27 -04:00
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , 0 ) ;
EntityManager - > FlushCommands ( ) ;
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , Entities . Num ( ) ) ;
2022-03-08 10:30:07 -05:00
for ( int i = 0 ; i < Entities . Num ( ) ; + + i )
{
FMassEntityView View ( FloatsIntsArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Int > ( ) . Value , i ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Float > ( ) . Value , ( float ) i ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_BuildEntitiesWithFragments , " System.Mass.Commands.BuildEntitiesWithFragments " ) ;
struct FCommands_BuildEntitiesInHoles : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
2022-08-12 07:56:27 -04:00
const int32 EntitiesPerChunk = EntityManager - > DebugGetArchetypeEntitiesCountPerChunk ( FloatsIntsArchetype ) ;
2024-03-21 09:44:11 -04:00
const int32 Count = static_cast < int32 > ( static_cast < float > ( EntitiesPerChunk ) * 1.25f ) * 2 ; // making sure it's even
2022-03-08 10:30:07 -05:00
TArray < FMassEntityHandle > Entities ;
2022-08-12 07:56:27 -04:00
EntityManager - > BatchCreateEntities ( FloatsIntsArchetype , Count , Entities ) ;
2022-03-08 10:30:07 -05:00
FMath : : SRandInit ( 0 ) ;
Algo : : RandomShuffle ( Entities ) ;
2022-08-12 07:56:27 -04:00
EntityManager - > BatchDestroyEntities ( MakeArrayView ( Entities . GetData ( ) , Entities . Num ( ) / 2 ) ) ;
2022-03-08 10:30:07 -05:00
Entities . Reset ( ) ;
for ( int i = 0 ; i < EntitiesPerChunk ; + + i )
{
2022-08-12 07:56:27 -04:00
Entities . Add ( EntityManager - > ReserveEntity ( ) ) ;
2022-11-17 10:22:33 -05:00
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddFragmentInstances > ( Entities . Last ( ) , FTestFragment_Int ( i ) , FTestFragment_Float ( ( float ) i ) ) ;
2022-03-08 10:30:07 -05:00
}
2022-08-12 07:56:27 -04:00
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , Count / 2 ) ;
EntityManager - > FlushCommands ( ) ;
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , Count / 2 + Entities . Num ( ) ) ;
2022-03-08 10:30:07 -05:00
for ( int i = 0 ; i < Entities . Num ( ) ; + + i )
{
FMassEntityView View ( FloatsIntsArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Int > ( ) . Value , i ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Float > ( ) . Value , ( float ) i ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_BuildEntitiesInHoles , " System.Mass.Commands.BuildEntitiesInHoles " ) ;
struct FCommands_BuildEntitiesWithFragmentInstances : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
2022-08-12 07:56:27 -04:00
const int32 EntitiesPerChunk = EntityManager - > DebugGetArchetypeEntitiesCountPerChunk ( FloatsIntsArchetype ) ;
2024-03-21 09:44:11 -04:00
const int32 Count = static_cast < int32 > ( static_cast < float > ( EntitiesPerChunk ) * 2.5f ) ;
2022-03-08 10:30:07 -05:00
TArray < FMassEntityHandle > Entities ;
for ( int i = 0 ; i < Count ; + + i )
{
2022-08-12 07:56:27 -04:00
Entities . Add ( EntityManager - > ReserveEntity ( ) ) ;
2022-11-17 10:22:33 -05:00
EntityManager - > Defer ( ) . PushCommand < FMassCommandBuildEntity > ( Entities . Last ( ) , FTestFragment_Int ( i ) , FTestFragment_Float ( ( float ) i ) ) ;
2022-03-08 10:30:07 -05:00
}
2022-08-12 07:56:27 -04:00
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , 0 ) ;
EntityManager - > FlushCommands ( ) ;
AITEST_EQUAL ( TEXT ( " All entities created should be in ArrayArchetype " ) , EntityManager - > DebugGetArchetypeEntitiesCount ( FloatsIntsArchetype ) , Entities . Num ( ) ) ;
2022-03-08 10:30:07 -05:00
for ( int i = 0 ; i < Entities . Num ( ) ; + + i )
{
FMassEntityView View ( FloatsIntsArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Int > ( ) . Value , i ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Float > ( ) . Value , ( float ) i ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_BuildEntitiesWithFragmentInstances , " System.Mass.Commands.BuildEntitiesWithFragmentInstances " ) ;
struct FCommands_DeferredFunction : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
constexpr int32 Count = 5 ;
const int32 Offset = 1000 ;
TArray < FMassEntityHandle > Entities ;
2022-08-12 07:56:27 -04:00
EntityManager - > BatchCreateEntities ( IntsArchetype , Count , Entities ) ;
2022-03-08 10:30:07 -05:00
int i = 0 ;
for ( FMassEntityHandle Entity : Entities )
{
FMassEntityView View ( IntsArchetype , Entity ) ;
View . GetFragmentData < FTestFragment_Int > ( ) . Value = Offset + i + + ;
2022-08-12 07:56:27 -04:00
EntityManager - > Defer ( ) . PushCommand < FMassDeferredSetCommand > ( [ Entity , Archetype = IntsArchetype , Offset ] ( FMassEntityManager & System )
2022-03-08 10:30:07 -05:00
{
FMassEntityView View ( Archetype , Entity ) ;
View . GetFragmentData < FTestFragment_Int > ( ) . Value - = Offset ;
} ) ;
}
2022-08-12 07:56:27 -04:00
EntityManager - > FlushCommands ( ) ;
2022-03-08 10:30:07 -05:00
for ( i = 0 ; i < Entities . Num ( ) ; + + i )
{
FMassEntityView View ( IntsArchetype , Entities [ i ] ) ;
AITEST_EQUAL ( TEXT ( " Should have predicted values " ) , View . GetFragmentData < FTestFragment_Int > ( ) . Value , i ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_DeferredFunction , " System.Mass.Commands.DeferredFunction " ) ;
2024-04-17 02:32:35 -04:00
// pushing commands while the main buffer is being flushed
struct FCommands_PushWhileFlushing : FEntityTestBase
{
virtual bool InstantTest ( ) override
{
constexpr int32 Count = 5 ;
// here's what we want to do:
// 1. Create a Count number of Int entities
// 2. Register TagA observer that will add a float fragment when the tag is added
// a. The observer will use EntityManager.Defer() directly for the testing purposes - it should use Context.Defer() in real world scenarios
// 3. Add TagA to all the created Entities
// 4. Test if all the affected entities have the float fragment after the flushing
TArray < FMassEntityHandle > Entities ;
EntityManager - > BatchCreateEntities ( IntsArchetype , Count , Entities ) ;
for ( const FMassEntityHandle & EntityHandle : Entities )
{
AITEST_NULL ( TEXT ( " None of the freshly created entities is expexted to contain a float fragment " )
, EntityManager - > GetFragmentDataPtr < FTestFragment_Float > ( EntityHandle ) ) ;
}
UMassTestProcessorBase * ObserverProcessor = NewObject < UMassTestProcessorBase > ( ) ;
ObserverProcessor - > ForEachEntityChunkExecutionFunction = [ ] ( FMassExecutionContext & Context )
{
for ( const FMassEntityHandle & EntityHandle : Context . GetEntities ( ) )
{
Context . GetEntityManagerChecked ( ) . Defer ( ) . AddFragment < FTestFragment_Float > ( EntityHandle ) ;
}
} ;
FMassObserverManager & ObserverManager = EntityManager - > GetObserverManager ( ) ;
ObserverManager . AddObserverInstance ( * FTestTag_A : : StaticStruct ( ) , EMassObservedOperation : : Add , * ObserverProcessor ) ;
EntityManager - > Defer ( ) . PushCommand < FMassCommandAddTag < FTestTag_A > > ( Entities ) ;
for ( const FMassEntityHandle & EntityHandle : Entities )
{
AITEST_NULL ( TEXT ( " Pushing the AddTag command should not result in adding the float fragment " )
, EntityManager - > GetFragmentDataPtr < FTestFragment_Float > ( EntityHandle ) ) ;
}
EntityManager - > FlushCommands ( ) ;
for ( const FMassEntityHandle & EntityHandle : Entities )
{
AITEST_NOT_NULL ( TEXT ( " After flushing all the observed entities should have the float fragment " )
, EntityManager - > GetFragmentDataPtr < FTestFragment_Float > ( EntityHandle ) ) ;
}
return true ;
}
} ;
IMPLEMENT_AI_INSTANT_TEST ( FCommands_PushWhileFlushing , " System.Mass.Commands.PushWhileFlushing " ) ;
2022-03-23 11:58:55 -04:00
# endif // WITH_MASSENTITY_DEBUG
2022-03-08 10:30:07 -05:00
} // FMassCommandsTest
2023-01-20 10:29:35 -05:00
UE_ENABLE_OPTIMIZATION_SHIP
2022-03-08 10:30:07 -05:00
# undef LOCTEXT_NAMESPACE