force alert on alarmable, enforces synchronization with alarmables to be bounded by the tags that it can sync with

This commit is contained in:
vulppine
2022-08-22 05:01:31 -07:00
parent 550ea771a7
commit 85effbd33d
4 changed files with 107 additions and 45 deletions

View File

@@ -17,6 +17,15 @@ namespace Content.Server.Atmos.Monitor.Systems
[Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNet = default!;
/// <summary>
/// An alarm. Has three valid states: Normal, Warning, Danger.
/// Will attempt to fetch the tags from the alarming entity
/// to send over.
/// </summary>
public const string AlertCmd = "atmos_alarm";
public const string AlertSource = "atmos_alarm_source";
/// <summary>
/// Syncs alerts from this alarm receiver to other alarm receivers.
/// Creates a network effect as a result. Note: if the alert receiver
@@ -47,38 +56,57 @@ namespace Content.Server.Atmos.Monitor.Systems
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn))
return;
if (args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd))
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)
|| !args.Data.TryGetValue(AlertSource, out List<string>? sourceTags))
{
return;
}
var isValid = false;
foreach (var source in sourceTags)
{
if (component.SyncWithTags.Contains(source))
{
isValid = true;
break;
}
}
if (!isValid)
{
return;
}
switch (cmd)
{
case AtmosMonitorSystem.AtmosMonitorAlarmCmd:
case AlertCmd:
// 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 (!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);
return;
}
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 ResetAll:
Reset(uid, component);
@@ -121,12 +149,48 @@ namespace Content.Server.Atmos.Monitor.Systems
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = SyncAlerts,
[SyncAlerts] = alarmable.NetworkAlarmStates
[SyncAlerts] = alarmable.NetworkAlarmStates,
[AlertSource] = alarmable.SyncWithTags
};
_deviceNet.QueuePacket(uid, address, payload);
}
/// <summary>
/// Forces this alarmable to have a specific alert. This will not be reset until the alarmable
/// is manually reset. This will store the alarmable as a device in its network states, and sync
/// it to the rest of the network.
/// </summary>
/// <param name="uid"></param>
/// <param name="alarmType"></param>
/// <param name="alarmable"></param>
public void ForceAlert(EntityUid uid, AtmosMonitorAlarmType alarmType,
AtmosAlarmableComponent? alarmable = null, DeviceNetworkComponent? devNet = null)
{
if (!Resolve(uid, ref alarmable, ref devNet))
{
return;
}
alarmable.LastAlarmState = alarmType;
if (!alarmable.NetworkAlarmStates.TryAdd(devNet.Address, alarmType))
{
alarmable.NetworkAlarmStates[devNet.Address] = alarmType;
}
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = AlertCmd,
[DeviceNetworkConstants.CmdSetState] = alarmType,
[AlertSource] = alarmable.SyncWithTags
};
_deviceNet.QueuePacket(uid, null, payload);
RaiseLocalEvent(uid, new AtmosMonitorAlarmEvent(alarmType, alarmType));
}
/// <summary>
/// Resets the state of this alarmable to normal.
/// </summary>
@@ -158,7 +222,8 @@ namespace Content.Server.Atmos.Monitor.Systems
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = ResetAll
[DeviceNetworkConstants.Command] = ResetAll,
[AlertSource] = alarmable.SyncWithTags
};
_deviceNet.QueuePacket(uid, null, payload);
@@ -171,7 +236,7 @@ namespace Content.Server.Atmos.Monitor.Systems
/// <param name="alarm"></param>
/// <param name="alarmable"></param>
/// <returns></returns>
private bool TryGetHighestAlert(EntityUid uid, [NotNullWhen(true)] out AtmosMonitorAlarmType? alarm,
public bool TryGetHighestAlert(EntityUid uid, [NotNullWhen(true)] out AtmosMonitorAlarmType? alarm,
AtmosAlarmableComponent? alarmable = null)
{
alarm = null;