mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
Fix OnAttachedChanged Lag when having a long chat history (#46050)
* I fucking hate chat code and UI code * while I'm at it I'll make this prettier * docs * typo * testfail * reset chat upon joining game * move code * remove unused imports and add doc * doc * final commit * oop * Revert "reset chat upon joining game" This reverts commit a851319521193d099b6d1571631b63917500bc47. * review stuff * testfail
This commit is contained in:
parent
32b60ae36c
commit
86adeec6db
6 changed files with 132 additions and 57 deletions
|
|
@ -1,13 +1,85 @@
|
|||
using Content.Client.UserInterface.ControlExtensions;
|
||||
using Content.Client.UserInterface.RichText;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
||||
namespace Content.Client.UserInterface.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Carries link data parsed and resolved from a TextLink <see cref="MarkupNode"/>,
|
||||
/// only one field per link should be populated at a time.
|
||||
/// only one LinkType field per link should be populated at a time.
|
||||
/// </summary>
|
||||
public sealed class TextLinkLabel : Label
|
||||
public sealed partial class TextLinkLabel : Label
|
||||
{
|
||||
public string? LinkString { get; init; }
|
||||
public NetEntity? LinkEntity { get; init; }
|
||||
public string? LinkString { get; init; } // default links
|
||||
public NetEntity? LinkEntity { get; init; } // entity links
|
||||
public Color LinkColor { get; set; }
|
||||
|
||||
[Dependency] private IEntityManager _entity = default!;
|
||||
private bool canClickLink;
|
||||
|
||||
public TextLinkLabel()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
OnKeyBindDown += OnKeybindDown;
|
||||
OnMouseEntered += _ => OnHoverChanged(true);
|
||||
OnMouseExited += _ => OnHoverChanged(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the label's properties based on the current link target
|
||||
/// and the viewer's permission to follow it. <br />Call after construction,
|
||||
/// and whenever that permission could have changed.
|
||||
/// </summary>
|
||||
/// <param name="visible">Whether the label should be shown at all. Defaults to true.</param>
|
||||
/// <param name="clickable">Additional override to force the label non-clickable. Defaults to true.</param>
|
||||
public void UpdateLabelProperties(SharedChatSystem chatSystem, bool? visible = null, bool? clickable = null)
|
||||
{
|
||||
visible ??= true;
|
||||
Visible = visible.Value;
|
||||
clickable ??= true;
|
||||
|
||||
canClickLink = (LinkString != null || (LinkEntity is { } netEntity && chatSystem.CanClickMessageSender(netEntity))) && (bool)clickable;
|
||||
|
||||
MouseFilter = canClickLink ? MouseFilterMode.Stop : MouseFilterMode.Ignore;
|
||||
DefaultCursorShape = canClickLink ? CursorShape.Hand : CursorShape.Arrow;
|
||||
|
||||
OnHoverChanged(false);
|
||||
}
|
||||
|
||||
private void OnHoverChanged(bool hovering)
|
||||
{
|
||||
FontColorOverride = (canClickLink, hovering) switch
|
||||
{
|
||||
(true, true) => Color.LightSkyBlue, // clickable and currently hovered
|
||||
_ => LinkColor, // not clickable, or not hovered
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegates click to the nearest ancestor ILinkClickHandler or IEntityLinkClickHandler;
|
||||
/// TextLinkLabel has no idea what a click actually does.
|
||||
/// </summary>
|
||||
private void OnKeybindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
if (LinkString is null && LinkEntity is null)
|
||||
return;
|
||||
|
||||
if (LinkEntity is { } entity &&
|
||||
this.TryGetParentHandler<IEntityLinkClickHandler>(out var entityLinkClickHandler))
|
||||
{
|
||||
entityLinkClickHandler.HandleClick(entity);
|
||||
}
|
||||
else if (LinkString != null && this.TryGetParentHandler<ILinkClickHandler>(out var linkClickHandler))
|
||||
{
|
||||
linkClickHandler.HandleClick(LinkString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,9 @@ public sealed partial class TextLinkTag
|
|||
if (!NetEntity.TryParse(entStr, out var netEntity))
|
||||
return false;
|
||||
|
||||
var chat = _entity.System<SharedChatSystem>();
|
||||
var clickable = chat.CanClickMessageSender(netEntity);
|
||||
|
||||
var color = GetLinkColor(node, netEntity);
|
||||
|
||||
data = new LinkData(LinkString: null, LinkEntity: netEntity, Color: color, Clickable: clickable);
|
||||
data = new LinkData(LinkString: null, LinkEntity: netEntity, Color: color);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.RichText;
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ public sealed partial class TextLinkTag
|
|||
return false;
|
||||
}
|
||||
|
||||
data = new LinkData(LinkString: linkStr, LinkEntity: null, Color: null, Clickable: true);
|
||||
data = new LinkData(LinkString: linkStr, LinkEntity: null, Color: null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,25 @@ using JetBrains.Annotations;
|
|||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.RichText;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Client.UserInterface.ControlExtensions;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.ResourceManagement;
|
||||
|
||||
namespace Content.Client.UserInterface.RichText;
|
||||
|
||||
/// <summary>
|
||||
/// Markup tag handler for <c>[textlink="LinkText"]</c> nodes. Renders a link
|
||||
/// <see cref="Label"/> in rich text, covering two types:
|
||||
/// plain links (<c>link=</c>) and entity links (<c>entity=</c>).
|
||||
/// optional <c>color=</c> and <c>entitynamecolor=</c> parameters
|
||||
/// allow setting a color override and opting into using entity name colors for entity links
|
||||
/// <see cref="Label"/> in rich text, covering two link types:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>link="GuideEntryPrototypeID" — a plain link.</description></item>
|
||||
/// <item><description>entity="NetEntity" — an entity link.</description></item>
|
||||
/// </list>
|
||||
/// Optional parameters:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>color="HexColor" — color override.</description></item>
|
||||
/// <item><description>entitynamecolor="Bool" — entity links only; opt into using the entity's name color.</description></item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class TextLinkTag : IMarkupTagHandler
|
||||
|
|
@ -25,6 +30,7 @@ public sealed partial class TextLinkTag : IMarkupTagHandler
|
|||
[Dependency] private IEntityManager _entity = default!;
|
||||
[Dependency] private IUserInterfaceManager _ui = default!;
|
||||
[Dependency] private IResourceCache _cache = default!;
|
||||
private SharedChatSystem? _chat;
|
||||
|
||||
public string Name => "textlink";
|
||||
public static Color DefaultLinkColor => Color.CornflowerBlue;
|
||||
|
|
@ -38,7 +44,7 @@ public sealed partial class TextLinkTag : IMarkupTagHandler
|
|||
/// <summary>
|
||||
/// Resolved Link Data, LinkString and LinkEntity should not be populated at the same time
|
||||
/// </summary>
|
||||
private readonly record struct LinkData(string? LinkString, NetEntity? LinkEntity, Color? Color, bool Clickable);
|
||||
private readonly record struct LinkData(string? LinkString, NetEntity? LinkEntity, Color? Color);
|
||||
|
||||
public TextLinkTag()
|
||||
{
|
||||
|
|
@ -67,25 +73,27 @@ public sealed partial class TextLinkTag : IMarkupTagHandler
|
|||
|
||||
foreach (var (attrname, resolver) in _resolvers)
|
||||
{
|
||||
if (node.Attributes.ContainsKey(attrname))
|
||||
if (!node.Attributes.ContainsKey(attrname))
|
||||
continue;
|
||||
|
||||
if(!resolver(node, out linkData))
|
||||
{
|
||||
if(!resolver(node, out linkData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
linkTypeResolved = true;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
linkTypeResolved = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!linkTypeResolved)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// color= > resolver-supplied color > default
|
||||
var linkColor = ResolveColorOverride(node) ?? linkData.Color ?? DefaultLinkColor;
|
||||
var linkLabel = new TextLinkLabel() { Text = text, LinkString = linkData.LinkString, LinkEntity = linkData.LinkEntity };
|
||||
linkLabel.FontColorOverride = linkColor;
|
||||
var linkLabel = new TextLinkLabel() { Text = text, LinkString = linkData.LinkString, LinkEntity = linkData.LinkEntity, LinkColor = linkColor};
|
||||
|
||||
// eat my ass about where this magic number comes from
|
||||
// our UI stack is awful. Finding this magic number was awful.
|
||||
|
|
@ -96,14 +104,8 @@ public sealed partial class TextLinkTag : IMarkupTagHandler
|
|||
linkLabel.FontOverride = boldFont;
|
||||
}
|
||||
|
||||
if (linkData.Clickable)
|
||||
{
|
||||
linkLabel.MouseFilter = Control.MouseFilterMode.Stop;
|
||||
linkLabel.DefaultCursorShape = Control.CursorShape.Hand;
|
||||
linkLabel.OnMouseEntered += _ => linkLabel.FontColorOverride = Color.LightSkyBlue;
|
||||
linkLabel.OnMouseExited += _ => linkLabel.FontColorOverride = linkColor;
|
||||
linkLabel.OnKeyBindDown += args => OnKeybindDown(args, linkLabel);
|
||||
}
|
||||
_chat ??= _entity.System<SharedChatSystem>();
|
||||
linkLabel.UpdateLabelProperties(_chat);
|
||||
|
||||
control = linkLabel;
|
||||
return true;
|
||||
|
|
@ -119,28 +121,6 @@ public sealed partial class TextLinkTag : IMarkupTagHandler
|
|||
|
||||
return Color.TryFromHex(colorStr, out var color) ? color : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegates to the nearest ancestor ILinkClickHandler or IEntityLinkClickHandler;
|
||||
/// TextLinkTag has no idea what a click actually does.
|
||||
/// </summary>
|
||||
private void OnKeybindDown(GUIBoundKeyEventArgs args, TextLinkLabel? control)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
if (control == null)
|
||||
return;
|
||||
|
||||
if (control.LinkEntity is { } entity && control.TryGetParentHandler<IEntityLinkClickHandler>(out var entityLinkClickHandler))
|
||||
{
|
||||
entityLinkClickHandler.HandleClick(entity);
|
||||
}
|
||||
else if (control.LinkString != null && control.TryGetParentHandler<ILinkClickHandler>(out var linkClickHandler))
|
||||
{
|
||||
linkClickHandler.HandleClick(control.LinkString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public sealed partial class ChatUIController : UIController
|
|||
[UISystemDependency] private readonly MindSystem? _mindSystem = default!;
|
||||
[UISystemDependency] private readonly RoleCodewordSystem? _roleCodewordSystem = default!;
|
||||
|
||||
private SharedChatSystem? _sharedChatSys;
|
||||
private static readonly ProtoId<ColorPalettePrototype> ChatNamePalette = "ChatNames";
|
||||
private string[] _chatNameColors = default!;
|
||||
private bool _chatNameColorsEnabled;
|
||||
|
|
@ -429,7 +430,7 @@ public sealed partial class ChatUIController : UIController
|
|||
{
|
||||
UpdateChannelPermissions();
|
||||
UpdateAutoFillHighlights();
|
||||
Repopulate();
|
||||
UpdateLinkLabels();
|
||||
}
|
||||
|
||||
private void AddSpeechBubble(ChatMessage msg, SpeechBubble.SpeechType speechType)
|
||||
|
|
@ -942,6 +943,16 @@ public sealed partial class ChatUIController : UIController
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateLinkLabels()
|
||||
{
|
||||
_sharedChatSys ??= _ent.System<SharedChatSystem>();
|
||||
|
||||
foreach (var chat in _chats)
|
||||
{
|
||||
chat.UpdateTextLinkLabelProperties(_sharedChatSys);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the chat name color for a mob
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Client.UserInterface.RichText;
|
||||
using Content.Client.UserInterface.Systems.Chat.Controls;
|
||||
using Content.Shared.Chat;
|
||||
|
|
@ -91,6 +92,20 @@ public partial class ChatBox : UIWidget, IEntityLinkClickHandler
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls update function on every child <see cref="TextLinkLabel"/> in the ChatBox's OutputPanel "Contents"
|
||||
/// </summary>
|
||||
public void UpdateTextLinkLabelProperties(SharedChatSystem _sharedChatSys)
|
||||
{
|
||||
foreach (var contentsChild in Contents.Children)
|
||||
{
|
||||
if (contentsChild is TextLinkLabel textLinkLabel)
|
||||
{
|
||||
textLinkLabel.UpdateLabelProperties(_sharedChatSys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnChannelFilter(ChatChannel channel, bool active)
|
||||
{
|
||||
Contents.Clear();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue