From 4bf8a5d527130169042d82b92cbc8c3196441737 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Sat, 16 Oct 2021 21:34:05 +0100 Subject: [PATCH] Adds hand labelers (#4903) * Adds hand labelers * Removes unnecessary thing * Docs * Reverts some changes * Addresses comments and adds inhand sprites * Addressed comments Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- Content.Client/Entry/IgnoredComponents.cs | 4 +- .../UI/HandLabelerBoundUserInterface.cs | 60 ++++++++++ .../HandLabeler/UI/HandLabelerWindow.xaml | 8 ++ .../HandLabeler/UI/HandLabelerWindow.xaml.cs | 26 +++++ .../Components/HandLabelerComponent.cs | 26 +++++ .../HandLabeler/Components/LabelComponent.cs | 18 +++ .../HandLabeler/HandLabelerSystem.cs | 110 ++++++++++++++++++ Content.Server/HandLabeler/LabelSystem.cs | 36 ++++++ .../HandLabeler/SharedHandLabelerComponent.cs | 41 +++++++ .../en-US/hand-labeler/hand-labeler.ftl | 11 ++ .../Entities/Objects/Tools/hand_labeler.yml | 23 ++++ .../Prototypes/Entities/Structures/base.yml | 6 + .../Tools/hand_labeler.rsi/hand_labeler.png | Bin 0 -> 273 bytes .../Tools/hand_labeler.rsi/inhand-left.png | Bin 0 -> 636 bytes .../Tools/hand_labeler.rsi/inhand-right.png | Bin 0 -> 648 bytes .../Objects/Tools/hand_labeler.rsi/meta.json | 22 ++++ 16 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 Content.Client/HandLabeler/UI/HandLabelerBoundUserInterface.cs create mode 100644 Content.Client/HandLabeler/UI/HandLabelerWindow.xaml create mode 100644 Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs create mode 100644 Content.Server/HandLabeler/Components/HandLabelerComponent.cs create mode 100644 Content.Server/HandLabeler/Components/LabelComponent.cs create mode 100644 Content.Server/HandLabeler/HandLabelerSystem.cs create mode 100644 Content.Server/HandLabeler/LabelSystem.cs create mode 100644 Content.Shared/HandLabeler/SharedHandLabelerComponent.cs create mode 100644 Resources/Locale/en-US/hand-labeler/hand-labeler.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml create mode 100644 Resources/Textures/Objects/Tools/hand_labeler.rsi/hand_labeler.png create mode 100644 Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/hand_labeler.rsi/meta.json diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 75f424ed44..38d417121a 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -285,7 +285,9 @@ namespace Content.Client.Entry "DeviceNetworkConnection", "WiredNetworkConnection", "WirelessNetworkConnection", - "GhostRadio" + "HandLabeler", + "Label", + "GhostRadio", }; } } diff --git a/Content.Client/HandLabeler/UI/HandLabelerBoundUserInterface.cs b/Content.Client/HandLabeler/UI/HandLabelerBoundUserInterface.cs new file mode 100644 index 0000000000..82625e8ede --- /dev/null +++ b/Content.Client/HandLabeler/UI/HandLabelerBoundUserInterface.cs @@ -0,0 +1,60 @@ +using Content.Shared.HandLabeler; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; + +namespace Content.Client.HandLabeler.UI +{ + /// + /// Initializes a and updates it when new server messages are received. + /// + public class HandLabelerBoundUserInterface : BoundUserInterface + { + private HandLabelerWindow? _window; + + public HandLabelerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _window = new HandLabelerWindow(); + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; + _window.OnLabelEntered += OnLabelChanged; + + } + + private void OnLabelChanged(string newLabel) + { + SendMessage(new HandLabelerLabelChangedMessage(newLabel)); + Close(); + } + + /// + /// Update the UI state based on server-sent info + /// + /// + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + if (_window == null || state is not HandLabelerBoundUserInterfaceState cast) + return; + + _window.SetCurrentLabel(cast.CurrentLabel); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } + } + +} diff --git a/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml b/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml new file mode 100644 index 0000000000..1b09257a43 --- /dev/null +++ b/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml @@ -0,0 +1,8 @@ + + + + diff --git a/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs b/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs new file mode 100644 index 0000000000..bfc27dda20 --- /dev/null +++ b/Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs @@ -0,0 +1,26 @@ +using System; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.HandLabeler.UI +{ + [GenerateTypedNameReferences] + public partial class HandLabelerWindow : SS14Window + { + public event Action? OnLabelEntered; + + public HandLabelerWindow() + { + RobustXamlLoader.Load(this); + + LabelLineEdit.OnTextEntered += e => OnLabelEntered?.Invoke(e.Text); + } + + public void SetCurrentLabel(string label) + { + LabelLineEdit.Text = label; + } + } +} diff --git a/Content.Server/HandLabeler/Components/HandLabelerComponent.cs b/Content.Server/HandLabeler/Components/HandLabelerComponent.cs new file mode 100644 index 0000000000..c7334eb4f4 --- /dev/null +++ b/Content.Server/HandLabeler/Components/HandLabelerComponent.cs @@ -0,0 +1,26 @@ +using System; +using Content.Server.Items; +using Content.Shared.Whitelist; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.HandLabeler.Components +{ + [RegisterComponent] + public class HandLabelerComponent : Component + { + public override string Name => "HandLabeler"; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("assignedLabel")] + public string AssignedLabel { get; set; } = string.Empty; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("maxLabelChars")] + public int MaxLabelChars { get; set; } = 50; + + [DataField("whitelist")] + public EntityWhitelist Whitelist = new(); + } +} diff --git a/Content.Server/HandLabeler/Components/LabelComponent.cs b/Content.Server/HandLabeler/Components/LabelComponent.cs new file mode 100644 index 0000000000..e98ff32b23 --- /dev/null +++ b/Content.Server/HandLabeler/Components/LabelComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.HandLabeler.Components +{ + [RegisterComponent] + public class LabelComponent : Component + { + public override string Name => "Label"; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("currentLabel")] + public string? CurrentLabel { get; set; } + + public string? OriginalName { get; set; } + } +} diff --git a/Content.Server/HandLabeler/HandLabelerSystem.cs b/Content.Server/HandLabeler/HandLabelerSystem.cs new file mode 100644 index 0000000000..a06ffc6d64 --- /dev/null +++ b/Content.Server/HandLabeler/HandLabelerSystem.cs @@ -0,0 +1,110 @@ +using Content.Server.HandLabeler.Components; +using Content.Server.UserInterface; +using Content.Shared.ActionBlocker; +using Content.Shared.HandLabeler; +using Content.Shared.Interaction; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Players; +using Robust.Shared.IoC; +using JetBrains.Annotations; +using Robust.Shared.Localization; +using Content.Shared.Popups; +using System; + +namespace Content.Server.HandLabeler +{ + /// + /// A hand labeler system that lets an object apply labels to objects with the . + /// + [UsedImplicitly] + public class HandLabelerSystem : EntitySystem + { + [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(AfterInteractOn); + SubscribeLocalEvent(OnUseInHand); + // Bound UI subscriptions + SubscribeLocalEvent(OnHandLabelerLabelChanged); + } + + private void AfterInteractOn(EntityUid uid, HandLabelerComponent handLabeler, AfterInteractEvent args) + { + if (args.Target == null || !handLabeler.Whitelist.IsValid(args.Target)) + return; + + AddLabelTo(uid, handLabeler, args.Target, out string? result); + if (result != null) + handLabeler.Owner.PopupMessage(args.User, result); + } + + private void AddLabelTo(EntityUid uid, HandLabelerComponent? handLabeler, IEntity target, out string? result) + { + if (!Resolve(uid, ref handLabeler)) + { + result = null; + return; + } + + LabelComponent label = target.EnsureComponent(); + + if (label.OriginalName != null) + target.Name = label.OriginalName; + label.OriginalName = null; + + if (handLabeler.AssignedLabel == string.Empty) + { + label.CurrentLabel = null; + result = Loc.GetString("hand-labeler-successfully-removed"); + return; + } + + label.OriginalName = target.Name; + target.Name += $" ({handLabeler.AssignedLabel})"; + label.CurrentLabel = handLabeler.AssignedLabel; + result = Loc.GetString("hand-labeler-successfully-applied"); + } + + private void OnUseInHand(EntityUid uid, HandLabelerComponent handLabeler, UseInHandEvent args) + { + if (!args.User.TryGetComponent(out ActorComponent? actor)) + return; + + handLabeler.Owner.GetUIOrNull(HandLabelerUiKey.Key)?.Open(actor.PlayerSession); + args.Handled = true; + } + + private bool CheckInteract(ICommonSession session) + { + if (session.AttachedEntity is not { } entity + || !Get().CanInteract(entity) + || !Get().CanUse(entity)) + return false; + + return true; + } + + private void OnHandLabelerLabelChanged(EntityUid uid, HandLabelerComponent handLabeler, HandLabelerLabelChangedMessage args) + { + if (!CheckInteract(args.Session)) + return; + + handLabeler.AssignedLabel = args.Label.Trim().Substring(0, Math.Min(handLabeler.MaxLabelChars, args.Label.Length)); + DirtyUI(uid, handLabeler); + } + + private void DirtyUI(EntityUid uid, + HandLabelerComponent? handLabeler = null) + { + if (!Resolve(uid, ref handLabeler)) + return; + + _userInterfaceSystem.TrySetUiState(uid, HandLabelerUiKey.Key, + new HandLabelerBoundUserInterfaceState(handLabeler.AssignedLabel)); + } + } +} diff --git a/Content.Server/HandLabeler/LabelSystem.cs b/Content.Server/HandLabeler/LabelSystem.cs new file mode 100644 index 0000000000..048a9a8b46 --- /dev/null +++ b/Content.Server/HandLabeler/LabelSystem.cs @@ -0,0 +1,36 @@ +using Content.Server.HandLabeler.Components; +using Content.Shared.Examine; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Utility; + +namespace Content.Server.HandLabeler +{ + /// + /// A system that lets players see the contents of a label on an object. + /// + [UsedImplicitly] + public class LabelSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamine); + } + + private void OnExamine(EntityUid uid, LabelComponent? label, ExaminedEvent args) + { + if (!Resolve(uid, ref label)) + return; + + if (label.CurrentLabel == null) + return; + + var message = new FormattedMessage(); + message.AddText(Loc.GetString("hand-labeler-has-label", ("label", label.CurrentLabel))); + args.PushMessage(message); + } + } +} diff --git a/Content.Shared/HandLabeler/SharedHandLabelerComponent.cs b/Content.Shared/HandLabeler/SharedHandLabelerComponent.cs new file mode 100644 index 0000000000..26eb165b5d --- /dev/null +++ b/Content.Shared/HandLabeler/SharedHandLabelerComponent.cs @@ -0,0 +1,41 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.HandLabeler +{ + /// + /// Key representing which is currently open. + /// Useful when there are multiple UI for an object. Here it's future-proofing only. + /// + [Serializable, NetSerializable] + public enum HandLabelerUiKey + { + Key, + } + + /// + /// Represents a state that can be sent to the client + /// + [Serializable, NetSerializable] + public class HandLabelerBoundUserInterfaceState : BoundUserInterfaceState + { + public string CurrentLabel { get; } + + public HandLabelerBoundUserInterfaceState(string currentLabel) + { + CurrentLabel = currentLabel; + } + } + + [Serializable, NetSerializable] + public class HandLabelerLabelChangedMessage : BoundUserInterfaceMessage + { + public string Label { get; } + + public HandLabelerLabelChangedMessage(string label) + { + Label = label; + } + } +} diff --git a/Resources/Locale/en-US/hand-labeler/hand-labeler.ftl b/Resources/Locale/en-US/hand-labeler/hand-labeler.ftl new file mode 100644 index 0000000000..27ed032825 --- /dev/null +++ b/Resources/Locale/en-US/hand-labeler/hand-labeler.ftl @@ -0,0 +1,11 @@ +# The content of the label in the UI above the text entry input. +hand-labeler-current-text-label = Label: + +# When the hand labeler applies a label successfully +hand-labeler-successfully-applied = Applied label successfully + +# When the hand labeler removes a label successfully +hand-labeler-successfully-removed = Removed label successfully + +# Appended to the description of an object with a label on input +hand-labeler-has-label = This object has a label on it, which reads '{$label}' diff --git a/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml b/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml new file mode 100644 index 0000000000..3b16f6938a --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml @@ -0,0 +1,23 @@ +- type: entity + parent: BaseItem + id: HandLabeler + name: hand labeler + description: A hand labeler, used to label items and objects. + components: + - type: Sprite + sprite: Objects/Tools/hand_labeler.rsi + state: hand_labeler + - type: Item + sprite: Objects/Tools/hand_labeler.rsi + - type: UseDelay + delay: 2.0 + - type: UserInterface + interfaces: + - key: enum.HandLabelerUiKey.Key + type: HandLabelerBoundUserInterface + - type: HandLabeler + whitelist: + components: + - Item + tags: + - Structure diff --git a/Resources/Prototypes/Entities/Structures/base.yml b/Resources/Prototypes/Entities/Structures/base.yml index 075f32b5dc..57abbe000a 100644 --- a/Resources/Prototypes/Entities/Structures/base.yml +++ b/Resources/Prototypes/Entities/Structures/base.yml @@ -19,6 +19,9 @@ mask: - Impassable - type: Pullable + - type: Tag + tags: + - Structure - type: entity # This means that it's not anchored on spawn. @@ -46,3 +49,6 @@ mask: - VaultImpassable - type: Anchorable + +- type: Tag + id: Structure diff --git a/Resources/Textures/Objects/Tools/hand_labeler.rsi/hand_labeler.png b/Resources/Textures/Objects/Tools/hand_labeler.rsi/hand_labeler.png new file mode 100644 index 0000000000000000000000000000000000000000..9938103840821ec610fa3ff217b4c8a3965985b5 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvl>na**8>L*gocLx|NsBy&714j zueZ0i7gf-X>s#Yey390gK7(hes;cVKG;b!Ldd89gy-*`Dq^#5}@KDB_X*nHA55n#}n>MXMWs==y-R!GIEc4eEr$vW` ziiUVbMMWJuGcz|fHa1t_=C@Cu&K>ni+njcG7Mmc$s)(HtC$p}untJ&`TFTj|twqny z%rt1cyL)@%4&!vEwGa7tdC$(WEWWxbl(Rr|_vWy*QPbGO8)nQoFriIOty!9Zfy3QI V@ORnuSfDc*JYD@<);T3K0RW#cX{`VN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..eb697134d65ee5febb84ef56a3ea5361d12ac1e8 GIT binary patch literal 636 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP*5S+ zBgmJ5p-Pp3p`n?9;pcxK{gQ#9)PRBERRRNp)eHs(@%%~gN8K10n3z0W978H@y_sp4 z#pEc`_Mfv$bBmzznI=u2^aE-$)HrrJ**F~eT*0x|r7s~fS@4Eh?}G-fAc>Ai2fPK{ zeKy=EO+R$%AOE(<8{0SEKUclkdcKfgisiWp9~BswFwu#GCo$?a`mulRCI-H~s$^}P z@Oj^nWp|x7U*5j_3Bwc*g|~&9R1GBiCp>w(KAhXd-UKix~p8ElW0WWDuCWIOY^{!>qGuFWDDNVQPqd z&veU|F{Jh7;z$pDCP35=6joc_Lr4hU)}0;l;;Qg*4$X;S##~o-pZN1KV35A zKyJB)=hliT8(!Ij+8)r#5s$L*y74*y%n`G`YGaOUr$*yHk*9E2=22WQ%mvv4FO#tcn{#*b6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/hand_labeler.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..303805398e9fec833b47a86c87edf195b9a425a2 GIT binary patch literal 648 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP*5S+ zBgmJ5p-Pp3p`n?9;pcxK{gQ#9)PRBERRRNp)eHs(@%%~gN8K10nD{(h978H@y_t0| z>yU#$+kaiLYJ=&MxU^q5=5xh$?VaKjzp%Dpnq5EtLj8;GA6^`FR-7Kk#hH=GFScrn z!QK+p+{J2nOOE|vW>!?0eK)^6ZStSRE-aPXn4jF?XkfrZMH#ItCcB^OwEXjNdy3iI z6?@h&7&hm}mmBWiarn<$%i?D1BEKUQj|67;s!Q;)&zyU6^X+{-ZOmtuO+H)f@ca`O zL%`Q}#-=}_7OOt|x86kX=i{T3wC6qde7;QmYE`iyU*Pq3i5?bVz+dtSvnb)e+w zb+NmcZY_UaJ@Lu4UT4?8V*l^4E{V}gwvl^$!;*#J>F+ua|eezG)xhvo5b1<