diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 50ce95d023..50386a4311 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -4,12 +4,20 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Content.Client.Shuttles.Systems; +using Content.Server.GameTicking; +using Content.Server.Maps; +using Content.Server.Shuttles.Components; +using Content.Server.Station.Components; using NUnit.Framework; using Robust.Server.Maps; using Robust.Shared.ContentPack; +using Robust.Shared.GameObjects; using Robust.Shared.Utility; using Robust.Shared.Map; +using Robust.Shared.Prototypes; using YamlDotNet.RepresentationModel; +using ShuttleSystem = Content.Server.Shuttles.Systems.ShuttleSystem; namespace Content.IntegrationTests.Tests { @@ -61,7 +69,7 @@ namespace Content.IntegrationTests.Tests await pairTracker.CleanReturnAsync(); } - private static string[] GetMapNames() + private static string[] GetGameMapNames() { Task task; using (ExecutionContext.SuppressFlow()) @@ -73,11 +81,128 @@ namespace Content.IntegrationTests.Tests new PoolSettings { Disconnected = true, - TestName = $"{nameof(PostMapInitTest)}.{nameof(GetMapNames)}" + TestName = $"{nameof(PostMapInitTest)}.{nameof(GetGameMapNames)}" } ); var server = pairTracker.Pair.Server; + var protoManager = server.ResolveDependency(); + + var maps = protoManager.EnumeratePrototypes().ToList(); + var mapNames = new List(); + var naughty = new HashSet() + { + "empty", + "infiltrator", + "pirate", + }; + + foreach (var map in maps) + { + // AAAAAAAAAA + // Why are they stations! + if (naughty.Contains(map.ID)) + continue; + + mapNames.Add(map.ID); + } + + await pairTracker.CleanReturnAsync(); + return mapNames.ToArray(); + }); + Task.WaitAll(task); + } + + return task.GetAwaiter().GetResult(); + } + + [Test, TestCaseSource(nameof(GetGameMapNames))] + public async Task GameMapsLoadableTest(string mapProto) + { + await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true}); + var server = pairTracker.Pair.Server; + + var mapLoader = server.ResolveDependency(); + var mapManager = server.ResolveDependency(); + var entManager = server.ResolveDependency(); + var protoManager = server.ResolveDependency(); + var ticker = entManager.EntitySysManager.GetEntitySystem(); + var shuttleSystem = entManager.EntitySysManager.GetEntitySystem(); + + await server.WaitPost(() => + { + var mapId = mapManager.CreateMap(); + try + { + ticker.LoadGameMap(protoManager.Index(mapProto), mapId, null); + } + catch (Exception ex) + { + throw new Exception($"Failed to load map {mapProto}", ex); + } + + var shuttleMap = mapManager.CreateMap(); + var largest = 0f; + EntityUid? targetGrid = null; + var memberQuery = entManager.GetEntityQuery(); + + var grids = mapManager.GetAllMapGrids(mapId); + + foreach (var grid in grids) + { + if (!memberQuery.HasComponent(grid.GridEntityId)) + continue; + + var area = grid.LocalAABB.Width * grid.LocalAABB.Height; + + if (area > largest) + { + largest = area; + targetGrid = grid.GridEntityId; + } + } + + // Test shuttle can dock. + // This is done inside gamemap test because loading the map takes ages and we already have it. + var station = entManager.GetComponent(targetGrid!.Value).Station; + var shuttlePath = entManager.GetComponent(station).EmergencyShuttlePath + .ToString(); + var shuttle = mapLoader.LoadGrid(shuttleMap, entManager.GetComponent(station).EmergencyShuttlePath.ToString()); + Assert.That(shuttleSystem.TryFTLDock(entManager.GetComponent(shuttle.gridId!.Value), targetGrid.Value), $"Unable to dock {shuttlePath} to {mapProto}"); + + mapManager.DeleteMap(shuttleMap); + + try + { + mapManager.DeleteMap(mapId); + } + catch (Exception ex) + { + throw new Exception($"Failed to delete map {mapProto}", ex); + } + }); + await server.WaitRunTicks(1); + + await pairTracker.CleanReturnAsync(); + } + + /// + /// Get the non-game map maps. + /// + private static string[] GetMaps() + { + Task task; + using (ExecutionContext.SuppressFlow()) + { + task = Task.Run(static async () => + { + await Task.Yield(); + await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{Disconnected = true}); + var server = pairTracker.Pair.Server; var resourceManager = server.ResolveDependency(); + var protoManager = server.ResolveDependency(); + + var gameMaps = protoManager.EnumeratePrototypes().Select(o => o.MapPath).ToHashSet(); + var mapFolder = new ResourcePath("/Maps"); var maps = resourceManager .ContentFindFiles(mapFolder) @@ -89,7 +214,8 @@ namespace Content.IntegrationTests.Tests var rootedPath = map.ToRootedPath(); // ReSharper disable once RedundantLogicalConditionalExpressionOperand - if (SkipTestMaps && rootedPath.ToString().StartsWith(TestMapsPath)) + if (SkipTestMaps && rootedPath.ToString().StartsWith(TestMapsPath) || + gameMaps.Contains(map)) { continue; } @@ -105,7 +231,7 @@ namespace Content.IntegrationTests.Tests return task.GetAwaiter().GetResult(); } - [Test, TestCaseSource(nameof(GetMapNames))] + [Test, TestCaseSource(nameof(GetMaps))] public async Task MapsLoadableTest(string mapName) { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true}); diff --git a/Content.IntegrationTests/Tests/ShuttleTest.cs b/Content.IntegrationTests/Tests/ShuttleTest.cs index 262dacd7a2..333a3bf4d6 100644 --- a/Content.IntegrationTests/Tests/ShuttleTest.cs +++ b/Content.IntegrationTests/Tests/ShuttleTest.cs @@ -1,4 +1,3 @@ -#nullable enable using System.Threading.Tasks; using Content.Server.Shuttles.Components; using NUnit.Framework; @@ -18,6 +17,7 @@ namespace Content.IntegrationTests.Tests { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true}); var server = pairTracker.Pair.Server; + await server.WaitIdleAsync(); var mapMan = server.ResolveDependency(); var sEntities = server.ResolveDependency(); @@ -30,8 +30,8 @@ namespace Content.IntegrationTests.Tests var grid = mapMan.CreateGrid(mapId); gridEnt = grid.GridEntityId; - Assert.That(sEntities.TryGetComponent(gridEnt, out ShuttleComponent? shuttleComponent)); - Assert.That(sEntities.TryGetComponent(gridEnt, out PhysicsComponent? physicsComponent)); + Assert.That(sEntities.HasComponent(gridEnt)); + Assert.That(sEntities.TryGetComponent(gridEnt, out var physicsComponent)); Assert.That(physicsComponent!.BodyType, Is.EqualTo(BodyType.Dynamic)); Assert.That(sEntities.GetComponent(gridEnt).LocalPosition, Is.EqualTo(Vector2.Zero)); physicsComponent.ApplyLinearImpulse(Vector2.One); diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index 1f597976ab..7f93902a6d 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -112,7 +112,7 @@ namespace Content.Server.GameTicking /// Map loading options, includes offset. /// Name to assign to the loaded station. /// All loaded entities and grids. - public (IReadOnlyList, IReadOnlyList) LoadGameMap(GameMapPrototype map, MapId targetMapId, MapLoadOptions? loadOptions, string? stationName = null) + public (IReadOnlyList Entities, IReadOnlyList Grids) LoadGameMap(GameMapPrototype map, MapId targetMapId, MapLoadOptions? loadOptions, string? stationName = null) { // Okay I specifically didn't set LoadMap here because this is typically called onto a new map. // whereas the command can also be used on an existing map. diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index f142a6affd..1402dabf7c 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -14,6 +14,7 @@ using Robust.Shared.Player; using Robust.Shared.Utility; using System.Diagnostics.CodeAnalysis; using Content.Server.Shuttles.Events; +using Content.Server.Station.Components; using Robust.Shared.Physics.Components; namespace Content.Server.Shuttles.Systems; diff --git a/Content.Server/Station/Components/StationDataComponent.cs b/Content.Server/Station/Components/StationDataComponent.cs index af5f3b58a9..d58567ab5f 100644 --- a/Content.Server/Station/Components/StationDataComponent.cs +++ b/Content.Server/Station/Components/StationDataComponent.cs @@ -35,6 +35,6 @@ public sealed class StationDataComponent : Component /// /// Emergency shuttle map path for this station. /// - [ViewVariables(VVAccess.ReadWrite), Access(typeof(ShuttleSystem), Friend = AccessPermissions.ReadExecute)] + [ViewVariables(VVAccess.ReadWrite), Access(typeof(ShuttleSystem), Other = AccessPermissions.ReadWriteExecute)] public ResourcePath EmergencyShuttlePath = new("/Maps/Shuttles/emergency_shuttle.yml"); }