]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Implement map text (#28705)
authorJulian Giebel <juliangiebel@live.de>
Sun, 9 Jun 2024 19:18:54 +0000 (21:18 +0200)
committerGitHub <noreply@github.com>
Sun, 9 Jun 2024 19:18:54 +0000 (15:18 -0400)
Content.Client/MapText/MapTextComponent.cs [new file with mode: 0644]
Content.Client/MapText/MapTextOverlay.cs [new file with mode: 0644]
Content.Client/MapText/MapTextSystem.cs [new file with mode: 0644]
Content.Server/MapText/MapTextComponent.cs [new file with mode: 0644]
Content.Server/MapText/MapTextSystem.cs [new file with mode: 0644]
Content.Shared/MapText/SharedMapTextComponent.cs [new file with mode: 0644]
Content.Shared/MapText/SharedMapTextSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/mapping/map-text-component.ftl [new file with mode: 0644]
Resources/Prototypes/Entities/Markers/map_text.yml [new file with mode: 0644]

diff --git a/Content.Client/MapText/MapTextComponent.cs b/Content.Client/MapText/MapTextComponent.cs
new file mode 100644 (file)
index 0000000..f70b3c8
--- /dev/null
@@ -0,0 +1,20 @@
+using Content.Shared.MapText;
+using Robust.Client.Graphics;
+
+namespace Content.Client.MapText;
+
+[RegisterComponent]
+public sealed partial class MapTextComponent : SharedMapTextComponent
+{
+    /// <summary>
+    /// The font that gets cached on component init or state changes
+    /// </summary>
+    [ViewVariables]
+    public VectorFont? CachedFont;
+
+    /// <summary>
+    /// The text currently being displayed. This is either <see cref="SharedMapTextComponent.Text"/> or the
+    /// localized text <see cref="SharedMapTextComponent.LocText"/> or
+    /// </summary>
+    public string CachedText = string.Empty;
+}
diff --git a/Content.Client/MapText/MapTextOverlay.cs b/Content.Client/MapText/MapTextOverlay.cs
new file mode 100644 (file)
index 0000000..70e708b
--- /dev/null
@@ -0,0 +1,85 @@
+using System.Numerics;
+using Content.Shared.MapText;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.RichText;
+using Robust.Shared;
+using Robust.Shared.Configuration;
+using Robust.Shared.Enums;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.MapText;
+
+/// <summary>
+/// Draws map text as an overlay
+/// </summary>
+public sealed class MapTextOverlay : Overlay
+{
+    private readonly IConfigurationManager _configManager;
+    private readonly IEntityManager _entManager;
+    private readonly IUserInterfaceManager _uiManager;
+    private readonly SharedTransformSystem _transform;
+    public override OverlaySpace Space => OverlaySpace.ScreenSpace;
+
+    public MapTextOverlay(
+        IConfigurationManager configManager,
+        IEntityManager entManager,
+        IUserInterfaceManager uiManager,
+        SharedTransformSystem transform,
+        IResourceCache resourceCache,
+        IPrototypeManager prototypeManager)
+    {
+        _configManager = configManager;
+        _entManager = entManager;
+        _uiManager = uiManager;
+        _transform = transform;
+    }
+
+    protected override void Draw(in OverlayDrawArgs args)
+    {
+        if (args.ViewportControl == null)
+            return;
+
+        args.DrawingHandle.SetTransform(Matrix3x2.Identity);
+
+        var scale = _configManager.GetCVar(CVars.DisplayUIScale);
+
+        if (scale == 0f)
+            scale = _uiManager.DefaultUIScale;
+
+        DrawWorld(args.ScreenHandle, args, scale);
+
+        args.DrawingHandle.UseShader(null);
+    }
+
+    private void DrawWorld(DrawingHandleScreen handle, OverlayDrawArgs args, float scale)
+    {
+        if ( args.ViewportControl == null)
+            return;
+
+        var matrix = args.ViewportControl.GetWorldToScreenMatrix();
+        var query = _entManager.AllEntityQueryEnumerator<MapTextComponent>();
+
+        // Enlarge bounds to try prevent pop-in due to large text.
+        var bounds = args.WorldBounds.Enlarged(2);
+
+        while(query.MoveNext(out var uid, out var mapText))
+        {
+            var mapPos = _transform.GetMapCoordinates(uid);
+
+            if (mapPos.MapId != args.MapId)
+                continue;
+
+            if (!bounds.Contains(mapPos.Position))
+                continue;
+
+            if (mapText.CachedFont == null)
+                continue;
+
+            var pos = Vector2.Transform(mapPos.Position, matrix) + mapText.Offset;
+            var dimensions = handle.GetDimensions(mapText.CachedFont, mapText.CachedText, scale);
+            handle.DrawString(mapText.CachedFont, pos - dimensions / 2f, mapText.CachedText, scale, mapText.Color);
+        }
+    }
+}
diff --git a/Content.Client/MapText/MapTextSystem.cs b/Content.Client/MapText/MapTextSystem.cs
new file mode 100644 (file)
index 0000000..96ce8f9
--- /dev/null
@@ -0,0 +1,81 @@
+using Content.Shared.MapText;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.RichText;
+using Robust.Shared.Configuration;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Client.MapText;
+
+/// <inheritdoc/>
+public sealed class MapTextSystem : SharedMapTextSystem
+{
+    [Dependency] private readonly IConfigurationManager _configManager = default!;
+    [Dependency] private readonly IUserInterfaceManager _uiManager = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
+    [Dependency] private readonly IResourceCache _resourceCache = default!;
+    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+    [Dependency] private readonly IOverlayManager _overlayManager = default!;
+
+    private MapTextOverlay _overlay = default!;
+
+    /// <inheritdoc/>
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<MapTextComponent, ComponentStartup>(OnComponentStartup);
+        SubscribeLocalEvent<MapTextComponent, ComponentHandleState>(HandleCompState);
+
+        _overlay = new MapTextOverlay(_configManager, EntityManager, _uiManager, _transform, _resourceCache, _prototypeManager);
+        _overlayManager.AddOverlay(_overlay);
+
+        // TODO move font prototype to robust.shared, then use ProtoId<FontPrototype>
+        DebugTools.Assert(_prototypeManager.HasIndex<FontPrototype>(SharedMapTextComponent.DefaultFont));
+    }
+
+    private void OnComponentStartup(Entity<MapTextComponent> ent, ref ComponentStartup args)
+    {
+        CacheText(ent.Comp);
+        // TODO move font prototype to robust.shared, then use ProtoId<FontPrototype>
+        DebugTools.Assert(_prototypeManager.HasIndex<FontPrototype>(ent.Comp.FontId));
+    }
+
+    private void HandleCompState(Entity<MapTextComponent> ent, ref ComponentHandleState args)
+    {
+        if (args.Current is not MapTextComponentState state)
+            return;
+
+        ent.Comp.Text = state.Text;
+        ent.Comp.LocText = state.LocText;
+        ent.Comp.Color = state.Color;
+        ent.Comp.FontId = state.FontId;
+        ent.Comp.FontSize = state.FontSize;
+        ent.Comp.Offset = state.Offset;
+
+        CacheText(ent.Comp);
+    }
+
+    private void CacheText(MapTextComponent component)
+    {
+        component.CachedFont = null;
+
+        component.CachedText = string.IsNullOrWhiteSpace(component.Text)
+            ? Loc.GetString(component.LocText)
+            : component.Text;
+
+        if (!_prototypeManager.TryIndex<FontPrototype>(component.FontId, out var fontPrototype))
+        {
+            component.CachedText = Loc.GetString("map-text-font-error");
+            component.Color = Color.Red;
+
+            if(_prototypeManager.TryIndex<FontPrototype>(SharedMapTextComponent.DefaultFont, out var @default))
+                component.CachedFont = new VectorFont(_resourceCache.GetResource<FontResource>(@default.Path), 14);
+            return;
+        }
+
+        var fontResource = _resourceCache.GetResource<FontResource>(fontPrototype.Path);
+        component.CachedFont = new VectorFont(fontResource, component.FontSize);
+    }
+}
diff --git a/Content.Server/MapText/MapTextComponent.cs b/Content.Server/MapText/MapTextComponent.cs
new file mode 100644 (file)
index 0000000..2af9583
--- /dev/null
@@ -0,0 +1,6 @@
+using Content.Shared.MapText;
+
+namespace Content.Server.MapText;
+
+[RegisterComponent]
+public sealed partial class MapTextComponent : SharedMapTextComponent;
diff --git a/Content.Server/MapText/MapTextSystem.cs b/Content.Server/MapText/MapTextSystem.cs
new file mode 100644 (file)
index 0000000..5632c06
--- /dev/null
@@ -0,0 +1,28 @@
+using Content.Shared.MapText;
+using Robust.Shared.GameStates;
+
+namespace Content.Server.MapText;
+
+/// <inheritdoc/>
+public sealed class MapTextSystem : SharedMapTextSystem
+{
+    /// <inheritdoc/>
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<MapTextComponent, ComponentGetState>(GetCompState);
+    }
+
+    private void GetCompState(Entity<MapTextComponent> ent, ref ComponentGetState args)
+    {
+        args.State = new MapTextComponentState
+        {
+            Text = ent.Comp.Text,
+            LocText = ent.Comp.LocText,
+            Color = ent.Comp.Color,
+            FontId = ent.Comp.FontId,
+            FontSize = ent.Comp.FontSize,
+            Offset = ent.Comp.Offset
+        };
+    }
+}
diff --git a/Content.Shared/MapText/SharedMapTextComponent.cs b/Content.Shared/MapText/SharedMapTextComponent.cs
new file mode 100644 (file)
index 0000000..7b8a02d
--- /dev/null
@@ -0,0 +1,51 @@
+using System.Numerics;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.MapText;
+
+/// <summary>
+/// This is used for displaying text in world space
+/// </summary>
+
+[NetworkedComponent, Access(typeof(SharedMapTextSystem))]
+public abstract partial class SharedMapTextComponent : Component
+{
+    public const string DefaultFont = "Default";
+
+    /// <summary>
+    /// The text to display. This will override <see cref="LocText"/>.
+    /// </summary>
+    [DataField]
+    public string? Text;
+
+    /// <summary>
+    /// The localized-id of the text that should be displayed.
+    /// </summary>
+    [DataField]
+    public LocId LocText = "map-text-default";
+    // TODO VV: LocId editing
+
+    [DataField]
+    public Color Color = Color.White;
+
+    [DataField]
+    public string FontId = DefaultFont;
+
+    [DataField]
+    public int FontSize = 12;
+
+    [DataField]
+    public Vector2 Offset = Vector2.Zero;
+}
+
+[Serializable, NetSerializable]
+public sealed class MapTextComponentState : ComponentState
+{
+    public string? Text { get; init;}
+    public LocId LocText { get; init;}
+    public Color Color { get; init;}
+    public string FontId { get; init; } = default!;
+    public int FontSize { get; init;}
+    public Vector2 Offset { get; init;}
+}
diff --git a/Content.Shared/MapText/SharedMapTextSystem.cs b/Content.Shared/MapText/SharedMapTextSystem.cs
new file mode 100644 (file)
index 0000000..da2adf1
--- /dev/null
@@ -0,0 +1,6 @@
+namespace Content.Shared.MapText;
+
+/// <summary>
+/// This handles registering the map text overlay, caching the text font and handling component state
+/// </summary>
+public abstract class SharedMapTextSystem : EntitySystem;
diff --git a/Resources/Locale/en-US/mapping/map-text-component.ftl b/Resources/Locale/en-US/mapping/map-text-component.ftl
new file mode 100644 (file)
index 0000000..0a4d54b
--- /dev/null
@@ -0,0 +1,2 @@
+map-text-default = Use VV to change the displayed text
+map-text-font-error = "Error - invalid font"
diff --git a/Resources/Prototypes/Entities/Markers/map_text.yml b/Resources/Prototypes/Entities/Markers/map_text.yml
new file mode 100644 (file)
index 0000000..e849613
--- /dev/null
@@ -0,0 +1,11 @@
+- type: entity
+  id: MapText
+  parent: MarkerBase
+  name: map text
+  placement:
+    mode: PlaceFree
+  components:
+  - type: MapText
+  - type: Sprite
+    state: pink
+