Add new entity spawn test & fix misc bugs (#19953)

This commit is contained in:
Leon Friedrich
2023-10-16 16:54:10 +11:00
committed by GitHub
parent 1f0c9314fd
commit 00e274ea38
14 changed files with 149 additions and 36 deletions

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.Humanoid.Components;
using Content.Shared.Coordinates;
using Content.Shared.Prototypes;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
@@ -183,7 +185,7 @@ namespace Content.IntegrationTests.Tests
var query = entityMan.AllEntityQueryEnumerator<TComp>();
while (query.MoveNext(out var uid, out var meta))
yield return (uid, meta);
};
}
var entityMetas = Query<MetaDataComponent>(sEntMan).ToList();
foreach (var (uid, meta) in entityMetas)
@@ -198,6 +200,100 @@ namespace Content.IntegrationTests.Tests
await pair.CleanReturnAsync();
}
/// <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"
/// bugs, where spawning some entity starts spawning unrelated entities in null space.
/// </remarks>
[Test]
public async Task SpawnAndDeleteEntityCountTest()
{
var settings = new PoolSettings { Connected = true, Dirty = true };
await using var pair = await PoolManager.GetServerClient(settings);
var server = pair.Server;
var client = pair.Client;
var excluded = new[]
{
"MapGrid",
"StationEvent",
"TimedDespawn",
// Spawner entities
"DragonRift",
"RandomHumanoidSpawner",
"RandomSpawner",
"ConditionalSpawner",
"GhostRoleMobSpawner",
"NukeOperativeSpawner",
"TimedSpawner",
};
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))
.Select(p => p.ID)
.ToList();
MapCoordinates coords = default;
await server.WaitPost(() =>
{
var map = server.MapMan.CreateMap();
coords = new MapCoordinates(default, map);
});
await pair.RunTicksSync(3);
List<string> badPrototypes = new();
foreach (var protoId in protoIds)
{
// TODO fix ninja
// Currently ninja fails to equip their own loadout.
if (protoId == "MobHumanSpaceNinja")
continue;
var count = server.EntMan.EntityCount;
var clientCount = client.EntMan.EntityCount;
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))
{
if (server.EntMan.EntityCount != count || client.EntMan.EntityCount != clientCount)
badPrototypes.Add(protoId);
continue;
}
// Check that the number of entities has increased.
if (server.EntMan.EntityCount <= count || client.EntMan.EntityCount <= clientCount)
{
badPrototypes.Add(protoId);
continue;
}
await server.WaitPost(() => server.EntMan.DeleteEntity(uid));
await pair.RunTicksSync(3);
// Check that the number of entities has gone back to the original value.
if (server.EntMan.EntityCount != count || client.EntMan.EntityCount != clientCount)
badPrototypes.Add(protoId);
}
Assert.That(badPrototypes, Is.Empty);
await pair.CleanReturnAsync();
}
[Test]
public async Task AllComponentsOneToOneDeleteTest()
{