]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add basic test of station initial power supply (#29698)
authorTayrtahn <tayrtahn@gmail.com>
Sun, 1 Jun 2025 15:51:37 +0000 (11:51 -0400)
committerGitHub <noreply@github.com>
Sun, 1 Jun 2025 15:51:37 +0000 (11:51 -0400)
* Add basic test of station initial power supply

* Add info about stored power vs needed amount

* Update map list

* Get it compiling again

* Get it working again

* Only run if explicitly requested

* Fix merge

* We call 'em batteries

* Mark the test as dirty

Content.IntegrationTests/Tests/Power/StationPowerTests.cs [new file with mode: 0644]

diff --git a/Content.IntegrationTests/Tests/Power/StationPowerTests.cs b/Content.IntegrationTests/Tests/Power/StationPowerTests.cs
new file mode 100644 (file)
index 0000000..c9f9498
--- /dev/null
@@ -0,0 +1,105 @@
+using System.Collections.Generic;
+using System.Linq;
+using Content.Server.GameTicking;
+using Content.Server.Maps;
+using Content.Server.Power.Components;
+using Content.Server.Power.NodeGroups;
+using Content.Server.Power.Pow3r;
+using Content.Shared.NodeContainer;
+using Robust.Shared.EntitySerialization;
+
+namespace Content.IntegrationTests.Tests.Power;
+
+[Explicit]
+public sealed class StationPowerTests
+{
+    /// <summary>
+    /// How long the station should be able to survive on stored power if nothing is changed from round start.
+    /// </summary>
+    private const float MinimumPowerDurationSeconds = 10 * 60;
+
+    private static readonly string[] GameMaps =
+    [
+        "Fland",
+        "Meta",
+        "Packed",
+        "Omega",
+        "Bagel",
+        "Box",
+        "Core",
+        "Marathon",
+        "Saltern",
+        "Reach",
+        "Train",
+        "Oasis",
+        "Gate",
+        "Amber",
+        "Loop",
+        "Plasma",
+        "Elkridge",
+        "Convex",
+        "Relic",
+    ];
+
+    [Test, TestCaseSource(nameof(GameMaps))]
+    public async Task TestStationStartingPowerWindow(string mapProtoId)
+    {
+        await using var pair = await PoolManager.GetServerClient(new PoolSettings
+        {
+            Dirty = true,
+        });
+        var server = pair.Server;
+
+        var entMan = server.EntMan;
+        var protoMan = server.ProtoMan;
+        var ticker = entMan.System<GameTicker>();
+
+        // Load the map
+        await server.WaitAssertion(() =>
+        {
+            Assert.That(protoMan.TryIndex<GameMapPrototype>(mapProtoId, out var mapProto));
+            var opts = DeserializationOptions.Default with { InitializeMaps = true };
+            ticker.LoadGameMap(mapProto, out var mapId, opts);
+        });
+
+        // Let powernet set up
+        await server.WaitRunTicks(1);
+
+        // Find the power network with the greatest stored charge in its batteries.
+        // This keeps backup SMESes out of the calculation.
+        var networks = new Dictionary<PowerState.Network, float>();
+        var batteryQuery = entMan.EntityQueryEnumerator<PowerNetworkBatteryComponent, BatteryComponent, NodeContainerComponent>();
+        while (batteryQuery.MoveNext(out var uid, out _, out var battery, out var nodeContainer))
+        {
+            if (!nodeContainer.Nodes.TryGetValue("output", out var node))
+                continue;
+            if (node.NodeGroup is not IBasePowerNet group)
+                continue;
+            networks.TryGetValue(group.NetworkNode, out var charge);
+            networks[group.NetworkNode] = charge + battery.CurrentCharge;
+        }
+        var totalStartingCharge = networks.MaxBy(n => n.Value).Value;
+
+        // Find how much charge all the APC-connected devices would like to use per second.
+        var totalAPCLoad = 0f;
+        var receiverQuery = entMan.EntityQueryEnumerator<ApcPowerReceiverComponent>();
+        while (receiverQuery.MoveNext(out _, out var receiver))
+        {
+            totalAPCLoad += receiver.Load;
+        }
+
+        var estimatedDuration = totalStartingCharge / totalAPCLoad;
+        var requiredStoredPower = totalAPCLoad * MinimumPowerDurationSeconds;
+        Assert.Multiple(() =>
+        {
+            Assert.That(estimatedDuration, Is.GreaterThanOrEqualTo(MinimumPowerDurationSeconds),
+                $"Initial power for {mapProtoId} does not last long enough! Needs at least {MinimumPowerDurationSeconds}s " +
+                $"but estimated to last only {estimatedDuration}s!");
+            Assert.That(totalStartingCharge, Is.GreaterThanOrEqualTo(requiredStoredPower),
+                $"Needs at least {requiredStoredPower - totalStartingCharge} more stored power!");
+        });
+
+
+        await pair.CleanReturnAsync();
+    }
+}