Files
OldThink/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs

666 lines
22 KiB
C#
Raw Normal View History

using System.Linq;
using Content.Server.Atmos.Monitor.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Server.DeviceLinking.Systems;
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Access.Components;
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.DeviceLinking;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Systems;
using Content.Shared.Interaction;
2023-03-24 03:09:45 +03:00
using Content.Shared.Wires;
using Robust.Server.GameObjects;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player;
2022-08-23 10:55:46 -07:00
namespace Content.Server.Atmos.Monitor.Systems;
// AirAlarm system - specific for atmos devices, rather than
// atmos monitors.
//
// oh boy, message passing!
//
// Commands should always be sent into packet's Command
// data key. In response, a packet will be transmitted
// with the response type as its command, and the
// response data in its data key.
public sealed class AirAlarmSystem : EntitySystem
{
[Dependency] private readonly AccessReaderSystem _access = default!;
2022-08-23 10:55:46 -07:00
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
[Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNet = default!;
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
[Dependency] private readonly DeviceListSystem _deviceList = default!;
2022-08-23 10:55:46 -07:00
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
2022-08-23 10:55:46 -07:00
#region Device Network API
/// <summary>
/// Command to set an air alarm's mode.
/// </summary>
public const string AirAlarmSetMode = "air_alarm_set_mode";
// -- API --
/// <summary>
/// Set the data for an air alarm managed device.
/// </summary>
/// <param name="address">The address of the device.</param>
/// <param name="data">The data to send to the device.</param>
public void SetData(EntityUid uid, string address, IAtmosDeviceData data)
{
_atmosDevNet.SetDeviceState(uid, address, data);
_atmosDevNet.Sync(uid, address);
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
/// <summary>
/// Broadcast a sync packet to an air alarm's local network.
/// </summary>
private void SyncAllDevices(EntityUid uid)
{
_atmosDevNet.Sync(uid, null);
2022-08-23 10:55:46 -07:00
}
/// <summary>
/// Send a sync packet to a specific device from an air alarm.
/// </summary>
/// <param name="address">The address of the device.</param>
private void SyncDevice(EntityUid uid, string address)
{
_atmosDevNet.Sync(uid, address);
2022-08-23 10:55:46 -07:00
}
/// <summary>
/// Register and synchronize with all devices
/// on this network.
/// </summary>
/// <param name="uid"></param>
private void SyncRegisterAllDevices(EntityUid uid)
2022-08-23 10:55:46 -07:00
{
_atmosDevNet.Register(uid, null);
_atmosDevNet.Sync(uid, null);
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
/// <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))
{
2022-08-23 10:55:46 -07:00
return;
}
2022-08-23 10:55:46 -07:00
foreach (var addr in monitor.SensorData.Keys)
{
2022-08-23 10:55:46 -07:00
SyncDevice(uid, addr);
}
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
private void SetThreshold(EntityUid uid, string address, AtmosMonitorThresholdType type,
AtmosAlarmThreshold threshold, Gas? gas = null)
{
var payload = new NetworkPayload
{
2022-08-23 10:55:46 -07:00
[DeviceNetworkConstants.Command] = AtmosMonitorSystem.AtmosMonitorSetThresholdCmd,
[AtmosMonitorSystem.AtmosMonitorThresholdDataType] = type,
[AtmosMonitorSystem.AtmosMonitorThresholdData] = threshold,
};
2022-08-23 10:55:46 -07:00
if (gas != null)
{
2022-08-23 10:55:46 -07:00
payload.Add(AtmosMonitorSystem.AtmosMonitorThresholdGasType, gas);
}
2022-08-23 10:55:46 -07:00
_deviceNet.QueuePacket(uid, address, payload);
2022-08-23 10:55:46 -07:00
SyncDevice(uid, address);
}
2022-08-23 10:55:46 -07:00
/// <summary>
/// Sync this air alarm's mode with the rest of the network.
/// </summary>
/// <param name="mode">The mode to sync with the rest of the network.</param>
private void SyncMode(EntityUid uid, AirAlarmMode mode)
2022-08-23 10:55:46 -07:00
{
if (TryComp<AtmosMonitorComponent>(uid, out var monitor) && !monitor.NetEnabled)
2022-08-23 10:55:46 -07:00
return;
2022-08-23 10:55:46 -07:00
var payload = new NetworkPayload
{
2022-08-23 10:55:46 -07:00
[DeviceNetworkConstants.Command] = AirAlarmSetMode,
[AirAlarmSetMode] = mode
};
2022-08-23 10:55:46 -07:00
_deviceNet.QueuePacket(uid, null, payload);
}
2022-08-23 10:55:46 -07:00
#endregion
2022-08-23 10:55:46 -07:00
#region Events
2022-08-23 10:55:46 -07:00
public override void Initialize()
{
SubscribeLocalEvent<AirAlarmComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
SubscribeLocalEvent<AirAlarmComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
SubscribeLocalEvent<AirAlarmComponent, AtmosAlarmEvent>(OnAtmosAlarm);
SubscribeLocalEvent<AirAlarmComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<AirAlarmComponent, DeviceListUpdateEvent>(OnDeviceListUpdate);
SubscribeLocalEvent<AirAlarmComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<AirAlarmComponent, MapInitEvent>(OnMapInit);
2022-08-23 10:55:46 -07:00
SubscribeLocalEvent<AirAlarmComponent, ComponentShutdown>(OnShutdown);
Adds the thermo-electric generator (#18840) * Basic TEG start. Connects via node group. * Basic TEG test map * Sensor monitoring basics, TEG circulator flow * Basic power generation (it doesn't work) * More sensor monitoring work * Battery (SMES) monitoring system. * Sensor monitoring fixes Make it work properly when mapped. * Test map improvements * Revise TEG power output mechanism. Now uses a fixed supplier with a custom ramping system. * TEG test map fixes * Make air alarms and pumps open UI on activate. * Clean up thermo machines power switch. Removed separate Enabled bool from the component that always matched the power receiver's state. This enables adding a PowerSwitch component to give us alt click/verb menu. * TEG but now fancy * Make sensor monitoring console obviously WiP to mappers. * Vending machine sound, because of course. * Terrible, terrible graph background color * Examine improvements for the TEG. * Account for electrical power when equalizing gas mixtures. * Get rid of the TegCirculatorArrow logic. Use TimedDespawn instead. The "no show in right-click menuu" goes into a new general-purpose component. Thanks Julian. * Put big notice of "not ready, here's why" on the sensor monitoring console. * TryGetComponent -> TryComp * Lol there's a HideContextMenu tag * Test fixes * Guidebook for TEG Fixed rotation on GuideEntityEmbed not working correctly. Added Margin property to GuideEntityEmbed * Make TEG power bar default to invisible. So it doesn't appear in the guidebook and spawn menu.
2023-08-12 22:41:55 +02:00
SubscribeLocalEvent<AirAlarmComponent, ActivateInWorldEvent>(OnActivate);
Subs.BuiEvents<AirAlarmComponent>(SharedAirAlarmInterfaceKey.Key, subs =>
{
subs.Event<BoundUIClosedEvent>(OnClose);
subs.Event<AirAlarmResyncAllDevicesMessage>(OnResyncAll);
subs.Event<AirAlarmUpdateAlarmModeMessage>(OnUpdateAlarmMode);
subs.Event<AirAlarmUpdateAutoModeMessage>(OnUpdateAutoMode);
subs.Event<AirAlarmUpdateAlarmThresholdMessage>(OnUpdateThreshold);
subs.Event<AirAlarmUpdateDeviceDataMessage>(OnUpdateDeviceData);
subs.Event<AirAlarmCopyDeviceDataMessage>(OnCopyDeviceData);
subs.Event<AirAlarmTabSetMessage>(OnTabChange);
});
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
private void OnDeviceListUpdate(EntityUid uid, AirAlarmComponent component, DeviceListUpdateEvent args)
{
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in args.OldDevices)
{
if (!query.TryGetComponent(device, out var deviceNet))
{
continue;
}
_atmosDevNet.Deregister(uid, deviceNet.Address);
}
component.ScrubberData.Clear();
component.SensorData.Clear();
component.VentData.Clear();
component.KnownDevices.Clear();
UpdateUI(uid, component);
2022-08-23 10:55:46 -07:00
SyncRegisterAllDevices(uid);
}
2022-08-23 10:55:46 -07:00
private void OnTabChange(EntityUid uid, AirAlarmComponent component, AirAlarmTabSetMessage msg)
{
component.CurrentTab = msg.Tab;
UpdateUI(uid, component);
}
private void OnPowerChanged(EntityUid uid, AirAlarmComponent component, ref PowerChangedEvent args)
2022-08-23 10:55:46 -07:00
{
2022-09-04 02:04:15 -07:00
if (args.Powered)
2022-08-18 08:14:18 -07:00
{
2022-09-04 02:04:15 -07:00
return;
}
2022-09-04 02:04:15 -07:00
ForceCloseAllInterfaces(uid);
component.CurrentModeUpdater = null;
component.KnownDevices.Clear();
component.ScrubberData.Clear();
component.SensorData.Clear();
component.VentData.Clear();
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
private void OnClose(EntityUid uid, AirAlarmComponent component, BoundUIClosedEvent args)
{
component.ActivePlayers.Remove(args.Session.UserId);
if (component.ActivePlayers.Count == 0)
RemoveActiveInterface(uid);
}
private void OnInit(EntityUid uid, AirAlarmComponent comp, ComponentInit args)
{
_deviceLink.EnsureSourcePorts(uid, comp.DangerPort, comp.WarningPort, comp.NormalPort);
}
private void OnMapInit(EntityUid uid, AirAlarmComponent comp, MapInitEvent args)
{
// for mapped linked air alarms, start with high so when it changes for the first time it goes from high to low
// without this the output would suddenly get sent a low signal after nothing which is bad
_deviceLink.SendSignal(uid, GetPort(comp), true);
}
2022-08-23 10:55:46 -07:00
private void OnShutdown(EntityUid uid, AirAlarmComponent component, ComponentShutdown args)
{
_activeUserInterfaces.Remove(uid);
}
Adds the thermo-electric generator (#18840) * Basic TEG start. Connects via node group. * Basic TEG test map * Sensor monitoring basics, TEG circulator flow * Basic power generation (it doesn't work) * More sensor monitoring work * Battery (SMES) monitoring system. * Sensor monitoring fixes Make it work properly when mapped. * Test map improvements * Revise TEG power output mechanism. Now uses a fixed supplier with a custom ramping system. * TEG test map fixes * Make air alarms and pumps open UI on activate. * Clean up thermo machines power switch. Removed separate Enabled bool from the component that always matched the power receiver's state. This enables adding a PowerSwitch component to give us alt click/verb menu. * TEG but now fancy * Make sensor monitoring console obviously WiP to mappers. * Vending machine sound, because of course. * Terrible, terrible graph background color * Examine improvements for the TEG. * Account for electrical power when equalizing gas mixtures. * Get rid of the TegCirculatorArrow logic. Use TimedDespawn instead. The "no show in right-click menuu" goes into a new general-purpose component. Thanks Julian. * Put big notice of "not ready, here's why" on the sensor monitoring console. * TryGetComponent -> TryComp * Lol there's a HideContextMenu tag * Test fixes * Guidebook for TEG Fixed rotation on GuideEntityEmbed not working correctly. Added Margin property to GuideEntityEmbed * Make TEG power bar default to invisible. So it doesn't appear in the guidebook and spawn menu.
2023-08-12 22:41:55 +02:00
private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWorldEvent args)
2022-08-23 10:55:46 -07:00
{
2023-03-24 03:09:45 +03:00
if (!TryComp<ActorComponent>(args.User, out var actor))
2022-08-23 10:55:46 -07:00
return;
2023-03-24 03:09:45 +03:00
if (TryComp<WiresPanelComponent>(uid, out var panel) && panel.Open)
{
2022-08-23 10:55:46 -07:00
args.Handled = false;
return;
}
2022-08-23 10:55:46 -07:00
if (!this.IsPowered(uid, EntityManager))
return;
var ui = _ui.GetUiOrNull(uid, SharedAirAlarmInterfaceKey.Key);
2023-03-24 03:09:45 +03:00
if (ui != null)
_ui.OpenUi(ui, actor.PlayerSession);
2022-08-23 10:55:46 -07:00
component.ActivePlayers.Add(actor.PlayerSession.UserId);
AddActiveInterface(uid);
SyncAllDevices(uid);
UpdateUI(uid, component);
}
private void OnResyncAll(EntityUid uid, AirAlarmComponent component, AirAlarmResyncAllDevicesMessage args)
{
if (!AccessCheck(uid, args.Session.AttachedEntity, component))
{
return;
2022-08-23 10:55:46 -07:00
}
component.KnownDevices.Clear();
component.VentData.Clear();
component.ScrubberData.Clear();
component.SensorData.Clear();
SyncRegisterAllDevices(uid);
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
private void OnUpdateAlarmMode(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmModeMessage args)
{
if (AccessCheck(uid, args.Session.AttachedEntity, component))
{
var addr = string.Empty;
if (TryComp<DeviceNetworkComponent>(uid, out var netConn))
{
addr = netConn.Address;
}
SetMode(uid, addr, args.Mode, false);
}
2022-08-23 10:55:46 -07:00
else
{
2022-08-23 10:55:46 -07:00
UpdateUI(uid, component);
}
2022-08-23 10:55:46 -07:00
}
private void OnUpdateAutoMode(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAutoModeMessage args)
{
component.AutoMode = args.Enabled;
UpdateUI(uid, component);
}
2022-08-23 10:55:46 -07:00
private void OnUpdateThreshold(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmThresholdMessage args)
{
if (AccessCheck(uid, args.Session.AttachedEntity, component))
SetThreshold(uid, args.Address, args.Type, args.Threshold, args.Gas);
else
UpdateUI(uid, component);
}
2022-08-23 10:55:46 -07:00
private void OnUpdateDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateDeviceDataMessage args)
{
if (AccessCheck(uid, args.Session.AttachedEntity, component)
&& _deviceList.ExistsInDeviceList(uid, args.Address))
{
2022-08-23 10:55:46 -07:00
SetDeviceData(uid, args.Address, args.Data);
}
2022-08-23 10:55:46 -07:00
else
{
UpdateUI(uid, component);
}
2022-08-23 10:55:46 -07:00
}
private void OnCopyDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmCopyDeviceDataMessage args)
{
if (!AccessCheck(uid, args.Session.AttachedEntity, component))
{
UpdateUI(uid, component);
return;
}
switch (args.Data)
{
case GasVentPumpData ventData:
foreach (string addr in component.VentData.Keys)
{
SetData(uid, addr, args.Data);
}
break;
case GasVentScrubberData scrubberData:
foreach (string addr in component.ScrubberData.Keys)
{
SetData(uid, addr, args.Data);
}
break;
}
}
2022-08-23 10:55:46 -07:00
private bool AccessCheck(EntityUid uid, EntityUid? user, AirAlarmComponent? component = null)
{
if (!Resolve(uid, ref component))
return false;
// if it has no access reader behave as if the user has AA
if (!TryComp<AccessReaderComponent>(uid, out var reader))
return true;
if (user == null)
2022-08-23 10:55:46 -07:00
return false;
if (!_access.IsAllowed(user.Value, uid, reader))
{
_popup.PopupEntity(Loc.GetString("air-alarm-ui-access-denied"), user.Value, user.Value);
2022-08-23 10:55:46 -07:00
return false;
}
2022-08-23 10:55:46 -07:00
return true;
}
2022-08-23 10:55:46 -07:00
private void OnAtmosAlarm(EntityUid uid, AirAlarmComponent component, AtmosAlarmEvent args)
{
if (component.ActivePlayers.Count != 0)
{
2022-08-23 10:55:46 -07:00
SyncAllDevices(uid);
}
var addr = string.Empty;
if (TryComp<DeviceNetworkComponent>(uid, out var netConn))
{
addr = netConn.Address;
}
if (component.AutoMode)
{
if (args.AlarmType == AtmosAlarmType.Danger)
{
SetMode(uid, addr, AirAlarmMode.WideFiltering, false);
}
else if (args.AlarmType == AtmosAlarmType.Normal || args.AlarmType == AtmosAlarmType.Warning)
{
SetMode(uid, addr, AirAlarmMode.Filtering, false);
}
2022-08-23 10:55:46 -07:00
}
if (component.State != args.AlarmType)
{
TryComp<DeviceLinkSourceComponent>(uid, out var source);
// send low to old state's port
_deviceLink.SendSignal(uid, GetPort(component), false, source);
// send high to new state's port, along with updating the cached state
component.State = args.AlarmType;
_deviceLink.SendSignal(uid, GetPort(component), true, source);
}
2022-08-23 10:55:46 -07:00
UpdateUI(uid, component);
}
private string GetPort(AirAlarmComponent comp)
{
if (comp.State == AtmosAlarmType.Danger)
return comp.DangerPort;
if (comp.State == AtmosAlarmType.Warning)
return comp.WarningPort;
return comp.NormalPort;
}
2022-08-23 10:55:46 -07:00
#endregion
2022-08-23 10:55:46 -07:00
#region Air Alarm Settings
2022-08-23 10:55:46 -07:00
/// <summary>
/// Set an air alarm's mode.
/// </summary>
/// <param name="origin">The origin address of this mode set. Used for network sync.</param>
/// <param name="mode">The mode to set the alarm to.</param>
/// <param name="uiOnly">Whether this change is for the UI only, or if it changes the air alarm's operating mode. Defaults to true.</param>
public void SetMode(EntityUid uid, string origin, AirAlarmMode mode, bool uiOnly = true, AirAlarmComponent? controller = null)
2022-08-23 10:55:46 -07:00
{
if (!Resolve(uid, ref controller) || controller.CurrentMode == mode)
{
return;
}
2022-08-23 10:55:46 -07:00
controller.CurrentMode = mode;
// setting it to UI only means we don't have
2022-08-23 10:55:46 -07:00
// to deal with the issue of not-single-owner
// alarm mode executors
if (!uiOnly)
{
2022-08-23 10:55:46 -07:00
var newMode = AirAlarmModeFactory.ModeToExecutor(mode);
if (newMode != null)
{
2022-08-23 10:55:46 -07:00
newMode.Execute(uid);
if (newMode is IAirAlarmModeUpdate updatedMode)
{
2022-08-23 10:55:46 -07:00
controller.CurrentModeUpdater = updatedMode;
controller.CurrentModeUpdater.NetOwner = origin;
}
2022-08-23 10:55:46 -07:00
else if (controller.CurrentModeUpdater != null)
controller.CurrentModeUpdater = null;
}
}
2022-08-23 10:55:46 -07:00
// only one air alarm in a network can use an air alarm mode
// that updates, so even if it's a ui-only change,
// we have to invalidate the last mode's updater and
2022-08-23 10:55:46 -07:00
// remove it because otherwise it'll execute a now
// invalid mode
else if (controller.CurrentModeUpdater != null
&& controller.CurrentModeUpdater.NetOwner != origin)
{
2022-08-23 10:55:46 -07:00
controller.CurrentModeUpdater = null;
}
2022-08-23 10:55:46 -07:00
UpdateUI(uid, controller);
// setting sync deals with the issue of air alarms
// in the same network needing to have the same mode
// as other alarms
SyncMode(uid, mode);
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
/// <summary>
/// Sets device data. Practically a wrapper around the packet sending function, SetData.
/// </summary>
/// <param name="address">The address to send the new data to.</param>
/// <param name="devData">The device data to be sent.</param>
private void SetDeviceData(EntityUid uid, string address, IAtmosDeviceData devData, AirAlarmComponent? controller = null)
2022-08-23 10:55:46 -07:00
{
if (!Resolve(uid, ref controller))
{
return;
}
2022-08-23 10:55:46 -07:00
devData.Dirty = true;
SetData(uid, address, devData);
}
2022-08-23 10:55:46 -07:00
private void OnPacketRecv(EntityUid uid, AirAlarmComponent controller, DeviceNetworkPacketEvent args)
{
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd))
return;
2022-08-23 10:55:46 -07:00
switch (cmd)
{
case AtmosDeviceNetworkSystem.SyncData:
if (!args.Data.TryGetValue(AtmosDeviceNetworkSystem.SyncData, out IAtmosDeviceData? data)
|| !controller.CanSync)
break;
// Save into component.
// Sync data to interface.
switch (data)
{
case GasVentPumpData ventData:
if (!controller.VentData.TryAdd(args.SenderAddress, ventData))
controller.VentData[args.SenderAddress] = ventData;
2022-08-17 20:32:31 -07:00
break;
2022-08-23 10:55:46 -07:00
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;
}
controller.KnownDevices.Add(args.SenderAddress);
2022-08-23 10:55:46 -07:00
UpdateUI(uid, controller);
2022-08-23 10:55:46 -07:00
return;
case AirAlarmSetMode:
if (!args.Data.TryGetValue(AirAlarmSetMode, out AirAlarmMode alarmMode))
break;
SetMode(uid, args.SenderAddress, alarmMode, uiOnly: false);
2022-08-23 10:55:46 -07:00
return;
}
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
#endregion
2022-08-23 10:55:46 -07:00
#region UI
2022-08-23 10:55:46 -07:00
// List of active user interfaces.
private readonly HashSet<EntityUid> _activeUserInterfaces = new();
2022-08-23 10:55:46 -07:00
/// <summary>
/// Adds an active interface to be updated.
/// </summary>
private void AddActiveInterface(EntityUid uid)
{
2022-08-23 10:55:46 -07:00
_activeUserInterfaces.Add(uid);
}
2022-08-23 10:55:46 -07:00
/// <summary>
/// Removes an active interface from the system update loop.
/// </summary>
private void RemoveActiveInterface(EntityUid uid)
{
2022-08-23 10:55:46 -07:00
_activeUserInterfaces.Remove(uid);
}
2022-08-23 10:55:46 -07:00
/// <summary>
/// Force closes all interfaces currently open related to this air alarm.
/// </summary>
private void ForceCloseAllInterfaces(EntityUid uid)
2022-08-23 10:55:46 -07:00
{
_ui.TryCloseAll(uid, SharedAirAlarmInterfaceKey.Key);
2022-08-23 10:55:46 -07:00
}
private void OnAtmosUpdate(EntityUid uid, AirAlarmComponent alarm, ref AtmosDeviceUpdateEvent args)
2022-08-23 10:55:46 -07:00
{
alarm.CurrentModeUpdater?.Update(uid);
2022-08-23 10:55:46 -07:00
}
2022-08-23 10:55:46 -07:00
public float CalculatePressureAverage(AirAlarmComponent alarm)
{
return alarm.SensorData.Count != 0
? alarm.SensorData.Values.Select(v => v.Pressure).Average()
: 0f;
}
2022-08-23 10:55:46 -07:00
public float CalculateTemperatureAverage(AirAlarmComponent alarm)
{
return alarm.SensorData.Count != 0
? alarm.SensorData.Values.Select(v => v.Temperature).Average()
: 0f;
}
2022-08-23 10:55:46 -07:00
public void UpdateUI(EntityUid uid, AirAlarmComponent? alarm = null, DeviceNetworkComponent? devNet = null, AtmosAlarmableComponent? alarmable = null)
{
if (!Resolve(uid, ref alarm, ref devNet, ref alarmable))
{
2022-08-23 10:55:46 -07:00
return;
}
2022-08-23 10:55:46 -07:00
var pressure = CalculatePressureAverage(alarm);
var temperature = CalculateTemperatureAverage(alarm);
var dataToSend = new Dictionary<string, IAtmosDeviceData>();
2022-08-23 10:55:46 -07:00
if (alarm.CurrentTab != AirAlarmTab.Settings)
{
switch (alarm.CurrentTab)
{
2022-08-23 10:55:46 -07:00
case AirAlarmTab.Vent:
foreach (var (addr, data) in alarm.VentData)
{
dataToSend.Add(addr, data);
}
2022-08-23 10:55:46 -07:00
break;
case AirAlarmTab.Scrubber:
foreach (var (addr, data) in alarm.ScrubberData)
{
dataToSend.Add(addr, data);
}
2022-08-23 10:55:46 -07:00
break;
case AirAlarmTab.Sensors:
foreach (var (addr, data) in alarm.SensorData)
{
dataToSend.Add(addr, data);
}
2022-08-23 10:55:46 -07:00
break;
}
2022-08-23 10:55:46 -07:00
}
var deviceCount = alarm.KnownDevices.Count;
2022-08-23 10:55:46 -07:00
if (!_atmosAlarmable.TryGetHighestAlert(uid, out var highestAlarm))
{
highestAlarm = AtmosAlarmType.Normal;
}
_ui.TrySetUiState(
2022-08-23 10:55:46 -07:00
uid,
SharedAirAlarmInterfaceKey.Key,
new AirAlarmUIState(devNet.Address, deviceCount, pressure, temperature, dataToSend, alarm.CurrentMode, alarm.CurrentTab, highestAlarm.Value, alarm.AutoMode));
2022-08-23 10:55:46 -07:00
}
private const float Delay = 8f;
private float _timer;
2022-08-23 10:55:46 -07:00
public override void Update(float frameTime)
{
_timer += frameTime;
if (_timer >= Delay)
{
2022-08-23 10:55:46 -07:00
_timer = 0f;
foreach (var uid in _activeUserInterfaces)
{
2022-08-23 10:55:46 -07:00
SyncAllSensors(uid);
}
}
}
2022-08-23 10:55:46 -07:00
#endregion
}