mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-20 15:08:46 +03:00
# Description We have a very large number of maps that outright have not received any meaningful updates in over a year. All of them being maps that we inherited from DeltaV during the initial forking. I've spent the entire past year trying to find people willing to maintain them, but to no avail. The rot is incredibly noticeable, and is particularly egregious when they get compared to maps being maintained by SiN Mapping Team and Estacao Pirata. We can't guarantee the quality of these maps, and the original maintainers from DeltaV have expressed zero desire to offer any assistance with maintaining them. I put it to a vote last night on the EE Discord, in order to find out which of the DeltaV maps were actually worth keeping, and the vote was overwhelmingly in favor of Shoko, Glacier, and Lighthouse. I'm willing to work with my existing map maintainers to focus on getting these three maps the care and attention they need in order to be on par with the quality expectation that maps like Gax and Lambda managed to set. If we want more maps, we need people willing to maintain the maps. These maps aren't being removed from the game, just set aside and essentially marked as "Unsupported". If in the future someone wishes to step forward and claim responsibility for one of the maps, they can submit a PR to re-rotate the map in question, assuming it is paired with *some* amount of work done to refurbish the map. It doesn't need to be a full rework, just enough work to prove the map is being taken care of.  # Changelog 🆑 - tweak: Removed the following maps from rotation: Pebble, Edge, Tortuga, Arena, Asterisk, Hive, Hammurabi, and Submarine. These maps aren't permanently gone, they just won't appear in the map vote list. If you want to see them return in an official capacity, and have any talent/desire for mapping, feel free to submit a PR to give one of these maps the attention and care it deserves. None of them have received any updates in over a year. (cherry picked from commit 4c560761cc68fe3a1a3317668fb1980fa2084d14)
412 lines
16 KiB
C#
412 lines
16 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Content.Server.GameTicking;
|
|
using Content.Server.Maps;
|
|
using Content.Server.Shuttles.Components;
|
|
using Content.Server.Shuttles.Systems;
|
|
using Content.Server.Spawners.Components;
|
|
using Content.Server.Station.Components;
|
|
using Content.Shared.CCVar;
|
|
using Content.Shared.Roles;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.ContentPack;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Utility;
|
|
using YamlDotNet.RepresentationModel;
|
|
|
|
namespace Content.IntegrationTests.Tests
|
|
{
|
|
[TestFixture]
|
|
public sealed class PostMapInitTest
|
|
{
|
|
private const bool SkipTestMaps = true;
|
|
private const string TestMapsPath = "/Maps/Test/";
|
|
|
|
private static readonly string[] NoSpawnMaps =
|
|
{
|
|
"CentCommMain",
|
|
"CentCommHarmony",
|
|
"Dart",
|
|
"NukieOutpost"
|
|
};
|
|
|
|
private static readonly string[] Grids =
|
|
{
|
|
"/Maps/CentralCommand/main.yml",
|
|
"/Maps/CentralCommand/harmony.yml", // Harmony CC version
|
|
"/Maps/Shuttles/cargo.yml",
|
|
"/Maps/Shuttles/emergency.yml",
|
|
"/Maps/Shuttles/infiltrator.yml",
|
|
};
|
|
|
|
private static readonly string[] GameMaps =
|
|
{
|
|
"Dev",
|
|
"TestTeg",
|
|
"CentCommMain",
|
|
"CentCommHarmony",
|
|
"MeteorArena",
|
|
"NukieOutpost",
|
|
"Core", // No current maintainer. In need of a rework...
|
|
// "Pebble", // De-rotated, no current maintainer.
|
|
// "Edge", // De-rotated, no current maintainer.
|
|
"Saltern", // Maintained by the Sin Mapping Team, ODJ, and TCJ.
|
|
"Shoukou", // Maintained by Violet
|
|
// "Tortuga", // De-rotated, no current maintainer.
|
|
// "Arena", // De-rotated, no current maintainer.
|
|
// "Asterisk", // De-rotated, no current maintainer.
|
|
"Glacier", // Maintained by Violet
|
|
// "TheHive", // De-rotated, no current maintainer.
|
|
// "Hammurabi", // De-rotated, no current maintainer.
|
|
"Lighthouse", // Maintained by Violet
|
|
// "Submarine", // De-rotated, no current maintainer.
|
|
"Gax", // Maintained by Estacao Pirata
|
|
"Rad", // Maintained by Estacao Pirata
|
|
// "Europa", // De-rotated, has significant issues.
|
|
"Meta", // Maintained by Estacao Pirata
|
|
"Box", // Maintained by Estacao Pirata
|
|
"Lambda", // Maintained by Estacao Pirata
|
|
"Bagel", // Maintained by Estacao Pirata
|
|
"Northway", // Maintained by Violet
|
|
"DryDock", //WWDP
|
|
"Moose", //WWDP
|
|
"WhiteBox", //WWDP
|
|
};
|
|
|
|
/// <summary>
|
|
/// Asserts that specific files have been saved as grids and not maps.
|
|
/// </summary>
|
|
[Test, TestCaseSource(nameof(Grids))]
|
|
public async Task GridsLoadableTest(string mapFile)
|
|
{
|
|
await using var pair = await PoolManager.GetServerClient();
|
|
var server = pair.Server;
|
|
|
|
var entManager = server.ResolveDependency<IEntityManager>();
|
|
var mapLoader = entManager.System<MapLoaderSystem>();
|
|
var mapSystem = entManager.System<SharedMapSystem>();
|
|
var mapManager = server.ResolveDependency<IMapManager>();
|
|
var cfg = server.ResolveDependency<IConfigurationManager>();
|
|
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
|
|
|
await server.WaitPost(() =>
|
|
{
|
|
mapSystem.CreateMap(out var mapId);
|
|
try
|
|
{
|
|
#pragma warning disable NUnit2045
|
|
Assert.That(mapLoader.TryLoad(mapId, mapFile, out var roots));
|
|
Assert.That(roots.Where(uid => entManager.HasComponent<MapGridComponent>(uid)), Is.Not.Empty);
|
|
#pragma warning restore NUnit2045
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to load map {mapFile}, was it saved as a map instead of a grid?", ex);
|
|
}
|
|
|
|
try
|
|
{
|
|
mapManager.DeleteMap(mapId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to delete map {mapFile}", ex);
|
|
}
|
|
});
|
|
await server.WaitRunTicks(1);
|
|
|
|
await pair.CleanReturnAsync();
|
|
}
|
|
|
|
[Test]
|
|
public async Task NoSavedPostMapInitTest()
|
|
{
|
|
await using var pair = await PoolManager.GetServerClient();
|
|
var server = pair.Server;
|
|
|
|
var resourceManager = server.ResolveDependency<IResourceManager>();
|
|
var mapFolder = new ResPath("/Maps");
|
|
var maps = resourceManager
|
|
.ContentFindFiles(mapFolder)
|
|
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith(".", StringComparison.Ordinal))
|
|
.ToArray();
|
|
|
|
foreach (var map in maps)
|
|
{
|
|
var rootedPath = map.ToRootedPath();
|
|
|
|
// ReSharper disable once RedundantLogicalConditionalExpressionOperand
|
|
if (SkipTestMaps && rootedPath.ToString().StartsWith(TestMapsPath, StringComparison.Ordinal))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!resourceManager.TryContentFileRead(rootedPath, out var fileStream))
|
|
{
|
|
Assert.Fail($"Map not found: {rootedPath}");
|
|
}
|
|
|
|
using var reader = new StreamReader(fileStream);
|
|
var yamlStream = new YamlStream();
|
|
|
|
yamlStream.Load(reader);
|
|
|
|
var root = yamlStream.Documents[0].RootNode;
|
|
var meta = root["meta"];
|
|
var postMapInit = meta["postmapinit"].AsBool();
|
|
|
|
Assert.That(postMapInit, Is.False, $"Map {map.Filename} was saved postmapinit");
|
|
}
|
|
await pair.CleanReturnAsync();
|
|
}
|
|
|
|
[Test, TestCaseSource(nameof(GameMaps))]
|
|
public async Task GameMapsLoadableTest(string mapProto)
|
|
{
|
|
await using var pair = await PoolManager.GetServerClient(new PoolSettings
|
|
{
|
|
Dirty = true // Stations spawn a bunch of nullspace entities and maps like centcomm.
|
|
});
|
|
var server = pair.Server;
|
|
|
|
var mapManager = server.ResolveDependency<IMapManager>();
|
|
var entManager = server.ResolveDependency<IEntityManager>();
|
|
var mapLoader = entManager.System<MapLoaderSystem>();
|
|
var mapSystem = entManager.System<SharedMapSystem>();
|
|
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
|
var ticker = entManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
|
var shuttleSystem = entManager.EntitySysManager.GetEntitySystem<ShuttleSystem>();
|
|
var xformQuery = entManager.GetEntityQuery<TransformComponent>();
|
|
var cfg = server.ResolveDependency<IConfigurationManager>();
|
|
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
|
|
|
await server.WaitPost(() =>
|
|
{
|
|
mapSystem.CreateMap(out var mapId);
|
|
try
|
|
{
|
|
ticker.LoadGameMap(protoManager.Index<GameMapPrototype>(mapProto), mapId, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to load map {mapProto}", ex);
|
|
}
|
|
|
|
mapSystem.CreateMap(out var shuttleMap);
|
|
var largest = 0f;
|
|
EntityUid? targetGrid = null;
|
|
var memberQuery = entManager.GetEntityQuery<StationMemberComponent>();
|
|
|
|
var grids = mapManager.GetAllGrids(mapId).ToList();
|
|
var gridUids = grids.Select(o => o.Owner).ToList();
|
|
targetGrid = gridUids.First();
|
|
|
|
foreach (var grid in grids)
|
|
{
|
|
var gridEnt = grid.Owner;
|
|
if (!memberQuery.HasComponent(gridEnt))
|
|
continue;
|
|
|
|
var area = grid.Comp.LocalAABB.Width * grid.Comp.LocalAABB.Height;
|
|
|
|
if (area > largest)
|
|
{
|
|
largest = area;
|
|
targetGrid = gridEnt;
|
|
}
|
|
}
|
|
|
|
// 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<StationMemberComponent>(targetGrid!.Value).Station;
|
|
if (entManager.TryGetComponent<StationEmergencyShuttleComponent>(station, out var stationEvac))
|
|
{
|
|
var shuttlePath = stationEvac.EmergencyShuttlePath;
|
|
#pragma warning disable NUnit2045
|
|
Assert.That(mapLoader.TryLoad(shuttleMap, shuttlePath.ToString(), out var roots));
|
|
EntityUid shuttle = default!;
|
|
Assert.DoesNotThrow(() =>
|
|
{
|
|
shuttle = roots.First(uid => entManager.HasComponent<MapGridComponent>(uid));
|
|
}, $"Failed to load {shuttlePath}");
|
|
Assert.That(
|
|
shuttleSystem.TryFTLDock(shuttle,
|
|
entManager.GetComponent<ShuttleComponent>(shuttle), targetGrid.Value),
|
|
$"Unable to dock {shuttlePath} to {mapProto}");
|
|
#pragma warning restore NUnit2045
|
|
}
|
|
|
|
mapManager.DeleteMap(shuttleMap);
|
|
|
|
if (entManager.HasComponent<StationJobsComponent>(station))
|
|
{
|
|
// Test that the map has valid latejoin spawn points or container spawn points
|
|
if (!NoSpawnMaps.Contains(mapProto))
|
|
{
|
|
var lateSpawns = 0;
|
|
|
|
lateSpawns += GetCountLateSpawn<SpawnPointComponent>(gridUids, entManager);
|
|
lateSpawns += GetCountLateSpawn<ContainerSpawnPointComponent>(gridUids, entManager);
|
|
|
|
Assert.That(lateSpawns, Is.GreaterThan(0), $"Found no latejoin spawn points on {mapProto}");
|
|
}
|
|
|
|
var comp = entManager.GetComponent<StationJobsComponent>(station);
|
|
var jobs = new HashSet<string>(comp.SetupAvailableJobs.Keys);
|
|
|
|
// Test all availableJobs have spawnPoints
|
|
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
|
var spawnPoints = entManager.EntityQuery<SpawnPointComponent>()
|
|
.Where(x => x.SpawnType == SpawnPointType.Job)
|
|
.Select(x => x.Job!.ID);
|
|
|
|
jobs.ExceptWith(spawnPoints);
|
|
|
|
foreach (var jobId in jobs)
|
|
{
|
|
var exists = protoManager.TryIndex<JobPrototype>(jobId, out var jobPrototype);
|
|
|
|
if (!exists)
|
|
continue;
|
|
|
|
if (jobPrototype.JobEntity != null)
|
|
jobs.Remove(jobId);
|
|
}
|
|
|
|
Assert.That(jobs, Is.Empty, $"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}.");
|
|
}
|
|
|
|
try
|
|
{
|
|
mapManager.DeleteMap(mapId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to delete map {mapProto}", ex);
|
|
}
|
|
});
|
|
await server.WaitRunTicks(1);
|
|
|
|
await pair.CleanReturnAsync();
|
|
}
|
|
|
|
|
|
|
|
private static int GetCountLateSpawn<T>(List<EntityUid> gridUids, IEntityManager entManager)
|
|
where T : ISpawnPoint, IComponent
|
|
{
|
|
var resultCount = 0;
|
|
var queryPoint = entManager.AllEntityQueryEnumerator<T, TransformComponent>();
|
|
#nullable enable
|
|
while (queryPoint.MoveNext(out T? comp, out var xform))
|
|
{
|
|
var spawner = (ISpawnPoint) comp;
|
|
|
|
if (spawner.SpawnType is not SpawnPointType.LateJoin
|
|
|| xform.GridUid == null
|
|
|| !gridUids.Contains(xform.GridUid.Value))
|
|
{
|
|
continue;
|
|
}
|
|
#nullable disable
|
|
resultCount++;
|
|
break;
|
|
}
|
|
|
|
return resultCount;
|
|
}
|
|
|
|
[Test]
|
|
public async Task AllMapsTested()
|
|
{
|
|
await using var pair = await PoolManager.GetServerClient();
|
|
var server = pair.Server;
|
|
var protoMan = server.ResolveDependency<IPrototypeManager>();
|
|
|
|
var gameMaps = protoMan.EnumeratePrototypes<GameMapPrototype>()
|
|
.Where(x => !pair.IsTestPrototype(x))
|
|
.Select(x => x.ID)
|
|
.ToHashSet();
|
|
|
|
Assert.That(gameMaps.Remove(PoolManager.TestMap));
|
|
|
|
Assert.That(gameMaps, Is.EquivalentTo(GameMaps.ToHashSet()), "Game map prototype missing from test cases.");
|
|
|
|
await pair.CleanReturnAsync();
|
|
}
|
|
|
|
[Test]
|
|
public async Task NonGameMapsLoadableTest()
|
|
{
|
|
await using var pair = await PoolManager.GetServerClient();
|
|
var server = pair.Server;
|
|
|
|
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
|
|
var mapManager = server.ResolveDependency<IMapManager>();
|
|
var resourceManager = server.ResolveDependency<IResourceManager>();
|
|
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
|
var cfg = server.ResolveDependency<IConfigurationManager>();
|
|
var mapSystem = server.System<SharedMapSystem>();
|
|
Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
|
|
|
|
var gameMaps = protoManager.EnumeratePrototypes<GameMapPrototype>().Select(o => o.MapPath).ToHashSet();
|
|
|
|
var mapFolder = new ResPath("/Maps");
|
|
var maps = resourceManager
|
|
.ContentFindFiles(mapFolder)
|
|
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith(".", StringComparison.Ordinal))
|
|
.ToArray();
|
|
|
|
var mapNames = new List<string>();
|
|
foreach (var map in maps)
|
|
{
|
|
if (gameMaps.Contains(map))
|
|
continue;
|
|
|
|
var rootedPath = map.ToRootedPath();
|
|
if (SkipTestMaps && rootedPath.ToString().StartsWith(TestMapsPath, StringComparison.Ordinal))
|
|
{
|
|
continue;
|
|
}
|
|
mapNames.Add(rootedPath.ToString());
|
|
}
|
|
|
|
await server.WaitPost(() =>
|
|
{
|
|
Assert.Multiple(() =>
|
|
{
|
|
foreach (var mapName in mapNames)
|
|
{
|
|
mapSystem.CreateMap(out var mapId);
|
|
try
|
|
{
|
|
Assert.That(mapLoader.TryLoad(mapId, mapName, out _));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to load map {mapName}", ex);
|
|
}
|
|
|
|
try
|
|
{
|
|
mapManager.DeleteMap(mapId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception($"Failed to delete map {mapName}", ex);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
await server.WaitRunTicks(1);
|
|
await pair.CleanReturnAsync();
|
|
}
|
|
}
|
|
}
|