diff --git a/Content.Client/Atmos/Piping/Unary/Systems/GasThermoMachineSystem.cs b/Content.Client/Atmos/Piping/Unary/Systems/GasThermoMachineSystem.cs new file mode 100644 index 0000000000..bd75fa0095 --- /dev/null +++ b/Content.Client/Atmos/Piping/Unary/Systems/GasThermoMachineSystem.cs @@ -0,0 +1,29 @@ +using Content.Client.Atmos.UI; +using Content.Shared.Atmos.Piping.Unary.Components; +using Content.Shared.Atmos.Piping.Unary.Systems; + +namespace Content.Client.Atmos.Piping.Unary.Systems; + +public sealed class GasThermoMachineSystem : SharedGasThermoMachineSystem +{ + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnGasAfterState); + } + + private void OnGasAfterState(Entity ent, ref AfterAutoHandleStateEvent args) + { + DirtyUI(ent.Owner, ent.Comp); + } + + protected override void DirtyUI(EntityUid uid, GasThermoMachineComponent? thermoMachine, UserInterfaceComponent? ui = null) + { + if (_ui.TryGetOpenUi(uid, ThermomachineUiKey.Key, out var bui)) + { + bui.Update(); + } + } +} diff --git a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs index d62be8f4bb..f9e1caf8f3 100644 --- a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs @@ -1,5 +1,8 @@ -using Content.Shared.Atmos; +using Content.Client.Power.EntitySystems; +using Content.Shared.Atmos; using Content.Shared.Atmos.Piping.Unary.Components; +using Content.Shared.Atmos.Piping.Unary.Systems; +using Content.Shared.Power.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.UserInterface; @@ -36,6 +39,8 @@ namespace Content.Client.Atmos.UI _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value); + _window.Entity = Owner; + Update(); } private void OnToggleStatusButtonPressed() @@ -43,7 +48,7 @@ namespace Content.Client.Atmos.UI if (_window is null) return; _window.SetActive(!_window.Active); - SendMessage(new GasThermomachineToggleMessage()); + SendPredictedMessage(new GasThermomachineToggleMessage()); } private void OnTemperatureChanged(float value) @@ -60,25 +65,32 @@ namespace Content.Client.Atmos.UI return; } - SendMessage(new GasThermomachineChangeTemperatureMessage(actual)); + SendPredictedMessage(new GasThermomachineChangeTemperatureMessage(actual)); } - /// - /// Update the UI state based on server-sent info - /// - /// - protected override void UpdateState(BoundUserInterfaceState state) + public override void Update() { - base.UpdateState(state); - if (_window == null || state is not GasThermomachineBoundUserInterfaceState cast) + if (_window == null || !EntMan.TryGetComponent(Owner, out GasThermoMachineComponent? thermo)) return; - _minTemp = cast.MinTemperature; - _maxTemp = cast.MaxTemperature; - _isHeater = cast.IsHeater; + var system = EntMan.System(); + _minTemp = thermo.MinTemperature; + _maxTemp = thermo.MaxTemperature; + _isHeater = system.IsHeater(thermo); + + _window.SetTemperature(thermo.TargetTemperature); + + var receiverSys = EntMan.System(); + SharedApcPowerReceiverComponent? receiver = null; + + receiverSys.ResolveApc(Owner, ref receiver); + + // Also set in frameupdates. + if (receiver != null) + { + _window.SetActive(!receiver.PowerDisabled); + } - _window.SetTemperature(cast.Temperature); - _window.SetActive(cast.Enabled); _window.Title = _isHeater switch { false => Loc.GetString("comp-gas-thermomachine-ui-title-freezer"), diff --git a/Content.Client/Atmos/UI/GasThermomachineWindow.xaml b/Content.Client/Atmos/UI/GasThermomachineWindow.xaml index de3f8f8036..207c31f087 100644 --- a/Content.Client/Atmos/UI/GasThermomachineWindow.xaml +++ b/Content.Client/Atmos/UI/GasThermomachineWindow.xaml @@ -1,5 +1,6 @@ - @@ -11,4 +12,4 @@ - + diff --git a/Content.Client/Atmos/UI/GasThermomachineWindow.xaml.cs b/Content.Client/Atmos/UI/GasThermomachineWindow.xaml.cs index bc8cb14336..00d53dc9b6 100644 --- a/Content.Client/Atmos/UI/GasThermomachineWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasThermomachineWindow.xaml.cs @@ -1,19 +1,26 @@ +using Content.Client.Power.Components; +using Content.Client.UserInterface.Controls; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Shared.Timing; namespace Content.Client.Atmos.UI; [GenerateTypedNameReferences] -public sealed partial class GasThermomachineWindow : DefaultWindow +public sealed partial class GasThermomachineWindow : FancyWindow { + [Dependency] private readonly IEntityManager _entManager = default!; + public bool Active = true; public FloatSpinBox TemperatureSpinbox; + public EntityUid Entity; + public GasThermomachineWindow() { + IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); SpinboxHBox.AddChild( @@ -27,12 +34,10 @@ public sealed partial class GasThermomachineWindow : DefaultWindow if (active) { ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-enabled"); - ToggleStatusButton.Pressed = true; } else { ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-disabled"); - ToggleStatusButton.Pressed = false; } } @@ -40,4 +45,14 @@ public sealed partial class GasThermomachineWindow : DefaultWindow { TemperatureSpinbox.Value = temperature; } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + if (_entManager.TryGetComponent(Entity, out ApcPowerReceiverComponent? receiver)) + { + SetActive(!receiver.PowerDisabled); + } + } } diff --git a/Content.Client/NodeContainer/NodeContainerSystem.cs b/Content.Client/NodeContainer/NodeContainerSystem.cs new file mode 100644 index 0000000000..512aa8f469 --- /dev/null +++ b/Content.Client/NodeContainer/NodeContainerSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.NodeContainer; + +namespace Content.Client.NodeContainer; + +public sealed class NodeContainerSystem : SharedNodeContainerSystem; diff --git a/Content.Client/Power/EntitySystems/PowerNetSystem.cs b/Content.Client/Power/EntitySystems/PowerNetSystem.cs index 6fb9f482ce..58ff03b28d 100644 --- a/Content.Client/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Client/Power/EntitySystems/PowerNetSystem.cs @@ -1,8 +1,19 @@ +using Content.Client.Power.Components; +using Content.Shared.Power.Components; using Content.Shared.Power.EntitySystems; namespace Content.Client.Power.EntitySystems; public sealed class PowerNetSystem : SharedPowerNetSystem { + public override bool IsPoweredCalculate(SharedApcPowerReceiverComponent comp) + { + return IsPoweredCalculate((ApcPowerReceiverComponent)comp); + } + private bool IsPoweredCalculate(ApcPowerReceiverComponent comp) + { + return !comp.PowerDisabled + && !comp.NeedsPower; + } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index e4f5f99ed7..35ff89c726 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -9,11 +9,8 @@ using Content.Server.Power.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Piping.Unary.Components; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Content.Server.Power.EntitySystems; -using Content.Shared.UserInterface; -using Content.Shared.Administration.Logs; -using Content.Shared.Database; +using Content.Shared.Atmos.Piping.Unary.Systems; using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Events; using Content.Shared.Examine; @@ -22,36 +19,23 @@ using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] - public sealed class GasThermoMachineSystem : EntitySystem + public sealed class GasThermoMachineSystem : SharedGasThermoMachineSystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; [Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnThermoMachineUpdated); - SubscribeLocalEvent(OnExamined); - - // UI events - SubscribeLocalEvent(OnBeforeOpened); - SubscribeLocalEvent(OnToggleMessage); - SubscribeLocalEvent(OnChangeTemperature); // Device network SubscribeLocalEvent(OnPacketRecv); } - private void OnBeforeOpened(Entity ent, ref BeforeActivatableUIOpenEvent args) - { - DirtyUI(ent, ent.Comp); - } - private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args) { thermoMachine.LastEnergyDelta = 0f; @@ -135,56 +119,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems } } - private bool IsHeater(GasThermoMachineComponent comp) - { - return comp.Cp >= 0; - } - - private void OnToggleMessage(EntityUid uid, GasThermoMachineComponent thermoMachine, GasThermomachineToggleMessage args) - { - var powerState = _power.TogglePower(uid); - _adminLogger.Add(LogType.AtmosPowerChanged, $"{ToPrettyString(args.Actor)} turned {(powerState ? "On" : "Off")} {ToPrettyString(uid)}"); - DirtyUI(uid, thermoMachine); - } - - private void OnChangeTemperature(EntityUid uid, GasThermoMachineComponent thermoMachine, GasThermomachineChangeTemperatureMessage args) - { - if (IsHeater(thermoMachine)) - thermoMachine.TargetTemperature = MathF.Min(args.Temperature, thermoMachine.MaxTemperature); - else - thermoMachine.TargetTemperature = MathF.Max(args.Temperature, thermoMachine.MinTemperature); - thermoMachine.TargetTemperature = MathF.Max(thermoMachine.TargetTemperature, Atmospherics.TCMB); - _adminLogger.Add(LogType.AtmosTemperatureChanged, $"{ToPrettyString(args.Actor)} set temperature on {ToPrettyString(uid)} to {thermoMachine.TargetTemperature}"); - DirtyUI(uid, thermoMachine); - } - - private void DirtyUI(EntityUid uid, GasThermoMachineComponent? thermoMachine, UserInterfaceComponent? ui=null) - { - if (!Resolve(uid, ref thermoMachine, ref ui, false)) - return; - - ApcPowerReceiverComponent? powerReceiver = null; - if (!Resolve(uid, ref powerReceiver)) - return; - - _userInterfaceSystem.SetUiState(uid, ThermomachineUiKey.Key, - new GasThermomachineBoundUserInterfaceState(thermoMachine.MinTemperature, thermoMachine.MaxTemperature, thermoMachine.TargetTemperature, !powerReceiver.PowerDisabled, IsHeater(thermoMachine))); - } - - private void OnExamined(EntityUid uid, GasThermoMachineComponent thermoMachine, ExaminedEvent args) - { - if (!args.IsInDetailsRange) - return; - - if (Loc.TryGetString("gas-thermomachine-system-examined", out var str, - ("machineName", !IsHeater(thermoMachine) ? "freezer" : "heater"), - ("tempColor", !IsHeater(thermoMachine) ? "deepskyblue" : "red"), - ("temp", Math.Round(thermoMachine.TargetTemperature,2)) - )) - - args.PushMarkup(str); - } - private void OnPacketRecv(EntityUid uid, GasThermoMachineComponent component, DeviceNetworkPacketEvent args) { if (!TryComp(uid, out DeviceNetworkComponent? netConn) diff --git a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs index 36ef59e743..1c05307c15 100644 --- a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs +++ b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Atmos.Piping.Portable.Components; +using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Atmos.Visuals; using Content.Shared.Power; using Content.Shared.UserInterface; @@ -41,6 +42,7 @@ public sealed class SpaceHeaterSystem : EntitySystem { if (!TryComp(uid, out var thermoMachine)) return; + thermoMachine.Cp = spaceHeater.HeatingCp; thermoMachine.HeatCapacity = spaceHeater.PowerConsumption; } diff --git a/Content.Server/NodeContainer/EntitySystems/NodeContainerSystem.cs b/Content.Server/NodeContainer/EntitySystems/NodeContainerSystem.cs index ac818e08dc..62f0391cf5 100644 --- a/Content.Server/NodeContainer/EntitySystems/NodeContainerSystem.cs +++ b/Content.Server/NodeContainer/EntitySystems/NodeContainerSystem.cs @@ -13,7 +13,7 @@ namespace Content.Server.NodeContainer.EntitySystems /// /// [UsedImplicitly] - public sealed class NodeContainerSystem : EntitySystem + public sealed class NodeContainerSystem : SharedNodeContainerSystem { [Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!; private EntityQuery _query; diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs index ab2e27600a..9dc0c2c498 100644 --- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs @@ -31,7 +31,6 @@ namespace Content.Server.Power.EntitySystems private readonly HashSet _apcNetReconnectQueue = new(); private EntityQuery _apcBatteryQuery; - private EntityQuery _appearanceQuery; private EntityQuery _batteryQuery; private BatteryRampPegSolver _solver = new(); @@ -41,7 +40,6 @@ namespace Content.Server.Power.EntitySystems base.Initialize(); _apcBatteryQuery = GetEntityQuery(); - _appearanceQuery = GetEntityQuery(); _batteryQuery = GetEntityQuery(); UpdatesAfter.Add(typeof(NodeGroupSystem)); @@ -317,15 +315,25 @@ namespace Content.Server.Power.EntitySystems _powerNetReconnectQueue.Clear(); } + private bool IsPoweredCalculate(ApcPowerReceiverComponent comp) + { + return !comp.PowerDisabled + && (!comp.NeedsPower + || MathHelper.CloseToPercent(comp.NetworkLoad.ReceivingPower, + comp.Load)); + } + + public override bool IsPoweredCalculate(SharedApcPowerReceiverComponent comp) + { + return IsPoweredCalculate((ApcPowerReceiverComponent)comp); + } + private void UpdateApcPowerReceiver(float frameTime) { var enumerator = AllEntityQuery(); while (enumerator.MoveNext(out var uid, out var apcReceiver)) { - var powered = !apcReceiver.PowerDisabled - && (!apcReceiver.NeedsPower - || MathHelper.CloseToPercent(apcReceiver.NetworkLoad.ReceivingPower, - apcReceiver.Load)); + var powered = IsPoweredCalculate(apcReceiver); MetaDataComponent? metadata = null; @@ -381,9 +389,6 @@ namespace Content.Server.Power.EntitySystems var ev = new PowerChangedEvent(powered, apcReceiver.NetworkLoad.ReceivingPower); RaiseLocalEvent(uid, ref ev); - - if (_appearanceQuery.TryComp(uid, out var appearance)) - _appearance.SetData(uid, PowerDeviceVisuals.Powered, powered, appearance); } } diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs similarity index 77% rename from Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs rename to Content.Shared/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs index f481443c94..9317594ad2 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs @@ -1,9 +1,10 @@ using Content.Shared.Atmos; using Content.Shared.Guidebook; +using Robust.Shared.GameStates; -namespace Content.Server.Atmos.Piping.Unary.Components +namespace Content.Shared.Atmos.Piping.Unary.Components { - [RegisterComponent] + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class GasThermoMachineComponent : Component { [DataField("inlet")] @@ -13,11 +14,11 @@ namespace Content.Server.Atmos.Piping.Unary.Components /// Current electrical power consumption, in watts. Increasing power increases the ability of the /// thermomachine to heat or cool air. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] [GuidebookData] public float HeatCapacity = 5000; - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public float TargetTemperature = Atmospherics.T20C; /// @@ -39,42 +40,41 @@ namespace Content.Server.Atmos.Piping.Unary.Components /// Positive for heaters, negative for freezers. /// [DataField("coefficientOfPerformance")] - [ViewVariables(VVAccess.ReadWrite)] public float Cp = 0.9f; // output power / input power, positive is heat /// /// Current minimum temperature /// Ignored if heater. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - [GuidebookData] + [DataField, AutoNetworkedField] + [GuidebookData] public float MinTemperature = 73.15f; /// /// Current maximum temperature /// Ignored if freezer. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - [GuidebookData] + [DataField, AutoNetworkedField] + [GuidebookData] public float MaxTemperature = 593.15f; /// /// Last amount of energy added/removed from the attached pipe network /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float LastEnergyDelta; /// /// An percentage of the energy change that is leaked into the surrounding environment rather than the inlet pipe. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - [GuidebookData] - public float EnergyLeakPercentage; + [DataField] + [GuidebookData] + public float EnergyLeakPercentage; /// /// If true, heat is exclusively exchanged with the local atmosphere instead of the inlet pipe air /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool Atmospheric = false; + [DataField] + public bool Atmospheric; } } diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs index 259ebf4eea..5d2beb9de5 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedGasThermomachineComponent.cs @@ -7,7 +7,7 @@ public sealed record GasThermoMachineData(float EnergyDelta); [Serializable] [NetSerializable] -public enum ThermomachineUiKey +public enum ThermomachineUiKey : byte { Key } @@ -29,23 +29,3 @@ public sealed class GasThermomachineChangeTemperatureMessage : BoundUserInterfac Temperature = temperature; } } - -[Serializable] -[NetSerializable] -public sealed class GasThermomachineBoundUserInterfaceState : BoundUserInterfaceState -{ - public float MinTemperature { get; } - public float MaxTemperature { get; } - public float Temperature { get; } - public bool Enabled { get; } - public bool IsHeater { get; } - - public GasThermomachineBoundUserInterfaceState(float minTemperature, float maxTemperature, float temperature, bool enabled, bool isHeater) - { - MinTemperature = minTemperature; - MaxTemperature = maxTemperature; - Temperature = temperature; - Enabled = enabled; - IsHeater = isHeater; - } -} diff --git a/Content.Shared/Atmos/Piping/Unary/Systems/SharedGasThermoMachineSystem.cs b/Content.Shared/Atmos/Piping/Unary/Systems/SharedGasThermoMachineSystem.cs new file mode 100644 index 0000000000..724552fe87 --- /dev/null +++ b/Content.Shared/Atmos/Piping/Unary/Systems/SharedGasThermoMachineSystem.cs @@ -0,0 +1,61 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Atmos.Piping.Unary.Components; +using Content.Shared.Database; +using Content.Shared.Examine; +using Content.Shared.Power.EntitySystems; + +namespace Content.Shared.Atmos.Piping.Unary.Systems; + +public abstract class SharedGasThermoMachineSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedPowerReceiverSystem _receiver = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnExamined); + + SubscribeLocalEvent(OnToggleMessage); + SubscribeLocalEvent(OnChangeTemperature); + } + + private void OnExamined(EntityUid uid, GasThermoMachineComponent thermoMachine, ExaminedEvent args) + { + if (Loc.TryGetString("gas-thermomachine-system-examined", + out var str, + ("machineName", !IsHeater(thermoMachine) ? "freezer" : "heater"), + ("tempColor", !IsHeater(thermoMachine) ? "deepskyblue" : "red"), + ("temp", Math.Round(thermoMachine.TargetTemperature, 2)) + )) + { + args.PushMarkup(str); + } + } + + public bool IsHeater(GasThermoMachineComponent comp) + { + return comp.Cp >= 0; + } + + private void OnToggleMessage(EntityUid uid, GasThermoMachineComponent thermoMachine, GasThermomachineToggleMessage args) + { + var powerState = _receiver.TogglePower(uid, user: args.Actor); + _adminLogger.Add(LogType.AtmosPowerChanged, $"{ToPrettyString(args.Actor)} turned {(powerState ? "On" : "Off")} {ToPrettyString(uid)}"); + DirtyUI(uid, thermoMachine); + } + + private void OnChangeTemperature(EntityUid uid, GasThermoMachineComponent thermoMachine, GasThermomachineChangeTemperatureMessage args) + { + if (IsHeater(thermoMachine)) + thermoMachine.TargetTemperature = MathF.Min(args.Temperature, thermoMachine.MaxTemperature); + else + thermoMachine.TargetTemperature = MathF.Max(args.Temperature, thermoMachine.MinTemperature); + thermoMachine.TargetTemperature = MathF.Max(thermoMachine.TargetTemperature, Atmospherics.TCMB); + _adminLogger.Add(LogType.AtmosTemperatureChanged, $"{ToPrettyString(args.Actor)} set temperature on {ToPrettyString(uid)} to {thermoMachine.TargetTemperature}"); + Dirty(uid, thermoMachine); + DirtyUI(uid, thermoMachine); + } + + protected virtual void DirtyUI(EntityUid uid, GasThermoMachineComponent? thermoMachine, UserInterfaceComponent? ui=null) {} +} diff --git a/Content.Shared/NodeContainer/SharedNodeContainerSystem.cs b/Content.Shared/NodeContainer/SharedNodeContainerSystem.cs new file mode 100644 index 0000000000..e639af21ab --- /dev/null +++ b/Content.Shared/NodeContainer/SharedNodeContainerSystem.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.NodeContainer; + +public abstract class SharedNodeContainerSystem : EntitySystem +{ + +} diff --git a/Content.Shared/Power/EntitySystems/SharedPowerNetSystem.cs b/Content.Shared/Power/EntitySystems/SharedPowerNetSystem.cs index 28f74536c4..7611074d80 100644 --- a/Content.Shared/Power/EntitySystems/SharedPowerNetSystem.cs +++ b/Content.Shared/Power/EntitySystems/SharedPowerNetSystem.cs @@ -1,6 +1,21 @@ +using Content.Shared.Power.Components; + namespace Content.Shared.Power.EntitySystems; public abstract class SharedPowerNetSystem : EntitySystem { + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + public abstract bool IsPoweredCalculate(SharedApcPowerReceiverComponent comp); + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnPowerAppearance); + } + + private void OnPowerAppearance(Entity ent, ref PowerChangedEvent args) + { + _appearance.SetData(ent, PowerDeviceVisuals.Powered, args.Powered, ent.Comp); + } } diff --git a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs index d86273974b..4a66a6ea97 100644 --- a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs +++ b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs @@ -4,13 +4,16 @@ using Content.Shared.Database; using Content.Shared.Power.Components; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; namespace Content.Shared.Power.EntitySystems; public abstract class SharedPowerReceiverSystem : EntitySystem { + [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPowerNetSystem _net = default!; public abstract bool ResolveApc(EntityUid entity, [NotNullWhen(true)] ref SharedApcPowerReceiverComponent? component); @@ -44,6 +47,15 @@ public abstract class SharedPowerReceiverSystem : EntitySystem // it'll save a lot of confusion if 'always powered' means 'always powered' if (!receiver.NeedsPower) { + var powered = _net.IsPoweredCalculate(receiver); + + // Server won't raise it here as it can raise the load event later with NeedsPower? + // This is mostly here for clientside predictions. + if (receiver.Powered != powered) + { + RaisePower((uid, receiver)); + } + SetPowerDisabled(uid, false, receiver); return true; } @@ -59,6 +71,19 @@ public abstract class SharedPowerReceiverSystem : EntitySystem AudioParams.Default.WithVolume(-2f)); } + if (_netMan.IsClient && receiver.PowerDisabled) + { + var powered = _net.IsPoweredCalculate(receiver); + + // Server won't raise it here as it can raise the load event later with NeedsPower? + // This is mostly here for clientside predictions. + if (receiver.Powered != powered) + { + receiver.Powered = powered; + RaisePower((uid, receiver)); + } + } + return !receiver.PowerDisabled; // i.e. PowerEnabled }