Implement map text (#28705)

This commit is contained in:
Julian Giebel
2024-06-09 21:18:54 +02:00
committed by GitHub
parent 3ceb92a0c4
commit de07c291de
9 changed files with 290 additions and 0 deletions

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,6 @@
using Content.Shared.MapText;
namespace Content.Server.MapText;
[RegisterComponent]
public sealed partial class MapTextComponent : SharedMapTextComponent;

View File

@@ -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
};
}
}

View File

@@ -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;}
}

View File

@@ -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;

View File

@@ -0,0 +1,2 @@
map-text-default = Use VV to change the displayed text
map-text-font-error = "Error - invalid font"

View File

@@ -0,0 +1,11 @@
- type: entity
id: MapText
parent: MarkerBase
name: map text
placement:
mode: PlaceFree
components:
- type: MapText
- type: Sprite
state: pink