Clean up APCs (#19841)

While here, fix an issue where APCs don't update the UI state after a load change.
This commit is contained in:
deltanedas
2023-09-05 22:19:43 +01:00
committed by GitHub
parent 8437038fd4
commit f2669b5771
2 changed files with 194 additions and 181 deletions

View File

@@ -1,6 +1,7 @@
using Content.Server.Power.NodeGroups; using Content.Server.Power.NodeGroups;
using Content.Shared.APC; using Content.Shared.APC;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Power.Components; namespace Content.Server.Power.Components;
@@ -10,16 +11,26 @@ public sealed partial class ApcComponent : BaseApcNetComponent
[DataField("onReceiveMessageSound")] [DataField("onReceiveMessageSound")]
public SoundSpecifier OnReceiveMessageSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg"); public SoundSpecifier OnReceiveMessageSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
[ViewVariables] [DataField("lastChargeState")]
public ApcChargeState LastChargeState; public ApcChargeState LastChargeState;
[DataField("lastChargeStateTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan LastChargeStateTime; public TimeSpan LastChargeStateTime;
[ViewVariables] [DataField("lastExternalState")]
public ApcExternalPowerState LastExternalState; public ApcExternalPowerState LastExternalState;
/// <summary>
/// Time the ui was last updated automatically.
/// Done after every <see cref="VisualsChangeDelay"/> to show the latest load.
/// If charge state changes it will be instantly updated.
/// </summary>
[DataField("lastUiUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan LastUiUpdate; public TimeSpan LastUiUpdate;
[ViewVariables] [DataField("enabled")]
public bool MainBreakerEnabled = true; public bool MainBreakerEnabled = true;
// TODO: remove this since it probably breaks when 2 people use it
[DataField("hasAccess")]
public bool HasAccess = false; public bool HasAccess = false;
public const float HighPowerThreshold = 0.9f; public const float HighPowerThreshold = 0.9f;

View File

@@ -8,22 +8,20 @@ using Content.Shared.APC;
using Content.Shared.Emag.Components; using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems; using Content.Shared.Emag.Systems;
using Content.Shared.Popups; using Content.Shared.Popups;
using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Power.EntitySystems namespace Content.Server.Power.EntitySystems;
{
[UsedImplicitly] public sealed class ApcSystem : EntitySystem
internal sealed class ApcSystem : EntitySystem
{ {
[Dependency] private readonly AccessReaderSystem _accessReader = default!; [Dependency] private readonly AccessReaderSystem _accessReader = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -40,6 +38,19 @@ namespace Content.Server.Power.EntitySystems
SubscribeLocalEvent<ApcComponent, EmpPulseEvent>(OnEmpPulse); SubscribeLocalEvent<ApcComponent, EmpPulseEvent>(OnEmpPulse);
} }
public override void Update(float deltaTime)
{
var query = EntityQueryEnumerator<ApcComponent, PowerNetworkBatteryComponent, ServerUserInterfaceComponent>();
while (query.MoveNext(out var uid, out var apc, out var battery, out var ui))
{
if (apc.LastUiUpdate + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
{
apc.LastUiUpdate = _gameTiming.CurTime;
UpdateUIState(uid, apc, battery, ui);
}
}
}
// Change the APC's state only when the battery state changes, or when it's first created. // Change the APC's state only when the battery state changes, or when it's first created.
private void OnBatteryChargeChanged(EntityUid uid, ApcComponent component, ref ChargeChangedEvent args) private void OnBatteryChargeChanged(EntityUid uid, ApcComponent component, ref ChargeChangedEvent args)
{ {
@@ -50,23 +61,18 @@ namespace Content.Server.Power.EntitySystems
{ {
UpdateApcState(uid, component); UpdateApcState(uid, component);
} }
//Update the HasAccess var for UI to read //Update the HasAccess var for UI to read
private void OnBoundUiOpen(EntityUid uid, ApcComponent component, BoundUIOpenedEvent args) private void OnBoundUiOpen(EntityUid uid, ApcComponent component, BoundUIOpenedEvent args)
{ {
TryComp<AccessReaderComponent>(uid, out var access);
if (args.Session.AttachedEntity == null) if (args.Session.AttachedEntity == null)
return; return;
if (access == null || _accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid, access)) // TODO: this should be per-player not stored on the apc
{ component.HasAccess = _accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid);
component.HasAccess = true;
}
else
{
component.HasAccess = false;
}
UpdateApcState(uid, component); UpdateApcState(uid, component);
} }
private void OnToggleMainBreaker(EntityUid uid, ApcComponent component, ApcToggleMainBreakerMessage args) private void OnToggleMainBreaker(EntityUid uid, ApcComponent component, ApcToggleMainBreakerMessage args)
{ {
var attemptEv = new ApcToggleMainBreakerAttemptEvent(); var attemptEv = new ApcToggleMainBreakerAttemptEvent();
@@ -78,11 +84,10 @@ namespace Content.Server.Power.EntitySystems
return; return;
} }
TryComp<AccessReaderComponent>(uid, out var access);
if (args.Session.AttachedEntity == null) if (args.Session.AttachedEntity == null)
return; return;
if (access == null || _accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid, access)) if (_accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid))
{ {
ApcToggleBreaker(uid, component); ApcToggleBreaker(uid, component);
} }
@@ -131,11 +136,9 @@ namespace Content.Server.Power.EntitySystems
} }
var extPowerState = CalcExtPowerState(uid, battery.NetworkBattery); var extPowerState = CalcExtPowerState(uid, battery.NetworkBattery);
if (extPowerState != apc.LastExternalState if (extPowerState != apc.LastExternalState)
|| apc.LastUiUpdate + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
{ {
apc.LastExternalState = extPowerState; apc.LastExternalState = extPowerState;
apc.LastUiUpdate = _gameTiming.CurTime;
UpdateUIState(uid, apc, battery); UpdateUIState(uid, apc, battery);
} }
} }
@@ -200,4 +203,3 @@ namespace Content.Server.Power.EntitySystems
[ByRefEvent] [ByRefEvent]
public record struct ApcToggleMainBreakerAttemptEvent(bool Cancelled); public record struct ApcToggleMainBreakerAttemptEvent(bool Cancelled);
}