--- /dev/null
+using Content.Shared.Coordinates;
+using Content.Shared.Power.Components;
+using Content.Shared.Power.EntitySystems;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Map;
+using Robust.Shared.Maths;
+
+namespace Content.IntegrationTests.Tests.Power;
+
+[TestFixture]
+public sealed class PowerStateTest
+{
+ [TestPrototypes]
+ private const string Prototypes = @"
+- type: entity
+ id: PowerStateApcReceiverDummy
+ components:
+ - type: ApcPowerReceiver
+ - type: ExtensionCableReceiver
+ - type: Transform
+ anchored: true
+ - type: PowerState
+ isWorking: false
+ idlePowerDraw: 10
+ workingPowerDraw: 50
+";
+
+ /// <summary>
+ /// Asserts that switching from idle to working updates the power receiver load to the working draw.
+ /// </summary>
+ [Test]
+ public async Task SetWorkingState_IdleToWorking_UpdatesLoad()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+ var server = pair.Server;
+
+ var mapManager = server.ResolveDependency<IMapManager>();
+ var entManager = server.ResolveDependency<IEntityManager>();
+ var mapSys = entManager.System<SharedMapSystem>();
+
+ await server.WaitAssertion(() =>
+ {
+ mapSys.CreateMap(out var mapId);
+ var grid = mapManager.CreateGridEntity(mapId);
+
+ mapSys.SetTile(grid, Vector2i.Zero, new Tile(1));
+
+ var ent = entManager.SpawnEntity("PowerStateApcReceiverDummy", grid.Owner.ToCoordinates());
+
+ var receiver = entManager.GetComponent<Server.Power.Components.ApcPowerReceiverComponent>(ent);
+ var powerState = entManager.GetComponent<PowerStateComponent>(ent);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.False);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.IdlePowerDraw).Within(0.01f));
+ });
+
+ var system = entManager.System<PowerStateSystem>();
+ system.SetWorkingState((ent, powerState), true);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.True);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.WorkingPowerDraw).Within(0.01f));
+ });
+ });
+
+ await pair.CleanReturnAsync();
+ }
+
+ /// <summary>
+ /// Asserts that switching from working to idle updates the power receiver load to the idle draw.
+ /// </summary>
+ [Test]
+ public async Task SetWorkingState_WorkingToIdle_UpdatesLoad()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+ var server = pair.Server;
+
+ var mapManager = server.ResolveDependency<IMapManager>();
+ var entManager = server.ResolveDependency<IEntityManager>();
+ var mapSys = entManager.System<SharedMapSystem>();
+
+ await server.WaitAssertion(() =>
+ {
+ mapSys.CreateMap(out var mapId);
+ var grid = mapManager.CreateGridEntity(mapId);
+
+ mapSys.SetTile(grid, Vector2i.Zero, new Tile(1));
+
+ var ent = entManager.SpawnEntity("PowerStateApcReceiverDummy", grid.Owner.ToCoordinates());
+
+ var receiver = entManager.GetComponent<Server.Power.Components.ApcPowerReceiverComponent>(ent);
+ var powerState = entManager.GetComponent<PowerStateComponent>(ent);
+ var system = entManager.System<PowerStateSystem>();
+ Entity<PowerStateComponent> newEnt = (ent, powerState);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.False);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.IdlePowerDraw).Within(0.01f));
+ });
+
+ system.SetWorkingState(newEnt, true);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.True);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.WorkingPowerDraw).Within(0.01f));
+ });
+
+ system.SetWorkingState(newEnt, false);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.False);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.IdlePowerDraw).Within(0.01f));
+ });
+ });
+
+ await pair.CleanReturnAsync();
+ }
+
+ /// <summary>
+ /// Asserts that setting the working state to the current state does not change the power receiver load.
+ /// </summary>
+ [Test]
+ public async Task SetWorkingState_AlreadyInState_NoChange()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+ var server = pair.Server;
+
+ var mapManager = server.ResolveDependency<IMapManager>();
+ var entManager = server.ResolveDependency<IEntityManager>();
+ var mapSys = entManager.System<SharedMapSystem>();
+
+ await server.WaitAssertion(() =>
+ {
+ mapSys.CreateMap(out var mapId);
+ var grid = mapManager.CreateGridEntity(mapId);
+
+ mapSys.SetTile(grid, Vector2i.Zero, new Tile(1));
+
+ var ent = entManager.SpawnEntity("PowerStateApcReceiverDummy", grid.Owner.ToCoordinates());
+
+ var receiver = entManager.GetComponent<Server.Power.Components.ApcPowerReceiverComponent>(ent);
+ var powerState = entManager.GetComponent<PowerStateComponent>(ent);
+ var system = entManager.System<PowerStateSystem>();
+ Entity<PowerStateComponent> valueTuple = (ent, powerState);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.False);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.IdlePowerDraw).Within(0.01f));
+ });
+
+ system.SetWorkingState(valueTuple, false);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.False);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.IdlePowerDraw).Within(0.01f));
+ });
+
+ system.SetWorkingState(valueTuple, true);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.True);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.WorkingPowerDraw).Within(0.01f));
+ });
+
+ system.SetWorkingState(valueTuple, true);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(powerState.IsWorking, Is.True);
+ Assert.That(receiver.Load, Is.EqualTo(powerState.WorkingPowerDraw).Within(0.01f));
+ });
+ });
+
+ await pair.CleanReturnAsync();
+ }
+}
+
--- /dev/null
+using Content.Shared.Power.Components;
+using JetBrains.Annotations;
+
+namespace Content.Shared.Power.EntitySystems;
+
+/// <summary>
+/// Generic system that handles entities with <see cref="PowerStateComponent"/>.
+/// Used for simple machines that only need to switch between "idle" and "working" power states.
+/// </summary>
+public sealed class PowerStateSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPowerReceiverSystem _powerReceiverSystem = default!;
+
+ private EntityQuery<PowerStateComponent> _powerStateQuery;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<PowerStateComponent, ComponentStartup>(OnComponentStartup);
+
+ _powerStateQuery = GetEntityQuery<PowerStateComponent>();
+ }
+
+ private void OnComponentStartup(Entity<PowerStateComponent> ent, ref ComponentStartup args)
+ {
+ SetWorkingState(ent.Owner, ent.Comp.IsWorking);
+ }
+
+ /// <summary>
+ /// Sets the working state of the entity, adjusting its power draw accordingly.
+ /// </summary>
+ /// <param name="ent">The entity to set the working state for.</param>
+ /// <param name="working">Whether the entity should be in the working state.</param>
+ [PublicAPI]
+ public void SetWorkingState(Entity<PowerStateComponent?> ent, bool working)
+ {
+ if (!_powerStateQuery.Resolve(ent, ref ent.Comp))
+ return;
+
+ _powerReceiverSystem.SetLoad(ent.Owner, working ? ent.Comp.WorkingPowerDraw : ent.Comp.IdlePowerDraw);
+ ent.Comp.IsWorking = working;
+ }
+}
--- /dev/null
+using Content.Shared.Power.Components;
+
+namespace Content.Shared.Power.EntitySystems;
+
+/// <summary>
+/// System for entities with <see cref="UIPowerStateComponent"/>.
+/// Entities with this component will increase their power usage to a working state
+/// when a UI on the entity is open.
+/// </summary>
+public sealed class UIPowerStateSystem : EntitySystem
+{
+ [Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
+ [Dependency] private readonly PowerStateSystem _powerState = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<UIPowerStateComponent, BoundUIOpenedEvent>(OnUiOpened);
+ SubscribeLocalEvent<UIPowerStateComponent, BoundUIClosedEvent>(OnUiClosed);
+ }
+
+ private void OnUiClosed(Entity<UIPowerStateComponent> ent, ref BoundUIClosedEvent args)
+ {
+ if (ent.Comp.Keys is null)
+ {
+ if (_ui.IsAnyUiOpen(ent.Owner))
+ return;
+ }
+ else
+ {
+ if (_ui.IsUiOpen(ent.Owner, ent.Comp.Keys))
+ return;
+ }
+
+ _powerState.SetWorkingState(ent.Owner, false);
+ }
+
+ private void OnUiOpened(Entity<UIPowerStateComponent> ent, ref BoundUIOpenedEvent args)
+ {
+ if (ent.Comp.Keys is not null && !ent.Comp.Keys.Contains(args.UiKey))
+ return;
+
+ _powerState.SetWorkingState(ent.Owner, true);
+ }
+}