From 1c651f051f5f7241f64a77d3670c6f7532aa12d0 Mon Sep 17 00:00:00 2001 From: vulppine Date: Wed, 17 Aug 2022 23:46:15 -0700 Subject: [PATCH] some backend stuff for air alarms finally, some UI states!!! --- .../Atmos/Monitor/UI/AirAlarmWindow.xaml | 7 +- .../Monitor/Components/AirAlarmComponent.cs | 7 + .../Atmos/Monitor/Systems/AirAlarmSystem.cs | 204 +++++++++--------- .../Monitor/Systems/AtmosAlarmableSystem.cs | 8 + .../Atmos/Monitor/AtmosSensorData.cs | 37 ++++ .../Components/SharedAirAlarmComponent.cs | 37 +++- 6 files changed, 188 insertions(+), 112 deletions(-) create mode 100644 Content.Shared/Atmos/Monitor/AtmosSensorData.cs diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml index 76a1a41cdb..734fd74de0 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml @@ -40,9 +40,10 @@ - + - + + diff --git a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs index d56d25d7c7..6d53721801 100644 --- a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs +++ b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Piping.Unary.Components; using Robust.Shared.Network; namespace Content.Server.Atmos.Monitor.Components @@ -11,7 +13,12 @@ namespace Content.Server.Atmos.Monitor.Components // Remember to null this afterwards. [ViewVariables] public IAirAlarmModeUpdate? CurrentModeUpdater { get; set; } + [ViewVariables] public AirAlarmTab CurrentTab { get; set; } + public Dictionary DeviceData = new(); + public Dictionary VentData = new(); + public Dictionary ScrubberData = new(); + public Dictionary SensorData = new(); public HashSet ActivePlayers = new(); diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs index c153e782c6..d70268d513 100644 --- a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Access.Systems; using Content.Shared.Atmos; using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; +using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Shared.Player; @@ -124,6 +125,24 @@ namespace Content.Server.Atmos.Monitor.Systems _deviceNet.QueuePacket(uid, address, payload); } + /// + /// Synchronize all sensors on an air alarm, but only if its current tab is set to Sensors. + /// + /// + /// + private void SyncAllSensors(EntityUid uid, AirAlarmComponent? monitor = null) + { + if (!Resolve(uid, ref monitor) || monitor.CurrentTab != AirAlarmTab.Sensors) + { + return; + } + + foreach (var addr in monitor.SensorData.Keys) + { + SyncDevice(uid, addr); + } + } + /// /// Sync this air alarm's mode with the rest of the network. /// @@ -168,7 +187,9 @@ namespace Content.Server.Atmos.Monitor.Systems { ForceCloseAllInterfaces(uid); component.CurrentModeUpdater = null; - component.DeviceData.Clear(); + component.ScrubberData.Clear(); + component.SensorData.Clear(); + component.VentData.Clear(); } else { @@ -208,18 +229,18 @@ namespace Content.Server.Atmos.Monitor.Systems _uiSystem.GetUiOrNull(component.Owner, SharedAirAlarmInterfaceKey.Key)?.Open(actor.PlayerSession); component.ActivePlayers.Add(actor.PlayerSession.UserId); AddActiveInterface(uid); - SendAddress(uid); - SendAlarmMode(uid); - SendThresholds(uid); SyncAllDevices(uid); - SendAirData(uid); + UpdateUI(uid, component); } private void OnResyncAll(EntityUid uid, AirAlarmComponent component, AirAlarmResyncAllDevicesMessage args) { if (AccessCheck(uid, args.Session.AttachedEntity, component)) { - component.DeviceData.Clear(); + component.VentData.Clear(); + component.ScrubberData.Clear(); + component.SensorData.Clear(); + SyncAllDevices(uid); } } @@ -231,7 +252,7 @@ namespace Content.Server.Atmos.Monitor.Systems if (AccessCheck(uid, args.Session.AttachedEntity, component)) SetMode(uid, addr, args.Mode, true, false); else - SendAlarmMode(uid); + UpdateUI(uid, component); } private void OnUpdateThreshold(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmThresholdMessage args) @@ -239,7 +260,7 @@ namespace Content.Server.Atmos.Monitor.Systems if (AccessCheck(uid, args.Session.AttachedEntity, component)) SetThreshold(uid, args.Threshold, args.Type, args.Gas); else - SendThresholds(uid); + UpdateUI(uid, component); } private void OnUpdateDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateDeviceDataMessage args) @@ -247,7 +268,7 @@ namespace Content.Server.Atmos.Monitor.Systems if (AccessCheck(uid, args.Session.AttachedEntity, component)) SetDeviceData(uid, args.Address, args.Data); else - SyncDevice(uid, args.Address); + UpdateUI(uid, component); } private bool AccessCheck(EntityUid uid, EntityUid? user, AirAlarmComponent? component = null) @@ -272,7 +293,6 @@ namespace Content.Server.Atmos.Monitor.Systems if (component.ActivePlayers.Count != 0) { SyncAllDevices(uid); - SendAirData(uid); } string addr = string.Empty; @@ -296,6 +316,8 @@ namespace Content.Server.Atmos.Monitor.Systems // no, this still doesn't execute the mode SetMode(uid, addr, AirAlarmMode.Filtering, true); } + + UpdateUI(uid, component); } #endregion @@ -355,10 +377,7 @@ namespace Content.Server.Atmos.Monitor.Systems && controller.CurrentModeUpdater.NetOwner != origin) controller.CurrentModeUpdater = null; - // controller.SendMessage(new AirAlarmUpdateAlarmModeMessage(mode)); - // TODO: Use BUI states instead... - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAlarmModeMessage(mode)); - + UpdateUI(uid, controller); // setting sync deals with the issue of air alarms // in the same network needing to have the same mode @@ -384,7 +403,6 @@ namespace Content.Server.Atmos.Monitor.Systems if (component.ActivePlayers.Count != 0) { SyncAllDevices(uid); - SendAirData(uid); } string addr = string.Empty; @@ -398,12 +416,6 @@ namespace Content.Server.Atmos.Monitor.Systems return; } - // set this air alarm's visuals to match the highest network alarm - if (TryComp(uid, out AppearanceComponent? appearanceComponent)) - { - appearanceComponent.SetData(AtmosMonitorVisuals.AlarmType, highestNetworkType); - } - if (highestNetworkType == AtmosMonitorAlarmType.Danger) { SetMode(uid, addr, AirAlarmMode.None, true); @@ -421,6 +433,8 @@ namespace Content.Server.Atmos.Monitor.Systems // no, this still doesn't execute the mode SetMode(uid, addr, AirAlarmMode.Filtering, true); } + + UpdateUI(uid, component); } private void OnPacketRecv(EntityUid uid, AirAlarmComponent controller, DeviceNetworkPacketEvent args) @@ -439,10 +453,23 @@ namespace Content.Server.Atmos.Monitor.Systems // Sync data to interface. // _airAlarmDataSystem.UpdateDeviceData(uid, args.SenderAddress, data); // - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateDeviceDataMessage(args.SenderAddress, data)); - // if (HasComp(uid)) controller.UpdateWires(); - if (!controller.DeviceData.TryAdd(args.SenderAddress, data)) - controller.DeviceData[args.SenderAddress] = data; + switch (data) + { + case GasVentPumpData ventData: + if (!controller.VentData.TryAdd(args.SenderAddress, ventData)) + controller.VentData[args.SenderAddress] = ventData; + break; + case GasVentScrubberData scrubberData: + if (!controller.ScrubberData.TryAdd(args.SenderAddress, scrubberData)) + controller.ScrubberData[args.SenderAddress] = scrubberData; + break; + case AtmosSensorData sensorData: + if (!controller.SensorData.TryAdd(args.SenderAddress, sensorData)) + controller.SensorData[args.SenderAddress] = sensorData; + break; + } + + UpdateUI(uid, controller); return; case AirAlarmSetDataStatus: @@ -486,84 +513,10 @@ namespace Content.Server.Atmos.Monitor.Systems /// /// Force closes all interfaces currently open related to this air alarm. /// - public void ForceCloseAllInterfaces(EntityUid uid) => + public void ForceCloseAllInterfaces(EntityUid uid) + { _uiSystem.TryCloseAll(uid, SharedAirAlarmInterfaceKey.Key); - - private void SendAddress(EntityUid uid, DeviceNetworkComponent? netConn = null) - { - if (!Resolve(uid, ref netConn)) return; - - // TODO: Use BUI states instead... - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmSetAddressMessage(netConn.Address)); - } - - /// - /// Update an interface's air data. This is all the 'hot' data - /// that an air alarm contains server-side. Updated with a whopping 8 - /// delay automatically once a UI is in the loop. - /// - public void SendAirData(EntityUid uid, AirAlarmComponent? alarm = null, AtmosMonitorComponent? monitor = null, ApcPowerReceiverComponent? power = null) - { - if (!Resolve(uid, ref alarm, ref monitor, ref power)) return; - - if (!power.Powered) return; - - - if (monitor.TileGas != null) - { - var gases = new Dictionary(); - - foreach (var gas in Enum.GetValues()) - gases.Add(gas, monitor.TileGas.GetMoles(gas)); - - var airData = new AirAlarmAirData(monitor.TileGas.Pressure, monitor.TileGas.Temperature, monitor.TileGas.TotalMoles, monitor.LastAlarmState, gases); - - // TODO: Use BUI states instead... - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAirDataMessage(airData)); - } - } - - /// - /// Send an air alarm mode to any open interface related to an air alarm. - /// - public void SendAlarmMode(EntityUid uid, AtmosMonitorComponent? monitor = null, ApcPowerReceiverComponent? power = null, AirAlarmComponent? controller = null) - { - if (!Resolve(uid, ref monitor, ref power, ref controller) - || !power.Powered) return; - - // TODO: Use BUI states instead... - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAlarmModeMessage(controller.CurrentMode)); - } - - /// - /// Send all thresholds to any open interface related to a given air alarm. - /// - public void SendThresholds(EntityUid uid, AtmosMonitorComponent? monitor = null, ApcPowerReceiverComponent? power = null, AirAlarmComponent? controller = null) - { - if (!Resolve(uid, ref monitor, ref power, ref controller) - || !power.Powered) return; - - if (monitor.PressureThreshold == null - && monitor.TemperatureThreshold == null - && monitor.GasThresholds == null) - return; - - // TODO: Use BUI states instead... - if (monitor.PressureThreshold != null) - { - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAlarmThresholdMessage(AtmosMonitorThresholdType.Pressure, monitor.PressureThreshold)); - } - - if (monitor.TemperatureThreshold != null) - { - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAlarmThresholdMessage(AtmosMonitorThresholdType.Temperature, monitor.TemperatureThreshold)); - } - - if (monitor.GasThresholds != null) - { - foreach (var (gas, threshold) in monitor.GasThresholds) - _uiSystem.TrySendUiMessage(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUpdateAlarmThresholdMessage(AtmosMonitorThresholdType.Gas, threshold, gas)); - } + RemoveActiveInterface(uid); } public void OnAtmosUpdate(EntityUid uid, AirAlarmComponent alarm, AtmosDeviceUpdateEvent args) @@ -572,6 +525,49 @@ namespace Content.Server.Atmos.Monitor.Systems alarm.CurrentModeUpdater.Update(uid); } + public void UpdateUI(EntityUid uid, AirAlarmComponent? alarm = null, AtmosAlarmableComponent? alarmable = null) + { + if (!Resolve(uid, ref alarm, ref alarmable)) + { + return; + } + + var dataToSend = new Dictionary(); + + if (alarm.CurrentTab != AirAlarmTab.Settings) + { + switch (alarm.CurrentTab) + { + case AirAlarmTab.Vent: + foreach (var (addr, data) in alarm.VentData) + { + dataToSend.Add(addr, data); + } + + break; + case AirAlarmTab.Scrubber: + foreach (var (addr, data) in alarm.ScrubberData) + { + dataToSend.Add(addr, data); + } + + break; + case AirAlarmTab.Sensors: + foreach (var (addr, data) in alarm.SensorData) + { + dataToSend.Add(addr, data); + } + + break; + } + } + + _uiSystem.TrySetUiState( + uid, + SharedAirAlarmInterfaceKey.Key, + new AirAlarmUIState(dataToSend, alarm.CurrentMode, alarm.CurrentTab, alarmable.HighestNetworkState)); + } + private const float _delay = 8f; private float _timer = 0f; @@ -583,9 +579,7 @@ namespace Content.Server.Atmos.Monitor.Systems _timer = 0f; foreach (var uid in _activeUserInterfaces) { - // TODO: Awful idea, use BUI states instead... - SendAirData(uid); - _uiSystem.TrySetUiState(uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUIState()); + SyncAllSensors(uid); } } } diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs index 221b1dba7e..ae8664ac54 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs @@ -3,11 +3,13 @@ using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Shared.Atmos.Monitor; +using Robust.Server.GameObjects; namespace Content.Server.Atmos.Monitor.Systems { public sealed class AtmosAlarmableSystem : EntitySystem { + [Dependency] private readonly AppearanceSystem _appearance = default!; public override void Initialize() { SubscribeLocalEvent(OnPacketRecv); @@ -34,9 +36,15 @@ namespace Content.Server.Atmos.Monitor.Systems { component.LastAlarmState = state; component.HighestNetworkState = netMax; + UpdateAppearance(uid, netMax); RaiseLocalEvent(component.Owner, new AtmosMonitorAlarmEvent(state, netMax), true); } } } + + private void UpdateAppearance(EntityUid uid, AtmosMonitorAlarmType alarm) + { + _appearance.SetData(uid, AtmosMonitorVisuals.AlarmType, alarm); + } } } diff --git a/Content.Shared/Atmos/Monitor/AtmosSensorData.cs b/Content.Shared/Atmos/Monitor/AtmosSensorData.cs new file mode 100644 index 0000000000..81adf5d91c --- /dev/null +++ b/Content.Shared/Atmos/Monitor/AtmosSensorData.cs @@ -0,0 +1,37 @@ +using Content.Shared.Atmos.Monitor.Components; + +namespace Content.Shared.Atmos.Monitor; + +public sealed class AtmosSensorData : IAtmosDeviceData +{ + public bool Enabled { get; set; } + public bool Dirty { get; set; } + public bool IgnoreAlarms { get; set; } + + /// Most fields are readonly, because it's data that's meant to be transmitted. + + /// + /// Current pressure detected by this sensor. + /// + public float? Pressure { get; } + /// + /// Current temperature detected by this sensor. + /// + public float? Temperature { get; } + /// + /// Current amount of moles detected by this sensor. + /// + public float? TotalMoles { get; } + /// + /// Current alarm state of this sensor. Does not reflect the highest alarm state on the network. + /// + public AtmosMonitorAlarmType AlarmState { get; } + /// + /// Current number of gases on this sensor. + /// + public Dictionary Gases { get; } + /// + /// If this sensor is currently detecting a fire. + /// + public bool OnFire { get; } +} diff --git a/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs b/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs index 5424c75920..b7075ee976 100644 --- a/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs +++ b/Content.Shared/Atmos/Monitor/Components/SharedAirAlarmComponent.cs @@ -55,11 +55,34 @@ namespace Content.Shared.Atmos.Monitor.Components public bool IgnoreAlarms { get; set; } } - // would be nice to include the entire state here - // but it's already handled by messages [Serializable, NetSerializable] public sealed class AirAlarmUIState : BoundUserInterfaceState - {} + { + public AirAlarmUIState(Dictionary deviceData, AirAlarmMode mode, AirAlarmTab tab, AtmosMonitorAlarmType alarmType) + { + DeviceData = deviceData; + Mode = mode; + Tab = tab; + AlarmType = alarmType; + } + + /// + /// Every single device data that can be seen from this + /// air alarm. This includes vents, scrubbers, and sensors. + /// The device data you get, however, depends on the current + /// selected tab. + /// + public Dictionary DeviceData { get; } + public AirAlarmMode Mode { get; } + public AirAlarmTab Tab { get; } + public AtmosMonitorAlarmType AlarmType { get; } + } + + [Serializable, NetSerializable] + public sealed class AirAlarmTabSetMessage : BoundUserInterfaceMessage + { + public AirAlarmTab Tab { get; } + } [Serializable, NetSerializable] public sealed class AirAlarmResyncAllDevicesMessage : BoundUserInterfaceMessage @@ -126,5 +149,11 @@ namespace Content.Shared.Atmos.Monitor.Components } } - + public enum AirAlarmTab + { + Vent, + Scrubber, + Sensors, + Settings + } }