Added FontTagHijackHolder to replace fonts resolved by FontTag.

Existing font prototype system is extremely half-baked and unusable. This allows bypassing it entirely for upcoming content changes.
This commit is contained in:
PJB3005
2025-10-26 20:40:39 +01:00
parent 8ac5fc58d2
commit ab775af7cd
6 changed files with 79 additions and 6 deletions

View File

@@ -42,6 +42,7 @@ END TEMPLATE-->
* CVars defined in `[CVarDefs]` can now be private or internal.
* Added config rollback system to `IConfigurationManager`. This enables CVars to be snapshot and rolled back, even in the event of client crash.
* `OptionButton` now has a `Filterable` property that gives it a text box to filter options.
* Added `FontTagHijackHolder` to replace fonts resolved by `FontTag`.
### Bugfixes

View File

@@ -67,6 +67,7 @@ namespace Robust.Client
deps.Register<IMapManagerInternal, NetworkedMapManager>();
deps.Register<INetworkedMapManager, NetworkedMapManager>();
deps.Register<IEntityManager, ClientEntityManager>();
deps.Register<FontTagHijackHolder>();
deps.Register<IReflectionManager, ClientReflectionManager>();
deps.Register<IConsoleHost, ClientConsoleHost>();
deps.Register<IClientConsoleHost, ClientConsoleHost>();

View File

@@ -266,7 +266,7 @@ namespace Robust.Client.UserInterface.Controls
return _getStyleBox()?.MinimumSize ?? Vector2.Zero;
}
private void _invalidateEntries()
internal void _invalidateEntries()
{
_totalContentHeight = 0;
var font = _getFont();

View File

@@ -1,3 +1,4 @@
using System;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility;
@@ -10,6 +11,7 @@ public sealed partial class FontPrototype : IPrototype
[IdDataField]
public string ID { get; private set; } = default!;
[Obsolete("Font prototype is a bad API.")]
[DataField("path", required: true)]
public ResPath Path { get; private set; } = default!;
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
@@ -40,12 +41,31 @@ public sealed class FontTag : IMarkupTagHandler
/// Creates the a vector font from the supplied font id.<br/>
/// The size of the resulting font will be either the size supplied as a parameter to the tag, the previous font size or 12
/// </summary>
[Obsolete("Stop using font prototypes")]
public static Font CreateFont(
Stack<Font> contextFontStack,
MarkupNode node,
IResourceCache cache,
IPrototypeManager prototypeManager,
string fontId)
{
var size = GetSizeForFontTag(contextFontStack, node);
var hijack = IoCManager.Resolve<FontTagHijackHolder>();
if (hijack.Hijack?.Invoke(fontId, size) is { } overriden)
return overriden;
if (!prototypeManager.TryIndex<FontPrototype>(fontId, out var prototype))
prototype = prototypeManager.Index<FontPrototype>(DefaultFont);
var fontResource = cache.GetResource<FontResource>(prototype.Path);
return new VectorFont(fontResource, size);
}
/// <summary>
/// Get the desired font size for the given markup node.
/// </summary>
public static int GetSizeForFontTag(Stack<Font> contextFontStack, MarkupNode node)
{
var size = DefaultSize;
@@ -68,10 +88,6 @@ public sealed class FontTag : IMarkupTagHandler
if (node.Attributes.TryGetValue("size", out var sizeParameter))
size = (int) (sizeParameter.LongValue ?? size);
if (!prototypeManager.TryIndex<FontPrototype>(fontId, out var prototype))
prototype = prototypeManager.Index<FontPrototype>(DefaultFont);
var fontResource = cache.GetResource<FontResource>(prototype.Path);
return new VectorFont(fontResource, size);
return size;
}
}

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
namespace Robust.Client.UserInterface.RichText;
/// <returns>The font to replace the lookup with. Return null to fall back to default behavior.</returns>
/// <seealso cref="FontTagHijackHolder"/>
public delegate Font? FontTagHijack(ProtoId<FontPrototype> protoId, int size);
/// <summary>
/// Allows replacing font resolution done by <see cref="FontPrototype"/>
/// </summary>
public sealed class FontTagHijackHolder
{
[Dependency] private readonly IUserInterfaceManager _ui = null!;
/// <summary>
/// Called when a font prototype gets resolved.
/// </summary>
public FontTagHijack? Hijack;
/// <summary>
/// Indicate that the results of <see cref="Hijack"/> may have changed,
/// and that engine things relying on it must be updated.
/// </summary>
public void HijackUpdated()
{
// This isn't fool-proof, but it's probably good enough.
// Recursively navigate the UI tree and invalidate rich text controls.
var queue = new Queue<Control>();
foreach (var root in _ui.AllRoots)
{
queue.Enqueue(root);
}
while (queue.TryDequeue(out var control))
{
foreach (var child in control.Children)
{
queue.Enqueue(child);
}
if (control is OutputPanel output)
output._invalidateEntries();
else if (control is RichTextLabel label)
label.InvalidateMeasure();
}
}
}