diff --git a/Content.IntegrationTests/Tests/Construction/ConstructionPrototypeTest.cs b/Content.IntegrationTests/Tests/Construction/ConstructionPrototypeTest.cs index 23dd76a14e..d908a2fa22 100644 --- a/Content.IntegrationTests/Tests/Construction/ConstructionPrototypeTest.cs +++ b/Content.IntegrationTests/Tests/Construction/ConstructionPrototypeTest.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Threading.Tasks; +using Content.Server.Construction.Components; using Content.Shared.Construction.Prototypes; using NUnit.Framework; using Robust.Shared.Prototypes; @@ -8,6 +10,9 @@ namespace Content.IntegrationTests.Tests.Construction [TestFixture] public sealed class ConstructionPrototypeTest : ContentIntegrationTest { + // discount linter for construction graphs + // TODO: Create serialization validators for these? + [Test] public async Task TestStartIsValid() { @@ -45,7 +50,7 @@ namespace Content.IntegrationTests.Tests.Construction } [Test] - public async Task TestStartReachesTarget() + public async Task TestStartReachesValidTarget() { var server = StartServer(); @@ -58,7 +63,12 @@ namespace Content.IntegrationTests.Tests.Construction var start = proto.StartNode; var target = proto.TargetNode; var graph = protoMan.Index(proto.Graph); - Assert.That(graph.TryPath(start, target, out _), $"Unable to find path from \"{start}\" to \"{target}\" on graph \"{graph.ID}\""); + Assert.That(graph.TryPath(start, target, out var path), $"Unable to find path from \"{start}\" to \"{target}\" on graph \"{graph.ID}\""); + Assert.That(path!.Length, Is.GreaterThanOrEqualTo(1), $"Unable to find path from \"{start}\" to \"{target}\" on graph \"{graph.ID}\"."); + var next = path[0]; + Assert.That(next.Entity, Is.Not.Null, $"The next node ({next.Name}) in the path from the start node ({start}) to the target node ({target}) must specify an entity! Graph: {graph.ID}"); + Assert.That(protoMan.TryIndex(next.Entity, out EntityPrototype entity), $"The next node ({next.Name}) in the path from the start node ({start}) to the target node ({target}) specified an invalid entity prototype ({next.Entity})"); + Assert.That(entity.Components.ContainsKey("Construction"), $"The next node ({next.Name}) in the path from the start node ({start}) to the target node ({target}) specified an entity prototype ({next.Entity}) without a ConstructionComponent."); } } } diff --git a/Content.Server/Construction/ConstructionSystem.Initial.cs b/Content.Server/Construction/ConstructionSystem.Initial.cs index 9436289df2..1c3d63f5c8 100644 --- a/Content.Server/Construction/ConstructionSystem.Initial.cs +++ b/Content.Server/Construction/ConstructionSystem.Initial.cs @@ -234,10 +234,15 @@ namespace Content.Server.Construction return null; } - var newEntity = EntityManager.SpawnEntity(graph.Nodes[edge.Target].Entity, EntityManager.GetComponent(user).Coordinates); + var newEntityProto = graph.Nodes[edge.Target].Entity; + var newEntity = EntityManager.SpawnEntity(newEntityProto, EntityManager.GetComponent(user).Coordinates); - // Yes, this should throw if it's missing the component. - var construction = EntityManager.GetComponent(newEntity); + if (!TryComp(newEntity, out ConstructionComponent? construction)) + { + _sawmill.Error($"Initial construction does not have a valid target entity! It is missing a ConstructionComponent.\nGraph: {graph.ID}, Initial Target: {edge.Target}, Ent. Prototype: {newEntityProto}\nCreated Entity {ToPrettyString(newEntity)} will be deleted."); + Del(newEntity); // Screw you, make proper construction graphs. + return null; + } // We attempt to set the pathfinding target. SetPathfindingTarget(newEntity, targetNode.Name, construction);