]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Alerts Cleanup and API (#39544)
authorPrincess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com>
Fri, 5 Sep 2025 09:45:48 +0000 (02:45 -0700)
committerGitHub <noreply@github.com>
Fri, 5 Sep 2025 09:45:48 +0000 (12:45 +0300)
* alert cleanup and API

* I expect update loops to be at the top.

* Address review

* Address review x 2

* Merg my PR

* Fix

* Update Content.Shared/Alert/AlertsSystem.cs

webedit

Co-authored-by: Perry Fraser <perryprog@users.noreply.github.com>
* FIX THAT TEST FAIL!!!!

* Me when I forget to actually give you alerts

* Hammedborgar

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Co-authored-by: Perry Fraser <perryprog@users.noreply.github.com>
18 files changed:
Content.Client/Physics/Controllers/MoverController.cs
Content.Server/Body/Systems/InternalsSystem.cs
Content.Server/Body/Systems/RespiratorSystem.cs
Content.Server/Silicons/Borgs/BorgSystem.cs
Content.Shared/Abilities/Mime/MimePowersSystem.cs
Content.Shared/Alert/AlertAutoRemoveComponent.cs
Content.Shared/Alert/AlertState.cs
Content.Shared/Alert/AlertsSystem.cs
Content.Shared/Body/Systems/SharedBloodstreamSystem.cs
Content.Shared/Body/Systems/SharedInternalsSystem.cs
Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs
Content.Shared/Damage/Systems/SharedStaminaSystem.cs
Content.Shared/Gravity/SharedGravitySystem.cs
Content.Shared/Movement/Systems/WormSystem.cs
Content.Shared/Rootable/SharedRootableSystem.cs
Content.Shared/StatusEffectNew/StatusEffectAlertSystem.cs
Content.Shared/Strip/ThievingSystem.cs
Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs

index 2fe5c18fe09997cac116b729ef1deddba2cf573a..0f95a817c993ce83730c50b970920381abe4eb92 100644 (file)
@@ -120,8 +120,8 @@ public sealed class MoverController : SharedMoverController
         base.SetSprinting(entity, subTick, walking);
 
         if (walking && _cfg.GetCVar(CCVars.ToggleWalk))
-            _alerts.ShowAlert(entity, WalkingAlert, showCooldown: false, autoRemove: false);
+            _alerts.ShowAlert(entity.Owner, WalkingAlert, showCooldown: false, autoRemove: false);
         else
-            _alerts.ClearAlert(entity, WalkingAlert);
+            _alerts.ClearAlert(entity.Owner, WalkingAlert);
     }
 }
index 77f17b384de797168481e0367b8eef6f7a75a70a..c470ae3f0d7844c66f7a94f7406677ae1ecd2027 100644 (file)
@@ -61,7 +61,7 @@ public sealed class InternalsSystem : SharedInternalsSystem
             var gasTank = Comp<GasTankComponent>(ent.Comp.GasTankEntity!.Value);
             args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), args.Respirator.BreathVolume);
             // TODO: Should listen to gas tank updates instead I guess?
-            _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
+            _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent));
         }
     }
 }
index c327f235de893cf1c0440fedb58e4852fbce3b9b..eab3e2e56c27e3366a56ce8bd4819406f22a2042 100644 (file)
@@ -390,7 +390,7 @@ public sealed class RespiratorSystem : EntitySystem
         var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((ent, null));
         foreach (var entity in organs)
         {
-            _alertsSystem.ShowAlert(ent, entity.Comp1.Alert);
+            _alertsSystem.ShowAlert(ent.Owner, entity.Comp1.Alert);
         }
     }
 
@@ -400,7 +400,7 @@ public sealed class RespiratorSystem : EntitySystem
         var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((ent, null));
         foreach (var entity in organs)
         {
-            _alertsSystem.ClearAlert(ent, entity.Comp1.Alert);
+            _alertsSystem.ClearAlert(ent.Owner, entity.Comp1.Alert);
         }
     }
 
index f33b71c54ed4892d7b7d2659b9c00f398070e58e..88d484b846729d0cfc2e48e6c339d0e1134c02cf 100644 (file)
@@ -290,8 +290,8 @@ public sealed partial class BorgSystem : SharedBorgSystem
     {
         if (!_powerCell.TryGetBatteryFromSlot(ent, out var battery, slotComponent))
         {
-            _alerts.ClearAlert(ent, ent.Comp.BatteryAlert);
-            _alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert);
+            _alerts.ClearAlert(ent.Owner, ent.Comp.BatteryAlert);
+            _alerts.ShowAlert(ent.Owner, ent.Comp.NoBatteryAlert);
             return;
         }
 
@@ -304,8 +304,8 @@ public sealed partial class BorgSystem : SharedBorgSystem
             chargePercent = 1;
         }
 
-        _alerts.ClearAlert(ent, ent.Comp.NoBatteryAlert);
-        _alerts.ShowAlert(ent, ent.Comp.BatteryAlert, chargePercent);
+        _alerts.ClearAlert(ent.Owner, ent.Comp.NoBatteryAlert);
+        _alerts.ShowAlert(ent.Owner, ent.Comp.BatteryAlert, chargePercent);
     }
 
     public bool TryEjectPowerCell(EntityUid uid, BorgChassisComponent component, [NotNullWhen(true)] out List<EntityUid>? ents)
@@ -315,7 +315,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
         if (!TryComp<PowerCellSlotComponent>(uid, out var slotComp) ||
             !Container.TryGetContainer(uid, slotComp.CellSlotId, out var container) ||
             !container.ContainedEntities.Any())
-                return false;
+            return false;
 
         ents = Container.EmptyContainer(container);
 
index 22ba7a35910519f3e7d9fcc4f165d2cb481fbd66..aa77ccb803990452e0d8b9cf59513b3d49764639 100644 (file)
@@ -67,7 +67,7 @@ public sealed class MimePowersSystem : EntitySystem
             Dirty(ent, illiterateComponent);
         }
 
-        _alertsSystem.ShowAlert(ent, ent.Comp.VowAlert);
+        _alertsSystem.ShowAlert(ent.Owner, ent.Comp.VowAlert);
         _actionsSystem.AddAction(ent, ref ent.Comp.InvisibleWallActionEntity, ent.Comp.InvisibleWallAction);
     }
 
index 44e2dc91dce59cbe7c68085f8cd230949fadef83..6dd983d3efff9e12c5f0f2b9c516c3cf93292692 100644 (file)
@@ -13,7 +13,7 @@ public sealed partial class AlertAutoRemoveComponent : Component
     /// </summary>
     [AutoNetworkedField]
     [DataField]
-    public List<AlertKey> AlertKeys = new();
+    public HashSet<AlertKey> AlertKeys = new();
 
     public override bool SendOnlyToOwner => true;
 }
index d6309f6b4265cd517fd7e9e06511c3f5f305bccc..d0d93cf76ab28df23087f7307017a8d83e1fd008 100644 (file)
@@ -4,10 +4,10 @@ using Robust.Shared.Serialization;
 namespace Content.Shared.Alert;
 
 [Serializable, NetSerializable]
-public struct AlertState
+public record struct AlertState
 {
     public short? Severity;
-    public (TimeSpan, TimeSpan)? Cooldown;
+    public (TimeSpan startTime, TimeSpan endTime)? Cooldown;
     public bool AutoRemove;
     public bool ShowCooldown;
     public ProtoId<AlertPrototype> Type;
index 94085c3a2749fcb6ec1f29f796df082bf37e9fe7..834a22b8debf42d8dcd6416c899b98168017bbad 100644 (file)
@@ -11,19 +11,78 @@ public abstract class AlertsSystem : EntitySystem
     [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
 
+    private EntityQuery<AlertsComponent> _alertsQuery;
     private FrozenDictionary<ProtoId<AlertPrototype>, AlertPrototype> _typeToAlert = default!;
 
-    public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid)
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        _alertsQuery = GetEntityQuery<AlertsComponent>();
+
+        SubscribeLocalEvent<AlertsComponent, ComponentStartup>(HandleComponentStartup);
+        SubscribeLocalEvent<AlertsComponent, ComponentShutdown>(HandleComponentShutdown);
+        SubscribeLocalEvent<AlertsComponent, PlayerAttachedEvent>(OnPlayerAttached);
+
+        SubscribeLocalEvent<AlertAutoRemoveComponent, EntityUnpausedEvent>(OnAutoRemoveUnPaused);
+
+        SubscribeAllEvent<ClickAlertEvent>(HandleClickAlert);
+        SubscribeLocalEvent<PrototypesReloadedEventArgs>(HandlePrototypesReloaded);
+        LoadPrototypes();
+    }
+
+    public override void Update(float frameTime)
     {
-        return TryComp(euid, out AlertsComponent? comp)
-            ? comp.Alerts
+        base.Update(frameTime);
+
+        var query = EntityQueryEnumerator<AlertAutoRemoveComponent>();
+        var curTime = _timing.CurTime;
+        while (query.MoveNext(out var uid, out var autoComp))
+        {
+            var removed = false;
+            if (autoComp.AlertKeys.Count <= 0 || !_alertsQuery.TryComp(uid, out var alertComp))
+            {
+                RemCompDeferred(uid, autoComp);
+                continue;
+            }
+
+            var removeList = new List<AlertKey>();
+            foreach (var alertKey in autoComp.AlertKeys)
+            {
+                alertComp.Alerts.TryGetValue(alertKey, out var alertState);
+
+                if (alertState.Cooldown is null || alertState.Cooldown.Value.endTime >= curTime)
+                    continue;
+
+                removeList.Add(alertKey);
+                alertComp.Alerts.Remove(alertKey);
+                removed = true;
+            }
+
+            if (!removed)
+                continue;
+
+            foreach (var alertKey in removeList)
+            {
+                autoComp.AlertKeys.Remove(alertKey);
+            }
+
+            Dirty(uid, alertComp);
+            Dirty(uid, autoComp);
+        }
+    }
+
+    public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(Entity<AlertsComponent?> entity)
+    {
+        return _alertsQuery.Resolve(entity, ref entity.Comp, false)
+            ? entity.Comp.Alerts
             : null;
     }
 
     public short GetSeverityRange(ProtoId<AlertPrototype> alertType)
     {
         var minSeverity = _typeToAlert[alertType].MinSeverity;
-        return (short)MathF.Max(minSeverity,_typeToAlert[alertType].MaxSeverity - minSeverity);
+        return (short)MathF.Max(minSeverity, _typeToAlert[alertType].MaxSeverity - minSeverity);
     }
 
     public short GetMaxSeverity(ProtoId<AlertPrototype> alertType)
@@ -36,31 +95,29 @@ public abstract class AlertsSystem : EntitySystem
         return _typeToAlert[alertType].MinSeverity;
     }
 
-    public bool IsShowingAlert(EntityUid euid, ProtoId<AlertPrototype> alertType)
+    public bool IsShowingAlert(Entity<AlertsComponent?> entity, ProtoId<AlertPrototype> alertType)
     {
-        if (!TryComp(euid, out AlertsComponent? alertsComponent))
+        if (!_alertsQuery.Resolve(entity, ref entity.Comp, false))
             return false;
 
         if (TryGet(alertType, out var alert))
-        {
-            return alertsComponent.Alerts.ContainsKey(alert.AlertKey);
-        }
+            return entity.Comp.Alerts.ContainsKey(alert.AlertKey);
 
-        Log.Debug("Unknown alert type {0}", alertType);
+        Log.Debug($"Unknown alert type {alertType}");
         return false;
     }
 
     /// <returns>true iff an alert of the indicated alert category is currently showing</returns>
-    public bool IsShowingAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> alertCategory)
+    public bool IsShowingAlertCategory(Entity<AlertsComponent?> entity, ProtoId<AlertCategoryPrototype> alertCategory)
     {
-        return TryComp(euid, out AlertsComponent? alertsComponent)
-               && alertsComponent.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory));
+        return _alertsQuery.Resolve(entity, ref entity.Comp, false)
+               && entity.Comp.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory));
     }
 
-    public bool TryGetAlertState(EntityUid euid, AlertKey key, out AlertState alertState)
+    public bool TryGetAlertState(Entity<AlertsComponent?> entity, AlertKey key, out AlertState alertState)
     {
-        if (TryComp(euid, out AlertsComponent? alertsComponent))
-            return alertsComponent.Alerts.TryGetValue(key, out alertState);
+        if (_alertsQuery.Resolve(entity, ref entity.Comp, false))
+            return entity.Comp.Alerts.TryGetValue(key, out alertState);
 
         alertState = default;
         return false;
@@ -71,107 +128,150 @@ public abstract class AlertsSystem : EntitySystem
     /// Shows the alert. If the alert or another alert of the same category is already showing,
     /// it will be updated / replaced with the specified values.
     /// </summary>
-    /// <param name="euid"></param>
+    /// <param name="entity">The entity who we are showing the alert for.</param>
     /// <param name="alertType">type of the alert to set</param>
     /// <param name="severity">severity, if supported by the alert</param>
     /// <param name="cooldown">cooldown start and end, if null there will be no cooldown (and it will
     ///     be erased if there is currently a cooldown for the alert)</param>
     /// <param name="autoRemove">if true, the alert will be removed at the end of the cooldown</param>
     /// <param name="showCooldown">if true, the cooldown will be visibly shown over the alert icon</param>
-    public void ShowAlert(EntityUid euid, ProtoId<AlertPrototype> alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true )
+    public void ShowAlert(Entity<AlertsComponent?> entity,
+        ProtoId<AlertPrototype> alertType,
+        short? severity = null,
+        (TimeSpan, TimeSpan)? cooldown = null,
+        bool autoRemove = false,
+        bool showCooldown = true )
+    {
+        ShowAlert(entity, new AlertState { Type = alertType, Severity = severity, Cooldown = cooldown, AutoRemove = autoRemove, ShowCooldown = showCooldown});
+    }
+
+    public void ShowAlert(Entity<AlertsComponent?> entity, AlertState state)
     {
         // This should be handled as part of networking.
         if (_timing.ApplyingState)
             return;
 
-        if (!TryComp(euid, out AlertsComponent? alertsComponent))
+        if (!_alertsQuery.Resolve(entity, ref entity.Comp, false))
             return;
 
-        if (TryGet(alertType, out var alert))
+        if (!TryGet(state.Type, out var alert))
         {
-            // Check whether the alert category we want to show is already being displayed, with the same type,
-            // severity, and cooldown.
-            if (alertsComponent.Alerts.TryGetValue(alert.AlertKey, out var alertStateCallback) &&
-                alertStateCallback.Type == alertType &&
-                alertStateCallback.Severity == severity &&
-                alertStateCallback.Cooldown == cooldown &&
-                alertStateCallback.AutoRemove == autoRemove &&
-                alertStateCallback.ShowCooldown == showCooldown)
-            {
-                return;
-            }
+            Log.Error($"Unable to show alert {state.Type}, please ensure this alertType has a corresponding YML alert prototype");
+            return;
+        }
 
-            // In the case we're changing the alert type but not the category, we need to remove it first.
-            alertsComponent.Alerts.Remove(alert.AlertKey);
+        // Check whether the alert category we want to show is already being displayed, with the same type,
+        // severity, and cooldown.
+        if (entity.Comp.Alerts.TryGetValue(alert.AlertKey, out var alertStateCallback))
+        {
+            if (state == alertStateCallback)
+                return;
 
-            var state = new AlertState
-                { Cooldown = cooldown, Severity = severity, Type = alertType, AutoRemove = autoRemove, ShowCooldown = showCooldown};
-            alertsComponent.Alerts[alert.AlertKey] = state;
+            // If the alert exists and we're updating it, we need to remove it first before adding it back.
+            entity.Comp.Alerts.Remove(alert.AlertKey);
+        }
 
-            // Keeping a list of AutoRemove alerts, so Update() doesn't need to check every alert
-            if (autoRemove)
-            {
-                var autoComp = EnsureComp<AlertAutoRemoveComponent>(euid);
-                if (!autoComp.AlertKeys.Contains(alert.AlertKey))
-                    autoComp.AlertKeys.Add(alert.AlertKey);
-            }
+        entity.Comp.Alerts.Add(alert.AlertKey, state);
 
-            AfterShowAlert((euid, alertsComponent));
+        // Keeping a list of AutoRemove alerts, so Update() doesn't need to check every alert
+        if (state.AutoRemove)
+        {
+            EnsureComp<AlertAutoRemoveComponent>(entity, out var autoComp);
 
-            Dirty(euid, alertsComponent);
+            if (autoComp.AlertKeys.Add(alert.AlertKey))
+                Dirty (entity, autoComp);
         }
-        else
+
+        AfterShowAlert((entity, entity.Comp));
+
+        Dirty(entity);
+    }
+
+    /// <summary>
+    /// An alternative to show alert with different behavior if an alert already exists.
+    /// </summary>
+    /// <param name="entity">Entity whose alert we're updating</param>
+    /// <param name="alertType">Prototype of the alert we're updating</param>
+    /// <param name="severity">Severity we're setting the alert to</param>
+    /// <param name="cooldown">Time left in the alert.</param>
+    /// <param name="autoRemove">Do we want to remove this alert when it expires?</param>
+    /// <param name="showCooldown">Should we show/hide the cooldown?</param>
+    public void UpdateAlert(Entity<AlertsComponent?> entity,
+        ProtoId<AlertPrototype> alertType,
+        short? severity = null,
+        TimeSpan? cooldown = null,
+        bool autoRemove = false,
+        bool showCooldown = true)
+    {
+        if (_timing.ApplyingState)
+            return;
+
+        if (!_alertsQuery.Resolve(entity, ref entity.Comp, false))
+            return;
+
+        if (!TryGet(alertType, out var alert))
+            return;
+
+        if (cooldown == null)
         {
-            Log.Error("Unable to show alert {0}, please ensure this alertType has" +
-                                   " a corresponding YML alert prototype",
-                alertType);
+            ShowAlert(entity, alertType, severity, null, autoRemove, showCooldown);
+            return;
         }
+
+        // Keep the progress duration the same but only if we're removing time.
+        // If the next cooldown is greater than our previous one we should reset the timer
+        TryGetAlertState(entity, alert.AlertKey, out var alertState);
+        var down = alertState.Cooldown?.endTime < cooldown.Value
+            ? (_timing.CurTime, cooldown.Value)
+            : (alertState.Cooldown?.startTime ?? _timing.CurTime, cooldown.Value);
+
+        ShowAlert(entity, alertType, severity, down, autoRemove, showCooldown);
     }
 
     /// <summary>
     /// Clear the alert with the given category, if one is currently showing.
     /// </summary>
-    public void ClearAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> category)
+    public void ClearAlertCategory(Entity<AlertsComponent?> entity, ProtoId<AlertCategoryPrototype> category)
     {
-        if(!TryComp(euid, out AlertsComponent? alertsComponent))
+        if(!_alertsQuery.Resolve(entity, ref entity.Comp, false))
             return;
 
         var key = AlertKey.ForCategory(category);
-        if (!alertsComponent.Alerts.Remove(key))
+        if (!entity.Comp.Alerts.Remove(key))
         {
             return;
         }
 
-        AfterClearAlert((euid, alertsComponent));
+        AfterClearAlert((entity, entity.Comp));
 
-        Dirty(euid, alertsComponent);
+        Dirty(entity);
     }
 
     /// <summary>
     /// Clear the alert of the given type if it is currently showing.
     /// </summary>
-    public void ClearAlert(EntityUid euid, ProtoId<AlertPrototype> alertType)
+    public void ClearAlert(Entity<AlertsComponent?> entity, ProtoId<AlertPrototype> alertType)
     {
         if (_timing.ApplyingState)
             return;
 
-        if (!TryComp(euid, out AlertsComponent? alertsComponent))
+        if (!_alertsQuery.Resolve(entity, ref entity.Comp, false))
             return;
 
         if (TryGet(alertType, out var alert))
         {
-            if (!alertsComponent.Alerts.Remove(alert.AlertKey))
+            if (!entity.Comp.Alerts.Remove(alert.AlertKey))
             {
                 return;
             }
 
-            AfterClearAlert((euid, alertsComponent));
+            AfterClearAlert((entity, entity.Comp));
 
-            Dirty(euid, alertsComponent);
+            Dirty(entity);
         }
         else
         {
-            Log.Error("Unable to clear alert, unknown alertType {0}", alertType);
+            Log.Error($"Unable to clear alert, unknown alertType {alertType}");
         }
     }
 
@@ -185,27 +285,10 @@ public abstract class AlertsSystem : EntitySystem
     /// </summary>
     protected virtual void AfterClearAlert(Entity<AlertsComponent> alerts) { }
 
-    public override void Initialize()
+    private void OnAutoRemoveUnPaused(Entity<AlertAutoRemoveComponent> entity, ref EntityUnpausedEvent args)
     {
-        base.Initialize();
-
-        SubscribeLocalEvent<AlertsComponent, ComponentStartup>(HandleComponentStartup);
-        SubscribeLocalEvent<AlertsComponent, ComponentShutdown>(HandleComponentShutdown);
-        SubscribeLocalEvent<AlertsComponent, PlayerAttachedEvent>(OnPlayerAttached);
-
-        SubscribeLocalEvent<AlertAutoRemoveComponent, EntityUnpausedEvent>(OnAutoRemoveUnPaused);
-
-        SubscribeAllEvent<ClickAlertEvent>(HandleClickAlert);
-        SubscribeLocalEvent<PrototypesReloadedEventArgs>(HandlePrototypesReloaded);
-        LoadPrototypes();
-    }
-
-    private void OnAutoRemoveUnPaused(EntityUid uid, AlertAutoRemoveComponent comp, EntityUnpausedEvent args)
-    {
-        if (!TryComp<AlertsComponent>(uid, out var alertComp))
-        {
+        if (!_alertsQuery.TryComp(entity, out var alertComp))
             return;
-        }
 
         var dirty = false;
 
@@ -214,58 +297,16 @@ public abstract class AlertsSystem : EntitySystem
             if (alert.Value.Cooldown is null)
                 continue;
 
-            var cooldown = (alert.Value.Cooldown.Value.Item1, alert.Value.Cooldown.Value.Item2 + args.PausedTime);
+            var (start, end) = alert.Value.Cooldown.Value;
+            var cooldown = (start, end + args.PausedTime);
 
-            var state = new AlertState
-            {
-                Severity = alert.Value.Severity,
-                Cooldown = cooldown,
-                ShowCooldown = alert.Value.ShowCooldown,
-                AutoRemove = alert.Value.AutoRemove,
-                Type = alert.Value.Type
-            };
+            var state = alert.Value with { Cooldown = cooldown };
             alertComp.Alerts[alert.Key] = state;
             dirty = true;
         }
 
         if (dirty)
-            Dirty(uid, comp);
-    }
-
-    public override void Update(float frameTime)
-    {
-        base.Update(frameTime);
-
-        var query = EntityQueryEnumerator<AlertAutoRemoveComponent>();
-        while (query.MoveNext(out var uid, out var autoComp))
-        {
-            var dirtyComp = false;
-            if (autoComp.AlertKeys.Count <= 0 || !TryComp<AlertsComponent>(uid, out var alertComp))
-            {
-                RemCompDeferred(uid, autoComp);
-                continue;
-            }
-
-            var removeList = new List<AlertKey>();
-            foreach (var alertKey in autoComp.AlertKeys)
-            {
-                alertComp.Alerts.TryGetValue(alertKey, out var alertState);
-
-                if (alertState.Cooldown is null || alertState.Cooldown.Value.Item2 >= _timing.CurTime)
-                    continue;
-                removeList.Add(alertKey);
-                alertComp.Alerts.Remove(alertKey);
-                dirtyComp = true;
-            }
-
-            foreach (var alertKey in removeList)
-            {
-                autoComp.AlertKeys.Remove(alertKey);
-            }
-
-            if (dirtyComp)
-                Dirty(uid, alertComp);
-        }
+            Dirty(entity, alertComp);
     }
 
     protected virtual void HandleComponentShutdown(EntityUid uid, AlertsComponent component, ComponentShutdown args)
@@ -290,10 +331,7 @@ public abstract class AlertsSystem : EntitySystem
         foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>())
         {
             if (!dict.TryAdd(alert.ID, alert))
-            {
-                Log.Error("Found alert with duplicate alertType {0} - all alerts must have" +
-                          " a unique alertType, this one will be skipped", alert.ID);
-            }
+                Log.Error($"Found alert with duplicate alertType {alert.ID} - all alerts must have a unique alertType, this one will be skipped");
         }
 
         _typeToAlert = dict.ToFrozenDictionary();
@@ -316,15 +354,13 @@ public abstract class AlertsSystem : EntitySystem
 
         if (!IsShowingAlert(player.Value, msg.Type))
         {
-            Log.Debug("User {0} attempted to" +
-                                   " click alert {1} which is not currently showing for them",
-                Comp<MetaDataComponent>(player.Value).EntityName, msg.Type);
+            Log.Debug($"User {ToPrettyString(player.Value)} attempted to click alert {msg.Type} which is not currently showing for them");
             return;
         }
 
         if (!TryGet(msg.Type, out var alert))
         {
-            Log.Warning("Unrecognized encoded alert {0}", msg.Type);
+            Log.Warning($"Unrecognized encoded alert {msg.Type}");
             return;
         }
 
index 7db9f42280ca69610b5d172944ebee8c867d1f43..4b3270f1ed8fbd33903ec1a121c557d11f5be929 100644 (file)
@@ -413,11 +413,11 @@ public abstract class SharedBloodstreamSystem : EntitySystem
         DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.BleedAmount));
 
         if (ent.Comp.BleedAmount == 0)
-            _alertsSystem.ClearAlert(ent, ent.Comp.BleedingAlert);
+            _alertsSystem.ClearAlert(ent.Owner, ent.Comp.BleedingAlert);
         else
         {
             var severity = (short)Math.Clamp(Math.Round(ent.Comp.BleedAmount, MidpointRounding.ToZero), 0, 10);
-            _alertsSystem.ShowAlert(ent, ent.Comp.BleedingAlert, severity);
+            _alertsSystem.ShowAlert(ent.Owner, ent.Comp.BleedingAlert, severity);
         }
 
         return true;
index 7749432281e3f3cf93d79d6fee46fb90f3cdb617..7db02a376c31280a29bc6f79fb0f13b6cb0cf858 100644 (file)
@@ -158,12 +158,12 @@ public abstract class SharedInternalsSystem : EntitySystem
 
     private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args)
     {
-        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
+        _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     private void OnInternalsShutdown(Entity<InternalsComponent> ent, ref ComponentShutdown args)
     {
-        _alerts.ClearAlert(ent, ent.Comp.InternalsAlert);
+        _alerts.ClearAlert(ent.Owner, ent.Comp.InternalsAlert);
     }
 
     public void ConnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEntity)
@@ -178,7 +178,7 @@ public abstract class SharedInternalsSystem : EntitySystem
         }
 
         Dirty(ent);
-        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
+        _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     public void DisconnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEntity, bool forced = false)
@@ -199,7 +199,7 @@ public abstract class SharedInternalsSystem : EntitySystem
             DisconnectTank(ent, forced: forced);
         }
 
-        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
+        _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     public void DisconnectTank(Entity<InternalsComponent> ent, bool forced = false)
@@ -222,7 +222,7 @@ public abstract class SharedInternalsSystem : EntitySystem
 
         ent.Comp.GasTankEntity = tankEntity;
         Dirty(ent);
-        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
+        _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent));
         return true;
     }
 
index e29ac8f4edcb5e77cfd6b64b099d294d2bf46d2b..7dd4ea4d1155299148e9c307a10543f4d985b345 100644 (file)
@@ -196,11 +196,11 @@ public abstract partial class SharedBuckleSystem
         {
             strapEnt.Comp.BuckledEntities.Add(buckle);
             Dirty(strapEnt);
-            _alerts.ShowAlert(buckle, strapEnt.Comp.BuckledAlertType);
+            _alerts.ShowAlert(buckle.Owner, strapEnt.Comp.BuckledAlertType);
         }
         else
         {
-            _alerts.ClearAlertCategory(buckle, BuckledAlertCategory);
+            _alerts.ClearAlertCategory(buckle.Owner, BuckledAlertCategory);
         }
 
         buckle.Comp.BuckledTo = strap;
index b2d22391ebe3e4e4c5949f42789b12409e2840c9..5a168f04a092bb52ffa26c672c77defad2951f68 100644 (file)
@@ -94,7 +94,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
         {
             RemCompDeferred<ActiveStaminaComponent>(entity);
         }
-        _alerts.ClearAlert(entity, entity.Comp.StaminaAlert);
+        _alerts.ClearAlert(entity.Owner, entity.Comp.StaminaAlert);
     }
 
     private void OnStartup(Entity<StaminaComponent> entity, ref ComponentStartup args)
index 4ba312f4e08f7833960ed2ca5a171cfb0e580afa..a8f1be828735f3c69b6622ef7c228489598e0c37 100644 (file)
@@ -132,9 +132,9 @@ public abstract partial class SharedGravitySystem : EntitySystem
     private void OnWeightlessnessChanged(Entity<AlertsComponent> entity, ref WeightlessnessChangedEvent args)
     {
         if (args.Weightless)
-            _alerts.ShowAlert(entity, WeightlessAlert);
+            _alerts.ShowAlert(entity.AsNullable(), WeightlessAlert);
         else
-            _alerts.ClearAlert(entity, WeightlessAlert);
+            _alerts.ClearAlert(entity.AsNullable(), WeightlessAlert);
     }
 
     private void OnEntParentChanged(Entity<GravityAffectedComponent> entity, ref EntParentChangedMessage args)
@@ -202,12 +202,12 @@ public abstract partial class SharedGravitySystem : EntitySystem
             _alerts.ClearAlert(ev.Euid, WeightlessAlert);
     }
 
-    private void OnAlertsParentChange(EntityUid uid, AlertsComponent component, ref EntParentChangedMessage args)
+    private void OnAlertsParentChange(Entity<AlertsComponent> entity, ref EntParentChangedMessage args)
     {
-        if (IsWeightless(uid))
-            _alerts.ShowAlert(uid, WeightlessAlert);
+        if (IsWeightless(entity.Owner))
+            _alerts.ShowAlert(entity.AsNullable(), WeightlessAlert);
         else
-            _alerts.ClearAlert(uid, WeightlessAlert);
+            _alerts.ClearAlert(entity.AsNullable(), WeightlessAlert);
     }
 
     private void OnGridInit(GridInitializeEvent ev)
index c6f2b7834ce952789e2f7de658b2269eba8d05c2..cb1dbaf809ec3d45a68d6aa88131998503772a64 100644 (file)
@@ -25,7 +25,7 @@ public sealed class WormSystem : EntitySystem
     private void OnMapInit(Entity<WormComponent> ent, ref MapInitEvent args)
     {
         EnsureComp<KnockedDownComponent>(ent, out var knocked);
-        _alerts.ShowAlert(ent, SharedStunSystem.KnockdownAlert);
+        _alerts.ShowAlert(ent.Owner, SharedStunSystem.KnockdownAlert);
         _stun.SetAutoStand((ent, knocked));
     }
 
index d646c7d97c953c7df7a338b9aedf7f89746b57f9..569fdf8e4dce76b53f3b41f8453552334454289a 100644 (file)
@@ -83,7 +83,7 @@ public abstract class SharedRootableSystem : EntitySystem
 
         var actions = new Entity<ActionsComponent?>(entity, comp);
         _actions.RemoveAction(actions, entity.Comp.ActionEntity);
-        _alerts.ClearAlert(entity, entity.Comp.RootedAlert);
+        _alerts.ClearAlert(entity.Owner, entity.Comp.RootedAlert);
     }
 
     private void OnRootableToggle(Entity<RootableComponent> entity, ref ToggleActionEvent args)
@@ -109,7 +109,7 @@ public abstract class SharedRootableSystem : EntitySystem
 
         if (entity.Comp.Rooted)
         {
-            _alerts.ShowAlert(entity, entity.Comp.RootedAlert);
+            _alerts.ShowAlert(entity.Owner, entity.Comp.RootedAlert);
             var curTime = _timing.CurTime;
             if (curTime > entity.Comp.NextUpdate)
             {
@@ -118,7 +118,7 @@ public abstract class SharedRootableSystem : EntitySystem
         }
         else
         {
-            _alerts.ClearAlert(entity, entity.Comp.RootedAlert);
+            _alerts.ClearAlert(entity.Owner, entity.Comp.RootedAlert);
         }
         _audio.PlayPredicted(entity.Comp.RootSound, entity.Owner.ToCoordinates(), entity);
 
index d540f865c018a1b0b8a3e388005a82aecb96c0e2..1405a5fd6249718fd2e7b7e288dd05bf59d1d37b 100644 (file)
@@ -1,6 +1,5 @@
 using Content.Shared.Alert;
 using Content.Shared.StatusEffectNew.Components;
-using Robust.Shared.Timing;
 
 namespace Content.Shared.StatusEffectNew;
 
@@ -9,7 +8,6 @@ namespace Content.Shared.StatusEffectNew;
 /// </summary>
 public sealed class StatusEffectAlertSystem : EntitySystem
 {
-    [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly AlertsSystem _alerts = default!;
 
     private EntityQuery<StatusEffectComponent> _effectQuery;
@@ -30,7 +28,7 @@ public sealed class StatusEffectAlertSystem : EntitySystem
         if (!_effectQuery.TryComp(ent, out var effectComp))
             return;
 
-        RefreshAlert(ent, args.Target, effectComp.EndEffectTime);
+        _alerts.UpdateAlert(args.Target, ent.Comp.Alert, cooldown: ent.Comp.ShowDuration ? effectComp.EndEffectTime : null);
     }
 
     private void OnStatusEffectRemoved(Entity<StatusEffectAlertComponent> ent, ref StatusEffectRemovedEvent args)
@@ -40,23 +38,6 @@ public sealed class StatusEffectAlertSystem : EntitySystem
 
     private void OnEndTimeUpdated(Entity<StatusEffectAlertComponent> ent, ref StatusEffectEndTimeUpdatedEvent args)
     {
-        RefreshAlert(ent, args.Target, args.EndTime);
-    }
-
-    private void RefreshAlert(Entity<StatusEffectAlertComponent> ent, EntityUid target, TimeSpan? endTime)
-    {
-        (TimeSpan Start, TimeSpan End)? cooldown = null;
-
-        // Make sure the start time of the alert cooldown is still accurate
-        // This ensures the progress wheel doesn't "reset" every duration change.
-        if (ent.Comp.ShowDuration
-            && endTime is not null
-            && _alerts.TryGet(ent.Comp.Alert, out var alert))
-        {
-            _alerts.TryGetAlertState(target, alert.AlertKey, out var alertState);
-            cooldown = (alertState.Cooldown?.Item1 ?? _timing.CurTime, endTime.Value);
-        }
-
-        _alerts.ShowAlert(target, ent.Comp.Alert, cooldown: cooldown);
+        _alerts.UpdateAlert(args.Target, ent.Comp.Alert, cooldown: ent.Comp.ShowDuration ? args.EndTime : null);
     }
 }
index 4a76354844b6842f5f97e4f86fc870ba7d3d66f5..3eacc90fbec8812aae6bc1a14e7eb78f4fa6fdc8 100644 (file)
@@ -32,12 +32,12 @@ public sealed partial class ThievingSystem : EntitySystem
 
     private void OnCompInit(Entity<ThievingComponent> entity, ref ComponentInit args)
     {
-        _alertsSystem.ShowAlert(entity, entity.Comp.StealthyAlertProtoId, 1);
+        _alertsSystem.ShowAlert(entity.Owner, entity.Comp.StealthyAlertProtoId, 1);
     }
 
     private void OnCompRemoved(Entity<ThievingComponent> entity, ref ComponentRemove args)
     {
-        _alertsSystem.ClearAlert(entity, entity.Comp.StealthyAlertProtoId);
+        _alertsSystem.ClearAlert(entity.Owner, entity.Comp.StealthyAlertProtoId);
     }
 
     private void OnToggleStealthy(Entity<ThievingComponent> ent, ref ToggleThievingEvent args)
index 3ab4791269df6364841714cdc9239dc5316f8eaf..3646dc8f2832bd37bd2f1329c314025704ca8745 100644 (file)
@@ -117,7 +117,7 @@ public abstract partial class SharedStunSystem
         entity.Comp.SpeedModifier = 1f;
 
         _standingState.Stand(entity);
-        Alerts.ClearAlert(entity, KnockdownAlert);
+        Alerts.ClearAlert(entity.Owner, KnockdownAlert);
     }
 
     #endregion
@@ -179,7 +179,7 @@ public abstract partial class SharedStunSystem
     {
         entity.Comp.NextUpdate = time;
         DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.NextUpdate));
-        Alerts.ShowAlert(entity, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate));
+        Alerts.ShowAlert(entity.Owner, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate));
     }
 
     /// <summary>
@@ -216,7 +216,7 @@ public abstract partial class SharedStunSystem
 
         entity.Comp.NextUpdate += time;
         DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.NextUpdate));
-        Alerts.ShowAlert(entity, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate));
+        Alerts.ShowAlert(entity.Owner, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate));
     }
 
     #endregion