From ed7c004de20e2554617b0d41315f739ccca7f0ae Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:41:44 +0100 Subject: [PATCH] Fix looking at verbs causing sounds or popups (#41609) * fix verb popups * spelling --- .../Power/ActivatableUIRequiresPowerSystem.cs | 4 +- .../Arcade/BlockGame/BlockGameArcadeSystem.cs | 8 +- .../Atmos/Portable/SpaceHeaterSystem.cs | 10 ++- .../Systems/NetworkConfiguratorSystem.cs | 6 -- Content.Server/NukeOps/WarDeclaratorSystem.cs | 7 +- Content.Server/Store/Systems/StoreSystem.cs | 4 +- .../ActivatableUIRequiresAccessSystem.cs | 2 +- .../ActivatableUIRequiresVisionSystem.cs | 3 +- Content.Shared/Lock/LockSystem.cs | 4 + .../Systems/SharedEmergencyShuttleSystem.cs | 4 +- .../UserInterface/ActivatableUIEvents.cs | 79 +++++++++++-------- .../ActivatableUIRequiresAnchorSystem.cs | 14 ++-- .../ActivatableUISystem.Power.cs | 5 +- .../UserInterface/ActivatableUISystem.cs | 29 ++++--- 14 files changed, 109 insertions(+), 70 deletions(-) diff --git a/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs b/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs index a6a20958f5..1db0daef2d 100644 --- a/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs +++ b/Content.Client/Power/ActivatableUIRequiresPowerSystem.cs @@ -18,7 +18,9 @@ public sealed class ActivatableUIRequiresPowerSystem : SharedActivatableUIRequir return; } - _popup.PopupClient(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent.Owner)), args.User, args.User); + if (!args.Silent) + _popup.PopupClient(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent.Owner)), args.User, args.User); + args.Cancel(); } } diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs index 1e8ed8cdf3..f21dc2471f 100644 --- a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs +++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs @@ -52,12 +52,12 @@ public sealed class BlockGameArcadeSystem : EntitySystem private void OnAfterUIOpen(EntityUid uid, BlockGameArcadeComponent component, AfterActivatableUIOpenEvent args) { if (component.Player == null) - component.Player = args.Actor; + component.Player = args.User; else - component.Spectators.Add(args.Actor); + component.Spectators.Add(args.User); - UpdatePlayerStatus(uid, args.Actor, component); - component.Game?.UpdateNewPlayerUI(args.Actor); + UpdatePlayerStatus(uid, args.User, component); + component.Game?.UpdateNewPlayerUI(args.User); } private void OnAfterUiClose(EntityUid uid, BlockGameArcadeComponent component, BoundUIClosedEvent args) diff --git a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs index 0d55ed12bd..7410810f8b 100644 --- a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs +++ b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs @@ -54,11 +54,13 @@ public sealed class SpaceHeaterSystem : EntitySystem private void OnUIActivationAttempt(EntityUid uid, SpaceHeaterComponent spaceHeater, ActivatableUIOpenAttemptEvent args) { - if (!Comp(uid).Anchored) - { + if (Comp(uid).Anchored) + return; + + if (!args.Silent) _popup.PopupEntity(Loc.GetString("comp-space-heater-unanchored", ("device", Loc.GetString("comp-space-heater-device-name"))), uid, args.User); - args.Cancel(); - } + + args.Cancel(); } private void OnDeviceUpdated(EntityUid uid, SpaceHeaterComponent spaceHeater, ref AtmosDeviceUpdateEvent args) diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index 97b27821fd..b31e6a6d3b 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -839,11 +839,5 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem UpdateListUiState(conf, conf.Comp); } - - private void OnUiOpenAttempt(EntityUid uid, NetworkConfiguratorComponent configurator, ActivatableUIOpenAttemptEvent args) - { - if (configurator.LinkModeActive) - args.Cancel(); - } #endregion } diff --git a/Content.Server/NukeOps/WarDeclaratorSystem.cs b/Content.Server/NukeOps/WarDeclaratorSystem.cs index a2d74e16b3..71e4431d73 100644 --- a/Content.Server/NukeOps/WarDeclaratorSystem.cs +++ b/Content.Server/NukeOps/WarDeclaratorSystem.cs @@ -44,8 +44,11 @@ public sealed class WarDeclaratorSystem : EntitySystem { if (!_accessReaderSystem.IsAllowed(args.User, ent)) { - var msg = Loc.GetString("war-declarator-not-working"); - _popupSystem.PopupEntity(msg, ent); + if (!args.Silent) + { + var msg = Loc.GetString("war-declarator-not-working"); + _popupSystem.PopupEntity(msg, ent); + } args.Cancel(); return; } diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index 279026c873..7c5c99b5b4 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -81,7 +81,9 @@ public sealed partial class StoreSystem : EntitySystem if (component.AccountOwner == mind) return; - _popup.PopupEntity(Loc.GetString("store-not-account-owner", ("store", uid)), uid, args.User); + if (!args.Silent) + _popup.PopupEntity(Loc.GetString("store-not-account-owner", ("store", uid)), uid, args.User); + args.Cancel(); } diff --git a/Content.Shared/Access/Systems/ActivatableUIRequiresAccessSystem.cs b/Content.Shared/Access/Systems/ActivatableUIRequiresAccessSystem.cs index 9020518f21..eb94ed324d 100644 --- a/Content.Shared/Access/Systems/ActivatableUIRequiresAccessSystem.cs +++ b/Content.Shared/Access/Systems/ActivatableUIRequiresAccessSystem.cs @@ -23,7 +23,7 @@ public sealed class ActivatableUIRequiresAccessSystem : EntitySystem if (!_access.IsAllowed(args.User, activatableUI)) { args.Cancel(); - if (activatableUI.Comp.PopupMessage != null) + if (activatableUI.Comp.PopupMessage != null && !args.Silent) _popup.PopupClient(Loc.GetString(activatableUI.Comp.PopupMessage), activatableUI, args.User); } } diff --git a/Content.Shared/Eye/Blinding/Systems/ActivatableUIRequiresVisionSystem.cs b/Content.Shared/Eye/Blinding/Systems/ActivatableUIRequiresVisionSystem.cs index 6ed0c4cd6d..01c83ded95 100644 --- a/Content.Shared/Eye/Blinding/Systems/ActivatableUIRequiresVisionSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/ActivatableUIRequiresVisionSystem.cs @@ -24,7 +24,8 @@ public sealed class ActivatableUIRequiresVisionSystem : EntitySystem if (TryComp(args.User, out var blindable) && blindable.IsBlind) { - _popupSystem.PopupClient(Loc.GetString("blindness-fail-attempt"), args.User, Shared.Popups.PopupType.MediumCaution); + if (!args.Silent) + _popupSystem.PopupClient(Loc.GetString("blindness-fail-attempt"), args.User, Shared.Popups.PopupType.MediumCaution); args.Cancel(); } } diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index 560bb296ac..4b44378cdf 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -477,6 +477,10 @@ public sealed class LockSystem : EntitySystem return; args.Cancel(); + + if (args.Silent) + return; + if (lockComp.Locked && component.Popup != null) { _sharedPopupSystem.PopupClient(Loc.GetString(component.Popup), uid, args.User); diff --git a/Content.Shared/Shuttles/Systems/SharedEmergencyShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedEmergencyShuttleSystem.cs index 7f818767ea..5f1477acc2 100644 --- a/Content.Shared/Shuttles/Systems/SharedEmergencyShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedEmergencyShuttleSystem.cs @@ -29,6 +29,8 @@ public abstract class SharedEmergencyShuttleSystem : EntitySystem return; args.Cancel(); - Popup.PopupClient(Loc.GetString("emergency-shuttle-console-no-early-launches"), ent, args.User); + + if (!args.Silent) + Popup.PopupClient(Loc.GetString("emergency-shuttle-console-no-early-launches"), ent, args.User); } } diff --git a/Content.Shared/UserInterface/ActivatableUIEvents.cs b/Content.Shared/UserInterface/ActivatableUIEvents.cs index ef2a7b1b9f..81aac54334 100644 --- a/Content.Shared/UserInterface/ActivatableUIEvents.cs +++ b/Content.Shared/UserInterface/ActivatableUIEvents.cs @@ -1,53 +1,70 @@ namespace Content.Shared.UserInterface; /// +/// Raised on the entity with an activatable UI when attempting to open it. /// This is raised BEFORE opening a UI! Do not listen and then open / do something use /// for that. /// -public sealed class ActivatableUIOpenAttemptEvent : CancellableEntityEventArgs +public sealed class ActivatableUIOpenAttemptEvent(EntityUid user, bool silent) : CancellableEntityEventArgs { - public EntityUid User { get; } - public ActivatableUIOpenAttemptEvent(EntityUid who) - { - User = who; - } + /// + /// The player trying to open the UI. + /// + public readonly EntityUid User = user; + + /// + /// Whether subscriptions are allowed to play a sound or show popups. + /// This is used to prevent just looking at the verb without even clicking on it showing a popup or playing sounds. + /// + public bool Silent = silent; } -public sealed class UserOpenActivatableUIAttemptEvent : CancellableEntityEventArgs //have to one-up the already stroke-inducing name +/// +/// Raised on the player when they are attempting to open an activatable UI. +/// This is raised BEFORE opening a UI! Do not listen and then open / do something use +/// for that. +/// +public sealed class UserOpenActivatableUIAttemptEvent(EntityUid user, EntityUid target, bool silent) : CancellableEntityEventArgs //have to one-up the already stroke-inducing name { - public EntityUid User { get; } - public EntityUid Target { get; } - public UserOpenActivatableUIAttemptEvent(EntityUid who, EntityUid target) - { - User = who; - Target = target; - } + /// + /// The player trying to open the UI. + /// + public readonly EntityUid User = user; + + /// + /// The target entity with the UI. + /// + public readonly EntityUid Target = target; + + /// + /// Whether subscriptions are allowed to play a sound or show popups. + /// This is used to prevent just looking at the verb without even clicking on it to show a popup or play sounds if the attempt is cancelled. + /// + public bool Silent = silent; } -public sealed class AfterActivatableUIOpenEvent : EntityEventArgs +/// +/// Raised on the entity with an activatable UI after the UI has been opened. +/// +public sealed class AfterActivatableUIOpenEvent(EntityUid user) : EntityEventArgs { - public EntityUid User { get; } - public readonly EntityUid Actor; - - public AfterActivatableUIOpenEvent(EntityUid who, EntityUid actor) - { - User = who; - Actor = actor; - } + /// + /// The player that opened the UI. + /// + public readonly EntityUid User = user; } /// -/// This is after it's decided the user can open the UI, +/// Raised on the entity with an activatable UI after it's decided the user can open the UI, /// but before the UI actually opens. -/// Use this if you need to prepare the UI itself +/// Use this if you need to prepare the UI itself. /// -public sealed class BeforeActivatableUIOpenEvent : EntityEventArgs +public sealed class BeforeActivatableUIOpenEvent(EntityUid user) : EntityEventArgs { - public EntityUid User { get; } - public BeforeActivatableUIOpenEvent(EntityUid who) - { - User = who; - } + /// + /// The player that is opening the UI. + /// + public readonly EntityUid User = user; } public sealed class ActivatableUIPlayerChangedEvent : EntityEventArgs diff --git a/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs b/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs index 6aa5059633..c9f4a0ce13 100644 --- a/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs +++ b/Content.Shared/UserInterface/ActivatableUIRequiresAnchorSystem.cs @@ -32,14 +32,14 @@ public sealed class ActivatableUIRequiresAnchorSystem : EntitySystem if (args.Cancelled) return; - if (!Transform(ent.Owner).Anchored) - { - if (ent.Comp.Popup != null) - { - _popup.PopupClient(Loc.GetString(ent.Comp.Popup), args.User); - } + if (Transform(ent.Owner).Anchored) + return; - args.Cancel(); + if (ent.Comp.Popup != null && !args.Silent) + { + _popup.PopupClient(Loc.GetString(ent.Comp.Popup), args.User); } + + args.Cancel(); } } diff --git a/Content.Shared/UserInterface/ActivatableUISystem.Power.cs b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs index 3e52e3ed36..f4b866044c 100644 --- a/Content.Shared/UserInterface/ActivatableUISystem.Power.cs +++ b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs @@ -74,8 +74,9 @@ public sealed partial class ActivatableUISystem return; // Check if we have the appropriate drawrate / userate to even open it. - if (!_cell.HasActivatableCharge(uid, user: args.User, predicted: true) || - !_cell.HasDrawCharge(uid, user: args.User, predicted: true)) + // Don't pass in the user for the popup if silent. + if (!_cell.HasActivatableCharge(uid, user: args.Silent ? null : args.User, predicted: true) || + !_cell.HasDrawCharge(uid, user: args.Silent ? null : args.User, predicted: true)) { args.Cancel(); } diff --git a/Content.Shared/UserInterface/ActivatableUISystem.cs b/Content.Shared/UserInterface/ActivatableUISystem.cs index d1df375ccb..8b2299ccfc 100644 --- a/Content.Shared/UserInterface/ActivatableUISystem.cs +++ b/Content.Shared/UserInterface/ActivatableUISystem.cs @@ -108,7 +108,7 @@ public sealed partial class ActivatableUISystem : EntitySystem if (component.InHandsOnly) { - if (!_hands.IsHolding((args.User, args.Hands), uid, out var hand )) + if (!_hands.IsHolding((args.User, args.Hands), uid, out var hand)) return false; if (component.RequireActiveHand && args.Hands.ActiveHandId != hand) @@ -116,7 +116,10 @@ public sealed partial class ActivatableUISystem : EntitySystem } } - return (args.CanInteract || HasComp(args.User) && !component.BlockSpectators) && !RaiseCanOpenEventChecks(args.User, uid); + return ((args.CanInteract + || HasComp(args.User) + && !component.BlockSpectators)) + && RaiseCanOpenEventChecks(args.User, uid, silent: true); // silent to prevent popups or sounds when only looking at the verb } private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args) @@ -225,7 +228,7 @@ public sealed partial class ActivatableUISystem : EntitySystem // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this. // This is so that stuff can require further conditions (like power). - if (RaiseCanOpenEventChecks(user, uiEntity)) + if (!RaiseCanOpenEventChecks(user, uiEntity)) return false; // Give the UI an opportunity to prepare itself if it needs to do anything @@ -237,7 +240,7 @@ public sealed partial class ActivatableUISystem : EntitySystem _uiSystem.OpenUi(uiEntity, aui.Key, user); //Let the component know a user opened it so it can do whatever it needs to do - var aae = new AfterActivatableUIOpenEvent(user, user); + var aae = new AfterActivatableUIOpenEvent(user); RaiseLocalEvent(uiEntity, aae); return true; @@ -283,14 +286,22 @@ public sealed partial class ActivatableUISystem : EntitySystem CloseAll(ent, ent); } - private bool RaiseCanOpenEventChecks(EntityUid user, EntityUid uiEntity) + private bool RaiseCanOpenEventChecks(EntityUid user, EntityUid uiEntity, bool silent = false) { - // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this. + // If we've gotten this far, fire a cancellable event that indicates someone is attempting to activate this UI. // This is so that stuff can require further conditions (like power). - var oae = new ActivatableUIOpenAttemptEvent(user); - var uae = new UserOpenActivatableUIAttemptEvent(user, uiEntity); + var uae = new UserOpenActivatableUIAttemptEvent(user, uiEntity, silent); RaiseLocalEvent(user, uae); + + if (uae.Cancelled) + return false; + + var oae = new ActivatableUIOpenAttemptEvent(user, silent); RaiseLocalEvent(uiEntity, oae); - return oae.Cancelled || uae.Cancelled; + + if (oae.Cancelled) + return false; + + return true; } } -- 2.52.0