Add docking window to shuttle consoles (#8756)
* lewd * A * Realtime * Sleepy dork * Draw radar position * Accurate infiltrator * experiments * Better drawing * Labels * I need aan adult * Cleanup * Show toggles * display I guess * A * fix * fix * cleanupsies * Bit more polish * Make sure mass scanners actually work * Remove dummy state * fren * opposite * aghost crash * comment * What's in a name * woops * Show docking ports * Dock highlighting * Drawing dock * Shitty docks * Lots of docking drawing * Autodock working * dork * More graceful shutdown * zoomies * Lines and distance change * revert * Good enough * cleanup * Fix default range * Dock UI and loc update * Update on undock * Loc fixes
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:radar="clr-namespace:Content.Client.Radar"
|
||||
Title="{Loc 'radar-window-title'}"
|
||||
Resizable="False">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<radar:RadarControl Name="Radar"/>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
@@ -1,116 +0,0 @@
|
||||
using System;
|
||||
using Content.Client.Computer;
|
||||
using Content.Shared.Radar;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.Radar;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RadarConsoleWindow : DefaultWindow, IComputerWindow<RadarConsoleBoundInterfaceState>
|
||||
{
|
||||
public RadarConsoleWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void SetupComputerWindow(ComputerBoundUserInterfaceBase cb)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void UpdateState(RadarConsoleBoundInterfaceState scc)
|
||||
{
|
||||
Radar.UpdateState(scc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public sealed class RadarControl : Control
|
||||
{
|
||||
private const int MinimapRadius = 256;
|
||||
private const int MinimapMargin = 4;
|
||||
private const float GridLinesDistance = 32f;
|
||||
|
||||
private float _radarRange = 256f;
|
||||
private RadarConsoleBoundInterfaceState _lastState = new(256f, Array.Empty<RadarObjectData>());
|
||||
|
||||
private int SizeFull => (int) ((MinimapRadius + MinimapMargin) * 2 * UIScale);
|
||||
private int ScaledMinimapRadius => (int) (MinimapRadius * UIScale);
|
||||
private float MinimapScale => _radarRange != 0 ? ScaledMinimapRadius / _radarRange : 0f;
|
||||
|
||||
public RadarControl()
|
||||
{
|
||||
MinSize = (SizeFull, SizeFull);
|
||||
}
|
||||
|
||||
public void UpdateState(RadarConsoleBoundInterfaceState ls)
|
||||
{
|
||||
if (!_radarRange.Equals(ls.Range))
|
||||
{
|
||||
_radarRange = ls.Range;
|
||||
}
|
||||
|
||||
_lastState = ls;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
var point = SizeFull / 2;
|
||||
var fakeAA = new Color(0.08f, 0.08f, 0.08f);
|
||||
var gridLines = new Color(0.08f, 0.08f, 0.08f);
|
||||
var gridLinesRadial = 8;
|
||||
var gridLinesEquatorial = (int) Math.Floor(_radarRange / GridLinesDistance);
|
||||
|
||||
handle.DrawCircle((point, point), ScaledMinimapRadius + 1, fakeAA);
|
||||
handle.DrawCircle((point, point), ScaledMinimapRadius, Color.Black);
|
||||
|
||||
for (var i = 1; i < gridLinesEquatorial + 1; i++)
|
||||
{
|
||||
handle.DrawCircle((point, point), GridLinesDistance * MinimapScale * i, gridLines, false);
|
||||
}
|
||||
|
||||
for (var i = 0; i < gridLinesRadial; i++)
|
||||
{
|
||||
Angle angle = (Math.PI / gridLinesRadial) * i;
|
||||
var aExtent = angle.ToVec() * ScaledMinimapRadius;
|
||||
handle.DrawLine((point, point) - aExtent, (point, point) + aExtent, gridLines);
|
||||
}
|
||||
|
||||
handle.DrawLine((point, point) + new Vector2(8, 8), (point, point) - new Vector2(0, 8), Color.Yellow);
|
||||
handle.DrawLine((point, point) + new Vector2(-8, 8), (point, point) - new Vector2(0, 8), Color.Yellow);
|
||||
|
||||
foreach (var obj in _lastState.Objects)
|
||||
{
|
||||
var minimapPos = obj.Position * MinimapScale;
|
||||
var radius = obj.Radius * MinimapScale;
|
||||
|
||||
if (minimapPos.Length + radius > ScaledMinimapRadius)
|
||||
continue;
|
||||
|
||||
switch (obj.Shape)
|
||||
{
|
||||
case RadarObjectShape.CircleFilled:
|
||||
case RadarObjectShape.Circle:
|
||||
{
|
||||
handle.DrawCircle(minimapPos + point, radius, obj.Color, obj.Shape == RadarObjectShape.CircleFilled);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class RadarConsoleBoundUserInterface : ComputerBoundUserInterface<RadarConsoleWindow, RadarConsoleBoundInterfaceState>
|
||||
{
|
||||
public RadarConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) {}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Content.Client.Shuttles.UI;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Shuttles.BUI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class RadarConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private RadarConsoleWindow? _window;
|
||||
|
||||
public RadarConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) {}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_window = new RadarConsoleWindow();
|
||||
_window?.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (state is not RadarConsoleBoundInterfaceState cState) return;
|
||||
|
||||
_window?.UpdateState(cState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using Content.Client.Shuttles.UI;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Shuttles.BUI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class ShuttleConsoleBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private ShuttleConsoleWindow? _window;
|
||||
|
||||
public ShuttleConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) {}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_window = new ShuttleConsoleWindow();
|
||||
_window.ShuttleModePressed += OnShuttleModePressed;
|
||||
_window.UndockPressed += OnUndockPressed;
|
||||
_window.StartAutodockPressed += OnAutodockPressed;
|
||||
_window.StopAutodockPressed += OnStopAutodockPressed;
|
||||
_window.OpenCentered();
|
||||
_window.OnClose += OnClose;
|
||||
}
|
||||
|
||||
private void OnClose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStopAutodockPressed(EntityUid obj)
|
||||
{
|
||||
SendMessage(new StopAutodockRequestMessage() {Entity = obj});
|
||||
}
|
||||
|
||||
private void OnAutodockPressed(EntityUid obj)
|
||||
{
|
||||
SendMessage(new AutodockRequestMessage() {Entity = obj});
|
||||
}
|
||||
|
||||
private void OnUndockPressed(EntityUid obj)
|
||||
{
|
||||
SendMessage(new UndockRequestMessage() {Entity = obj});
|
||||
}
|
||||
|
||||
private void OnShuttleModePressed(ShuttleMode obj)
|
||||
{
|
||||
SendMessage(new ShuttleModeRequestMessage() {Mode = obj});
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (state is not ShuttleConsoleBoundInterfaceState cState) return;
|
||||
_window?.UpdateState(cState);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,7 @@
|
||||
using Content.Shared.Shuttles;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.Shuttles
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedShuttleConsoleComponent))]
|
||||
internal sealed class ShuttleConsoleComponent : SharedShuttleConsoleComponent
|
||||
{
|
||||
|
||||
}
|
||||
public sealed class ShuttleConsoleComponent : SharedShuttleConsoleComponent {}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Content.Shared.Shuttles;
|
||||
|
||||
namespace Content.Client.Shuttles
|
||||
{
|
||||
internal sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
21
Content.Client/Shuttles/Systems/DockingSystem.cs
Normal file
21
Content.Client/Shuttles/Systems/DockingSystem.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Content.Shared.Shuttles.Events;
|
||||
|
||||
namespace Content.Client.Shuttles.Systems;
|
||||
|
||||
public sealed class DockingSystem : EntitySystem
|
||||
{
|
||||
public void StartAutodock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new AutodockRequestMessage {Entity = uid});
|
||||
}
|
||||
|
||||
public void StopAutodock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new StopAutodockRequestMessage() {Entity = uid});
|
||||
}
|
||||
|
||||
public void Undock(EntityUid uid)
|
||||
{
|
||||
RaiseNetworkEvent(new UndockRequestMessage() {Entity = uid});
|
||||
}
|
||||
}
|
||||
8
Content.Client/Shuttles/Systems/RadarConsoleSystem.cs
Normal file
8
Content.Client/Shuttles/Systems/RadarConsoleSystem.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
|
||||
namespace Content.Client.Shuttles.Systems;
|
||||
|
||||
public sealed class RadarConsoleSystem : SharedRadarConsoleSystem
|
||||
{
|
||||
|
||||
}
|
||||
37
Content.Client/Shuttles/Systems/ShuttleConsoleSystem.cs
Normal file
37
Content.Client/Shuttles/Systems/ShuttleConsoleSystem.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.Shuttles.Systems
|
||||
{
|
||||
public sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<PilotComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, PilotComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not PilotComponentState state) return;
|
||||
|
||||
var console = state.Console.GetValueOrDefault();
|
||||
if (!console.IsValid())
|
||||
{
|
||||
component.Console = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<ShuttleConsoleComponent>(console, out var shuttleConsoleComponent))
|
||||
{
|
||||
Logger.Warning($"Unable to set Helmsman console to {console}");
|
||||
return;
|
||||
}
|
||||
|
||||
component.Console = shuttleConsoleComponent;
|
||||
ActionBlockerSystem.UpdateCanMove(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
251
Content.Client/Shuttles/UI/DockingControl.cs
Normal file
251
Content.Client/Shuttles/UI/DockingControl.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision.Shapes;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Displays the docking view from a specific docking port
|
||||
/// </summary>
|
||||
[Virtual]
|
||||
public class DockingControl : Control
|
||||
{
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IMapManager _mapManager;
|
||||
|
||||
private const int MinimapRadius = 384;
|
||||
private const int MinimapMargin = 4;
|
||||
|
||||
private float _range = 8f;
|
||||
private float _rangeSquared = 0f;
|
||||
private const float GridLinesDistance = 32f;
|
||||
|
||||
private int MidPoint => SizeFull / 2;
|
||||
private int SizeFull => (int) ((MinimapRadius + MinimapMargin) * 2 * UIScale);
|
||||
private int ScaledMinimapRadius => (int) (MinimapRadius * UIScale);
|
||||
private float MinimapScale => _range != 0 ? ScaledMinimapRadius / _range : 0f;
|
||||
|
||||
public EntityUid? ViewedDock;
|
||||
public EntityUid? GridEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Stored by GridID then by docks
|
||||
/// </summary>
|
||||
public Dictionary<EntityUid, List<DockingInterfaceState>> Docks = new();
|
||||
|
||||
public DockingControl()
|
||||
{
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
_mapManager = IoCManager.Resolve<IMapManager>();
|
||||
_rangeSquared = _range * _range;
|
||||
MinSize = (SizeFull, SizeFull);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
var fakeAA = new Color(0.08f, 0.08f, 0.08f);
|
||||
|
||||
handle.DrawCircle((MidPoint, MidPoint), ScaledMinimapRadius + 1, fakeAA);
|
||||
handle.DrawCircle((MidPoint, MidPoint), ScaledMinimapRadius, Color.Black);
|
||||
|
||||
var gridLines = new Color(0.08f, 0.08f, 0.08f);
|
||||
var gridLinesRadial = 8;
|
||||
var gridLinesEquatorial = (int) Math.Floor(_range / GridLinesDistance);
|
||||
|
||||
for (var i = 1; i < gridLinesEquatorial + 1; i++)
|
||||
{
|
||||
handle.DrawCircle((MidPoint, MidPoint), GridLinesDistance * MinimapScale * i, gridLines, false);
|
||||
}
|
||||
|
||||
for (var i = 0; i < gridLinesRadial; i++)
|
||||
{
|
||||
Angle angle = (Math.PI / gridLinesRadial) * i;
|
||||
var aExtent = angle.ToVec() * ScaledMinimapRadius;
|
||||
handle.DrawLine((MidPoint, MidPoint) - aExtent, (MidPoint, MidPoint) + aExtent, gridLines);
|
||||
}
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(ViewedDock, out var xform) ||
|
||||
!_entManager.TryGetComponent<TransformComponent>(GridEntity, out var gridXform)) return;
|
||||
|
||||
var rotation = Matrix3.CreateRotation(xform.LocalRotation);
|
||||
var matrix = Matrix3.CreateTranslation(-xform.LocalPosition);
|
||||
|
||||
// Draw the fixtures around the dock before drawing it
|
||||
if (_entManager.TryGetComponent<FixturesComponent>(GridEntity, out var fixtures))
|
||||
{
|
||||
foreach (var (_, fixture) in fixtures.Fixtures)
|
||||
{
|
||||
var poly = (PolygonShape) fixture.Shape;
|
||||
|
||||
for (var i = 0; i < poly.VertexCount; i++)
|
||||
{
|
||||
var start = matrix.Transform(poly.Vertices[i]);
|
||||
var end = matrix.Transform(poly.Vertices[(i + 1) % poly.VertexCount]);
|
||||
|
||||
var startOut = start.LengthSquared > _rangeSquared;
|
||||
var endOut = end.LengthSquared > _rangeSquared;
|
||||
|
||||
// We need to draw to the radar border so we'll cap the range,
|
||||
// but if none of the verts are in range then just leave it.
|
||||
if (startOut && endOut)
|
||||
continue;
|
||||
|
||||
start.Y = -start.Y;
|
||||
end.Y = -end.Y;
|
||||
|
||||
// If start is outside we draw capped from end to start
|
||||
if (startOut)
|
||||
{
|
||||
// It's called Jobseeker now.
|
||||
if (!MathHelper.TryGetIntersecting(start, end, _range, out var newStart)) continue;
|
||||
start = newStart.Value;
|
||||
}
|
||||
// otherwise vice versa
|
||||
else if (endOut)
|
||||
{
|
||||
if (!MathHelper.TryGetIntersecting(end, start, _range, out var newEnd)) continue;
|
||||
end = newEnd.Value;
|
||||
}
|
||||
|
||||
handle.DrawLine(ScalePosition(start), ScalePosition(end), Color.Goldenrod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the dock's collision
|
||||
handle.DrawRect(new UIBox2(
|
||||
ScalePosition(rotation.Transform(new Vector2(-0.2f, -0.7f))),
|
||||
ScalePosition(rotation.Transform(new Vector2(0.2f, -0.5f)))), Color.Aquamarine);
|
||||
|
||||
// Draw the dock itself
|
||||
handle.DrawRect(new UIBox2(
|
||||
ScalePosition(rotation.Transform(new Vector2(-0.5f, 0.5f))),
|
||||
ScalePosition(rotation.Transform(new Vector2(0.5f, -0.5f)))), Color.Green);
|
||||
|
||||
// Draw nearby grids
|
||||
var worldPos = gridXform.WorldMatrix.Transform(xform.LocalPosition);
|
||||
var gridInvMatrix = gridXform.InvWorldMatrix;
|
||||
Matrix3.Multiply(in gridInvMatrix, in matrix, out var invMatrix);
|
||||
|
||||
// TODO: Getting some overdraw so need to fix that.
|
||||
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(gridXform.MapID,
|
||||
new Box2(worldPos - _range, worldPos + _range)))
|
||||
{
|
||||
if (grid.GridEntityId == GridEntity) continue;
|
||||
|
||||
// Draw the fixtures before drawing any docks in range.
|
||||
if (!_entManager.TryGetComponent<FixturesComponent>(grid.GridEntityId, out var gridFixtures)) continue;
|
||||
|
||||
var gridMatrix = grid.WorldMatrix;
|
||||
|
||||
Matrix3.Multiply(in gridMatrix, in invMatrix, out var matty);
|
||||
|
||||
foreach (var (_, fixture) in gridFixtures.Fixtures)
|
||||
{
|
||||
var poly = (PolygonShape) fixture.Shape;
|
||||
|
||||
for (var i = 0; i < poly.VertexCount; i++)
|
||||
{
|
||||
// This is because the same line might be on different fixtures so we don't want to draw it twice.
|
||||
var startPos = poly.Vertices[i];
|
||||
var endPos = poly.Vertices[(i + 1) % poly.VertexCount];
|
||||
|
||||
var start = matty.Transform(startPos);
|
||||
var end = matty.Transform(endPos);
|
||||
|
||||
var startOut = start.LengthSquared > _rangeSquared;
|
||||
var endOut = end.LengthSquared > _rangeSquared;
|
||||
|
||||
// We need to draw to the radar border so we'll cap the range,
|
||||
// but if none of the verts are in range then just leave it.
|
||||
if (startOut && endOut)
|
||||
continue;
|
||||
|
||||
start.Y = -start.Y;
|
||||
end.Y = -end.Y;
|
||||
|
||||
// If start is outside we draw capped from end to start
|
||||
if (startOut)
|
||||
{
|
||||
// It's called Jobseeker now.
|
||||
if (!MathHelper.TryGetIntersecting(start, end, _range, out var newStart)) continue;
|
||||
start = newStart.Value;
|
||||
}
|
||||
// otherwise vice versa
|
||||
else if (endOut)
|
||||
{
|
||||
if (!MathHelper.TryGetIntersecting(end, start, _range, out var newEnd)) continue;
|
||||
end = newEnd.Value;
|
||||
}
|
||||
|
||||
handle.DrawLine(ScalePosition(start), ScalePosition(end), Color.Aquamarine);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw any docks on that grid
|
||||
if (Docks.TryGetValue(grid.GridEntityId, out var gridDocks))
|
||||
{
|
||||
foreach (var dock in gridDocks)
|
||||
{
|
||||
var position = matty.Transform(dock.Coordinates.Position);
|
||||
|
||||
if (position.Length > _range - 0.8f) continue;
|
||||
|
||||
var otherDockRotation = Matrix3.CreateRotation(dock.Angle);
|
||||
|
||||
// Draw the dock's collision
|
||||
var verts = new[]
|
||||
{
|
||||
matty.Transform(dock.Coordinates.Position +
|
||||
otherDockRotation.Transform(new Vector2(-0.2f, -0.7f))),
|
||||
matty.Transform(dock.Coordinates.Position +
|
||||
otherDockRotation.Transform(new Vector2(0.2f, -0.7f))),
|
||||
matty.Transform(dock.Coordinates.Position +
|
||||
otherDockRotation.Transform(new Vector2(0.2f, -0.5f))),
|
||||
matty.Transform(dock.Coordinates.Position +
|
||||
otherDockRotation.Transform(new Vector2(-0.2f, -0.5f))),
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, Color.Turquoise);
|
||||
|
||||
// Draw the dock itself
|
||||
verts = new[]
|
||||
{
|
||||
matty.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f)),
|
||||
matty.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f)),
|
||||
matty.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f)),
|
||||
matty.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f)),
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, Color.Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Vector2 ScalePosition(Vector2 value)
|
||||
{
|
||||
return value * MinimapScale + MidPoint;
|
||||
}
|
||||
}
|
||||
6
Content.Client/Shuttles/UI/RadarConsoleWindow.xaml
Normal file
6
Content.Client/Shuttles/UI/RadarConsoleWindow.xaml
Normal file
@@ -0,0 +1,6 @@
|
||||
<userInterface:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:userInterface="clr-namespace:Content.Client.UserInterface"
|
||||
xmlns:ui="clr-namespace:Content.Client.Shuttles.UI"
|
||||
Title="{Loc 'radar-console-window-title'}">
|
||||
<ui:RadarControl Name="RadarScreen"/>
|
||||
</userInterface:FancyWindow>
|
||||
22
Content.Client/Shuttles/UI/RadarConsoleWindow.xaml.cs
Normal file
22
Content.Client/Shuttles/UI/RadarConsoleWindow.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Content.Client.Computer;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RadarConsoleWindow : FancyWindow,
|
||||
IComputerWindow<RadarConsoleBoundInterfaceState>
|
||||
{
|
||||
public RadarConsoleWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void UpdateState(RadarConsoleBoundInterfaceState scc)
|
||||
{
|
||||
RadarScreen.UpdateState(scc);
|
||||
}
|
||||
}
|
||||
348
Content.Client/Shuttles/UI/RadarControl.cs
Normal file
348
Content.Client/Shuttles/UI/RadarControl.cs
Normal file
@@ -0,0 +1,348 @@
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision.Shapes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Displays nearby grids inside of a control.
|
||||
/// </summary>
|
||||
public sealed class RadarControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private const float ScrollSensitivity = 8f;
|
||||
|
||||
private const int MinimapRadius = 384;
|
||||
private const int MinimapMargin = 4;
|
||||
private const float GridLinesDistance = 32f;
|
||||
|
||||
/// <summary>
|
||||
/// Entity used to transform all of the radar objects.
|
||||
/// </summary>
|
||||
private EntityUid? _entity;
|
||||
|
||||
private float _radarMinRange = 64f;
|
||||
private float _radarMaxRange = 256f;
|
||||
public float RadarRange { get; private set; } = 256f;
|
||||
|
||||
private int MidPoint => SizeFull / 2;
|
||||
private int SizeFull => (int) ((MinimapRadius + MinimapMargin) * 2 * UIScale);
|
||||
private int ScaledMinimapRadius => (int) (MinimapRadius * UIScale);
|
||||
private float MinimapScale => RadarRange != 0 ? ScaledMinimapRadius / RadarRange : 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Shows a label on each radar object.
|
||||
/// </summary>
|
||||
private Dictionary<EntityUid, Control> _iffControls = new();
|
||||
|
||||
private Dictionary<EntityUid, Dictionary<EntityUid, DockingInterfaceState>> _docks = new();
|
||||
|
||||
public bool ShowIFF { get; set; } = true;
|
||||
public bool ShowDocks { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Currently hovered docked to show on the map.
|
||||
/// </summary>
|
||||
public EntityUid? HighlightedDock;
|
||||
|
||||
public Action<float>? OnRadarRangeChanged;
|
||||
|
||||
public RadarControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
MinSize = (SizeFull, SizeFull);
|
||||
}
|
||||
|
||||
public void UpdateState(RadarConsoleBoundInterfaceState ls)
|
||||
{
|
||||
_radarMaxRange = ls.MaxRange;
|
||||
|
||||
if (_radarMaxRange < RadarRange)
|
||||
{
|
||||
RadarRange = _radarMaxRange;
|
||||
OnRadarRangeChanged?.Invoke(RadarRange);
|
||||
}
|
||||
|
||||
if (_radarMaxRange < _radarMinRange)
|
||||
_radarMinRange = _radarMaxRange;
|
||||
|
||||
_entity = ls.Entity;
|
||||
_docks.Clear();
|
||||
|
||||
foreach (var state in ls.Docks)
|
||||
{
|
||||
var coordinates = state.Coordinates;
|
||||
var grid = _docks.GetOrNew(coordinates.EntityId);
|
||||
grid.Add(state.Entity, state);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void MouseWheel(GUIMouseWheelEventArgs args)
|
||||
{
|
||||
base.MouseWheel(args);
|
||||
AddRadarRange(-args.Delta.Y * ScrollSensitivity);
|
||||
}
|
||||
|
||||
public void AddRadarRange(float value)
|
||||
{
|
||||
var oldValue = RadarRange;
|
||||
RadarRange = MathF.Max(0f, MathF.Max(_radarMinRange, MathF.Min(RadarRange + value, _radarMaxRange)));
|
||||
|
||||
if (oldValue.Equals(RadarRange)) return;
|
||||
|
||||
OnRadarRangeChanged?.Invoke(RadarRange);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
var fakeAA = new Color(0.08f, 0.08f, 0.08f);
|
||||
|
||||
handle.DrawCircle((MidPoint, MidPoint), ScaledMinimapRadius + 1, fakeAA);
|
||||
handle.DrawCircle((MidPoint, MidPoint), ScaledMinimapRadius, Color.Black);
|
||||
|
||||
// No data
|
||||
if (_entity == null)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var gridLines = new Color(0.08f, 0.08f, 0.08f);
|
||||
var gridLinesRadial = 8;
|
||||
var gridLinesEquatorial = (int) Math.Floor(RadarRange / GridLinesDistance);
|
||||
|
||||
for (var i = 1; i < gridLinesEquatorial + 1; i++)
|
||||
{
|
||||
handle.DrawCircle((MidPoint, MidPoint), GridLinesDistance * MinimapScale * i, gridLines, false);
|
||||
}
|
||||
|
||||
for (var i = 0; i < gridLinesRadial; i++)
|
||||
{
|
||||
Angle angle = (Math.PI / gridLinesRadial) * i;
|
||||
var aExtent = angle.ToVec() * ScaledMinimapRadius;
|
||||
handle.DrawLine((MidPoint, MidPoint) - aExtent, (MidPoint, MidPoint) + aExtent, gridLines);
|
||||
}
|
||||
|
||||
var metaQuery = _entManager.GetEntityQuery<MetaDataComponent>();
|
||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||
var fixturesQuery = _entManager.GetEntityQuery<FixturesComponent>();
|
||||
var bodyQuery = _entManager.GetEntityQuery<PhysicsComponent>();
|
||||
var xform = xformQuery.GetComponent(_entity.Value);
|
||||
var mapPosition = xform.MapPosition;
|
||||
|
||||
if (mapPosition.MapId == MapId.Nullspace)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Can also use ourGridBody.LocalCenter
|
||||
var offset = xform.Coordinates.Position;
|
||||
var offsetMatrix = Matrix3.CreateTranslation(-offset);
|
||||
Matrix3 matrix;
|
||||
|
||||
// Draw our grid in detail
|
||||
var ourGridId = xform.GridID;
|
||||
if (ourGridId != GridId.Invalid)
|
||||
{
|
||||
matrix = xform.InvWorldMatrix;
|
||||
var ourGridFixtures = fixturesQuery.GetComponent(ourGridId);
|
||||
// Draw our grid; use non-filled boxes so it doesn't look awful.
|
||||
DrawGrid(handle, offsetMatrix, ourGridFixtures, Color.Yellow);
|
||||
|
||||
DrawDocks(handle, xform.GridEntityId, offsetMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix = Matrix3.CreateTranslation(-offset);
|
||||
}
|
||||
|
||||
var invertedPosition = xform.Coordinates.Position - offset;
|
||||
invertedPosition.Y = -invertedPosition.Y;
|
||||
// Don't need to transform the InvWorldMatrix again as it's already offset to its position.
|
||||
|
||||
// Draw radar position on the station
|
||||
handle.DrawCircle(ScalePosition(invertedPosition), 5f, Color.Lime);
|
||||
|
||||
var shown = new HashSet<EntityUid>();
|
||||
|
||||
// Draw other grids... differently
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(mapPosition.MapId,
|
||||
new Box2(mapPosition.Position - RadarRange, mapPosition.Position + RadarRange)))
|
||||
{
|
||||
if (grid.Index == ourGridId) continue;
|
||||
|
||||
var gridBody = bodyQuery.GetComponent(grid.GridEntityId);
|
||||
if (gridBody.Mass < 10f)
|
||||
{
|
||||
ClearLabel(grid.GridEntityId);
|
||||
continue;
|
||||
}
|
||||
|
||||
shown.Add(grid.GridEntityId);
|
||||
var name = metaQuery.GetComponent(grid.GridEntityId).EntityName;
|
||||
|
||||
if (name == string.Empty)
|
||||
name = Loc.GetString("shuttle-console-unknown");
|
||||
|
||||
var gridXform = xformQuery.GetComponent(grid.GridEntityId);
|
||||
var gridFixtures = fixturesQuery.GetComponent(grid.GridEntityId);
|
||||
var gridMatrix = gridXform.WorldMatrix;
|
||||
Matrix3.Multiply(in gridMatrix, in matrix, out var matty);
|
||||
|
||||
if (ShowIFF)
|
||||
{
|
||||
if (!_iffControls.TryGetValue(grid.GridEntityId, out var control))
|
||||
{
|
||||
var label = new Label()
|
||||
{
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
};
|
||||
|
||||
control = new PanelContainer()
|
||||
{
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
VerticalAlignment = VAlignment.Top,
|
||||
Children = { label },
|
||||
StyleClasses = { StyleNano.StyleClassTooltipPanel },
|
||||
};
|
||||
|
||||
_iffControls[grid.GridEntityId] = control;
|
||||
AddChild(control);
|
||||
}
|
||||
|
||||
var gridCentre = matty.Transform(gridBody.LocalCenter);
|
||||
gridCentre.Y = -gridCentre.Y;
|
||||
|
||||
// TODO: When we get IFF or whatever we can show controls at a further distance; for now
|
||||
// we don't do that because it would immediately reveal nukies.
|
||||
if (gridCentre.Length < RadarRange)
|
||||
{
|
||||
control.Visible = true;
|
||||
var label = (Label) control.GetChild(0);
|
||||
label.Text = Loc.GetString("shuttle-console-iff-label", ("name", name), ("distance", $"{gridCentre.Length:0.0}"));
|
||||
LayoutContainer.SetPosition(control, ScalePosition(gridCentre) / UIScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
control.Visible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearLabel(grid.GridEntityId);
|
||||
}
|
||||
|
||||
// Detailed view
|
||||
DrawGrid(handle, matty, gridFixtures, Color.Aquamarine);
|
||||
|
||||
DrawDocks(handle, grid.GridEntityId, matty);
|
||||
}
|
||||
|
||||
foreach (var (ent, _) in _iffControls)
|
||||
{
|
||||
if (shown.Contains(ent)) continue;
|
||||
ClearLabel(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
foreach (var (_, label) in _iffControls)
|
||||
{
|
||||
label.Dispose();
|
||||
}
|
||||
|
||||
_iffControls.Clear();
|
||||
}
|
||||
|
||||
private void ClearLabel(EntityUid uid)
|
||||
{
|
||||
if (!_iffControls.TryGetValue(uid, out var label)) return;
|
||||
label.Dispose();
|
||||
_iffControls.Remove(uid);
|
||||
}
|
||||
|
||||
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3 matrix)
|
||||
{
|
||||
if (!ShowDocks) return;
|
||||
|
||||
const float DockScale = 1.2f;
|
||||
|
||||
if (_docks.TryGetValue(uid, out var docks))
|
||||
{
|
||||
foreach (var (ent, state) in docks)
|
||||
{
|
||||
var position = state.Coordinates.Position;
|
||||
var uiPosition = matrix.Transform(position);
|
||||
|
||||
if (uiPosition.Length > RadarRange - DockScale) continue;
|
||||
|
||||
var color = HighlightedDock == ent ? Color.Magenta : Color.DarkViolet;
|
||||
|
||||
uiPosition.Y = -uiPosition.Y;
|
||||
|
||||
var verts = new[]
|
||||
{
|
||||
matrix.Transform(position + new Vector2(-DockScale, -DockScale)),
|
||||
matrix.Transform(position + new Vector2(DockScale, -DockScale)),
|
||||
matrix.Transform(position + new Vector2(DockScale, DockScale)),
|
||||
matrix.Transform(position + new Vector2(-DockScale, DockScale)),
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawGrid(DrawingHandleScreen handle, Matrix3 matrix, FixturesComponent component, Color color)
|
||||
{
|
||||
foreach (var (_, fixture) in component.Fixtures)
|
||||
{
|
||||
// If the fixture has any points out of range we won't draw any of it.
|
||||
var invalid = false;
|
||||
var poly = (PolygonShape) fixture.Shape;
|
||||
var verts = new Vector2[poly.VertexCount + 1];
|
||||
|
||||
for (var i = 0; i < poly.VertexCount; i++)
|
||||
{
|
||||
var vert = matrix.Transform(poly.Vertices[i]);
|
||||
|
||||
if (vert.Length > RadarRange)
|
||||
{
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
if (invalid) continue;
|
||||
|
||||
// Closed list
|
||||
verts[poly.VertexCount] = verts[0];
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 ScalePosition(Vector2 value)
|
||||
{
|
||||
return value * MinimapScale + MidPoint;
|
||||
}
|
||||
}
|
||||
81
Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml
Normal file
81
Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml
Normal file
@@ -0,0 +1,81 @@
|
||||
<userInterface:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:userInterface="clr-namespace:Content.Client.UserInterface"
|
||||
xmlns:ui="clr-namespace:Content.Client.Shuttles.UI"
|
||||
Title="{Loc 'shuttle-console-window-title'}">
|
||||
<GridContainer Columns="3"
|
||||
HorizontalAlignment="Stretch">
|
||||
<BoxContainer Name="LeftDisplay"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="256"
|
||||
Align="Center"
|
||||
Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="BorderedWindowPanel">
|
||||
<BoxContainer Name="DockPorts"
|
||||
Orientation="Vertical">
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<PanelContainer>
|
||||
<ui:RadarControl Name="RadarScreen"
|
||||
MouseFilter="Stop"/>
|
||||
<ui:DockingControl Name="DockingScreen"
|
||||
Visible="False"
|
||||
MouseFilter="Stop"/>
|
||||
</PanelContainer>
|
||||
<BoxContainer Name="RightDisplay"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="256"
|
||||
Align="Center"
|
||||
Orientation="Vertical">
|
||||
<PanelContainer Name="ReadonlyDisplay"
|
||||
StyleClasses="BorderedWindowPanel">
|
||||
<GridContainer Columns="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top">
|
||||
<Label Text="{Loc 'shuttle-console-max-radar'}"/>
|
||||
<Label Name="MaxRadarRange"
|
||||
Text="0.0"
|
||||
HorizontalAlignment="Right"/>
|
||||
<Label Text="{Loc 'shuttle-console-radar'}"/>
|
||||
<Label Name="RadarRange"
|
||||
Text="0.0"
|
||||
HorizontalAlignment="Right"/>
|
||||
<Label Text="{Loc 'shuttle-console-position'}"/>
|
||||
<Label Name="GridPosition"
|
||||
Text="0.0, 0.0"
|
||||
Align="Right"/>
|
||||
<Label Text="{Loc 'shuttle-console-orientation'}"/>
|
||||
<Label Name="GridOrientation"
|
||||
Text="0.0"
|
||||
Align="Right"/>
|
||||
<Label Text="{Loc 'shuttle-console-linear-velocity'}"/>
|
||||
<Label Name="GridLinearVelocity"
|
||||
Text="0.0, 0.0"
|
||||
Align="Right"/>
|
||||
<Label Text="{Loc 'shuttle-console-angular-velocity'}"/>
|
||||
<Label Name="GridAngularVelocity"
|
||||
Text="0.0"
|
||||
Align="Right"/>
|
||||
</GridContainer>
|
||||
</PanelContainer>
|
||||
<Button Name="ShuttleModeDisplay"
|
||||
Text="{Loc 'shuttle-console-strafing'}"
|
||||
TextAlign="Center"
|
||||
ToggleMode="True"/>
|
||||
<Button Name="IFFToggle"
|
||||
Text="{Loc 'shuttle-console-iff-toggle'}"
|
||||
TextAlign="Center"
|
||||
ToggleMode="True"/>
|
||||
<Button Name="DockToggle"
|
||||
Text="{Loc 'shuttle-console-dock-toggle'}"
|
||||
TextAlign="Center"
|
||||
ToggleMode="True"/>
|
||||
<Button Name="UndockButton"
|
||||
Text="{Loc 'shuttle-console-undock'}"
|
||||
TextAlign="Center"
|
||||
Disabled="True"/>
|
||||
</BoxContainer>
|
||||
</GridContainer>
|
||||
</userInterface:FancyWindow>
|
||||
239
Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs
Normal file
239
Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using Content.Client.Computer;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Shuttles.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
IComputerWindow<ShuttleConsoleBoundInterfaceState>
|
||||
{
|
||||
private readonly IEntityManager _entManager;
|
||||
|
||||
/// <summary>
|
||||
/// EntityUid of the open console.
|
||||
/// </summary>
|
||||
private EntityUid? _entity;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected dock button for camera.
|
||||
/// </summary>
|
||||
private BaseButton? _selectedDock;
|
||||
|
||||
/// <summary>
|
||||
/// Stored by grid entityid then by states
|
||||
/// </summary>
|
||||
private Dictionary<EntityUid, List<DockingInterfaceState>> _docks = new();
|
||||
|
||||
public Action<ShuttleMode>? ShuttleModePressed;
|
||||
public Action<EntityUid>? UndockPressed;
|
||||
public Action<EntityUid>? StartAutodockPressed;
|
||||
public Action<EntityUid>? StopAutodockPressed;
|
||||
|
||||
public ShuttleConsoleWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
OnRadarRangeChange(RadarScreen.RadarRange);
|
||||
RadarScreen.OnRadarRangeChanged += OnRadarRangeChange;
|
||||
|
||||
IFFToggle.OnToggled += OnIFFTogglePressed;
|
||||
IFFToggle.Pressed = RadarScreen.ShowIFF;
|
||||
|
||||
DockToggle.OnToggled += OnDockTogglePressed;
|
||||
DockToggle.Pressed = RadarScreen.ShowDocks;
|
||||
|
||||
ShuttleModeDisplay.OnToggled += OnShuttleModePressed;
|
||||
|
||||
UndockButton.OnPressed += OnUndockPressed;
|
||||
}
|
||||
|
||||
private void OnRadarRangeChange(float value)
|
||||
{
|
||||
RadarRange.Text = $"{value:0}";
|
||||
}
|
||||
|
||||
private void OnShuttleModePressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
ShuttleModePressed?.Invoke(obj.Button.Pressed ? ShuttleMode.Strafing : ShuttleMode.Cruise);
|
||||
}
|
||||
|
||||
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
RadarScreen.ShowIFF ^= true;
|
||||
args.Button.Pressed = RadarScreen.ShowIFF;
|
||||
}
|
||||
|
||||
private void OnDockTogglePressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
RadarScreen.ShowDocks ^= true;
|
||||
args.Button.Pressed = RadarScreen.ShowDocks;
|
||||
}
|
||||
|
||||
private void OnUndockPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (DockingScreen.ViewedDock == null) return;
|
||||
UndockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
||||
}
|
||||
|
||||
public void UpdateState(ShuttleConsoleBoundInterfaceState scc)
|
||||
{
|
||||
_entity = scc.Entity;
|
||||
UpdateDocks(scc.Docks);
|
||||
RadarScreen.UpdateState(scc);
|
||||
MaxRadarRange.Text = $"{scc.MaxRange:0}";
|
||||
ShuttleModeDisplay.Pressed = scc.Mode == ShuttleMode.Strafing;
|
||||
}
|
||||
|
||||
#region Docking
|
||||
|
||||
private void UpdateDocks(List<DockingInterfaceState> docks)
|
||||
{
|
||||
// TODO: We should check for changes so any existing highlighted doesn't delete.
|
||||
// We also need to make up some pseudonumber as well for these.
|
||||
_docks.Clear();
|
||||
|
||||
foreach (var dock in docks)
|
||||
{
|
||||
var grid = _docks.GetOrNew(dock.Coordinates.EntityId);
|
||||
grid.Add(dock);
|
||||
}
|
||||
|
||||
DockPorts.DisposeAllChildren();
|
||||
DockingScreen.Docks = _docks;
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(_entity, out var xform))
|
||||
{
|
||||
// TODO: Show Placeholder
|
||||
return;
|
||||
}
|
||||
|
||||
if (_docks.TryGetValue(xform.GridEntityId, out var gridDocks))
|
||||
{
|
||||
var index = 1;
|
||||
|
||||
foreach (var state in gridDocks)
|
||||
{
|
||||
var ent = state.Entity;
|
||||
var pressed = ent == DockingScreen.ViewedDock;
|
||||
string suffix;
|
||||
|
||||
if (state.Connected)
|
||||
{
|
||||
suffix = Loc.GetString("shuttle-console-docked", ("index", index));
|
||||
}
|
||||
else
|
||||
{
|
||||
suffix = $"{index}";
|
||||
}
|
||||
|
||||
var button = new Button()
|
||||
{
|
||||
Text = Loc.GetString("shuttle-console-dock-button", ("suffix", suffix)),
|
||||
ToggleMode = true,
|
||||
Pressed = pressed,
|
||||
};
|
||||
|
||||
button.OnMouseEntered += args => OnDockMouseEntered(args, ent);
|
||||
button.OnMouseExited += args => OnDockMouseExited(args, ent);
|
||||
button.OnToggled += args => OnDockToggled(args, ent);
|
||||
DockPorts.AddChild(button);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDockMouseEntered(GUIMouseHoverEventArgs obj, EntityUid uid)
|
||||
{
|
||||
RadarScreen.HighlightedDock = uid;
|
||||
}
|
||||
|
||||
private void OnDockMouseExited(GUIMouseHoverEventArgs obj, EntityUid uid)
|
||||
{
|
||||
RadarScreen.HighlightedDock = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a docking camera instead of radar screen.
|
||||
/// </summary>
|
||||
private void OnDockToggled(BaseButton.ButtonEventArgs obj, EntityUid ent)
|
||||
{
|
||||
if (_selectedDock != null)
|
||||
{
|
||||
_selectedDock.Pressed = false;
|
||||
_selectedDock = null;
|
||||
}
|
||||
|
||||
if (!obj.Button.Pressed)
|
||||
{
|
||||
if (DockingScreen.ViewedDock != null)
|
||||
{
|
||||
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
||||
DockingScreen.ViewedDock = null;
|
||||
}
|
||||
|
||||
UndockButton.Disabled = true;
|
||||
DockingScreen.Visible = false;
|
||||
RadarScreen.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// DebugTools.Assert(DockingScreen.ViewedDock == null);
|
||||
_entManager.TryGetComponent<TransformComponent>(_entity, out var xform);
|
||||
|
||||
UndockButton.Disabled = false;
|
||||
RadarScreen.Visible = false;
|
||||
DockingScreen.Visible = true;
|
||||
DockingScreen.ViewedDock = ent;
|
||||
StartAutodockPressed?.Invoke(ent);
|
||||
DockingScreen.GridEntity = xform?.GridEntityId;
|
||||
_selectedDock = obj.Button;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
if (DockingScreen.ViewedDock != null)
|
||||
{
|
||||
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (!_entManager.TryGetComponent<TransformComponent>(_entity, out var entXform) ||
|
||||
!_entManager.TryGetComponent<PhysicsComponent>(entXform.GridEntityId, out var gridBody) ||
|
||||
!_entManager.TryGetComponent<TransformComponent>(entXform.GridEntityId, out var gridXform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var (_, worldRot, worldMatrix) = gridXform.GetWorldPositionRotationMatrix();
|
||||
var worldPos = worldMatrix.Transform(gridBody.LocalCenter);
|
||||
|
||||
// Get the positive reduced angle.
|
||||
var displayRot = -worldRot.Reduced();
|
||||
|
||||
GridPosition.Text = $"{worldPos.X:0.0}, {worldPos.Y:0.0}";
|
||||
GridOrientation.Text = $"{displayRot.Degrees:0.0}";
|
||||
|
||||
var gridVelocity = gridBody.LinearVelocity;
|
||||
gridVelocity = displayRot.RotateVec(gridVelocity);
|
||||
// Get linear velocity relative to the console entity
|
||||
GridLinearVelocity.Text = $"{gridVelocity.X:0.0}, {gridVelocity.Y:0.0}";
|
||||
GridAngularVelocity.Text = $"{-gridBody.AngularVelocity:0.0}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user