some backend stuff for air alarms

finally, some UI states!!!
This commit is contained in:
vulppine
2022-08-17 23:46:15 -07:00
parent 32e2686a4b
commit 1c651f051f
6 changed files with 188 additions and 112 deletions

View File

@@ -40,9 +40,10 @@
<ScrollContainer VerticalExpand="True">
<BoxContainer Name="CScrubberContainer" Orientation="Vertical"/>
</ScrollContainer>
<!-- Alarm thresholds -->
<!-- Sensors -->
<ScrollContainer VerticalExpand="True">
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="CSensorContainer" Orientation="Vertical"/>
<!-- <BoxContainer Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="CPressureThreshold" Orientation="Vertical" Margin="2 0 2 0" />
<BoxContainer Name="CTemperatureThreshold" Orientation="Vertical" Margin="2 0 2 0" />
<Collapsible Orientation="Vertical">
@@ -51,7 +52,7 @@
<BoxContainer Name="CGasThresholdContainer" Orientation="Vertical" Margin="2 0 2 0" />
</CollapsibleBody>
</Collapsible>
</BoxContainer>
</BoxContainer> -->
</ScrollContainer>
</TabContainer>

View File

@@ -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<string, IAtmosDeviceData> DeviceData = new();
public Dictionary<string, GasVentPumpData> VentData = new();
public Dictionary<string, GasVentScrubberData> ScrubberData = new();
public Dictionary<string, AtmosSensorData> SensorData = new();
public HashSet<NetUserId> ActivePlayers = new();

View File

@@ -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);
}
/// <summary>
/// Synchronize all sensors on an air alarm, but only if its current tab is set to Sensors.
/// </summary>
/// <param name="uid"></param>
/// <param name="monitor"></param>
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);
}
}
/// <summary>
/// Sync this air alarm's mode with the rest of the network.
/// </summary>
@@ -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<WiresComponent>(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
/// <summary>
/// Force closes all interfaces currently open related to this air alarm.
/// </summary>
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));
}
/// <summary>
/// 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.
/// </summary>
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<Gas, float>();
foreach (var gas in Enum.GetValues<Gas>())
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));
}
}
/// <summary>
/// Send an air alarm mode to any open interface related to an air alarm.
/// </summary>
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));
}
/// <summary>
/// Send all thresholds to any open interface related to a given air alarm.
/// </summary>
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<string, IAtmosDeviceData>();
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);
}
}
}

View File

@@ -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<AtmosAlarmableComponent, DeviceNetworkPacketEvent>(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);
}
}
}

View File

@@ -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.
/// <summary>
/// Current pressure detected by this sensor.
/// </summary>
public float? Pressure { get; }
/// <summary>
/// Current temperature detected by this sensor.
/// </summary>
public float? Temperature { get; }
/// <summary>
/// Current amount of moles detected by this sensor.
/// </summary>
public float? TotalMoles { get; }
/// <summary>
/// Current alarm state of this sensor. Does not reflect the highest alarm state on the network.
/// </summary>
public AtmosMonitorAlarmType AlarmState { get; }
/// <summary>
/// Current number of gases on this sensor.
/// </summary>
public Dictionary<Gas, float> Gases { get; }
/// <summary>
/// If this sensor is currently detecting a fire.
/// </summary>
public bool OnFire { get; }
}

View File

@@ -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<string, IAtmosDeviceData> deviceData, AirAlarmMode mode, AirAlarmTab tab, AtmosMonitorAlarmType alarmType)
{
DeviceData = deviceData;
Mode = mode;
Tab = tab;
AlarmType = alarmType;
}
/// <summary>
/// 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.
/// </summary>
public Dictionary<string, IAtmosDeviceData> 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
}
}