starts moving alarm sync logic to alarmables
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.Monitor.Components;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Atmos.Monitor.Systems
|
||||
{
|
||||
@@ -12,9 +15,26 @@ namespace Content.Server.Atmos.Monitor.Systems
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Syncs alerts from this alarm receiver to other alarm receivers.
|
||||
/// Creates a network effect as a result. Note: if the alert receiver
|
||||
/// is not aware of the device beforehand, it will not sync.
|
||||
/// </summary>
|
||||
public const string SyncAlerts = "atmos_alarmable_sync_alerts";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<AtmosAlarmableComponent, DeviceNetworkPacketEvent>(OnPacketRecv);
|
||||
SubscribeLocalEvent<AtmosAlarmableComponent, PowerChangedEvent>(OnPowerChange);
|
||||
}
|
||||
|
||||
private void OnPowerChange(EntityUid uid, AtmosAlarmableComponent component, PowerChangedEvent args)
|
||||
{
|
||||
if (!args.Powered)
|
||||
{
|
||||
Reset(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPacketRecv(EntityUid uid, AtmosAlarmableComponent component, DeviceNetworkPacketEvent args)
|
||||
@@ -24,25 +44,108 @@ namespace Content.Server.Atmos.Monitor.Systems
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn))
|
||||
return;
|
||||
|
||||
if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)
|
||||
&& cmd == AtmosMonitorSystem.AtmosMonitorAlarmCmd)
|
||||
if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd))
|
||||
{
|
||||
// does it have a state & network max state?
|
||||
// does it have a source?
|
||||
// and can this be alarmed by the source?
|
||||
// if so, raise an alarm
|
||||
if (args.Data.TryGetValue(DeviceNetworkConstants.CmdSetState, out AtmosMonitorAlarmType state)
|
||||
&& args.Data.TryGetValue(AtmosMonitorSystem.AtmosMonitorAlarmNetMax, out AtmosMonitorAlarmType netMax)
|
||||
&& args.Data.TryGetValue(AtmosMonitorSystem.AtmosMonitorAlarmSrc, out string? source)
|
||||
&& component.AlarmedByPrototypes.Contains(source))
|
||||
{
|
||||
component.LastAlarmState = state;
|
||||
component.HighestNetworkState = netMax;
|
||||
UpdateAppearance(uid, netMax);
|
||||
PlayAlertSound(uid, netMax, component);
|
||||
RaiseLocalEvent(component.Owner, new AtmosMonitorAlarmEvent(state, netMax), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case AtmosMonitorSystem.AtmosMonitorAlarmCmd:
|
||||
// Set the alert state, and then cache it so we can calculate
|
||||
// the maximum alarm state at all times.
|
||||
if (args.Data.TryGetValue(DeviceNetworkConstants.CmdSetState, out AtmosMonitorAlarmType state))
|
||||
{
|
||||
if (!component.NetworkAlarmStates.ContainsKey(args.SenderAddress))
|
||||
{
|
||||
component.NetworkAlarmStates.Add(args.SenderAddress, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
component.NetworkAlarmStates[args.SenderAddress] = state;
|
||||
}
|
||||
|
||||
if (!TryGetHighestAlert(uid, out var netMax, component))
|
||||
{
|
||||
netMax = AtmosMonitorAlarmType.Normal;
|
||||
}
|
||||
|
||||
component.LastAlarmState = netMax.Value;
|
||||
|
||||
UpdateAppearance(uid, netMax.Value);
|
||||
PlayAlertSound(uid, netMax.Value, component);
|
||||
RaiseLocalEvent(component.Owner, new AtmosMonitorAlarmEvent(state, netMax.Value), true);
|
||||
}
|
||||
break;
|
||||
case SyncAlerts:
|
||||
// Synchronize alerts, but only if they're already known by this monitor.
|
||||
// This should help eliminate the chain effect, especially with
|
||||
if (!args.Data.TryGetValue(SyncAlerts,
|
||||
out IReadOnlyDictionary<string, AtmosMonitorAlarmType>? alarms))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var (key, alarm) in alarms)
|
||||
{
|
||||
if (component.NetworkAlarmStates.ContainsKey(key))
|
||||
{
|
||||
component.NetworkAlarmStates[key] = alarm;
|
||||
}
|
||||
}
|
||||
|
||||
if (TryGetHighestAlert(uid, out var maxAlert, component)
|
||||
&& component.LastAlarmState < maxAlert)
|
||||
{
|
||||
component.LastAlarmState = maxAlert.Value;
|
||||
RaiseLocalEvent(uid, new AtmosMonitorAlarmEvent(maxAlert.Value, maxAlert.Value));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the state of this alarmable to normal.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="alarmable"></param>
|
||||
public void Reset(EntityUid uid, AtmosAlarmableComponent? alarmable = null)
|
||||
{
|
||||
if (!Resolve(uid, ref alarmable))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
alarmable.LastAlarmState = AtmosMonitorAlarmType.Normal;
|
||||
alarmable.NetworkAlarmStates.Clear();
|
||||
|
||||
RaiseLocalEvent(uid, new AtmosMonitorAlarmEvent(AtmosMonitorAlarmType.Normal, AtmosMonitorAlarmType.Normal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the highest possible alert stored in this alarm.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="alarm"></param>
|
||||
/// <param name="alarmable"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryGetHighestAlert(EntityUid uid, [NotNullWhen(true)] out AtmosMonitorAlarmType? alarm,
|
||||
AtmosAlarmableComponent? alarmable = null)
|
||||
{
|
||||
alarm = null;
|
||||
|
||||
if (!Resolve(uid, ref alarmable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var alarmState in alarmable.NetworkAlarmStates.Values)
|
||||
{
|
||||
alarm = alarm < alarmState ? alarmState : alarm;
|
||||
}
|
||||
|
||||
return alarm != null;
|
||||
}
|
||||
|
||||
private void PlayAlertSound(EntityUid uid, AtmosMonitorAlarmType alarm, AtmosAlarmableComponent alarmable)
|
||||
|
||||
Reference in New Issue
Block a user