diff --git a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs index b50d8fa6b21867..a5411005391df0 100644 --- a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs +++ b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs @@ -116,7 +116,7 @@ protected void DrawCircles(DrawingHandleScreen handle) } } - protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity grid, Color color, float alpha = 0.01f) + protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 gridToView, Entity grid, Color color, float alpha = 0.01f) { var rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp); var minimapScale = MinimapScale; @@ -264,7 +264,7 @@ protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity 16; + public int BatchSize => 64; public float MinimapScale; public Vector2 MidPoint; @@ -297,12 +297,7 @@ private record struct GridDrawJob : IParallelRobustJob 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); } } } diff --git a/Content.Client/Shuttles/UI/NavScreen.xaml.cs b/Content.Client/Shuttles/UI/NavScreen.xaml.cs index 91d95aaa042727..7236714ef29fde 100644 --- a/Content.Client/Shuttles/UI/NavScreen.xaml.cs +++ b/Content.Client/Shuttles/UI/NavScreen.xaml.cs @@ -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 void SetShuttle(EntityUid? shuttle) _shuttleEntity = shuttle; } + public void SetConsole(EntityUid? console) + { + _consoleEntity = console; + NavRadar.SetConsole(console); + } + private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args) { NavRadar.ShowIFF ^= true; diff --git a/Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs b/Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs index a4b42fb672c75f..d0e6f9ebf7b806 100644 --- a/Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleConsoleWindow.xaml.cs @@ -138,6 +138,7 @@ public void UpdateState(EntityUid owner, ShuttleBoundUserInterfaceState cState) { var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates); NavContainer.SetShuttle(coordinates?.EntityId); + NavContainer.SetConsole(owner); MapContainer.SetShuttle(coordinates?.EntityId); MapContainer.SetConsole(owner); diff --git a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs index 61ae0699266508..2b575b480596fa 100644 --- a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs @@ -107,16 +107,19 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) { // 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); } diff --git a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs index 2674343e059144..805608c9a53852 100644 --- a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs @@ -29,6 +29,11 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl /// private EntityCoordinates? _coordinates; + /// + /// Entity of controlling console + /// + private EntityUid? _consoleEntity; + private Angle? _rotation; private Dictionary> _docks = new(); @@ -57,6 +62,11 @@ public void SetMatrix(EntityCoordinates? coordinates, Angle? angle) _rotation = angle; } + public void SetConsole(EntityUid? consoleEntity) + { + _consoleEntity = consoleEntity; + } + protected override void KeyBindUp(GUIBoundKeyEventArgs args) { base.KeyBindUp(args); @@ -139,40 +149,35 @@ protected override void Draw(DrawingHandleScreen handle) } 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(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 @@ protected override void Draw(DrawingHandleScreen handle) 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 @@ protected override void Draw(DrawingHandleScreen handle) { 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 @@ protected override void Draw(DrawingHandleScreen handle) // 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 @@ protected override void Draw(DrawingHandleScreen handle) } // 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 @@ private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 matr 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); }