From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 6 May 2025 17:49:42 +0000 (+0200) Subject: Port fancy speech bubbles (#29349) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=740ce0e8ad522393d6f05430954742e969b449c6;p=space-station-14.git Port fancy speech bubbles (#29349) --- diff --git a/Content.Client/Chat/TypingIndicator/TypingIndicatorSystem.cs b/Content.Client/Chat/TypingIndicator/TypingIndicatorSystem.cs index 33dbc06ad8..c126f08db1 100644 --- a/Content.Client/Chat/TypingIndicator/TypingIndicatorSystem.cs +++ b/Content.Client/Chat/TypingIndicator/TypingIndicatorSystem.cs @@ -16,6 +16,7 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem private readonly TimeSpan _typingTimeout = TimeSpan.FromSeconds(2); private TimeSpan _lastTextChange; private bool _isClientTyping; + private bool _isClientChatFocused; public override void Initialize() { @@ -31,7 +32,8 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem return; // client typed something - show typing indicator - ClientUpdateTyping(true); + _isClientTyping = true; + ClientUpdateTyping(); _lastTextChange = _time.CurTime; } @@ -42,7 +44,19 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem return; // client submitted text - hide typing indicator - ClientUpdateTyping(false); + _isClientTyping = false; + ClientUpdateTyping(); + } + + public void ClientChangedChatFocus(bool isFocused) + { + // don't update it if player don't want to show typing + if (!_cfg.GetCVar(CCVars.ChatShowTypingIndicator)) + return; + + // client submitted text - hide typing indicator + _isClientChatFocused = isFocused; + ClientUpdateTyping(); } public override void Update(float frameTime) @@ -55,23 +69,25 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem var dif = _time.CurTime - _lastTextChange; if (dif > _typingTimeout) { - // client didn't typed anything for a long time - hide indicator - ClientUpdateTyping(false); + // client didn't typed anything for a long time - change indicator + _isClientTyping = false; + ClientUpdateTyping(); } } } - private void ClientUpdateTyping(bool isClientTyping) + private void ClientUpdateTyping() { - if (_isClientTyping == isClientTyping) - return; - - // check if player controls any entity. + // check if player controls any pawn if (_playerManager.LocalEntity == null) return; - _isClientTyping = isClientTyping; - RaisePredictiveEvent(new TypingChangedEvent(isClientTyping)); + var state = TypingIndicatorState.None; + if (_isClientChatFocused) + state = _isClientTyping ? TypingIndicatorState.Typing : TypingIndicatorState.Idle; + + // send a networked event to server + RaisePredictiveEvent(new TypingChangedEvent(state)); } private void OnShowTypingChanged(bool showTyping) @@ -79,7 +95,8 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem // hide typing indicator immediately if player don't want to show it anymore if (!showTyping) { - ClientUpdateTyping(false); + _isClientTyping = false; + ClientUpdateTyping(); } } } diff --git a/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs b/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs index e89f7ab500..a9af045c0c 100644 --- a/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs +++ b/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs @@ -35,7 +35,6 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem(uid, TypingIndicatorVisuals.IsTyping, out var isTyping, args.Component); var layerExists = args.Sprite.LayerMapTryGet(TypingIndicatorLayers.Base, out var layer); if (!layerExists) layer = args.Sprite.LayerMapReserveBlank(TypingIndicatorLayers.Base); @@ -44,6 +43,17 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem(uid, TypingIndicatorVisuals.State, out var state); + args.Sprite.LayerSetVisible(layer, state != TypingIndicatorState.None); + switch (state) + { + case TypingIndicatorState.Idle: + args.Sprite.LayerSetState(layer, proto.IdleState); + break; + case TypingIndicatorState.Typing: + args.Sprite.LayerSetState(layer, proto.TypingState); + break; + } } } diff --git a/Content.Client/Holopad/HolopadSystem.cs b/Content.Client/Holopad/HolopadSystem.cs index 6aad39fe24..40226b9851 100644 --- a/Content.Client/Holopad/HolopadSystem.cs +++ b/Content.Client/Holopad/HolopadSystem.cs @@ -46,7 +46,7 @@ public sealed class HolopadSystem : SharedHolopadSystem if (!HasComp(uid)) return; - var netEv = new HolopadUserTypingChangedEvent(GetNetEntity(uid.Value), ev.IsTyping); + var netEv = new HolopadUserTypingChangedEvent(GetNetEntity(uid.Value), ev.State); RaiseNetworkEvent(netEv); } diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index a77bc10f7b..1ccba1ae20 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -918,6 +918,11 @@ public sealed class ChatUIController : UIController _typingIndicator?.ClientChangedChatText(); } + public void NotifyChatFocus(bool isFocused) + { + _typingIndicator?.ClientChangedChatFocus(isFocused); + } + public void Repopulate() { foreach (var chat in _chats) diff --git a/Content.Client/UserInterface/Systems/Chat/Widgets/ChatBox.xaml.cs b/Content.Client/UserInterface/Systems/Chat/Widgets/ChatBox.xaml.cs index 62b3b19e38..068cf4e87e 100644 --- a/Content.Client/UserInterface/Systems/Chat/Widgets/ChatBox.xaml.cs +++ b/Content.Client/UserInterface/Systems/Chat/Widgets/ChatBox.xaml.cs @@ -34,6 +34,8 @@ public partial class ChatBox : UIWidget ChatInput.Input.OnTextEntered += OnTextEntered; ChatInput.Input.OnKeyBindDown += OnInputKeyBindDown; ChatInput.Input.OnTextChanged += OnTextChanged; + ChatInput.Input.OnFocusEnter += OnFocusEnter; + ChatInput.Input.OnFocusExit += OnFocusExit; ChatInput.ChannelSelector.OnChannelSelect += OnChannelSelect; ChatInput.FilterButton.Popup.OnChannelFilter += OnChannelFilter; @@ -174,6 +176,18 @@ public partial class ChatBox : UIWidget _controller.NotifyChatTextChange(); } + private void OnFocusEnter(LineEditEventArgs args) + { + // Warn typing indicator about focus + _controller.NotifyChatFocus(true); + } + + private void OnFocusExit(LineEditEventArgs args) + { + // Warn typing indicator about focus + _controller.NotifyChatFocus(false); + } + protected override void Dispose(bool disposing) { base.Dispose(disposing); diff --git a/Content.Server/Holopad/HolopadSystem.cs b/Content.Server/Holopad/HolopadSystem.cs index af8c5a36a1..f2bd0e05ad 100644 --- a/Content.Server/Holopad/HolopadSystem.cs +++ b/Content.Server/Holopad/HolopadSystem.cs @@ -309,7 +309,7 @@ public sealed class HolopadSystem : SharedHolopadSystem if (receiverHolopad.Comp.Hologram == null) continue; - _appearanceSystem.SetData(receiverHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.IsTyping, ev.IsTyping); + _appearanceSystem.SetData(receiverHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.State, ev.State); } } } @@ -591,7 +591,7 @@ public sealed class HolopadSystem : SharedHolopadSystem continue; if (user == null) - _appearanceSystem.SetData(linkedHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.IsTyping, false); + _appearanceSystem.SetData(linkedHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.State, false); linkedHolopad.Comp.Hologram.Value.Comp.LinkedEntity = user; Dirty(linkedHolopad.Comp.Hologram.Value); diff --git a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs index 9d60d334db..bc5c95c8ab 100644 --- a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs +++ b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs @@ -45,7 +45,7 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem private void OnPlayerDetached(EntityUid uid, TypingIndicatorComponent component, PlayerDetachedEvent args) { // player left entity body - hide typing indicator - SetTypingIndicatorEnabled(uid, false); + SetTypingIndicatorState(uid, TypingIndicatorState.None); } private void OnGotEquipped(Entity entity, ref ClothingGotEquippedEvent args) @@ -76,18 +76,18 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem if (!_actionBlocker.CanEmote(uid.Value) && !_actionBlocker.CanSpeak(uid.Value)) { // nah, make sure that typing indicator is disabled - SetTypingIndicatorEnabled(uid.Value, false); + SetTypingIndicatorState(uid.Value, TypingIndicatorState.None); return; } - SetTypingIndicatorEnabled(uid.Value, ev.IsTyping); + SetTypingIndicatorState(uid.Value, ev.State); } - private void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null) + private void SetTypingIndicatorState(EntityUid uid, TypingIndicatorState state, AppearanceComponent? appearance = null) { if (!Resolve(uid, ref appearance, false)) return; - _appearance.SetData(uid, TypingIndicatorVisuals.IsTyping, isEnabled, appearance); + _appearance.SetData(uid, TypingIndicatorVisuals.State, state, appearance); } } diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs index 600f86c0d2..29a5d85be8 100644 --- a/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs @@ -12,11 +12,11 @@ namespace Content.Shared.Chat.TypingIndicator; [Serializable, NetSerializable] public sealed class TypingChangedEvent : EntityEventArgs { - public readonly bool IsTyping; + public readonly TypingIndicatorState State; - public TypingChangedEvent(bool isTyping) + public TypingChangedEvent(TypingIndicatorState state) { - IsTyping = isTyping; + State = state; } } diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorPrototype.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorPrototype.cs index fbd647d035..970fed969a 100644 --- a/Content.Shared/Chat/TypingIndicator/TypingIndicatorPrototype.cs +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorPrototype.cs @@ -19,6 +19,9 @@ public sealed partial class TypingIndicatorPrototype : IPrototype [DataField("typingState", required: true)] public string TypingState = default!; + [DataField("idleState", required: true)] + public string IdleState = default!; + [DataField("offset")] public Vector2 Offset = new(0, 0); diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorState.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorState.cs new file mode 100644 index 0000000000..087610a11b --- /dev/null +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorState.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Chat.TypingIndicator; + +[Serializable, NetSerializable] +public enum TypingIndicatorState +{ + None = 0, + Idle = 1, + Typing = 2, +} diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorVisuals.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorVisuals.cs index 0368819eff..b9ed15fe9a 100644 --- a/Content.Shared/Chat/TypingIndicator/TypingIndicatorVisuals.cs +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorVisuals.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Chat.TypingIndicator; [Serializable, NetSerializable] public enum TypingIndicatorVisuals : byte { - IsTyping + State } [Serializable] diff --git a/Content.Shared/Holopad/HolopadUserComponent.cs b/Content.Shared/Holopad/HolopadUserComponent.cs index c9c2a8828b..d8e4699ee0 100644 --- a/Content.Shared/Holopad/HolopadUserComponent.cs +++ b/Content.Shared/Holopad/HolopadUserComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chat.TypingIndicator; using Robust.Shared.GameStates; using Robust.Shared.Serialization; @@ -34,11 +35,11 @@ public sealed class HolopadUserTypingChangedEvent : EntityEventArgs /// /// The typing indicator state /// - public readonly bool IsTyping; + public readonly TypingIndicatorState State; - public HolopadUserTypingChangedEvent(NetEntity user, bool isTyping) + public HolopadUserTypingChangedEvent(NetEntity user, TypingIndicatorState state) { User = user; - IsTyping = isTyping; + State = state; } } diff --git a/Resources/Prototypes/typing_indicator.yml b/Resources/Prototypes/typing_indicator.yml index 295af30d16..99c06496ac 100644 --- a/Resources/Prototypes/typing_indicator.yml +++ b/Resources/Prototypes/typing_indicator.yml @@ -1,60 +1,73 @@ - type: typingIndicator id: default typingState: default0 + idleState: default3 - type: typingIndicator id: robot typingState: robot0 + idleState: robot3 - type: typingIndicator id: alien typingState: alien0 + idleState: alien3 - type: typingIndicator id: guardian typingState: guardian0 + idleState: guardian3 - type: typingIndicator id: holo typingState: holo0 + idleState: holo3 offset: 0, 0.0625 - type: typingIndicator id: lawyer typingState: lawyer0 + idleState: lawyer3 offset: 0, 0.125 - type: typingIndicator id: moth typingState: moth0 + idleState: moth3 offset: 0, 0.125 - type: typingIndicator id: spider typingState: spider0 + idleState: spider3 offset: 0, 0.125 - type: typingIndicator id: vox typingState: vox0 + idleState: vox0 # TODO add idle state sprite offset: -0.125, 0.125 - type: typingIndicator id: lizard typingState: lizard0 + idleState: lizard3 offset: 0, 0.0625 - type: typingIndicator id: slime typingState: slime0 + idleState: slime3 offset: 0, 0.125 - type: typingIndicator id: gingerbread typingState: gingerbread0 + idleState: gingerbread0 offset: 0, 0.125 - type: typingIndicator id: diona typingState: diona0 + idleState: diona0 offset: 0, 0.125 diff --git a/Resources/Textures/Effects/speech.rsi/alien3.png b/Resources/Textures/Effects/speech.rsi/alien3.png new file mode 100644 index 0000000000..83080b2c18 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/alien3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/alienroyal3.png b/Resources/Textures/Effects/speech.rsi/alienroyal3.png new file mode 100644 index 0000000000..d619232324 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/alienroyal3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/default3.png b/Resources/Textures/Effects/speech.rsi/default3.png new file mode 100644 index 0000000000..7c15716975 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/default3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/guardian3.png b/Resources/Textures/Effects/speech.rsi/guardian3.png new file mode 100644 index 0000000000..730a8213e3 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/guardian3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/holo3.png b/Resources/Textures/Effects/speech.rsi/holo3.png new file mode 100644 index 0000000000..d2ed579f93 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/holo3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/lawyer3.png b/Resources/Textures/Effects/speech.rsi/lawyer3.png new file mode 100644 index 0000000000..7d9d7af8fe Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/lawyer3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/lizard3.png b/Resources/Textures/Effects/speech.rsi/lizard3.png new file mode 100644 index 0000000000..75095cfad6 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/lizard3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/meta.json b/Resources/Textures/Effects/speech.rsi/meta.json index 17cf95079d..82e676cfb0 100644 --- a/Resources/Textures/Effects/speech.rsi/meta.json +++ b/Resources/Textures/Effects/speech.rsi/meta.json @@ -1,11 +1,11 @@ { "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 | Moth sprites made by PuroSlavKing (Github) | Spider sprites made by PixelTheKermit (Github) | Lizard sprites made by AmalgoMyte (Github) | Diona and Gingerbread sprites made by YoungThugSS14 (Github)", "size": { "x": 32, "y": 32 }, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 | Moth sprites made by PuroSlavKing (Github) | Spider sprites made by PixelTheKermit (Github) | Lizard sprites made by AmalgoMyte (Github) | Diona and Gingerbread sprites made by YoungThugSS14 (Github)", "states": [ { "name": "alien0", @@ -26,9 +26,39 @@ { "name": "alien2" }, + { + "name": "alien3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "alienroyal0", - + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.3, + 0.3, + 0.5 + ] + ] + }, + { + "name": "alienroyal1" + }, + { + "name": "alienroyal2" + }, + { + "name": "alienroyal3", "delays": [ [ 0.2, @@ -40,12 +70,6 @@ ] ] }, - { - "name": "alienroyal1" - }, - { - "name": "alienroyal2" - }, { "name": "blob0", "delays": [ @@ -125,6 +149,18 @@ { "name": "default2" }, + { + "name": "default3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "diona0", "delays": [ @@ -176,6 +212,18 @@ { "name": "guardian2" }, + { + "name": "guardian3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "holo0", "delays": [ @@ -195,6 +243,18 @@ { "name": "holo2" }, + { + "name": "holo3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "lawyer0", "delays": [ @@ -232,6 +292,21 @@ ] ] }, + { + "name": "lawyer3", + "delays": [ + [ + 0.15, + 0.15, + 0.15, + 0.15, + 0.125, + 0.1, + 0.125, + 0.15 + ] + ] + }, { "name": "lizard0", "delays": [ @@ -249,6 +324,18 @@ { "name": "lizard2" }, + { + "name": "lizard3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "moth0", "delays": [ @@ -286,6 +373,27 @@ ] ] }, + { + "name": "moth3", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, { "name": "machine0", "delays": [ @@ -320,6 +428,20 @@ { "name": "robot2" }, + { + "name": "robot3", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, { "name": "slime0", "delays": [ @@ -361,6 +483,18 @@ ] ] }, + { + "name": "slime3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, { "name": "swarmer0", "delays": [ @@ -429,6 +563,20 @@ { "name": "syndibot2" }, + { + "name": "syndibot3", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, { "name": "spider0", "delays": [ @@ -446,7 +594,19 @@ { "name": "spider2" }, - { + { + "name": "spider3", + "delays": [ + [ + 0.2, + 0.3, + 0.3, + 0.5, + 0.5 + ] + ] + }, + { "name": "vox0", "delays": [ [ diff --git a/Resources/Textures/Effects/speech.rsi/moth3.png b/Resources/Textures/Effects/speech.rsi/moth3.png new file mode 100644 index 0000000000..93b1d1be74 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/moth3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/robot3.png b/Resources/Textures/Effects/speech.rsi/robot3.png new file mode 100644 index 0000000000..b1686502eb Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/robot3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/slime3.png b/Resources/Textures/Effects/speech.rsi/slime3.png new file mode 100644 index 0000000000..155ab5e3a7 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/slime3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/spider3.png b/Resources/Textures/Effects/speech.rsi/spider3.png new file mode 100644 index 0000000000..4cf57ba563 Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/spider3.png differ diff --git a/Resources/Textures/Effects/speech.rsi/syndibot3.png b/Resources/Textures/Effects/speech.rsi/syndibot3.png new file mode 100644 index 0000000000..5f58ab31ad Binary files /dev/null and b/Resources/Textures/Effects/speech.rsi/syndibot3.png differ