diff --git a/Content.IntegrationTests/Pair/TestPair.Timing.cs b/Content.IntegrationTests/Pair/TestPair.Timing.cs
index 3487ea6801..e0859660d4 100644
--- a/Content.IntegrationTests/Pair/TestPair.Timing.cs
+++ b/Content.IntegrationTests/Pair/TestPair.Timing.cs
@@ -1,5 +1,4 @@
#nullable enable
-using Robust.Shared.Timing;
namespace Content.IntegrationTests.Pair;
@@ -19,6 +18,22 @@ public sealed partial class TestPair
}
}
+ ///
+ /// Convert a time interval to some number of ticks.
+ ///
+ public int SecondsToTicks(float seconds)
+ {
+ return (int) Math.Ceiling(seconds / Server.Timing.TickPeriod.TotalSeconds);
+ }
+
+ ///
+ /// Run the server & client in sync for some amount of time
+ ///
+ public async Task RunSeconds(float seconds)
+ {
+ await RunTicksSync(SecondsToTicks(seconds));
+ }
+
///
/// Runs the server-client pair in sync, but also ensures they are both idle each tick.
///
@@ -59,4 +74,4 @@ public sealed partial class TestPair
delta = cTick - sTick;
Assert.That(delta, Is.EqualTo(targetDelta));
}
-}
\ No newline at end of file
+}
diff --git a/Content.IntegrationTests/PoolManager.Cvars.cs b/Content.IntegrationTests/PoolManager.Cvars.cs
index 327ec627f5..d39c7284d0 100644
--- a/Content.IntegrationTests/PoolManager.Cvars.cs
+++ b/Content.IntegrationTests/PoolManager.Cvars.cs
@@ -32,6 +32,7 @@ public static partial class PoolManager
(CCVars.GameLobbyEnabled.Name, "false"),
(CCVars.ConfigPresetDevelopment.Name, "false"),
(CCVars.AdminLogsEnabled.Name, "false"),
+ (CCVars.AutosaveEnabled.Name, "false"),
(CVars.NetBufferSize.Name, "0")
};
diff --git a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs
new file mode 100644
index 0000000000..5833db0a10
--- /dev/null
+++ b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs
@@ -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
+{
+ ///
+ /// Check that a nuke ops game mode can start without issue. I.e., that the nuke station and such all get loaded.
+ ///
+ [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();
+ var ticker = server.System();
+ var mindSys = server.System();
+ var roleSys = server.System();
+ var invSys = server.System();
+ var factionSys = server.System();
+
+ 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(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+
+ // And no nukie related components
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), Is.Zero);
+ Assert.That(entMan.Count(), 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(), Is.GreaterThan(0));
+ Assert.That(entMan.Count(), Is.GreaterThan(0));
+ Assert.That(entMan.Count(), Is.EqualTo(2)); // The main station & nukie station
+ Assert.That(entMan.Count(), Is.GreaterThan(3)); // Each station has at least 1 grid, plus some shuttles
+ Assert.That(entMan.Count(), Is.EqualTo(1));
+
+ // And we now have nukie related components
+ Assert.That(entMan.Count(), Is.EqualTo(1));
+ Assert.That(entMan.Count(), Is.EqualTo(1));
+ Assert.That(entMan.Count(), Is.EqualTo(1));
+ Assert.That(entMan.Count(), Is.EqualTo(1));
+
+ // The player entity should be the nukie commander
+ var mind = mindSys.GetMind(player)!.Value;
+ Assert.That(entMan.HasComponent(player));
+ Assert.That(roleSys.MindIsAntagonist(mind));
+ Assert.That(roleSys.MindHasRole(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().Single().Component;
+ Assert.That(entMan.EntityExists(rule.NukieOutpost));
+ Assert.That(entMan.EntityExists(rule.NukieShuttle));
+ Assert.That(entMan.EntityExists(rule.TargetStation));
+
+ Assert.That(entMan.HasComponent(rule.NukieOutpost));
+ Assert.That(entMan.HasComponent(rule.NukieShuttle));
+
+ Assert.That(entMan.HasComponent(rule.NukieOutpost));
+ Assert.That(entMan.HasComponent(rule.TargetStation));
+
+ var nukieStation = entMan.GetComponent(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(rule.TargetStation!.Value);
+ var targetGrid = targetStation.Grids.First();
+ var targetMap = entMan.GetComponent(targetGrid).MapUid!.Value;
+ Assert.That(targetMap, Is.Not.EqualTo(nukieMap));
+
+ Assert.That(entMan.GetComponent(player).MapUid, Is.EqualTo(nukieMap));
+ Assert.That(entMan.GetComponent(rule.NukieOutpost!.Value).MapUid, Is.EqualTo(nukieMap));
+ Assert.That(entMan.GetComponent(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(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(player));
+ Assert.That(entMan.GetComponent(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(player);
+ var damage = entMan.GetComponent(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();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs
index 1e3f9c9854..0707bd64c6 100644
--- a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs
+++ b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs
@@ -19,6 +19,9 @@ namespace Content.IntegrationTests.Tests.GameRules
await using var pair = await PoolManager.GetServerClient(new PoolSettings { InLobby = true });
var server = pair.Server;
+ Assert.That(server.EntMan.Count(), Is.Zero);
+ Assert.That(server.EntMan.Count(), Is.Zero);
+
var entityManager = server.ResolveDependency();
var sGameTicker = server.ResolveDependency().GetEntitySystem();
var sGameTiming = server.ResolveDependency();
@@ -26,6 +29,9 @@ namespace Content.IntegrationTests.Tests.GameRules
sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity);
Assert.That(entityManager.TryGetComponent(ruleEntity, out var maxTime));
+ Assert.That(server.EntMan.Count(), Is.EqualTo(1));
+ Assert.That(server.EntMan.Count(), Is.EqualTo(1));
+
await server.WaitAssertion(() =>
{
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
@@ -33,6 +39,9 @@ namespace Content.IntegrationTests.Tests.GameRules
sGameTicker.StartRound();
});
+ Assert.That(server.EntMan.Count(), Is.EqualTo(1));
+ Assert.That(server.EntMan.Count(), Is.EqualTo(1));
+
await server.WaitAssertion(() =>
{
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs
index 480fd9cde6..d45290c866 100644
--- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs
+++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs
@@ -767,14 +767,9 @@ public abstract partial class InteractionTest
await Pair.RunTicksSync(ticks);
}
- protected int SecondsToTicks(float seconds)
- {
- return (int) Math.Ceiling(seconds / TickPeriod);
- }
-
protected async Task RunSeconds(float seconds)
{
- await RunTicks(SecondsToTicks(seconds));
+ await Pair.RunSeconds(seconds);
}
#endregion
diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs
index a4ed31e998..42f64b344c 100644
--- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs
+++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs
@@ -12,7 +12,6 @@ using Content.Shared.Body.Part;
using Content.Shared.DoAfter;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
-using Content.Server.Item;
using Content.Shared.Mind;
using Content.Shared.Players;
using Robust.Client.Input;
diff --git a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs
new file mode 100644
index 0000000000..287e30eb8b
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs
@@ -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
+{
+ ///
+ /// Checks that the mapping command creates paused & uninitialized maps.
+ ///
+ [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();
+
+ 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();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs b/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs
index 5750be09c2..532e481ac2 100644
--- a/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs
+++ b/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs
@@ -28,10 +28,11 @@ public sealed class EvacShuttleTest
// Dummy ticker tests should not have centcomm
Assert.That(entMan.Count(), Is.Zero);
- var shuttleEnabled = pair.Server.CfgMan.GetCVar(CCVars.EmergencyShuttleEnabled);
- pair.Server.CfgMan.SetCVar(CCVars.GameMap, "Saltern");
- pair.Server.CfgMan.SetCVar(CCVars.GameDummyTicker, false);
+ Assert.That(pair.Server.CfgMan.GetCVar(CCVars.GridFill), Is.False);
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 pair.RunTicksSync(25);
@@ -71,6 +72,20 @@ public sealed class EvacShuttleTest
Assert.That(shuttleXform.MapUid, Is.Not.Null);
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
+ // All of these should have been map-initialized.
+ var mapSys = entMan.System();
+ 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(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
var evacSys = server.System();
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);
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.
await pair.WaitCommand("callshuttle 0:02");
- await RunSeconds(3);
+ await pair.RunSeconds(3);
// Shuttle should have arrived on the station
Assert.That(shuttleXform.MapUid, Is.EqualTo(salternXform.MapUid));
- await RunSeconds(2);
+ await pair.RunSeconds(2);
// Shuttle should be FTLing back to centcomm
Assert.That(entMan.Count(), Is.EqualTo(1));
@@ -101,14 +112,15 @@ public sealed class EvacShuttleTest
Assert.That(shuttleXform.MapUid, Is.EqualTo(ftl.Owner));
// Shuttle should have arrived at centcomm
- await RunSeconds(ShuttleSystem.DefaultTravelTime);
+ await pair.RunSeconds(ShuttleSystem.DefaultTravelTime);
Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap));
// Round should be ending now
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PostRound));
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();
}
}
diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs
index 4290726cc4..fe53ea268c 100644
--- a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs
+++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs
@@ -253,6 +253,8 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
{
var name = Identity.Name(uid, EntityManager);
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);
if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id)
diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs
index b97a16ab99..a1946d34a0 100644
--- a/Content.Server/GameTicking/GameTicker.GamePreset.cs
+++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs
@@ -100,7 +100,7 @@ namespace Content.Server.GameTicking
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!
if (DummyTicker)
diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
index 202daf256d..792d838169 100644
--- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs
+++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
@@ -165,7 +165,7 @@ namespace Content.Server.GameTicking
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();
RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName));
diff --git a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs
index c66a9d12a1..8f11e70560 100644
--- a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs
+++ b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs
@@ -6,11 +6,7 @@ using Content.Shared.NPC.Prototypes;
using Content.Shared.Roles;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations;
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;
@@ -116,13 +112,14 @@ public sealed partial class NukeopsRuleComponent : Component
[DataField]
public List WinConditions = new ();
- public MapId? NukiePlanet;
-
+ // TODO full game save
// 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.
+ // Whenever this gets fixed, update NukiesTest.
public EntityUid? NukieOutpost;
public EntityUid? NukieShuttle;
public EntityUid? TargetStation;
+ public MapId? NukiePlanet;
///
/// Data to be used in for an operative once the Mind has been added.
@@ -131,7 +128,7 @@ public sealed partial class NukeopsRuleComponent : Component
public Dictionary OperativeMindPendingData = new();
[DataField(required: true)]
- public ProtoId Faction = default!;
+ public ProtoId Faction;
[DataField]
public NukeopSpawnPreset CommanderSpawnDetails = new() { AntagRoleProto = "NukeopsCommander", GearProto = "SyndicateCommanderGearFull", NamePrefix = "nukeops-role-commander", NameList = "SyndicateNamesElite" };
diff --git a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs
index e792a004df..2522ebb53b 100644
--- a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs
+++ b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs
@@ -33,6 +33,7 @@ public sealed class MaxTimeRestartRuleSystem : GameRuleSystem TimerFired(component), component.TimerCancel.Token);
@@ -49,6 +50,7 @@ public sealed class MaxTimeRestartRuleSystem : GameRuleSystem GameTicker.RestartRound());
}
diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs
index 08f3dcccf9..46534f7059 100644
--- a/Content.Server/Mapping/MappingCommand.cs
+++ b/Content.Server/Mapping/MappingCommand.cs
@@ -53,7 +53,7 @@ namespace Content.Server.Mapping
}
#if DEBUG
- shell.WriteError(Loc.GetString("cmd-mapping-warning"));
+ shell.WriteLine(Loc.GetString("cmd-mapping-warning"));
#endif
MapId mapId;
diff --git a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs
index 67f50d7a4e..58c4c876c5 100644
--- a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs
+++ b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs
@@ -211,7 +211,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
///
public uint? GetRecordByName(EntityUid station, string name, StationRecordsComponent? records = null)
{
- if (!Resolve(station, ref records))
+ if (!Resolve(station, ref records, false))
return null;
foreach (var (id, record) in GetRecordsOfType(station, records))
diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs
index e8053e4c67..c25ac1968d 100644
--- a/Content.Shared/Roles/SharedRoleSystem.cs
+++ b/Content.Shared/Roles/SharedRoleSystem.cs
@@ -137,11 +137,13 @@ public abstract class SharedRoleSystem : EntitySystem
public bool MindHasRole(EntityUid mindId) where T : IComponent
{
+ DebugTools.Assert(HasComp(mindId));
return HasComp(mindId);
}
public List MindGetAllRoles(EntityUid mindId)
{
+ DebugTools.Assert(HasComp(mindId));
var ev = new MindGetAllRolesEvent(new List());
RaiseLocalEvent(mindId, ref ev);
return ev.Roles;
@@ -152,6 +154,7 @@ public abstract class SharedRoleSystem : EntitySystem
if (mindId == null)
return false;
+ DebugTools.Assert(HasComp(mindId));
var ev = new MindIsAntagonistEvent();
RaiseLocalEvent(mindId.Value, ref ev);
return ev.IsAntagonist;