]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Minor improvements & fixes to Shuttle Console UI (#31623)
authoreoineoineoin <github@eoinrul.es>
Sat, 23 Nov 2024 06:55:09 +0000 (06:55 +0000)
committerGitHub <noreply@github.com>
Sat, 23 Nov 2024 06:55:09 +0000 (17:55 +1100)
* Fix grids and docks being culled from display prematurely

* Fix inconsistent disabling of "Undock" buttons

* Add a radar icon to indicate where the controlling console is

* Tidy up math

Remove lots of sketchy transforms-of-transforms, which should have been
as single matrix multiply. Assign proper names to matrices. Remove some
redundant calculations.

* Feedback

Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs
Content.Client/Shuttles/UI/NavScreen.xaml.cs
Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs
Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs
Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs

index b50d8fa6b21867c5bc530665f2d1396b534f67f5..a5411005391df0fffbaba69554d317c624c896ab 100644 (file)
@@ -116,7 +116,7 @@ public partial class BaseShuttleControl : MapGridControl
         }
     }
 
-    protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
+    protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 gridToView, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
     {
         var rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp);
         var minimapScale = MinimapScale;
@@ -264,7 +264,7 @@ public partial class BaseShuttleControl : MapGridControl
         Extensions.EnsureLength(ref _allVertices, totalData);
 
         _drawJob.MidPoint = midpoint;
-        _drawJob.Matrix = matrix;
+        _drawJob.Matrix = gridToView;
         _drawJob.MinimapScale = minimapScale;
         _drawJob.Vertices = gridData.Vertices;
         _drawJob.ScaledVertices = _allVertices;
@@ -286,7 +286,7 @@ public partial class BaseShuttleControl : MapGridControl
 
     private record struct GridDrawJob : IParallelRobustJob
     {
-        public int BatchSize => 16;
+        public int BatchSize => 64;
 
         public float MinimapScale;
         public Vector2 MidPoint;
@@ -297,12 +297,7 @@ public partial class BaseShuttleControl : MapGridControl
 
         public void Execute(int index)
         {
-            var vert = Vertices[index];
-            var adjustedVert = Vector2.Transform(vert, Matrix);
-            adjustedVert = adjustedVert with { Y = -adjustedVert.Y };
-
-            var scaledVert = ScalePosition(adjustedVert, MinimapScale, MidPoint);
-            ScaledVertices[index] = scaledVert;
+            ScaledVertices[index] = Vector2.Transform(Vertices[index], Matrix);
         }
     }
 }
index 91d95aaa0427274ab3dd51ca57cd805dde9b6398..7236714ef29fde824b478dfa987777b92745b614 100644 (file)
@@ -15,6 +15,7 @@ public sealed partial class NavScreen : BoxContainer
     [Dependency] private readonly IEntityManager _entManager = default!;
     private SharedTransformSystem _xformSystem;
 
+    private EntityUid? _consoleEntity; // Entity of controlling console
     private EntityUid? _shuttleEntity;
 
     public NavScreen()
@@ -35,6 +36,12 @@ public sealed partial class NavScreen : BoxContainer
         _shuttleEntity = shuttle;
     }
 
+    public void SetConsole(EntityUid? console)
+    {
+        _consoleEntity = console;
+        NavRadar.SetConsole(console);
+    }
+
     private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
     {
         NavRadar.ShowIFF ^= true;
index a4b42fb672c75f479c1666a05bd58b6b8bed4c6f..d0e6f9ebf7b806f6072b19ffe70c4007249bca45 100644 (file)
@@ -138,6 +138,7 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
     {
         var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates);
         NavContainer.SetShuttle(coordinates?.EntityId);
+        NavContainer.SetConsole(owner);
         MapContainer.SetShuttle(coordinates?.EntityId);
         MapContainer.SetConsole(owner);
 
index 61ae0699266508997be73ddd51ca4c92d946626e..2b575b480596fa2d3ae7dbc5f8296e5251493ad0 100644 (file)
@@ -107,16 +107,19 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
         DrawCircles(handle);
         var gridNent = EntManager.GetNetEntity(GridEntity);
         var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value);
-        var ourGridMatrix = _xformSystem.GetWorldMatrix(GridEntity.Value);
-        var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
-        var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix);
+        var ourGridToWorld = _xformSystem.GetWorldMatrix(GridEntity.Value);
+        var selectedDockToOurGrid = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
+        var selectedDockToWorld = Matrix3x2.Multiply(selectedDockToOurGrid, ourGridToWorld);
 
-        Matrix3x2.Invert(worldFromDock, out var offsetMatrix);
+        Box2 viewBoundsWorld = Matrix3Helpers.TransformBox(selectedDockToWorld, new Box2(-WorldRangeVector, WorldRangeVector));
+
+        Matrix3x2.Invert(selectedDockToWorld, out var worldToSelectedDock);
+        var selectedDockToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
 
         // Draw nearby grids
         var controlBounds = PixelSizeBox;
         _grids.Clear();
-        _mapManager.FindGridsIntersecting(gridXform.MapID, new Box2(mapPos.Position - WorldRangeVector, mapPos.Position + WorldRangeVector), ref _grids);
+        _mapManager.FindGridsIntersecting(gridXform.MapID, viewBoundsWorld, ref _grids);
 
         // offset the dotted-line position to the bounds.
         Vector2? viewedDockPos = _viewedState != null ? MidPointVector : null;
@@ -136,11 +139,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
             if (grid.Owner != GridEntity && !_shuttles.CanDraw(grid.Owner, iffComp: iffComp))
                 continue;
 
-            var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
-            var matty = Matrix3x2.Multiply(gridMatrix, offsetMatrix);
+            var curGridToWorld = _xformSystem.GetWorldMatrix(grid.Owner);
+            var curGridToView = curGridToWorld * worldToSelectedDock * selectedDockToView;
             var color = _shuttles.GetIFFColor(grid.Owner, grid.Owner == GridEntity, component: iffComp);
 
-            DrawGrid(handle, matty, grid, color);
+            DrawGrid(handle, curGridToView, grid, color);
 
             // Draw any docks on that grid
             if (!DockState.Docks.TryGetValue(EntManager.GetNetEntity(grid), out var gridDocks))
@@ -151,23 +154,24 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                 if (ViewedDock == dock.Entity)
                     continue;
 
-                var position = Vector2.Transform(dock.Coordinates.Position, matty);
-
                 var otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle);
-                var scaledPos = ScalePosition(position with {Y = -position.Y});
 
-                if (!controlBounds.Contains(scaledPos.Floored()))
+                // This box is the AABB of all the vertices we draw below.
+                var dockRenderBoundsLocal = new Box2(-0.5f, -0.7f, 0.5f, 0.5f);
+                var currentDockToCurGrid = Matrix3Helpers.CreateTransform(dock.Coordinates.Position, dock.Angle);
+                var currentDockToWorld = Matrix3x2.Multiply(currentDockToCurGrid, curGridToWorld);
+                var dockRenderBoundsWorld = Matrix3Helpers.TransformBox(currentDockToWorld, dockRenderBoundsLocal);
+                if (!viewBoundsWorld.Intersects(dockRenderBoundsWorld))
                     continue;
 
-                // Draw the dock's collision
                 var collisionBL = Vector2.Transform(dock.Coordinates.Position +
-                                                  Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), matty);
+                                                  Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), curGridToView);
                 var collisionBR = Vector2.Transform(dock.Coordinates.Position +
-                                                  Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), matty);
+                                                  Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), curGridToView);
                 var collisionTR = Vector2.Transform(dock.Coordinates.Position +
-                                                  Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), matty);
+                                                  Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), curGridToView);
                 var collisionTL = Vector2.Transform(dock.Coordinates.Position +
-                                                  Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), matty);
+                                                  Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), curGridToView);
 
                 var verts = new[]
                 {
@@ -181,13 +185,6 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                     collisionBL,
                 };
 
-                for (var i = 0; i < verts.Length; i++)
-                {
-                    var vert = verts[i];
-                    vert.Y = -vert.Y;
-                    verts[i] = ScalePosition(vert);
-                }
-
                 var collisionCenter = verts[0] + verts[1] + verts[3] + verts[5];
 
                 var otherDockConnection = Color.ToSrgb(Color.Pink);
@@ -195,10 +192,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                 handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection);
 
                 // Draw the dock itself
-                var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), matty);
-                var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), matty);
-                var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), matty);
-                var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), matty);
+                var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), curGridToView);
+                var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), curGridToView);
+                var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), curGridToView);
+                var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), curGridToView);
 
                 verts = new[]
                 {
@@ -212,13 +209,6 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                     dockBL
                 };
 
-                for (var i = 0; i < verts.Length; i++)
-                {
-                    var vert = verts[i];
-                    vert.Y = -vert.Y;
-                    verts[i] = ScalePosition(vert);
-                }
-
                 Color otherDockColor;
 
                 if (HighlightedDock == dock.Entity)
@@ -253,9 +243,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                     collisionCenter /= 4;
                     var range = viewedDockPos.Value - collisionCenter;
 
-                    if (range.Length() < SharedDockingSystem.DockingHiglightRange * MinimapScale)
+                    var maxRange = SharedDockingSystem.DockingHiglightRange * MinimapScale;
+                    var maxRangeSq = maxRange * maxRange;
+                    if (range.LengthSquared() < maxRangeSq)
                     {
-                        if (_viewedState?.GridDockedWith == null)
+                        if (dock.GridDockedWith == null)
                         {
                             var coordsOne = EntManager.GetCoordinates(_viewedState!.Coordinates);
                             var coordsTwo = EntManager.GetCoordinates(dock.Coordinates);
@@ -265,10 +257,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                             var rotA = _xformSystem.GetWorldRotation(coordsOne.EntityId) + _viewedState!.Angle;
                             var rotB = _xformSystem.GetWorldRotation(coordsTwo.EntityId) + dock.Angle;
 
-                            var distance = (mapOne.Position - mapTwo.Position).Length();
+                            var distanceSq = (mapOne.Position - mapTwo.Position).LengthSquared();
 
                             var inAlignment = _dockSystem.InAlignment(mapOne, rotA, mapTwo, rotB);
-                            var canDock = distance < SharedDockingSystem.DockRange && inAlignment;
+                            var maxDockDistSq = SharedDockingSystem.DockRange * SharedDockingSystem.DockRange;
+                            var canDock = distanceSq < maxDockDistSq && inAlignment;
 
                             if (dockButton != null)
                                 dockButton.Disabled = !canDock || !canDockChange;
@@ -297,7 +290,8 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
                 {
                     // Because it's being layed out top-down we have to arrange for first frame.
                     container.Arrange(PixelRect);
-                    var containerPos = scaledPos / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
+                    var dockPositionInView = Vector2.Transform(dock.Coordinates.Position, curGridToView);
+                    var containerPos = dockPositionInView / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
                     SetPosition(container, containerPos);
                 }
 
index 2674343e059144414d1fa4362b14de305ba9aa38..805608c9a5385295b5723f910e48d96be2efe619 100644 (file)
@@ -29,6 +29,11 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
     /// </summary>
     private EntityCoordinates? _coordinates;
 
+    /// <summary>
+    /// Entity of controlling console
+    /// </summary>
+    private EntityUid? _consoleEntity;
+
     private Angle? _rotation;
 
     private Dictionary<NetEntity, List<DockingPortState>> _docks = new();
@@ -57,6 +62,11 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
         _rotation = angle;
     }
 
+    public void SetConsole(EntityUid? consoleEntity)
+    {
+        _consoleEntity = consoleEntity;
+    }
+
     protected override void KeyBindUp(GUIBoundKeyEventArgs args)
     {
         base.KeyBindUp(args);
@@ -139,40 +149,35 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
         }
 
         var mapPos = _transform.ToMapCoordinates(_coordinates.Value);
-        var offset = _coordinates.Value.Position;
-        var posMatrix = Matrix3Helpers.CreateTransform(offset, _rotation.Value);
+        var posMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, _rotation.Value);
         var ourEntRot = RotateWithEntity ? _transform.GetWorldRotation(xform) : _rotation.Value;
         var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
-        var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
-        Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert);
+        var shuttleToWorld = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
+        Matrix3x2.Invert(shuttleToWorld, out var worldToShuttle);
+        var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
 
         // Draw our grid in detail
         var ourGridId = xform.GridUid;
         if (EntManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
             fixturesQuery.HasComponent(ourGridId.Value))
         {
-            var ourGridMatrix = _transform.GetWorldMatrix(ourGridId.Value);
-            var matrix = Matrix3x2.Multiply(ourGridMatrix, ourWorldMatrixInvert);
+            var ourGridToWorld = _transform.GetWorldMatrix(ourGridId.Value);
+            var ourGridToShuttle = Matrix3x2.Multiply(ourGridToWorld, worldToShuttle);
+            var ourGridToView = ourGridToShuttle * shuttleToView;
             var color = _shuttles.GetIFFColor(ourGridId.Value, self: true);
 
-            DrawGrid(handle, matrix, (ourGridId.Value, ourGrid), color);
-            DrawDocks(handle, ourGridId.Value, matrix);
+            DrawGrid(handle, ourGridToView, (ourGridId.Value, ourGrid), color);
+            DrawDocks(handle, ourGridId.Value, ourGridToView);
         }
 
-        var invertedPosition = _coordinates.Value.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
-        var radarPos = invertedPosition;
         const float radarVertRadius = 2f;
-
         var radarPosVerts = new Vector2[]
         {
-            ScalePosition(radarPos + new Vector2(0f, -radarVertRadius)),
-            ScalePosition(radarPos + new Vector2(radarVertRadius / 2f, 0f)),
-            ScalePosition(radarPos + new Vector2(0f, radarVertRadius)),
-            ScalePosition(radarPos + new Vector2(radarVertRadius / -2f, 0f)),
+            ScalePosition(new Vector2(0f, -radarVertRadius)),
+            ScalePosition(new Vector2(radarVertRadius / 2f, 0f)),
+            ScalePosition(new Vector2(0f, radarVertRadius)),
+            ScalePosition(new Vector2(radarVertRadius / -2f, 0f)),
         };
 
         handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, radarPosVerts, Color.Lime);
@@ -197,8 +202,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
             if (!_shuttles.CanDraw(gUid, gridBody, iff))
                 continue;
 
-            var gridMatrix = _transform.GetWorldMatrix(gUid);
-            var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert);
+            var curGridToWorld = _transform.GetWorldMatrix(gUid);
+            var curGridToView = curGridToWorld * worldToShuttle * shuttleToView;
 
             var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
             var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f);
@@ -213,8 +218,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
             {
                 var gridBounds = grid.Comp.LocalAABB;
 
-                var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty);
-                gridCentre.Y = -gridCentre.Y;
+                var gridCentre = Vector2.Transform(gridBody.LocalCenter, curGridToView);
 
                 var distance = gridCentre.Length();
                 var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName),
@@ -230,9 +234,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
                 // y-offset the control to always render below the grid (vertically)
                 var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
 
-                // The actual position in the UI. We centre the label by offsetting the matrix position 
-                // by half the label's width, plus the y-offset
-                var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset);
+                // The actual position in the UI.
+                var gridScaledPosition = gridCentre - new Vector2(0, -yOffset);
 
                 // Normalize the grid position if it exceeds the viewport bounds
                 // normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging
@@ -264,18 +267,32 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
             }
 
             // Detailed view
-            var gridAABB = gridMatrix.TransformBox(grid.Comp.LocalAABB);
+            var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB);
 
             // Skip drawing if it's out of range.
             if (!gridAABB.Intersects(viewAABB))
                 continue;
 
-            DrawGrid(handle, matty, grid, labelColor);
-            DrawDocks(handle, gUid, matty);
+            DrawGrid(handle, curGridToView, grid, labelColor);
+            DrawDocks(handle, gUid, curGridToView);
         }
+
+        // If we've set the controlling console, and it's on a different grid
+        // to the shuttle itself, then draw an additional marker to help the
+        // player determine where they are relative to the shuttle.
+        if (_consoleEntity != null && xformQuery.TryGetComponent(_consoleEntity, out var consoleXform))
+        {
+            if (consoleXform.ParentUid != _coordinates.Value.EntityId)
+            {
+                var consolePositionWorld = _transform.GetWorldPosition((EntityUid)_consoleEntity);
+                var p = Vector2.Transform(consolePositionWorld, worldToShuttle * shuttleToView);
+                handle.DrawCircle(p, 5, Color.ToSrgb(Color.Cyan), true);
+            }
+        }
+
     }
 
-    private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 matrix)
+    private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 gridToView)
     {
         if (!ShowDocks)
             return;
@@ -283,33 +300,32 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
         const float DockScale = 0.6f;
         var nent = EntManager.GetNetEntity(uid);
 
+        const float sqrt2 = 1.41421356f;
+        const float dockRadius = DockScale * sqrt2;
+        // Worst-case bounds used to cull a dock:
+        Box2 viewBounds = new Box2(-dockRadius, -dockRadius, Size.X + dockRadius, Size.Y + dockRadius);
         if (_docks.TryGetValue(nent, out var docks))
         {
             foreach (var state in docks)
             {
                 var position = state.Coordinates.Position;
-                var uiPosition = Vector2.Transform(position, matrix);
 
-                if (uiPosition.Length() > (WorldRange * 2f) - DockScale)
+                var positionInView = Vector2.Transform(position, gridToView);
+                if (!viewBounds.Contains(positionInView))
+                {
                     continue;
+                }
 
                 var color = Color.ToSrgb(Color.Magenta);
 
                 var verts = new[]
                 {
-                    Vector2.Transform(position + new Vector2(-DockScale, -DockScale), matrix),
-                    Vector2.Transform(position + new Vector2(DockScale, -DockScale), matrix),
-                    Vector2.Transform(position + new Vector2(DockScale, DockScale), matrix),
-                    Vector2.Transform(position + new Vector2(-DockScale, DockScale), matrix),
+                    Vector2.Transform(position + new Vector2(-DockScale, -DockScale), gridToView),
+                    Vector2.Transform(position + new Vector2(DockScale, -DockScale), gridToView),
+                    Vector2.Transform(position + new Vector2(DockScale, DockScale), gridToView),
+                    Vector2.Transform(position + new Vector2(-DockScale, DockScale), gridToView),
                 };
 
-                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.WithAlpha(0.8f));
                 handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
             }