diff --git a/Content.Server/Atmos/Monitor/Components/AtmosAlarmableComponent.cs b/Content.Server/Atmos/Monitor/Components/AtmosAlarmableComponent.cs index 23a903ff9c..23f25ad4de 100644 --- a/Content.Server/Atmos/Monitor/Components/AtmosAlarmableComponent.cs +++ b/Content.Server/Atmos/Monitor/Components/AtmosAlarmableComponent.cs @@ -1,5 +1,7 @@ using Content.Shared.Atmos.Monitor; +using Content.Shared.Tag; using Robust.Shared.Audio; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; namespace Content.Server.Atmos.Monitor.Components { @@ -41,12 +43,10 @@ namespace Content.Server.Atmos.Monitor.Components public float AlarmVolume { get; set; } = -10; /// - /// List of prototypes that this alarmable can - /// sync with - this is so that you can sync without - /// having to worry about cross-contamination. + /// List of tags to check for when synchronizing alarms. /// - [DataField("syncWith")] - public List SyncWithPrototypes { get; } = new(); + [DataField("syncWith", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] + public HashSet SyncWithTags { get; } = new(); /// /// If this device should receive only. If it can only diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs index 2a0b449cdd..db8db150a8 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosAlarmableSystem.cs @@ -17,6 +17,15 @@ namespace Content.Server.Atmos.Monitor.Systems [Dependency] private readonly AudioSystem _audioSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNet = default!; + /// + /// An alarm. Has three valid states: Normal, Warning, Danger. + /// Will attempt to fetch the tags from the alarming entity + /// to send over. + /// + public const string AlertCmd = "atmos_alarm"; + + public const string AlertSource = "atmos_alarm_source"; + /// /// 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? 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); } + /// + /// 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. + /// + /// + /// + /// + 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)); + } + /// /// Resets the state of this alarmable to normal. /// @@ -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 /// /// /// - 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; diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs b/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs index 0262aee0cd..3190cbd37f 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosDeviceNetwork.cs @@ -10,11 +10,6 @@ namespace Content.Server.Atmos.Monitor.Systems; /// public sealed class AtmosDeviceNetworkSystem : EntitySystem { - /// - /// Any information about atmosphere that a device can scan. - /// - public const string AtmosData = "atmos_atmosphere_data"; - /// /// Register a device's address on this device. /// @@ -25,11 +20,6 @@ public sealed class AtmosDeviceNetworkSystem : EntitySystem /// public const string SyncData = "atmos_sync_data"; - /// - /// Set the state of this device using the contained data. - /// - public const string SetState = "atmos_set_state"; - [Dependency] private readonly DeviceNetworkSystem _deviceNet = default!; public void Register(EntityUid uid, string? address) @@ -56,8 +46,8 @@ public sealed class AtmosDeviceNetworkSystem : EntitySystem { var payload = new NetworkPayload() { - [DeviceNetworkConstants.Command] = SetState, - [SetState] = data + [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdSetState, + [DeviceNetworkConstants.CmdSetState] = data }; _deviceNet.QueuePacket(uid, address, payload); diff --git a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs index 9949f326db..4e7f94de59 100644 --- a/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AtmosMonitoringSystem.cs @@ -9,6 +9,7 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Atmos; using Content.Shared.Atmos.Monitor; +using Content.Shared.Tag; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Player; @@ -332,10 +333,16 @@ namespace Content.Server.Atmos.Monitor.Systems /// is synced between monitors the moment a monitor sends out an alarm, /// or if it is explicitly synced (see ResetAll/Sync). /// - private void BroadcastAlertPacket(AtmosMonitorComponent monitor, IEnumerable? alarms = null) + private void BroadcastAlertPacket(AtmosMonitorComponent monitor, IEnumerable? alarms = null, TagComponent? tags = null) { if (!monitor.NetEnabled) return; + if (!Resolve(monitor.Owner, ref tags)) + { + return; + } + + string source = string.Empty; if (alarms == null) alarms = new List(); var prototype = Prototype(monitor.Owner); @@ -343,9 +350,9 @@ namespace Content.Server.Atmos.Monitor.Systems var payload = new NetworkPayload { - [DeviceNetworkConstants.Command] = AtmosMonitorAlarmCmd, + [DeviceNetworkConstants.Command] = AtmosAlarmableSystem.AlertCmd, [DeviceNetworkConstants.CmdSetState] = monitor.LastAlarmState, - [AtmosMonitorAlarmSrc] = source + [AtmosAlarmableSystem.AlertSource] = tags.Tags }; foreach (var addr in monitor.RegisteredDevices)