diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index 569e279ef4..391ac2bae8 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -484,7 +484,7 @@ namespace Content.IntegrationTests.Tests.Power supplier.MaxSupply = draw/2; supplier.SupplyRampRate = rampRate; supplier.SupplyRampTolerance = rampTol; - + battery.MaxCharge = 100_000; battery.CurrentCharge = 100_000; netBattery.MaxSupply = draw/2; @@ -817,7 +817,7 @@ namespace Content.IntegrationTests.Tests.Power /// /// Checks that if there is insufficient supply to meet demand, generators will run at full power instead of - /// having generators and batteries sharing the load. + /// having generators and batteries sharing the load. /// [Test] public async Task TestSupplyPrioritized() @@ -1189,28 +1189,37 @@ namespace Content.IntegrationTests.Tests.Power var extensionCableSystem = entityManager.EntitySysManager.GetEntitySystem(); PowerNetworkBatteryComponent apcNetBattery = default!; ApcPowerReceiverComponent receiver = default!; + ApcPowerReceiverComponent unpoweredReceiver = default!; await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + const int range = 5; + // Power only works when anchored - for (var i = 0; i < 3; i++) + for (var i = 0; i < range; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); } var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.ToCoordinates(0, 0)); var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", grid.ToCoordinates(0, 0)); - var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, 2)); + // Create a powered receiver in range (range is 0 indexed) + var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range - 1)); receiver = entityManager.GetComponent(powerReceiverEnt); + + // Create an unpowered receiver outside range + var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range)); + unpoweredReceiver = entityManager.GetComponent(unpoweredReceiverEnt); + var battery = entityManager.GetComponent(apcEnt); apcNetBattery = entityManager.GetComponent(apcEnt); - extensionCableSystem.SetProviderTransferRange(apcExtensionEnt, 5); - extensionCableSystem.SetReceiverReceptionRange(powerReceiverEnt, 5); + extensionCableSystem.SetProviderTransferRange(apcExtensionEnt, range); + extensionCableSystem.SetReceiverReceptionRange(powerReceiverEnt, range); battery.MaxCharge = 10000; //arbitrary nonzero amount of charge battery.CurrentCharge = battery.MaxCharge; //fill battery @@ -1220,13 +1229,17 @@ namespace Content.IntegrationTests.Tests.Power server.RunTicks(1); //let run a tick for ApcNet to process power - await server.WaitAssertion(() => - { - Assert.That(receiver.Powered); - Assert.That(apcNetBattery.CurrentSupply, Is.EqualTo(1).Within(0.1)); + await server.WaitAssertion(() => { + Assert.Multiple(() => + { + Assert.That(receiver.Powered, "Receiver in range should be powered"); + Assert.That(!unpoweredReceiver.Powered, "Out of range receiver should not be powered"); + Assert.That(apcNetBattery.CurrentSupply, Is.EqualTo(1).Within(0.1)); + }); }); await pairTracker.CleanReturnAsync(); } + } } diff --git a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs index 23bad50dea..143192a811 100644 --- a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs +++ b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Server.Power.Components; using Robust.Shared.Map; using Robust.Shared.Physics; @@ -247,24 +248,42 @@ namespace Content.Server.Power.EntitySystems var coordinates = xform.Coordinates; var nearbyEntities = grid.GetCellsInSquareArea(coordinates, (int) Math.Ceiling(range / grid.TileSize)); + var cableQuery = GetEntityQuery(); + var metaQuery = GetEntityQuery(); + var xformQuery = GetEntityQuery(); + ExtensionCableProviderComponent? closestCandidate = null; + var closestDistanceFound = float.MaxValue; foreach (var entity in nearbyEntities) { - if (entity == owner || !EntityManager.TryGetComponent(entity, out var provider)) continue; + if (entity == owner || !cableQuery.TryGetComponent(entity, out var provider) || !provider.Connectable) + continue; - if (EntityManager.IsQueuedForDeletion(entity)) continue; + if (EntityManager.IsQueuedForDeletion(entity)) + continue; - if (MetaData(entity).EntityLifeStage > EntityLifeStage.MapInitialized) continue; + if (!metaQuery.TryGetComponent(entity, out var meta) || meta.EntityLifeStage > EntityLifeStage.MapInitialized) + continue; - if (!provider.Connectable) continue; + // Find the closest provider + if (!xformQuery.TryGetComponent(entity, out var entityXform)) + continue; + var distance = (entityXform.LocalPosition - xform.LocalPosition).Length; + if (distance >= closestDistanceFound) + continue; - if ((Transform(entity).LocalPosition - xform.LocalPosition).Length > Math.Min(range, provider.TransferRange)) continue; + closestCandidate = provider; + closestDistanceFound = distance; + } - foundProvider = provider; + // Make sure the provider is in range before claiming success + if (closestCandidate != null && closestDistanceFound <= Math.Min(range, closestCandidate.TransferRange)) + { + foundProvider = closestCandidate; return true; } - foundProvider = default; + foundProvider = null; return false; }