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>
This commit is contained in:
@@ -285,7 +285,9 @@ namespace Content.Client.Entry
|
||||
"DeviceNetworkConnection",
|
||||
"WiredNetworkConnection",
|
||||
"WirelessNetworkConnection",
|
||||
"GhostRadio"
|
||||
"HandLabeler",
|
||||
"Label",
|
||||
"GhostRadio",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using Content.Shared.HandLabeler;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.HandLabeler.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="HandLabelerWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the UI state based on server-sent info
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
8
Content.Client/HandLabeler/UI/HandLabelerWindow.xaml
Normal file
8
Content.Client/HandLabeler/UI/HandLabelerWindow.xaml
Normal file
@@ -0,0 +1,8 @@
|
||||
<SS14Window xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Hand Labeler">
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
|
||||
<Label Name="CurrentTextLabel" Text="{Loc 'hand-labeler-current-text-label'}" />
|
||||
<LineEdit Name="LabelLineEdit" />
|
||||
</BoxContainer>
|
||||
</SS14Window>
|
||||
26
Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs
Normal file
26
Content.Client/HandLabeler/UI/HandLabelerWindow.xaml.cs
Normal file
@@ -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<string>? OnLabelEntered;
|
||||
|
||||
public HandLabelerWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
LabelLineEdit.OnTextEntered += e => OnLabelEntered?.Invoke(e.Text);
|
||||
}
|
||||
|
||||
public void SetCurrentLabel(string label)
|
||||
{
|
||||
LabelLineEdit.Text = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
18
Content.Server/HandLabeler/Components/LabelComponent.cs
Normal file
18
Content.Server/HandLabeler/Components/LabelComponent.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
||||
110
Content.Server/HandLabeler/HandLabelerSystem.cs
Normal file
110
Content.Server/HandLabeler/HandLabelerSystem.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A hand labeler system that lets an object apply labels to objects with the <see cref="LabelComponent"/> .
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class HandLabelerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HandLabelerComponent, AfterInteractEvent>(AfterInteractOn);
|
||||
SubscribeLocalEvent<HandLabelerComponent, UseInHandEvent>(OnUseInHand);
|
||||
// Bound UI subscriptions
|
||||
SubscribeLocalEvent<HandLabelerComponent, HandLabelerLabelChangedMessage>(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<LabelComponent>();
|
||||
|
||||
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<ActionBlockerSystem>().CanInteract(entity)
|
||||
|| !Get<ActionBlockerSystem>().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));
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Content.Server/HandLabeler/LabelSystem.cs
Normal file
36
Content.Server/HandLabeler/LabelSystem.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A system that lets players see the contents of a label on an object.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class LabelSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LabelComponent, ExaminedEvent>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Content.Shared/HandLabeler/SharedHandLabelerComponent.cs
Normal file
41
Content.Shared/HandLabeler/SharedHandLabelerComponent.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.HandLabeler
|
||||
{
|
||||
/// <summary>
|
||||
/// Key representing which <see cref="BoundUserInterface"/> is currently open.
|
||||
/// Useful when there are multiple UI for an object. Here it's future-proofing only.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum HandLabelerUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <see cref="HandLabelerComponent"/> state that can be sent to the client
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Resources/Locale/en-US/hand-labeler/hand-labeler.ftl
Normal file
11
Resources/Locale/en-US/hand-labeler/hand-labeler.ftl
Normal file
@@ -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}'
|
||||
23
Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml
Normal file
23
Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 273 B |
Binary file not shown.
|
After Width: | Height: | Size: 636 B |
Binary file not shown.
|
After Width: | Height: | Size: 648 B |
22
Resources/Textures/Objects/Tools/hand_labeler.rsi/meta.json
Normal file
22
Resources/Textures/Objects/Tools/hand_labeler.rsi/meta.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/tgstation/tgstation at commit 44636483b7b2868b3e42c92205539f11f6d7968f. Inhand sprites by Macoron.",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "hand_labeler"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user