diff --git a/Content.Server/Power/Components/ApcComponent.cs b/Content.Server/Power/Components/ApcComponent.cs
index 8f74146b45..bee8defc43 100644
--- a/Content.Server/Power/Components/ApcComponent.cs
+++ b/Content.Server/Power/Components/ApcComponent.cs
@@ -11,12 +11,9 @@ public sealed partial class ApcComponent : BaseApcNetComponent
[DataField("onReceiveMessageSound")]
public SoundSpecifier OnReceiveMessageSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
- [DataField("lastChargeState")]
public ApcChargeState LastChargeState;
- [DataField("lastChargeStateTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
- public TimeSpan LastChargeStateTime;
+ public TimeSpan? LastChargeStateTime;
- [DataField("lastExternalState")]
public ApcExternalPowerState LastExternalState;
///
@@ -24,7 +21,6 @@ public sealed partial class ApcComponent : BaseApcNetComponent
/// Done after every to show the latest load.
/// If charge state changes it will be instantly updated.
///
- [DataField("lastUiUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan LastUiUpdate;
[DataField("enabled")]
@@ -33,6 +29,11 @@ public sealed partial class ApcComponent : BaseApcNetComponent
[DataField("hasAccess")]
public bool HasAccess = false;
+ ///
+ /// APC state needs to always be updated after first processing tick.
+ ///
+ public bool NeedStateUpdate;
+
public const float HighPowerThreshold = 0.9f;
public static TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
diff --git a/Content.Server/Power/EntitySystems/ApcSystem.cs b/Content.Server/Power/EntitySystems/ApcSystem.cs
index d88edd85cb..52c19c302c 100644
--- a/Content.Server/Power/EntitySystems/ApcSystem.cs
+++ b/Content.Server/Power/EntitySystems/ApcSystem.cs
@@ -32,7 +32,7 @@ public sealed class ApcSystem : EntitySystem
UpdatesAfter.Add(typeof(PowerNetSystem));
SubscribeLocalEvent(OnBoundUiOpen);
- SubscribeLocalEvent(OnApcInit);
+ SubscribeLocalEvent(OnApcStartup);
SubscribeLocalEvent(OnBatteryChargeChanged);
SubscribeLocalEvent(OnToggleMainBreaker);
SubscribeLocalEvent(OnEmagged);
@@ -50,6 +50,11 @@ public sealed class ApcSystem : EntitySystem
apc.LastUiUpdate = _gameTiming.CurTime;
UpdateUIState(uid, apc, battery);
}
+
+ if (apc.NeedStateUpdate)
+ {
+ UpdateApcState(uid, apc, battery);
+ }
}
}
@@ -59,9 +64,11 @@ public sealed class ApcSystem : EntitySystem
UpdateApcState(uid, component);
}
- private void OnApcInit(EntityUid uid, ApcComponent component, MapInitEvent args)
+ private static void OnApcStartup(EntityUid uid, ApcComponent component, ComponentStartup args)
{
- UpdateApcState(uid, component);
+ // We cannot update immediately, as various network/battery state is not valid yet.
+ // Defer until the next tick.
+ component.NeedStateUpdate = true;
}
//Update the HasAccess var for UI to read
@@ -119,15 +126,18 @@ public sealed class ApcSystem : EntitySystem
if (!Resolve(uid, ref apc, ref battery, false))
return;
- var newState = CalcChargeState(uid, battery.NetworkBattery);
- if (newState != apc.LastChargeState && apc.LastChargeStateTime + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
+ if (apc.LastChargeStateTime == null || apc.LastChargeStateTime + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
{
- apc.LastChargeState = newState;
- apc.LastChargeStateTime = _gameTiming.CurTime;
-
- if (TryComp(uid, out AppearanceComponent? appearance))
+ var newState = CalcChargeState(uid, battery.NetworkBattery);
+ if (newState != apc.LastChargeState)
{
- _appearance.SetData(uid, ApcVisuals.ChargeState, newState, appearance);
+ apc.LastChargeState = newState;
+ apc.LastChargeStateTime = _gameTiming.CurTime;
+
+ if (TryComp(uid, out AppearanceComponent? appearance))
+ {
+ _appearance.SetData(uid, ApcVisuals.ChargeState, newState, appearance);
+ }
}
}
@@ -137,6 +147,8 @@ public sealed class ApcSystem : EntitySystem
apc.LastExternalState = extPowerState;
UpdateUIState(uid, apc, battery);
}
+
+ apc.NeedStateUpdate = false;
}
public void UpdateUIState(EntityUid uid,