Add NukeOps Test (#27207)
* Add NukeOps Test * Update EvacShuttleTest to also check mapinit * Update RuleMaxTimeRestartTest * Fix cvar cleanup * A * Revert some changes * comments * Add MappingTests * Finally fix the test * A
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Pair;
|
namespace Content.IntegrationTests.Pair;
|
||||||
|
|
||||||
@@ -19,6 +18,22 @@ public sealed partial class TestPair
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a time interval to some number of ticks.
|
||||||
|
/// </summary>
|
||||||
|
public int SecondsToTicks(float seconds)
|
||||||
|
{
|
||||||
|
return (int) Math.Ceiling(seconds / Server.Timing.TickPeriod.TotalSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run the server & client in sync for some amount of time
|
||||||
|
/// </summary>
|
||||||
|
public async Task RunSeconds(float seconds)
|
||||||
|
{
|
||||||
|
await RunTicksSync(SecondsToTicks(seconds));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the server-client pair in sync, but also ensures they are both idle each tick.
|
/// Runs the server-client pair in sync, but also ensures they are both idle each tick.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public static partial class PoolManager
|
|||||||
(CCVars.GameLobbyEnabled.Name, "false"),
|
(CCVars.GameLobbyEnabled.Name, "false"),
|
||||||
(CCVars.ConfigPresetDevelopment.Name, "false"),
|
(CCVars.ConfigPresetDevelopment.Name, "false"),
|
||||||
(CCVars.AdminLogsEnabled.Name, "false"),
|
(CCVars.AdminLogsEnabled.Name, "false"),
|
||||||
|
(CCVars.AutosaveEnabled.Name, "false"),
|
||||||
(CVars.NetBufferSize.Name, "0")
|
(CVars.NetBufferSize.Name, "0")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
187
Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs
Normal file
187
Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Body.Components;
|
||||||
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.GameTicking.Presets;
|
||||||
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
|
using Content.Server.Mind;
|
||||||
|
using Content.Server.Pinpointer;
|
||||||
|
using Content.Server.Roles;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.NPC.Systems;
|
||||||
|
using Content.Shared.NukeOps;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Map.Components;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.GameRules;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public sealed class NukeOpsTest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Check that a nuke ops game mode can start without issue. I.e., that the nuke station and such all get loaded.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task TryStopNukeOpsFromConstantlyFailing()
|
||||||
|
{
|
||||||
|
await using var pair = await PoolManager.GetServerClient(new PoolSettings
|
||||||
|
{
|
||||||
|
Dirty = true,
|
||||||
|
DummyTicker = false,
|
||||||
|
Connected = true,
|
||||||
|
InLobby = true
|
||||||
|
});
|
||||||
|
|
||||||
|
var server = pair.Server;
|
||||||
|
var client = pair.Client;
|
||||||
|
var entMan = server.EntMan;
|
||||||
|
var mapSys = server.System<MapSystem>();
|
||||||
|
var ticker = server.System<GameTicker>();
|
||||||
|
var mindSys = server.System<MindSystem>();
|
||||||
|
var roleSys = server.System<RoleSystem>();
|
||||||
|
var invSys = server.System<InventorySystem>();
|
||||||
|
var factionSys = server.System<NpcFactionSystem>();
|
||||||
|
|
||||||
|
Assert.That(server.CfgMan.GetCVar(CCVars.GridFill), Is.False);
|
||||||
|
server.CfgMan.SetCVar(CCVars.GridFill, true);
|
||||||
|
|
||||||
|
// Initially in the lobby
|
||||||
|
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
||||||
|
Assert.That(client.AttachedEntity, Is.Null);
|
||||||
|
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay));
|
||||||
|
|
||||||
|
// There are no grids or maps
|
||||||
|
Assert.That(entMan.Count<MapComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<MapGridComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<StationMapComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<StationMemberComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<StationCentcommComponent>(), Is.Zero);
|
||||||
|
|
||||||
|
// And no nukie related components
|
||||||
|
Assert.That(entMan.Count<NukeopsRuleComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<NukeopsRoleComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<NukeOperativeComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<NukeOpsShuttleComponent>(), Is.Zero);
|
||||||
|
Assert.That(entMan.Count<NukeOperativeSpawnerComponent>(), Is.Zero);
|
||||||
|
|
||||||
|
// Ready up and start nukeops
|
||||||
|
await pair.WaitClientCommand("toggleready True");
|
||||||
|
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.ReadyToPlay));
|
||||||
|
await pair.WaitCommand("forcepreset Nukeops");
|
||||||
|
await pair.RunTicksSync(10);
|
||||||
|
|
||||||
|
// Game should have started
|
||||||
|
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
|
||||||
|
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.JoinedGame));
|
||||||
|
Assert.That(client.EntMan.EntityExists(client.AttachedEntity));
|
||||||
|
var player = pair.Player!.AttachedEntity!.Value;
|
||||||
|
Assert.That(entMan.EntityExists(player));
|
||||||
|
|
||||||
|
// Maps now exist
|
||||||
|
Assert.That(entMan.Count<MapComponent>(), Is.GreaterThan(0));
|
||||||
|
Assert.That(entMan.Count<MapGridComponent>(), Is.GreaterThan(0));
|
||||||
|
Assert.That(entMan.Count<StationDataComponent>(), Is.EqualTo(2)); // The main station & nukie station
|
||||||
|
Assert.That(entMan.Count<StationMemberComponent>(), Is.GreaterThan(3)); // Each station has at least 1 grid, plus some shuttles
|
||||||
|
Assert.That(entMan.Count<StationCentcommComponent>(), Is.EqualTo(1));
|
||||||
|
|
||||||
|
// And we now have nukie related components
|
||||||
|
Assert.That(entMan.Count<NukeopsRuleComponent>(), Is.EqualTo(1));
|
||||||
|
Assert.That(entMan.Count<NukeopsRoleComponent>(), Is.EqualTo(1));
|
||||||
|
Assert.That(entMan.Count<NukeOperativeComponent>(), Is.EqualTo(1));
|
||||||
|
Assert.That(entMan.Count<NukeOpsShuttleComponent>(), Is.EqualTo(1));
|
||||||
|
|
||||||
|
// The player entity should be the nukie commander
|
||||||
|
var mind = mindSys.GetMind(player)!.Value;
|
||||||
|
Assert.That(entMan.HasComponent<NukeOperativeComponent>(player));
|
||||||
|
Assert.That(roleSys.MindIsAntagonist(mind));
|
||||||
|
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
|
||||||
|
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
|
||||||
|
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
|
||||||
|
|
||||||
|
var roles = roleSys.MindGetAllRoles(mind);
|
||||||
|
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander" && x.Component is NukeopsRoleComponent);
|
||||||
|
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
|
||||||
|
|
||||||
|
// The game rule exists, and all the stations/shuttles/maps are properly initialized
|
||||||
|
var rule = entMan.AllComponents<NukeopsRuleComponent>().Single().Component;
|
||||||
|
Assert.That(entMan.EntityExists(rule.NukieOutpost));
|
||||||
|
Assert.That(entMan.EntityExists(rule.NukieShuttle));
|
||||||
|
Assert.That(entMan.EntityExists(rule.TargetStation));
|
||||||
|
|
||||||
|
Assert.That(entMan.HasComponent<MapGridComponent>(rule.NukieOutpost));
|
||||||
|
Assert.That(entMan.HasComponent<MapGridComponent>(rule.NukieShuttle));
|
||||||
|
|
||||||
|
Assert.That(entMan.HasComponent<StationMemberComponent>(rule.NukieOutpost));
|
||||||
|
Assert.That(entMan.HasComponent<StationDataComponent>(rule.TargetStation));
|
||||||
|
|
||||||
|
var nukieStation = entMan.GetComponent<StationMemberComponent>(rule.NukieOutpost!.Value);
|
||||||
|
Assert.That(entMan.EntityExists(nukieStation.Station));
|
||||||
|
Assert.That(nukieStation.Station, Is.Not.EqualTo(rule.TargetStation));
|
||||||
|
|
||||||
|
Assert.That(server.MapMan.MapExists(rule.NukiePlanet));
|
||||||
|
var nukieMap = mapSys.GetMap(rule.NukiePlanet!.Value);
|
||||||
|
|
||||||
|
var targetStation = entMan.GetComponent<StationDataComponent>(rule.TargetStation!.Value);
|
||||||
|
var targetGrid = targetStation.Grids.First();
|
||||||
|
var targetMap = entMan.GetComponent<TransformComponent>(targetGrid).MapUid!.Value;
|
||||||
|
Assert.That(targetMap, Is.Not.EqualTo(nukieMap));
|
||||||
|
|
||||||
|
Assert.That(entMan.GetComponent<TransformComponent>(player).MapUid, Is.EqualTo(nukieMap));
|
||||||
|
Assert.That(entMan.GetComponent<TransformComponent>(rule.NukieOutpost!.Value).MapUid, Is.EqualTo(nukieMap));
|
||||||
|
Assert.That(entMan.GetComponent<TransformComponent>(rule.NukieShuttle!.Value).MapUid, Is.EqualTo(nukieMap));
|
||||||
|
|
||||||
|
// The maps are all map-initialized, including the player
|
||||||
|
// Yes, this is necessary as this has repeatedly been broken somehow.
|
||||||
|
Assert.That(mapSys.IsInitialized(nukieMap));
|
||||||
|
Assert.That(mapSys.IsInitialized(targetMap));
|
||||||
|
Assert.That(mapSys.IsPaused(nukieMap), Is.False);
|
||||||
|
Assert.That(mapSys.IsPaused(targetMap), Is.False);
|
||||||
|
|
||||||
|
EntityLifeStage LifeStage(EntityUid? uid) => entMan.GetComponent<MetaDataComponent>(uid!.Value).EntityLifeStage;
|
||||||
|
Assert.That(LifeStage(player), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(LifeStage(nukieMap), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(LifeStage(targetMap), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(LifeStage(rule.NukieOutpost), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(LifeStage(rule.NukieShuttle), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(LifeStage(rule.TargetStation), Is.GreaterThan(EntityLifeStage.Initialized));
|
||||||
|
|
||||||
|
// Make sure the player has hands. We've had fucking disarmed nukies before.
|
||||||
|
Assert.That(entMan.HasComponent<HandsComponent>(player));
|
||||||
|
Assert.That(entMan.GetComponent<HandsComponent>(player).Hands.Count, Is.GreaterThan(0));
|
||||||
|
|
||||||
|
// While we're at it, lets make sure they aren't naked. I don't know how many inventory slots all mobs will be
|
||||||
|
// likely to have in the future. But nukies should probably have at least 3 slots with something in them.
|
||||||
|
var enumerator = invSys.GetSlotEnumerator(player);
|
||||||
|
int total = 0;
|
||||||
|
while (enumerator.NextItem(out _))
|
||||||
|
{
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
Assert.That(total, Is.GreaterThan(3));
|
||||||
|
|
||||||
|
// Finally lets check the nukie commander passed basic training and figured out how to breathe.
|
||||||
|
var totalSeconds = 30;
|
||||||
|
var totalTicks = (int) Math.Ceiling(totalSeconds / server.Timing.TickPeriod.TotalSeconds);
|
||||||
|
int increment = 5;
|
||||||
|
var resp = entMan.GetComponent<RespiratorComponent>(player);
|
||||||
|
var damage = entMan.GetComponent<DamageableComponent>(player);
|
||||||
|
for (var tick = 0; tick < totalTicks; tick += increment)
|
||||||
|
{
|
||||||
|
await pair.RunTicksSync(increment);
|
||||||
|
Assert.That(resp.SuffocationCycles, Is.LessThanOrEqualTo(resp.SuffocationCycleThreshold));
|
||||||
|
Assert.That(damage.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker.SetGamePreset((GamePresetPrototype?)null);
|
||||||
|
server.CfgMan.SetCVar(CCVars.GridFill, false);
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,9 @@ namespace Content.IntegrationTests.Tests.GameRules
|
|||||||
await using var pair = await PoolManager.GetServerClient(new PoolSettings { InLobby = true });
|
await using var pair = await PoolManager.GetServerClient(new PoolSettings { InLobby = true });
|
||||||
var server = pair.Server;
|
var server = pair.Server;
|
||||||
|
|
||||||
|
Assert.That(server.EntMan.Count<GameRuleComponent>(), Is.Zero);
|
||||||
|
Assert.That(server.EntMan.Count<ActiveGameRuleComponent>(), Is.Zero);
|
||||||
|
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
var sGameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
|
var sGameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
|
||||||
var sGameTiming = server.ResolveDependency<IGameTiming>();
|
var sGameTiming = server.ResolveDependency<IGameTiming>();
|
||||||
@@ -26,6 +29,9 @@ namespace Content.IntegrationTests.Tests.GameRules
|
|||||||
sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity);
|
sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity);
|
||||||
Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out var maxTime));
|
Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out var maxTime));
|
||||||
|
|
||||||
|
Assert.That(server.EntMan.Count<GameRuleComponent>(), Is.EqualTo(1));
|
||||||
|
Assert.That(server.EntMan.Count<ActiveGameRuleComponent>(), Is.EqualTo(1));
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
||||||
@@ -33,6 +39,9 @@ namespace Content.IntegrationTests.Tests.GameRules
|
|||||||
sGameTicker.StartRound();
|
sGameTicker.StartRound();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Assert.That(server.EntMan.Count<GameRuleComponent>(), Is.EqualTo(1));
|
||||||
|
Assert.That(server.EntMan.Count<ActiveGameRuleComponent>(), Is.EqualTo(1));
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
|
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
|
||||||
|
|||||||
@@ -767,14 +767,9 @@ public abstract partial class InteractionTest
|
|||||||
await Pair.RunTicksSync(ticks);
|
await Pair.RunTicksSync(ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int SecondsToTicks(float seconds)
|
|
||||||
{
|
|
||||||
return (int) Math.Ceiling(seconds / TickPeriod);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task RunSeconds(float seconds)
|
protected async Task RunSeconds(float seconds)
|
||||||
{
|
{
|
||||||
await RunTicks(SecondsToTicks(seconds));
|
await Pair.RunSeconds(seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ using Content.Shared.Body.Part;
|
|||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Server.Item;
|
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Players;
|
using Content.Shared.Players;
|
||||||
using Robust.Client.Input;
|
using Robust.Client.Input;
|
||||||
|
|||||||
102
Content.IntegrationTests/Tests/Mapping/MappingTests.cs
Normal file
102
Content.IntegrationTests/Tests/Mapping/MappingTests.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Mapping;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public sealed class MappingTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks that the mapping command creates paused & uninitialized maps.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task MappingTest()
|
||||||
|
{
|
||||||
|
await using var pair = await PoolManager.GetServerClient(new PoolSettings {Dirty = true, Connected = true, DummyTicker = false});
|
||||||
|
|
||||||
|
var server = pair.Server;
|
||||||
|
var entMan = server.EntMan;
|
||||||
|
var mapSys = server.System<MapSystem>();
|
||||||
|
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
var mapId = 1;
|
||||||
|
while (mapSys.MapExists(new(mapId)))
|
||||||
|
{
|
||||||
|
mapId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pair.WaitClientCommand($"mapping {mapId}");
|
||||||
|
var map = mapSys.GetMap(new MapId(mapId));
|
||||||
|
|
||||||
|
var mapXform = server.Transform(map);
|
||||||
|
Assert.That(mapXform.MapUid, Is.EqualTo(map));
|
||||||
|
Assert.That(mapXform.MapID, Is.EqualTo(new MapId(mapId)));
|
||||||
|
|
||||||
|
var xform = server.Transform(pair.Player!.AttachedEntity!.Value);
|
||||||
|
|
||||||
|
Assert.That(xform.MapUid, Is.EqualTo(map));
|
||||||
|
Assert.That(mapSys.IsInitialized(map), Is.False);
|
||||||
|
Assert.That(mapSys.IsPaused(map), Is.True);
|
||||||
|
Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(server.MetaData(map).EntityPaused, Is.True);
|
||||||
|
|
||||||
|
// Spawn a new entity
|
||||||
|
EntityUid ent = default;
|
||||||
|
await server.WaitPost(() =>
|
||||||
|
{
|
||||||
|
ent = entMan.Spawn(null, new MapCoordinates(default, new(mapId)));
|
||||||
|
});
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(server.MetaData(ent).EntityPaused, Is.True);
|
||||||
|
|
||||||
|
// Save the map
|
||||||
|
var file = $"{nameof(MappingTest)}.yml";
|
||||||
|
await pair.WaitClientCommand($"savemap {mapId} {file}");
|
||||||
|
|
||||||
|
// Mapinitialize it
|
||||||
|
await pair.WaitClientCommand($"mapinit {mapId}");
|
||||||
|
Assert.That(mapSys.IsInitialized(map), Is.True);
|
||||||
|
Assert.That(mapSys.IsPaused(map), Is.False);
|
||||||
|
Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(server.MetaData(map).EntityPaused, Is.False);
|
||||||
|
Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(server.MetaData(ent).EntityPaused, Is.False);
|
||||||
|
|
||||||
|
await server.WaitPost(() => entMan.DeleteEntity(map));
|
||||||
|
|
||||||
|
// Load the saved map
|
||||||
|
mapId++;
|
||||||
|
while (mapSys.MapExists(new(mapId)))
|
||||||
|
{
|
||||||
|
mapId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pair.WaitClientCommand($"mapping {mapId} {file}");
|
||||||
|
map = mapSys.GetMap(new MapId(mapId));
|
||||||
|
|
||||||
|
// And it should all be paused and un-initialized
|
||||||
|
xform = server.Transform(pair.Player!.AttachedEntity!.Value);
|
||||||
|
Assert.That(xform.MapUid, Is.EqualTo(map));
|
||||||
|
Assert.That(mapSys.IsInitialized(map), Is.False);
|
||||||
|
Assert.That(mapSys.IsPaused(map), Is.True);
|
||||||
|
Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(server.MetaData(map).EntityPaused, Is.True);
|
||||||
|
|
||||||
|
mapXform = server.Transform(map);
|
||||||
|
Assert.That(mapXform.MapUid, Is.EqualTo(map));
|
||||||
|
Assert.That(mapXform.MapID, Is.EqualTo(new MapId(mapId)));
|
||||||
|
Assert.That(mapXform.ChildCount, Is.EqualTo(2));
|
||||||
|
|
||||||
|
mapXform.ChildEnumerator.MoveNext(out ent);
|
||||||
|
if (ent == pair.Player.AttachedEntity)
|
||||||
|
mapXform.ChildEnumerator.MoveNext(out ent);
|
||||||
|
|
||||||
|
Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized));
|
||||||
|
Assert.That(server.MetaData(ent).EntityPaused, Is.True);
|
||||||
|
|
||||||
|
await server.WaitPost(() => entMan.DeleteEntity(map));
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,10 +28,11 @@ public sealed class EvacShuttleTest
|
|||||||
// Dummy ticker tests should not have centcomm
|
// Dummy ticker tests should not have centcomm
|
||||||
Assert.That(entMan.Count<StationCentcommComponent>(), Is.Zero);
|
Assert.That(entMan.Count<StationCentcommComponent>(), Is.Zero);
|
||||||
|
|
||||||
var shuttleEnabled = pair.Server.CfgMan.GetCVar(CCVars.EmergencyShuttleEnabled);
|
Assert.That(pair.Server.CfgMan.GetCVar(CCVars.GridFill), Is.False);
|
||||||
pair.Server.CfgMan.SetCVar(CCVars.GameMap, "Saltern");
|
|
||||||
pair.Server.CfgMan.SetCVar(CCVars.GameDummyTicker, false);
|
|
||||||
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, true);
|
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, true);
|
||||||
|
pair.Server.CfgMan.SetCVar(CCVars.GameDummyTicker, false);
|
||||||
|
var gameMap = pair.Server.CfgMan.GetCVar(CCVars.GameMap);
|
||||||
|
pair.Server.CfgMan.SetCVar(CCVars.GameMap, "Saltern");
|
||||||
|
|
||||||
await server.WaitPost(() => ticker.RestartRound());
|
await server.WaitPost(() => ticker.RestartRound());
|
||||||
await pair.RunTicksSync(25);
|
await pair.RunTicksSync(25);
|
||||||
@@ -71,6 +72,20 @@ public sealed class EvacShuttleTest
|
|||||||
Assert.That(shuttleXform.MapUid, Is.Not.Null);
|
Assert.That(shuttleXform.MapUid, Is.Not.Null);
|
||||||
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
|
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
|
||||||
|
|
||||||
|
// All of these should have been map-initialized.
|
||||||
|
var mapSys = entMan.System<SharedMapSystem>();
|
||||||
|
Assert.That(mapSys.IsInitialized(centcommMap), Is.True);
|
||||||
|
Assert.That(mapSys.IsInitialized(salternXform.MapUid), Is.True);
|
||||||
|
Assert.That(mapSys.IsPaused(centcommMap), Is.False);
|
||||||
|
Assert.That(mapSys.IsPaused(salternXform.MapUid!.Value), Is.False);
|
||||||
|
|
||||||
|
EntityLifeStage LifeStage(EntityUid uid) => entMan.GetComponent<MetaDataComponent>(uid).EntityLifeStage;
|
||||||
|
Assert.That(LifeStage(saltern), Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(LifeStage(shuttle), Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(LifeStage(centcomm), Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(LifeStage(centcommMap), Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
Assert.That(LifeStage(salternXform.MapUid.Value), Is.EqualTo(EntityLifeStage.MapInitialized));
|
||||||
|
|
||||||
// Set up shuttle timing
|
// Set up shuttle timing
|
||||||
var evacSys = server.System<EmergencyShuttleSystem>();
|
var evacSys = server.System<EmergencyShuttleSystem>();
|
||||||
evacSys.TransitTime = ShuttleSystem.DefaultTravelTime; // Absolute minimum transit time, so the test has to run for at least this long
|
evacSys.TransitTime = ShuttleSystem.DefaultTravelTime; // Absolute minimum transit time, so the test has to run for at least this long
|
||||||
@@ -78,19 +93,15 @@ public sealed class EvacShuttleTest
|
|||||||
|
|
||||||
var dockTime = server.CfgMan.GetCVar(CCVars.EmergencyShuttleDockTime);
|
var dockTime = server.CfgMan.GetCVar(CCVars.EmergencyShuttleDockTime);
|
||||||
server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, 2);
|
server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, 2);
|
||||||
async Task RunSeconds(float seconds)
|
|
||||||
{
|
|
||||||
await pair.RunTicksSync((int) Math.Ceiling(seconds / server.Timing.TickPeriod.TotalSeconds));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call evac shuttle.
|
// Call evac shuttle.
|
||||||
await pair.WaitCommand("callshuttle 0:02");
|
await pair.WaitCommand("callshuttle 0:02");
|
||||||
await RunSeconds(3);
|
await pair.RunSeconds(3);
|
||||||
|
|
||||||
// Shuttle should have arrived on the station
|
// Shuttle should have arrived on the station
|
||||||
Assert.That(shuttleXform.MapUid, Is.EqualTo(salternXform.MapUid));
|
Assert.That(shuttleXform.MapUid, Is.EqualTo(salternXform.MapUid));
|
||||||
|
|
||||||
await RunSeconds(2);
|
await pair.RunSeconds(2);
|
||||||
|
|
||||||
// Shuttle should be FTLing back to centcomm
|
// Shuttle should be FTLing back to centcomm
|
||||||
Assert.That(entMan.Count<FTLMapComponent>(), Is.EqualTo(1));
|
Assert.That(entMan.Count<FTLMapComponent>(), Is.EqualTo(1));
|
||||||
@@ -101,14 +112,15 @@ public sealed class EvacShuttleTest
|
|||||||
Assert.That(shuttleXform.MapUid, Is.EqualTo(ftl.Owner));
|
Assert.That(shuttleXform.MapUid, Is.EqualTo(ftl.Owner));
|
||||||
|
|
||||||
// Shuttle should have arrived at centcomm
|
// Shuttle should have arrived at centcomm
|
||||||
await RunSeconds(ShuttleSystem.DefaultTravelTime);
|
await pair.RunSeconds(ShuttleSystem.DefaultTravelTime);
|
||||||
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
|
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
|
||||||
|
|
||||||
// Round should be ending now
|
// Round should be ending now
|
||||||
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PostRound));
|
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PostRound));
|
||||||
|
|
||||||
server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, dockTime);
|
server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, dockTime);
|
||||||
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, shuttleEnabled);
|
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, false);
|
||||||
|
pair.Server.CfgMan.SetCVar(CCVars.GameMap, gameMap);
|
||||||
await pair.CleanReturnAsync();
|
await pair.CleanReturnAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,6 +253,8 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
{
|
{
|
||||||
var name = Identity.Name(uid, EntityManager);
|
var name = Identity.Name(uid, EntityManager);
|
||||||
var xform = Transform(uid);
|
var xform = Transform(uid);
|
||||||
|
|
||||||
|
// TODO use the entity's station? Not the station of the map that it happens to currently be on?
|
||||||
var station = _station.GetStationInMap(xform.MapID);
|
var station = _station.GetStationInMap(xform.MapID);
|
||||||
|
|
||||||
if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id)
|
if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace Content.Server.GameTicking
|
|||||||
SetGamePreset(LobbyEnabled ? _configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset) : "sandbox");
|
SetGamePreset(LobbyEnabled ? _configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset) : "sandbox");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGamePreset(GamePresetPrototype preset, bool force = false)
|
public void SetGamePreset(GamePresetPrototype? preset, bool force = false)
|
||||||
{
|
{
|
||||||
// Do nothing if this game ticker is a dummy!
|
// Do nothing if this game ticker is a dummy!
|
||||||
if (DummyTicker)
|
if (DummyTicker)
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
var gridIds = _map.LoadMap(targetMapId, ev.GameMap.MapPath.ToString(), ev.Options);
|
var gridIds = _map.LoadMap(targetMapId, ev.GameMap.MapPath.ToString(), ev.Options);
|
||||||
|
|
||||||
_metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), "Station map");
|
_metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), $"station map - {map.MapName}");
|
||||||
|
|
||||||
var gridUids = gridIds.ToList();
|
var gridUids = gridIds.ToList();
|
||||||
RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName));
|
RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName));
|
||||||
|
|||||||
@@ -6,11 +6,7 @@ using Content.Shared.NPC.Prototypes;
|
|||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules.Components;
|
namespace Content.Server.GameTicking.Rules.Components;
|
||||||
|
|
||||||
@@ -116,13 +112,14 @@ public sealed partial class NukeopsRuleComponent : Component
|
|||||||
[DataField]
|
[DataField]
|
||||||
public List<WinCondition> WinConditions = new ();
|
public List<WinCondition> WinConditions = new ();
|
||||||
|
|
||||||
public MapId? NukiePlanet;
|
// TODO full game save
|
||||||
|
|
||||||
// TODO: use components, don't just cache entity UIDs
|
// TODO: use components, don't just cache entity UIDs
|
||||||
// There have been (and probably still are) bugs where these refer to deleted entities from old rounds.
|
// There have been (and probably still are) bugs where these refer to deleted entities from old rounds.
|
||||||
|
// Whenever this gets fixed, update NukiesTest.
|
||||||
public EntityUid? NukieOutpost;
|
public EntityUid? NukieOutpost;
|
||||||
public EntityUid? NukieShuttle;
|
public EntityUid? NukieShuttle;
|
||||||
public EntityUid? TargetStation;
|
public EntityUid? TargetStation;
|
||||||
|
public MapId? NukiePlanet;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Data to be used in <see cref="OnMindAdded"/> for an operative once the Mind has been added.
|
/// Data to be used in <see cref="OnMindAdded"/> for an operative once the Mind has been added.
|
||||||
@@ -131,7 +128,7 @@ public sealed partial class NukeopsRuleComponent : Component
|
|||||||
public Dictionary<EntityUid, string> OperativeMindPendingData = new();
|
public Dictionary<EntityUid, string> OperativeMindPendingData = new();
|
||||||
|
|
||||||
[DataField(required: true)]
|
[DataField(required: true)]
|
||||||
public ProtoId<NpcFactionPrototype> Faction = default!;
|
public ProtoId<NpcFactionPrototype> Faction;
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public NukeopSpawnPreset CommanderSpawnDetails = new() { AntagRoleProto = "NukeopsCommander", GearProto = "SyndicateCommanderGearFull", NamePrefix = "nukeops-role-commander", NameList = "SyndicateNamesElite" };
|
public NukeopSpawnPreset CommanderSpawnDetails = new() { AntagRoleProto = "NukeopsCommander", GearProto = "SyndicateCommanderGearFull", NamePrefix = "nukeops-role-commander", NameList = "SyndicateNamesElite" };
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public sealed class MaxTimeRestartRuleSystem : GameRuleSystem<MaxTimeRestartRule
|
|||||||
|
|
||||||
public void RestartTimer(MaxTimeRestartRuleComponent component)
|
public void RestartTimer(MaxTimeRestartRuleComponent component)
|
||||||
{
|
{
|
||||||
|
// TODO FULL GAME SAVE
|
||||||
component.TimerCancel.Cancel();
|
component.TimerCancel.Cancel();
|
||||||
component.TimerCancel = new CancellationTokenSource();
|
component.TimerCancel = new CancellationTokenSource();
|
||||||
Timer.Spawn(component.RoundMaxTime, () => TimerFired(component), component.TimerCancel.Token);
|
Timer.Spawn(component.RoundMaxTime, () => TimerFired(component), component.TimerCancel.Token);
|
||||||
@@ -49,6 +50,7 @@ public sealed class MaxTimeRestartRuleSystem : GameRuleSystem<MaxTimeRestartRule
|
|||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-restarting-in-seconds",("seconds", (int) component.RoundEndDelay.TotalSeconds)));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-restarting-in-seconds",("seconds", (int) component.RoundEndDelay.TotalSeconds)));
|
||||||
|
|
||||||
|
// TODO FULL GAME SAVE
|
||||||
Timer.Spawn(component.RoundEndDelay, () => GameTicker.RestartRound());
|
Timer.Spawn(component.RoundEndDelay, () => GameTicker.RestartRound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Content.Server.Mapping
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
shell.WriteError(Loc.GetString("cmd-mapping-warning"));
|
shell.WriteLine(Loc.GetString("cmd-mapping-warning"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MapId mapId;
|
MapId mapId;
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public uint? GetRecordByName(EntityUid station, string name, StationRecordsComponent? records = null)
|
public uint? GetRecordByName(EntityUid station, string name, StationRecordsComponent? records = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(station, ref records))
|
if (!Resolve(station, ref records, false))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
foreach (var (id, record) in GetRecordsOfType<GeneralStationRecord>(station, records))
|
foreach (var (id, record) in GetRecordsOfType<GeneralStationRecord>(station, records))
|
||||||
|
|||||||
@@ -137,11 +137,13 @@ public abstract class SharedRoleSystem : EntitySystem
|
|||||||
|
|
||||||
public bool MindHasRole<T>(EntityUid mindId) where T : IComponent
|
public bool MindHasRole<T>(EntityUid mindId) where T : IComponent
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(HasComp<MindComponent>(mindId));
|
||||||
return HasComp<T>(mindId);
|
return HasComp<T>(mindId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RoleInfo> MindGetAllRoles(EntityUid mindId)
|
public List<RoleInfo> MindGetAllRoles(EntityUid mindId)
|
||||||
{
|
{
|
||||||
|
DebugTools.Assert(HasComp<MindComponent>(mindId));
|
||||||
var ev = new MindGetAllRolesEvent(new List<RoleInfo>());
|
var ev = new MindGetAllRolesEvent(new List<RoleInfo>());
|
||||||
RaiseLocalEvent(mindId, ref ev);
|
RaiseLocalEvent(mindId, ref ev);
|
||||||
return ev.Roles;
|
return ev.Roles;
|
||||||
@@ -152,6 +154,7 @@ public abstract class SharedRoleSystem : EntitySystem
|
|||||||
if (mindId == null)
|
if (mindId == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
DebugTools.Assert(HasComp<MindComponent>(mindId));
|
||||||
var ev = new MindIsAntagonistEvent();
|
var ev = new MindIsAntagonistEvent();
|
||||||
RaiseLocalEvent(mindId.Value, ref ev);
|
RaiseLocalEvent(mindId.Value, ref ev);
|
||||||
return ev.IsAntagonist;
|
return ev.IsAntagonist;
|
||||||
|
|||||||
Reference in New Issue
Block a user