diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs index 5f29aaa023..25b1a3ee67 100644 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ b/Content.Server/UserInterface/ActivatableUIComponent.cs @@ -33,6 +33,22 @@ namespace Content.Server.UserInterface [DataField("verbText")] public string VerbText = "ui-verb-toggle-open"; + /// + /// Whether you need a hand to operate this UI. The hand does not need to be free, you just need to have one. + /// + /// + /// This should probably be true for most machines & computers, but there will still be UIs that represent a + /// more generic interaction / configuration that might not require hands. + /// + [DataField("requireHands")] + public bool RequireHands = true; + + /// + /// Whether spectators (non-admin ghosts) should be allowed to view this UI. + /// + [DataField("allowSpectator")] + public bool AllowSpectator = true; + /// /// The client channel currently using the object, or null if there's none/not single user. /// NOTE: DO NOT DIRECTLY SET, USE ActivatableUISystem.SetCurrentSingleUser diff --git a/Content.Server/UserInterface/ActivatableUISystem.cs b/Content.Server/UserInterface/ActivatableUISystem.cs index c5e85d3d84..2278a4cc86 100644 --- a/Content.Server/UserInterface/ActivatableUISystem.cs +++ b/Content.Server/UserInterface/ActivatableUISystem.cs @@ -1,8 +1,7 @@ using Content.Server.Administration.Managers; using Content.Server.Ghost.Components; -using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Hands; +using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Verbs; @@ -28,12 +27,25 @@ namespace Content.Server.UserInterface // *THIS IS A BLATANT WORKAROUND!* RATIONALE: Microwaves need it SubscribeLocalEvent(OnParentChanged); SubscribeLocalEvent(OnUIClose); + SubscribeLocalEvent(OnBoundInterfaceInteractAttempt); SubscribeLocalEvent>(AddOpenUiVerb); SubscribeLocalEvent(OnActionPerform); } + private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev) + { + if (!TryComp(ev.Target, out ActivatableUIComponent? comp)) + return; + + if (!comp.RequireHands) + return; + + if (!TryComp(ev.Sender.AttachedEntity, out SharedHandsComponent? hands) || hands.Hands.Count == 0) + ev.Cancel(); + } + private void OnActionPerform(EntityUid uid, ServerUserInterfaceComponent component, OpenUiActionEvent args) { if (args.Handled || args.Key == null) @@ -57,7 +69,7 @@ namespace Content.Server.UserInterface if (component.InHandsOnly && args.Using != uid) return; - if (!args.CanInteract && !HasComp(args.User)) + if (!args.CanInteract && (!component.AllowSpectator || !HasComp(args.User))) return; ActivationVerb verb = new(); diff --git a/Resources/Prototypes/Entities/Structures/Furniture/instruments.yml b/Resources/Prototypes/Entities/Structures/Furniture/instruments.yml index ac4ce701ea..0ae142426f 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/instruments.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/instruments.yml @@ -6,6 +6,7 @@ components: - type: Instrument - type: ActivatableUI + allowSpectator: false # otherwise they can play client-side music inHandsOnly: false singleUser: true verbText: verb-instrument-openui