2020-08-13 14:40:27 +02:00
using System.Collections.Generic ;
2020-08-22 22:29:20 +02:00
using System.Linq ;
2023-11-29 13:32:59 +11:00
using System.Numerics ;
2025-04-17 07:43:28 -04:00
using System.Text ;
2023-04-25 21:27:57 +12:00
using Robust.Shared ;
2024-12-28 11:54:32 +11:00
using Robust.Shared.Audio.Components ;
2023-04-25 11:48:29 +12:00
using Robust.Shared.Configuration ;
2020-03-27 00:32:24 -04:00
using Robust.Shared.GameObjects ;
2020-08-13 14:40:27 +02:00
using Robust.Shared.Log ;
2020-03-27 00:32:24 -04:00
using Robust.Shared.Map ;
2022-04-24 13:54:25 +10:00
using Robust.Shared.Maths ;
2020-03-27 00:32:24 -04:00
using Robust.Shared.Prototypes ;
2025-04-17 06:10:23 -04:00
using Robust.Shared.Serialization.Manager.Attributes ;
2020-03-27 00:32:24 -04:00
namespace Content.IntegrationTests.Tests
{
[TestFixture]
2021-12-05 18:09:01 +01:00
[TestOf(typeof(EntityUid))]
2022-06-19 20:22:28 -07:00
public sealed class EntityTest
2020-03-27 00:32:24 -04:00
{
2024-06-02 16:08:15 +12:00
private static readonly ProtoId < EntityCategoryPrototype > SpawnerCategory = "Spawner" ;
2020-03-27 00:32:24 -04:00
[Test]
2022-08-28 15:13:59 -07:00
public async Task SpawnAndDeleteAllEntitiesOnDifferentMaps ( )
2020-03-27 00:32:24 -04:00
{
2023-08-02 03:09:25 +12:00
// This test dirties the pair as it simply deletes ALL entities when done. Overhead of restarting the round
// is minimal relative to the rest of the test.
2023-08-06 14:30:28 +12:00
var settings = new PoolSettings { Dirty = true } ;
2023-08-25 02:56:51 +02:00
await using var pair = await PoolManager . GetServerClient ( settings ) ;
var server = pair . Server ;
2020-09-01 12:29:58 +02:00
2023-05-31 11:13:02 +10:00
var entityMan = server . ResolveDependency < IEntityManager > ( ) ;
var mapManager = server . ResolveDependency < IMapManager > ( ) ;
var prototypeMan = server . ResolveDependency < IPrototypeManager > ( ) ;
2024-01-20 17:15:10 +11:00
var mapSystem = entityMan . System < SharedMapSystem > ( ) ;
2020-09-01 12:29:58 +02:00
2022-06-19 20:22:28 -07:00
await server . WaitPost ( ( ) = >
2020-03-27 00:32:24 -04:00
{
2022-08-28 15:13:59 -07:00
var protoIds = prototypeMan
. EnumeratePrototypes < EntityPrototype > ( )
2023-07-05 21:54:25 -07:00
. Where ( p = > ! p . Abstract )
2023-08-25 02:56:51 +02:00
. Where ( p = > ! pair . IsTestPrototype ( p ) )
2023-05-16 06:36:45 -05:00
. Where ( p = > ! p . Components . ContainsKey ( "MapGrid" ) ) // This will smash stuff otherwise.
2025-02-12 15:47:48 +03:00
. Where ( p = > ! p . Components . ContainsKey ( "RoomFill" ) ) // This comp can delete all entities, and spawn others
2025-04-10 22:28:50 +03:00
. Where ( p = > ! p . Components . ContainsKey ( "CP14BiomeSpawner" ) ) // CP14 this component delete all entities on this tile
2025-04-21 19:20:26 +10:00
. Where ( p = > ! p . Components . ContainsKey ( "CP14AreaEntityEffect" ) ) // CP14 lightning detonates entities
2022-08-28 15:13:59 -07:00
. Select ( p = > p . ID )
. ToList ( ) ;
2024-01-20 17:15:10 +11:00
2022-08-28 15:13:59 -07:00
foreach ( var protoId in protoIds )
{
2024-07-02 20:01:37 -04:00
mapSystem . CreateMap ( out var mapId ) ;
2024-01-20 17:15:10 +11:00
var grid = mapManager . CreateGridEntity ( mapId ) ;
2023-09-11 09:42:41 +10:00
// TODO: Fix this better in engine.
2024-01-20 17:15:10 +11:00
mapSystem . SetTile ( grid . Owner , grid . Comp , Vector2i . Zero , new Tile ( 1 ) ) ;
2022-12-12 14:59:02 +11:00
var coord = new EntityCoordinates ( grid . Owner , 0 , 0 ) ;
2022-08-28 15:13:59 -07:00
entityMan . SpawnEntity ( protoId , coord ) ;
}
} ) ;
2020-09-01 12:29:58 +02:00
2025-08-06 12:38:45 +03:00
await server . WaitRunTicks ( 15 ) ; // 15 seconds, enough to trigger most update loops //CP14 returned back to 15 ticks (operation was cancelled github issue)
2020-09-01 12:29:58 +02:00
2022-08-28 15:13:59 -07:00
await server . WaitPost ( ( ) = >
{
2023-07-05 21:54:25 -07:00
static IEnumerable < ( EntityUid , TComp ) > Query < TComp > ( IEntityManager entityMan )
where TComp : Component
2022-08-28 15:13:59 -07:00
{
2023-07-05 21:54:25 -07:00
var query = entityMan . AllEntityQueryEnumerator < TComp > ( ) ;
while ( query . MoveNext ( out var uid , out var meta ) )
2024-01-20 17:15:10 +11:00
{
2023-07-05 21:54:25 -07:00
yield return ( uid , meta ) ;
2024-01-20 17:15:10 +11:00
}
2023-09-11 09:42:41 +10:00
}
2023-07-05 21:54:25 -07:00
var entityMetas = Query < MetaDataComponent > ( entityMan ) . ToList ( ) ;
foreach ( var ( uid , meta ) in entityMetas )
{
if ( ! meta . EntityDeleted )
entityMan . DeleteEntity ( uid ) ;
2022-08-28 15:13:59 -07:00
}
2020-09-01 12:29:58 +02:00
2022-08-28 15:13:59 -07:00
Assert . That ( entityMan . EntityCount , Is . Zero ) ;
} ) ;
2023-04-25 11:48:29 +12:00
2023-08-25 02:56:51 +02:00
await pair . CleanReturnAsync ( ) ;
2022-08-28 15:13:59 -07:00
}
[Test]
public async Task SpawnAndDeleteAllEntitiesInTheSameSpot ( )
{
2023-08-02 03:09:25 +12:00
// This test dirties the pair as it simply deletes ALL entities when done. Overhead of restarting the round
// is minimal relative to the rest of the test.
2023-08-06 14:30:28 +12:00
var settings = new PoolSettings { Dirty = true } ;
2023-08-25 02:56:51 +02:00
await using var pair = await PoolManager . GetServerClient ( settings ) ;
var server = pair . Server ;
2023-08-25 04:13:11 +02:00
var map = await pair . CreateTestMap ( ) ;
2020-09-01 12:29:58 +02:00
2023-05-31 11:13:02 +10:00
var entityMan = server . ResolveDependency < IEntityManager > ( ) ;
var prototypeMan = server . ResolveDependency < IPrototypeManager > ( ) ;
2023-04-25 11:48:29 +12:00
2022-08-28 15:13:59 -07:00
await server . WaitPost ( ( ) = >
{
var protoIds = prototypeMan
. EnumeratePrototypes < EntityPrototype > ( )
2023-07-05 21:54:25 -07:00
. Where ( p = > ! p . Abstract )
2023-08-25 02:56:51 +02:00
. Where ( p = > ! pair . IsTestPrototype ( p ) )
2023-05-16 06:36:45 -05:00
. Where ( p = > ! p . Components . ContainsKey ( "MapGrid" ) ) // This will smash stuff otherwise.
2025-02-12 15:47:48 +03:00
. Where ( p = > ! p . Components . ContainsKey ( "RoomFill" ) ) // This comp can delete all entities, and spawn others
2025-04-10 22:28:50 +03:00
. Where ( p = > ! p . Components . ContainsKey ( "CP14BiomeSpawner" ) ) // CP14 this component delete all entities on this tile
2025-04-21 19:20:26 +10:00
. Where ( p = > ! p . Components . ContainsKey ( "CP14AreaEntityEffect" ) ) // CP14 lightning detonates entities
2022-08-28 15:13:59 -07:00
. Select ( p = > p . ID )
. ToList ( ) ;
foreach ( var protoId in protoIds )
{
2023-01-24 13:33:49 +13:00
entityMan . SpawnEntity ( protoId , map . GridCoords ) ;
2022-08-28 15:13:59 -07:00
}
2020-03-27 00:32:24 -04:00
} ) ;
2025-08-06 12:38:45 +03:00
await server . WaitRunTicks ( 15 ) ; // 15 seconds, enough to trigger most update loops //CP14 returned back to 15 ticks (operation was cancelled github issue)
2022-08-28 15:13:59 -07:00
await server . WaitPost ( ( ) = >
2020-08-18 13:46:12 +02:00
{
2023-07-05 21:54:25 -07:00
static IEnumerable < ( EntityUid , TComp ) > Query < TComp > ( IEntityManager entityMan )
where TComp : Component
{
var query = entityMan . AllEntityQueryEnumerator < TComp > ( ) ;
while ( query . MoveNext ( out var uid , out var meta ) )
2024-01-20 17:15:10 +11:00
{
2023-07-05 21:54:25 -07:00
yield return ( uid , meta ) ;
2024-01-20 17:15:10 +11:00
}
}
2023-07-05 21:54:25 -07:00
var entityMetas = Query < MetaDataComponent > ( entityMan ) . ToList ( ) ;
foreach ( var ( uid , meta ) in entityMetas )
2020-08-18 13:46:12 +02:00
{
2023-07-05 21:54:25 -07:00
if ( ! meta . EntityDeleted )
entityMan . DeleteEntity ( uid ) ;
2020-08-18 13:46:12 +02:00
}
2020-03-27 00:32:24 -04:00
2022-08-28 15:13:59 -07:00
Assert . That ( entityMan . EntityCount , Is . Zero ) ;
2020-08-18 13:46:12 +02:00
} ) ;
2023-04-25 11:48:29 +12:00
2023-08-25 02:56:51 +02:00
await pair . CleanReturnAsync ( ) ;
2020-03-27 00:32:24 -04:00
}
2023-01-24 13:33:49 +13:00
/// <summary>
2023-04-25 21:27:57 +12:00
/// Variant of <see cref="SpawnAndDeleteAllEntitiesOnDifferentMaps"/> that also launches a client and dirties
2023-01-24 13:33:49 +13:00
/// all components on every entity.
/// </summary>
[Test]
public async Task SpawnAndDirtyAllEntities ( )
{
2023-08-02 03:09:25 +12:00
// This test dirties the pair as it simply deletes ALL entities when done. Overhead of restarting the round
// is minimal relative to the rest of the test.
2023-08-06 14:30:28 +12:00
var settings = new PoolSettings { Connected = true , Dirty = true } ;
2023-08-25 02:56:51 +02:00
await using var pair = await PoolManager . GetServerClient ( settings ) ;
var server = pair . Server ;
var client = pair . Client ;
2023-01-24 13:33:49 +13:00
2023-04-25 11:48:29 +12:00
var cfg = server . ResolveDependency < IConfigurationManager > ( ) ;
2023-04-25 21:27:57 +12:00
var prototypeMan = server . ResolveDependency < IPrototypeManager > ( ) ;
var mapManager = server . ResolveDependency < IMapManager > ( ) ;
var sEntMan = server . ResolveDependency < IEntityManager > ( ) ;
2024-07-02 20:01:37 -04:00
var mapSys = server . System < SharedMapSystem > ( ) ;
2023-04-25 21:27:57 +12:00
Assert . That ( cfg . GetCVar ( CVars . NetPVS ) , Is . False ) ;
var protoIds = prototypeMan
. EnumeratePrototypes < EntityPrototype > ( )
. Where ( p = > ! p . Abstract )
2023-08-25 02:56:51 +02:00
. Where ( p = > ! pair . IsTestPrototype ( p ) )
2023-05-16 06:36:45 -05:00
. Where ( p = > ! p . Components . ContainsKey ( "MapGrid" ) ) // This will smash stuff otherwise.
2023-04-25 21:27:57 +12:00
. Select ( p = > p . ID )
. ToList ( ) ;
2023-01-24 13:33:49 +13:00
await server . WaitPost ( ( ) = >
{
foreach ( var protoId in protoIds )
{
2024-07-02 20:01:37 -04:00
mapSys . CreateMap ( out var mapId ) ;
2024-01-20 17:15:10 +11:00
var grid = mapManager . CreateGridEntity ( mapId ) ;
2023-04-25 21:27:57 +12:00
var ent = sEntMan . SpawnEntity ( protoId , new EntityCoordinates ( grid . Owner , 0.5f , 0.5f ) ) ;
foreach ( var ( _ , component ) in sEntMan . GetNetComponents ( ent ) )
2023-01-24 13:33:49 +13:00
{
2024-01-20 17:15:10 +11:00
sEntMan . Dirty ( ent , component ) ;
2023-01-24 13:33:49 +13:00
}
}
} ) ;
2023-04-25 21:27:57 +12:00
2023-08-25 04:13:11 +02:00
await pair . RunTicksSync ( 15 ) ;
2023-04-25 21:27:57 +12:00
// Make sure the client actually received the entities
// 500 is completely arbitrary. Note that the client & sever entity counts aren't expected to match.
Assert . That ( client . ResolveDependency < IEntityManager > ( ) . EntityCount , Is . GreaterThan ( 500 ) ) ;
2023-01-24 13:33:49 +13:00
await server . WaitPost ( ( ) = >
{
2023-07-05 21:54:25 -07:00
static IEnumerable < ( EntityUid , TComp ) > Query < TComp > ( IEntityManager entityMan )
where TComp : Component
{
var query = entityMan . AllEntityQueryEnumerator < TComp > ( ) ;
while ( query . MoveNext ( out var uid , out var meta ) )
2024-01-20 17:15:10 +11:00
{
2023-07-05 21:54:25 -07:00
yield return ( uid , meta ) ;
2024-01-20 17:15:10 +11:00
}
2023-10-16 16:54:10 +11:00
}
2023-07-05 21:54:25 -07:00
var entityMetas = Query < MetaDataComponent > ( sEntMan ) . ToList ( ) ;
foreach ( var ( uid , meta ) in entityMetas )
2023-01-24 13:33:49 +13:00
{
if ( ! meta . EntityDeleted )
2023-07-05 21:54:25 -07:00
sEntMan . DeleteEntity ( uid ) ;
2023-01-24 13:33:49 +13:00
}
2023-04-25 21:27:57 +12:00
Assert . That ( sEntMan . EntityCount , Is . Zero ) ;
2023-01-24 13:33:49 +13:00
} ) ;
2023-04-25 11:48:29 +12:00
2023-08-25 02:56:51 +02:00
await pair . CleanReturnAsync ( ) ;
2023-01-24 13:33:49 +13:00
}
2023-10-16 16:54:10 +11:00
/// <summary>
/// This test checks that spawning and deleting an entity doesn't somehow create other unrelated entities.
/// </summary>
/// <remarks>
/// Unless an entity is intentionally designed to spawn other entities (e.g., mob spawners), they should
/// generally not spawn unrelated / detached entities. Any entities that do get spawned should be parented to
/// the spawned entity (e.g., in a container). If an entity needs to spawn an entity somewhere in null-space,
/// it should delete that entity when it is no longer required. This test mainly exists to prevent "entity leak"
2024-12-28 11:54:32 +11:00
/// bugs, where spawning some entity starts spawning unrelated entities in null space that stick around after
/// the original entity is gone.
///
/// Note that this isn't really a strict requirement, and there are probably quite a few edge cases. Its a pretty
/// crude test to try catch issues like this, and possibly should just be disabled.
2023-10-16 16:54:10 +11:00
/// </remarks>
[Test]
public async Task SpawnAndDeleteEntityCountTest ( )
{
var settings = new PoolSettings { Connected = true , Dirty = true } ;
await using var pair = await PoolManager . GetServerClient ( settings ) ;
2024-07-02 20:01:37 -04:00
var mapSys = pair . Server . System < SharedMapSystem > ( ) ;
2023-10-16 16:54:10 +11:00
var server = pair . Server ;
var client = pair . Client ;
var excluded = new [ ]
{
"MapGrid" ,
"StationEvent" ,
"TimedDespawn" ,
2023-12-07 00:58:08 -05:00
// makes an announcement on mapInit.
"AnnounceOnSpawn" ,
2023-10-16 16:54:10 +11:00
} ;
Assert . That ( server . CfgMan . GetCVar ( CVars . NetPVS ) , Is . False ) ;
var protoIds = server . ProtoMan
. EnumeratePrototypes < EntityPrototype > ( )
. Where ( p = > ! p . Abstract )
. Where ( p = > ! pair . IsTestPrototype ( p ) )
. Where ( p = > ! excluded . Any ( p . Components . ContainsKey ) )
2024-06-02 16:08:15 +12:00
. Where ( p = > p . Categories . All ( x = > x . ID ! = SpawnerCategory ) )
2023-10-16 16:54:10 +11:00
. Select ( p = > p . ID )
. ToList ( ) ;
2023-11-30 22:08:08 +11:00
protoIds . Sort ( ) ;
var mapId = MapId . Nullspace ;
await server . WaitPost ( ( ) = >
{
2024-07-02 20:01:37 -04:00
mapSys . CreateMap ( out mapId ) ;
2023-11-30 22:08:08 +11:00
} ) ;
var coords = new MapCoordinates ( Vector2 . Zero , mapId ) ;
2023-10-16 16:54:10 +11:00
await pair . RunTicksSync ( 3 ) ;
2024-12-28 11:54:32 +11:00
// We consider only non-audio entities, as some entities will just play sounds when they spawn.
2025-07-23 03:21:10 +02:00
int Count ( IEntityManager ent ) = > ent . EntityCount - ent . Count < AudioComponent > ( ) ;
2025-04-17 07:43:28 -04:00
IEnumerable < EntityUid > Entities ( IEntityManager entMan ) = > entMan . GetEntities ( ) . Where ( entMan . HasComponent < AudioComponent > ) ;
2024-12-28 11:54:32 +11:00
2025-04-17 07:43:28 -04:00
await Assert . MultipleAsync ( async ( ) = >
2023-10-16 16:54:10 +11:00
{
2025-04-17 07:43:28 -04:00
foreach ( var protoId in protoIds )
2023-10-16 16:54:10 +11:00
{
2025-04-17 07:43:28 -04:00
var count = Count ( server . EntMan ) ;
var clientCount = Count ( client . EntMan ) ;
var serverEntities = new HashSet < EntityUid > ( Entities ( server . EntMan ) ) ;
var clientEntities = new HashSet < EntityUid > ( Entities ( client . EntMan ) ) ;
EntityUid uid = default ;
await server . WaitPost ( ( ) = > uid = server . EntMan . SpawnEntity ( protoId , coords ) ) ;
await pair . RunTicksSync ( 3 ) ;
// If the entity deleted itself, check that it didn't spawn other entities
if ( ! server . EntMan . EntityExists ( uid ) )
2023-11-29 13:32:59 +11:00
{
2025-04-17 07:43:28 -04:00
Assert . That ( Count ( server . EntMan ) , Is . EqualTo ( count ) , $"Server prototype {protoId} failed on deleting itself\n" +
BuildDiffString ( serverEntities , Entities ( server . EntMan ) , server . EntMan ) ) ;
Assert . That ( Count ( client . EntMan ) , Is . EqualTo ( clientCount ) , $"Client prototype {protoId} failed on deleting itself\n" +
$"Expected {clientCount} and found {client.EntMan.EntityCount}.\n" +
$"Server count was {count}.\n" +
BuildDiffString ( clientEntities , Entities ( client . EntMan ) , client . EntMan ) ) ;
continue ;
2023-11-29 13:32:59 +11:00
}
2023-10-16 16:54:10 +11:00
2025-04-17 07:43:28 -04:00
// Check that the number of entities has increased.
Assert . That ( Count ( server . EntMan ) , Is . GreaterThan ( count ) , $"Server prototype {protoId} failed on spawning as entity count didn't increase\n" +
BuildDiffString ( serverEntities , Entities ( server . EntMan ) , server . EntMan ) ) ;
Assert . That ( Count ( client . EntMan ) , Is . GreaterThan ( clientCount ) , $"Client prototype {protoId} failed on spawning as entity count didn't increase\n" +
$"Expected at least {clientCount} and found {client.EntMan.EntityCount}. " +
$"Server count was {count}.\n" +
BuildDiffString ( clientEntities , Entities ( client . EntMan ) , client . EntMan ) ) ;
await server . WaitPost ( ( ) = > server . EntMan . DeleteEntity ( uid ) ) ;
await pair . RunTicksSync ( 3 ) ;
// Check that the number of entities has gone back to the original value.
Assert . That ( Count ( server . EntMan ) , Is . EqualTo ( count ) , $"Server prototype {protoId} failed on deletion: count didn't reset properly\n" +
BuildDiffString ( serverEntities , Entities ( server . EntMan ) , server . EntMan ) ) ;
Assert . That ( client . EntMan . EntityCount , Is . EqualTo ( clientCount ) , $"Client prototype {protoId} failed on deletion: count didn't reset properly:\n" +
$"Expected {clientCount} and found {client.EntMan.EntityCount}.\n" +
$"Server count was {count}.\n" +
BuildDiffString ( clientEntities , Entities ( client . EntMan ) , client . EntMan ) ) ;
2023-11-29 13:32:59 +11:00
}
2025-04-17 07:43:28 -04:00
} ) ;
2023-11-29 13:32:59 +11:00
2025-04-17 07:43:28 -04:00
await pair . CleanReturnAsync ( ) ;
}
2023-10-16 16:54:10 +11:00
2025-04-17 07:43:28 -04:00
private static string BuildDiffString ( IEnumerable < EntityUid > oldEnts , IEnumerable < EntityUid > newEnts , IEntityManager entMan )
{
var sb = new StringBuilder ( ) ;
var addedEnts = newEnts . Except ( oldEnts ) ;
var removedEnts = oldEnts . Except ( newEnts ) ;
if ( addedEnts . Any ( ) )
sb . AppendLine ( "Listing new entities:" ) ;
foreach ( var addedEnt in addedEnts )
{
sb . AppendLine ( entMan . ToPrettyString ( addedEnt ) ) ;
2023-10-16 16:54:10 +11:00
}
2025-04-17 07:43:28 -04:00
if ( removedEnts . Any ( ) )
sb . AppendLine ( "Listing removed entities:" ) ;
foreach ( var removedEnt in removedEnts )
{
sb . AppendLine ( "\t" + entMan . ToPrettyString ( removedEnt ) ) ;
}
return sb . ToString ( ) ;
2023-10-16 16:54:10 +11:00
}
2025-04-17 06:10:23 -04:00
private static bool HasRequiredDataField ( Component component )
{
foreach ( var field in component . GetType ( ) . GetFields ( ) )
{
foreach ( var attribute in field . GetCustomAttributes ( true ) )
2023-11-29 13:32:59 +11:00
{
2025-04-17 06:10:23 -04:00
if ( attribute is not DataFieldAttribute dataField )
continue ;
2023-11-29 13:32:59 +11:00
2025-04-17 06:10:23 -04:00
if ( dataField . Required )
return true ;
2023-11-29 13:32:59 +11:00
}
2023-10-16 16:54:10 +11:00
}
2025-04-17 06:10:23 -04:00
foreach ( var property in component . GetType ( ) . GetProperties ( ) )
{
foreach ( var attribute in property . GetCustomAttributes ( true ) )
{
if ( attribute is not DataFieldAttribute dataField )
continue ;
2023-10-16 16:54:10 +11:00
2025-04-17 06:10:23 -04:00
if ( dataField . Required )
return true ;
}
}
return false ;
2023-10-16 16:54:10 +11:00
}
2020-08-24 13:39:00 +02:00
[Test]
public async Task AllComponentsOneToOneDeleteTest ( )
{
var skipComponents = new [ ]
{
"DebugExceptionOnAdd" , // Debug components that explicitly throw exceptions
"DebugExceptionExposeData" ,
"DebugExceptionInitialize" ,
"DebugExceptionStartup" ,
2023-11-29 13:20:37 +11:00
"GridFill" ,
2025-02-12 15:47:48 +03:00
"RoomFill" ,
2025-04-10 22:28:50 +03:00
"CP14BiomeSpawner" , // CP14 this component delete all entities on this tile
2025-04-21 19:20:26 +10:00
"CP14AreaEntityEffect" , // CP14 lightning detonates entities
2020-08-24 13:39:00 +02:00
"Map" , // We aren't testing a map entity in this test
2021-05-30 12:10:03 +02:00
"MapGrid" ,
2023-09-10 12:35:05 +12:00
"Broadphase" ,
2022-08-07 15:53:07 +12:00
"StationData" , // errors when removed mid-round
2024-06-06 02:19:24 +12:00
"StationJobs" ,
2021-05-30 12:10:03 +02:00
"Actor" , // We aren't testing actor components, those need their player session set.
2023-05-16 06:36:45 -05:00
"BlobFloorPlanBuilder" , // Implodes if unconfigured.
"DebrisFeaturePlacerController" , // Above.
"LoadedChunk" , // Worldgen chunk loading malding.
"BiomeSelection" , // Whaddya know, requires config.
2024-05-24 17:03:03 +12:00
"ActivatableUI" , // Requires enum key
2020-08-24 13:39:00 +02:00
} ;
2023-08-25 02:56:51 +02:00
await using var pair = await PoolManager . GetServerClient ( ) ;
var server = pair . Server ;
2020-08-24 13:39:00 +02:00
var entityManager = server . ResolveDependency < IEntityManager > ( ) ;
var componentFactory = server . ResolveDependency < IComponentFactory > ( ) ;
2023-07-05 21:54:25 -07:00
var logmill = server . ResolveDependency < ILogManager > ( ) . GetSawmill ( "EntityTest" ) ;
2020-08-24 13:39:00 +02:00
2024-04-20 17:01:15 -04:00
await pair . CreateTestMap ( ) ;
2022-06-19 20:22:28 -07:00
await server . WaitRunTicks ( 5 ) ;
2024-04-20 17:01:15 -04:00
var testLocation = pair . TestMap . GridCoords ;
2022-06-19 20:22:28 -07:00
await server . WaitAssertion ( ( ) = >
2020-08-24 13:39:00 +02:00
{
2021-03-31 12:41:23 -07:00
Assert . Multiple ( ( ) = >
2020-08-24 13:39:00 +02:00
{
2021-03-31 12:41:23 -07:00
foreach ( var type in componentFactory . AllRegisteredTypes )
2020-08-24 13:39:00 +02:00
{
2025-04-17 06:10:23 -04:00
var component = ( Component ) componentFactory . GetComponent ( type ) ;
2022-07-20 14:48:44 +10:00
var name = componentFactory . GetComponentName ( type ) ;
2020-08-24 13:39:00 +02:00
2025-04-17 06:10:23 -04:00
if ( HasRequiredDataField ( component ) )
continue ;
2021-03-31 12:41:23 -07:00
// If this component is ignored
2022-07-20 14:48:44 +10:00
if ( skipComponents . Contains ( name ) )
2021-03-31 12:41:23 -07:00
{
continue ;
}
2020-08-24 13:39:00 +02:00
2023-08-02 03:09:25 +12:00
var entity = entityManager . SpawnEntity ( null , testLocation ) ;
2020-08-24 13:39:00 +02:00
2021-12-08 12:43:38 +01:00
Assert . That ( entityManager . GetComponent < MetaDataComponent > ( entity ) . EntityInitialized ) ;
2020-08-24 13:39:00 +02:00
2021-03-31 12:41:23 -07:00
// The component may already exist if it is a mandatory component
// such as MetaData or Transform
2021-12-08 12:43:38 +01:00
if ( entityManager . HasComponent ( entity , type ) )
2021-03-31 12:41:23 -07:00
{
2023-07-30 20:29:33 +10:00
entityManager . DeleteEntity ( entity ) ;
2021-03-31 12:41:23 -07:00
continue ;
}
2020-08-24 13:39:00 +02:00
2023-07-05 21:54:25 -07:00
logmill . Debug ( $"Adding component: {name}" ) ;
2020-08-24 13:39:00 +02:00
2021-03-31 12:41:23 -07:00
Assert . DoesNotThrow ( ( ) = >
{
2021-09-28 13:35:29 +02:00
entityManager . AddComponent ( entity , component ) ;
2021-03-31 12:41:23 -07:00
} , "Component '{0}' threw an exception." ,
2022-07-20 14:48:44 +10:00
name ) ;
2020-08-24 13:39:00 +02:00
2021-12-05 18:09:01 +01:00
entityManager . DeleteEntity ( entity ) ;
2021-03-31 12:41:23 -07:00
}
} ) ;
2020-08-24 13:39:00 +02:00
} ) ;
2023-08-25 02:56:51 +02:00
await pair . CleanReturnAsync ( ) ;
2020-08-24 13:39:00 +02:00
}
2020-03-27 00:32:24 -04:00
}
}