Add navmap beacons (#19388)

This commit is contained in:
metalgearsloth
2023-09-16 18:11:47 +10:00
committed by GitHub
parent a0170dc613
commit e08b0954e5
7 changed files with 261 additions and 33 deletions

View File

@@ -29,6 +29,9 @@ public sealed class NavMapSystem : SharedNavMapSystem
TileData = data, TileData = data,
}); });
} }
component.Beacons.Clear();
component.Beacons.AddRange(state.Beacons);
} }
} }

View File

@@ -2,7 +2,9 @@ using System.Numerics;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Content.Shared.Pinpointer; using Content.Shared.Pinpointer;
using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input; using Robust.Shared.Input;
@@ -20,18 +22,19 @@ namespace Content.Client.Pinpointer.UI;
public sealed class NavMapControl : MapGridControl public sealed class NavMapControl : MapGridControl
{ {
[Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IEntityManager _entManager = default!;
private SharedTransformSystem _transform;
public EntityUid? MapUid; public EntityUid? MapUid;
public Dictionary<EntityCoordinates, (bool Visible, Color Color)> TrackedCoordinates = new(); public Dictionary<EntityCoordinates, (bool Visible, Color Color)> TrackedCoordinates = new();
private Vector2 _offset; private Vector2 _offset;
private bool _draggin; private bool _draggin;
private bool _recentering = false; private bool _recentering = false;
private readonly float _recenterMinimum = 0.05f;
private float _recenterMinimum = 0.05f; private readonly Font _font;
private static readonly Color TileColor = new(30, 67, 30);
private static readonly Color BeaconColor = Color.FromSrgb(TileColor.WithAlpha(0.8f));
// TODO: https://github.com/space-wizards/RobustToolbox/issues/3818 // TODO: https://github.com/space-wizards/RobustToolbox/issues/3818
private readonly Label _zoom = new() private readonly Label _zoom = new()
@@ -52,6 +55,11 @@ public sealed class NavMapControl : MapGridControl
public NavMapControl() : base(8f, 128f, 48f) public NavMapControl() : base(8f, 128f, 48f)
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_transform = _entManager.System<SharedTransformSystem>();
var cache = IoCManager.Resolve<IResourceCache>();
_font = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 16);
RectClipContent = true; RectClipContent = true;
HorizontalExpand = true; HorizontalExpand = true;
VerticalExpand = true; VerticalExpand = true;
@@ -175,7 +183,6 @@ public sealed class NavMapControl : MapGridControl
} }
var offset = _offset; var offset = _offset;
var tileColor = new Color(30, 67, 30);
var lineColor = new Color(102, 217, 102); var lineColor = new Color(102, 217, 102);
if (_entManager.TryGetComponent<PhysicsComponent>(MapUid, out var physics)) if (_entManager.TryGetComponent<PhysicsComponent>(MapUid, out var physics))
@@ -200,7 +207,7 @@ public sealed class NavMapControl : MapGridControl
verts[i] = Scale(new Vector2(vert.X, -vert.Y)); verts[i] = Scale(new Vector2(vert.X, -vert.Y));
} }
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts[..poly.VertexCount], tileColor); handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts[..poly.VertexCount], TileColor);
} }
} }
@@ -333,6 +340,24 @@ public sealed class NavMapControl : MapGridControl
} }
} }
} }
// Beacons
var labelOffset = new Vector2(0.5f, 0.5f) * MinimapScale;
var rectBuffer = new Vector2(5f, 3f);
foreach (var beacon in navMap.Beacons)
{
var position = beacon.Position - offset;
position = Scale(position with { Y = -position.Y });
handle.DrawCircle(position, MinimapScale / 2f, beacon.Color);
var textDimensions = handle.GetDimensions(_font, beacon.Text, 1f);
var labelPosition = position + labelOffset;
handle.DrawRect(new UIBox2(labelPosition, labelPosition + textDimensions + rectBuffer * 2), BeaconColor);
handle.DrawString(_font, labelPosition + rectBuffer, beacon.Text, beacon.Color);
}
} }
private Vector2 Scale(Vector2 position) private Vector2 Scale(Vector2 position)

View File

@@ -1,5 +1,6 @@
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
using Content.Server.Warps;
using Content.Shared.Pinpointer; using Content.Shared.Pinpointer;
using Content.Shared.Tag; using Content.Shared.Tag;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
@@ -16,40 +17,87 @@ public sealed class NavMapSystem : SharedNavMapSystem
{ {
[Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly TagSystem _tags = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TagComponent> _tagQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_tagQuery = GetEntityQuery<TagComponent>();
SubscribeLocalEvent<AnchorStateChangedEvent>(OnAnchorChange); SubscribeLocalEvent<AnchorStateChangedEvent>(OnAnchorChange);
SubscribeLocalEvent<ReAnchorEvent>(OnReAnchor); SubscribeLocalEvent<ReAnchorEvent>(OnReAnchor);
SubscribeLocalEvent<StationGridAddedEvent>(OnStationInit);
SubscribeLocalEvent<NavMapComponent, ComponentStartup>(OnNavMapStartup);
SubscribeLocalEvent<NavMapComponent, ComponentGetState>(OnGetState); SubscribeLocalEvent<NavMapComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<NavMapComponent, GridSplitEvent>(OnNavMapSplit); SubscribeLocalEvent<NavMapComponent, GridSplitEvent>(OnNavMapSplit);
SubscribeLocalEvent<StationGridAddedEvent>(OnStationInit);
SubscribeLocalEvent<NavMapBeaconComponent, ComponentStartup>(OnNavMapBeaconStartup);
SubscribeLocalEvent<NavMapBeaconComponent, AnchorStateChangedEvent>(OnNavMapBeaconAnchor);
} }
private void OnStationInit(StationGridAddedEvent ev) private void OnStationInit(StationGridAddedEvent ev)
{ {
var comp = EnsureComp<NavMapComponent>(ev.GridId); var comp = EnsureComp<NavMapComponent>(ev.GridId);
var physicsQuery = GetEntityQuery<PhysicsComponent>(); RefreshGrid(comp, Comp<MapGridComponent>(ev.GridId));
var tagQuery = GetEntityQuery<TagComponent>(); }
RefreshGrid(comp, Comp<MapGridComponent>(ev.GridId), physicsQuery, tagQuery);
private void OnNavMapBeaconStartup(EntityUid uid, NavMapBeaconComponent component, ComponentStartup args)
{
RefreshNavGrid(uid);
}
private void OnNavMapBeaconAnchor(EntityUid uid, NavMapBeaconComponent component, ref AnchorStateChangedEvent args)
{
RefreshNavGrid(uid);
}
/// <summary>
/// Refreshes the grid for the corresponding beacon.
/// </summary>
/// <param name="uid"></param>
private void RefreshNavGrid(EntityUid uid)
{
var xform = Transform(uid);
if (!CanBeacon(uid, xform) || !TryComp<NavMapComponent>(xform.GridUid, out var navMap))
return;
Dirty(xform.GridUid.Value, navMap);
}
private bool CanBeacon(EntityUid uid, TransformComponent? xform = null)
{
if (!Resolve(uid, ref xform))
return false;
return xform.GridUid != null && xform.Anchored;
}
private void OnNavMapStartup(EntityUid uid, NavMapComponent component, ComponentStartup args)
{
if (!TryComp<MapGridComponent>(uid, out var grid))
return;
RefreshGrid(component, grid);
} }
private void OnNavMapSplit(EntityUid uid, NavMapComponent component, ref GridSplitEvent args) private void OnNavMapSplit(EntityUid uid, NavMapComponent component, ref GridSplitEvent args)
{ {
var physicsQuery = GetEntityQuery<PhysicsComponent>();
var tagQuery = GetEntityQuery<TagComponent>();
var gridQuery = GetEntityQuery<MapGridComponent>(); var gridQuery = GetEntityQuery<MapGridComponent>();
foreach (var grid in args.NewGrids) foreach (var grid in args.NewGrids)
{ {
var newComp = EnsureComp<NavMapComponent>(grid); var newComp = EnsureComp<NavMapComponent>(grid);
RefreshGrid(newComp, gridQuery.GetComponent(grid), physicsQuery, tagQuery); RefreshGrid(newComp, gridQuery.GetComponent(grid));
} }
RefreshGrid(component, gridQuery.GetComponent(uid), physicsQuery, tagQuery); RefreshGrid(component, gridQuery.GetComponent(uid));
} }
private void RefreshGrid(NavMapComponent component, MapGridComponent grid, EntityQuery<PhysicsComponent> physicsQuery, EntityQuery<TagComponent> tagQuery) private void RefreshGrid(NavMapComponent component, MapGridComponent grid)
{ {
component.Chunks.Clear(); component.Chunks.Clear();
@@ -65,7 +113,7 @@ public sealed class NavMapSystem : SharedNavMapSystem
component.Chunks[chunkOrigin] = chunk; component.Chunks[chunkOrigin] = chunk;
} }
RefreshTile(grid, component, chunk, tile.Value.GridIndices, physicsQuery, tagQuery); RefreshTile(grid, component, chunk, tile.Value.GridIndices);
} }
} }
@@ -77,10 +125,37 @@ public sealed class NavMapSystem : SharedNavMapSystem
data.Add(index, chunk.TileData); data.Add(index, chunk.TileData);
} }
var beaconQuery = AllEntityQuery<NavMapBeaconComponent, TransformComponent>();
var beacons = new List<NavMapBeacon>();
while (beaconQuery.MoveNext(out var beaconUid, out var beacon, out var xform))
{
if (xform.GridUid != uid || !CanBeacon(beaconUid, xform))
continue;
// TODO: Make warp points use metadata name instead.
string? name = beacon.Text;
if (name == null)
{
if (TryComp<WarpPointComponent>(beaconUid, out var warpPoint) && warpPoint.Location != null)
{
name = warpPoint.Location;
}
else
{
name = MetaData(beaconUid).EntityName;
}
}
beacons.Add(new NavMapBeacon(beacon.Color, name, xform.LocalPosition));
}
// TODO: Diffs // TODO: Diffs
args.State = new NavMapComponentState() args.State = new NavMapComponentState()
{ {
TileData = data, TileData = data,
Beacons = beacons,
}; };
} }
@@ -93,9 +168,7 @@ public sealed class NavMapSystem : SharedNavMapSystem
if (navMap.Chunks.TryGetValue(chunkOrigin, out var chunk)) if (navMap.Chunks.TryGetValue(chunkOrigin, out var chunk))
{ {
var physicsQuery = GetEntityQuery<PhysicsComponent>(); RefreshTile(oldGrid, navMap, chunk, ev.TilePos);
var tagQuery = GetEntityQuery<TagComponent>();
RefreshTile(oldGrid, navMap, chunk, ev.TilePos, physicsQuery, tagQuery);
} }
} }
@@ -115,8 +188,6 @@ public sealed class NavMapSystem : SharedNavMapSystem
var tile = grid.LocalToTile(xform.Coordinates); var tile = grid.LocalToTile(xform.Coordinates);
var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize); var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize);
var physicsQuery = GetEntityQuery<PhysicsComponent>();
var tagQuery = GetEntityQuery<TagComponent>();
if (!navMap.Chunks.TryGetValue(chunkOrigin, out var chunk)) if (!navMap.Chunks.TryGetValue(chunkOrigin, out var chunk))
{ {
@@ -124,12 +195,10 @@ public sealed class NavMapSystem : SharedNavMapSystem
navMap.Chunks[chunkOrigin] = chunk; navMap.Chunks[chunkOrigin] = chunk;
} }
RefreshTile(grid, navMap, chunk, tile, physicsQuery, tagQuery); RefreshTile(grid, navMap, chunk, tile);
} }
private void RefreshTile(MapGridComponent grid, NavMapComponent component, NavMapChunk chunk, Vector2i tile, private void RefreshTile(MapGridComponent grid, NavMapComponent component, NavMapChunk chunk, Vector2i tile)
EntityQuery<PhysicsComponent> physicsQuery,
EntityQuery<TagComponent> tagQuery)
{ {
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize); var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
@@ -143,12 +212,12 @@ public sealed class NavMapSystem : SharedNavMapSystem
while (enumerator.MoveNext(out var ent)) while (enumerator.MoveNext(out var ent))
{ {
if (!physicsQuery.TryGetComponent(ent, out var body) || if (!_physicsQuery.TryGetComponent(ent, out var body) ||
!body.CanCollide || !body.CanCollide ||
!body.Hard || !body.Hard ||
body.BodyType != BodyType.Static || body.BodyType != BodyType.Static ||
(!_tags.HasTag(ent.Value, "Wall", tagQuery) && (!_tags.HasTag(ent.Value, "Wall", _tagQuery) &&
!_tags.HasTag(ent.Value, "Window", tagQuery))) !_tags.HasTag(ent.Value, "Window", _tagQuery)))
{ {
continue; continue;
} }

View File

@@ -0,0 +1,19 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Pinpointer;
/// <summary>
/// Will show a marker on a NavMap.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class NavMapBeaconComponent : Component
{
/// <summary>
/// Defaults to entity name if nothing found.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("text"), AutoNetworkedField]
public string? Text;
[ViewVariables(VVAccess.ReadWrite), DataField("color"), AutoNetworkedField]
public Color Color = Color.Orange;
}

View File

@@ -9,8 +9,14 @@ namespace Content.Shared.Pinpointer;
[RegisterComponent, NetworkedComponent] [RegisterComponent, NetworkedComponent]
public sealed partial class NavMapComponent : Component public sealed partial class NavMapComponent : Component
{ {
/*
* Don't need DataFields as this can be reconstructed
*/
[ViewVariables] [ViewVariables]
public readonly Dictionary<Vector2i, NavMapChunk> Chunks = new(); public readonly Dictionary<Vector2i, NavMapChunk> Chunks = new();
[ViewVariables] public readonly List<SharedNavMapSystem.NavMapBeacon> Beacons = new();
} }
public sealed class NavMapChunk public sealed class NavMapChunk

View File

@@ -1,3 +1,4 @@
using System.Numerics;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -34,12 +35,10 @@ public abstract class SharedNavMapSystem : EntitySystem
protected sealed class NavMapComponentState : ComponentState protected sealed class NavMapComponentState : ComponentState
{ {
public Dictionary<Vector2i, int> TileData = new(); public Dictionary<Vector2i, int> TileData = new();
public List<NavMapBeacon> Beacons = new();
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]
protected sealed class NavMapDiffComponentState : ComponentState public readonly record struct NavMapBeacon(Color Color, string Text, Vector2 Position);
{
public Dictionary<Vector2i, int> TileData = new();
public List<Vector2i> RemovedChunks = new();
}
} }

View File

@@ -7,6 +7,16 @@
- type: Sprite - type: Sprite
state: pink state: pink
- type: entity
id: WarpPointBeacon
parent: MarkerBase
name: warp point (beacon)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
- type: entity - type: entity
parent: WarpPoint parent: WarpPoint
id: WarpPointBombing id: WarpPointBombing
@@ -19,3 +29,100 @@
- state: pink - state: pink
- sprite: Objects/Weapons/Bombs/spidercharge.rsi - sprite: Objects/Weapons/Bombs/spidercharge.rsi
state: icon state: icon
# Departments
- type: entity
id: WarpPointBeaconBar
parent: MarkerBase
name: warp point (bar)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: bar
color: "#791500"
- type: entity
id: WarpPointBeaconCargo
parent: MarkerBase
name: warp point (cargo)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: cargo
color: "#A46106"
- type: entity
id: WarpPointBeaconCommand
parent: MarkerBase
name: warp point (command)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: command
color: "#334E6D"
- type: entity
id: WarpPointBeaconEngineering
parent: MarkerBase
name: warp point (engineering)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: engineering
color: "#EFB341"
- type: entity
id: WarpPointBeaconMedical
parent: MarkerBase
name: warp point (medical)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: medical
color: "#52B4E9"
- type: entity
id: WarpPointBeaconNeutral
parent: MarkerBase
name: warp point (neutral)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: neutral
color: "#D4D4D4"
- type: entity
id: WarpPointBeaconScience
parent: MarkerBase
name: warp point (science)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: science
color: "#D381C9"
- type: entity
id: WarpPointBeaconService
parent: MarkerBase
name: warp point (service)
components:
- type: WarpPoint
- type: Sprite
state: pink
- type: NavMapBeacon
text: service
color: "#9FED58"