diff --git a/Content.Client/Maps/GridDraggingCommand.cs b/Content.Client/Maps/GridDraggingCommand.cs new file mode 100644 index 0000000000..eb8579aa5f --- /dev/null +++ b/Content.Client/Maps/GridDraggingCommand.cs @@ -0,0 +1,18 @@ +using Content.Shared.Maps; +using Robust.Shared.Console; + +namespace Content.Client.Maps; + +/// +/// Toggles GridDragging on the system. +/// +public sealed class GridDraggingCommand : IConsoleCommand +{ + public string Command => SharedGridDraggingSystem.CommandName; + public string Description => $"Allows someone with permissions to drag grids around."; + public string Help => $"{Command}"; + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + IoCManager.Resolve().GetEntitySystem().Enabled ^= true; + } +} diff --git a/Content.Client/Maps/GridDraggingSystem.cs b/Content.Client/Maps/GridDraggingSystem.cs new file mode 100644 index 0000000000..556cd12992 --- /dev/null +++ b/Content.Client/Maps/GridDraggingSystem.cs @@ -0,0 +1,114 @@ +using Content.Client.Administration.Managers; +using Content.Shared.Maps; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Shared.Input; +using Robust.Shared.Map; +using Robust.Shared.Timing; + +namespace Content.Client.Maps; + +/// +public sealed class GridDraggingSystem : SharedGridDraggingSystem +{ + [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly InputSystem _inputSystem = default!; + + public bool Enabled { get; set; } + + private EntityUid? _dragging; + private Vector2 _localPosition; + private MapCoordinates? _lastMousePosition; + + private void StartDragging(EntityUid grid, Vector2 localPosition) + { + _dragging = grid; + _localPosition = localPosition; + + if (TryComp(grid, out var body)) + { + RaiseNetworkEvent(new GridDragVelocityRequest() + { + Grid = grid, + LinearVelocity = Vector2.Zero + }); + } + } + + private void StopDragging() + { + if (_dragging == null) return; + + if (_lastMousePosition != null && TryComp(_dragging.Value, out var xform) && + TryComp(_dragging.Value, out var body) && + xform.MapID == _lastMousePosition.Value.MapId) + { + var tickTime = _gameTiming.TickPeriod; + var distance = _lastMousePosition.Value.Position - xform.WorldPosition; + RaiseNetworkEvent(new GridDragVelocityRequest() + { + Grid = _dragging.Value, + LinearVelocity = distance.LengthSquared > 0f ? (distance / (float) tickTime.TotalSeconds) * 0.25f : Vector2.Zero, + }); + } + + _dragging = null; + _localPosition = Vector2.Zero; + _lastMousePosition = null; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!Enabled || !_gameTiming.IsFirstTimePredicted) return; + + var state = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use); + + if (state != BoundKeyState.Down) + { + StopDragging(); + return; + } + + var mouseScreenPos = _inputManager.MouseScreenPosition; + var mousePos = _eyeManager.ScreenToMap(mouseScreenPos); + + if (_dragging == null) + { + if (!_mapManager.TryFindGridAt(mousePos, out var grid)) + return; + + StartDragging(grid.GridEntityId, Transform(grid.GridEntityId).InvWorldMatrix.Transform(mousePos.Position)); + } + + if (!TryComp(_dragging, out var xform)) + { + StopDragging(); + return; + } + + if (xform.MapID != mousePos.MapId) + { + StopDragging(); + return; + } + + var localToWorld = xform.WorldMatrix.Transform(_localPosition); + + if (localToWorld.EqualsApprox(mousePos.Position, 0.01f)) return; + + var requestedGridOrigin = mousePos.Position - xform.WorldRotation.RotateVec(_localPosition); + _lastMousePosition = new MapCoordinates(requestedGridOrigin, mousePos.MapId); + + RaiseNetworkEvent(new GridDragRequestPosition() + { + Grid = _dragging.Value, + WorldPosition = requestedGridOrigin, + }); + } +} diff --git a/Content.Server/Maps/GridDraggingSystem.cs b/Content.Server/Maps/GridDraggingSystem.cs new file mode 100644 index 0000000000..2bfd0c8dac --- /dev/null +++ b/Content.Server/Maps/GridDraggingSystem.cs @@ -0,0 +1,42 @@ +using Content.Shared.Maps; +using Robust.Server.Console; +using Robust.Server.Player; + +namespace Content.Server.Maps; + +/// +public sealed class GridDraggingSystem : SharedGridDraggingSystem +{ + [Dependency] private readonly IConGroupController _admin = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnRequestDrag); + SubscribeNetworkEvent(OnRequestVelocity); + } + + private void OnRequestVelocity(GridDragVelocityRequest ev, EntitySessionEventArgs args) + { + if (args.SenderSession is not IPlayerSession playerSession || + !_admin.CanCommand(playerSession, CommandName) || + !Exists(ev.Grid) || + Deleted(ev.Grid)) return; + + var gridBody = Comp(ev.Grid); + gridBody.LinearVelocity = ev.LinearVelocity; + gridBody.AngularVelocity = 0f; + } + + private void OnRequestDrag(GridDragRequestPosition msg, EntitySessionEventArgs args) + { + if (args.SenderSession is not IPlayerSession playerSession || + !_admin.CanCommand(playerSession, CommandName) || + !Exists(msg.Grid) || + Deleted(msg.Grid)) return; + + var gridXform = Transform(msg.Grid); + + gridXform.WorldPosition = msg.WorldPosition; + } +} diff --git a/Content.Shared/Maps/SharedGridDraggingSystem.cs b/Content.Shared/Maps/SharedGridDraggingSystem.cs new file mode 100644 index 0000000000..02ff95751d --- /dev/null +++ b/Content.Shared/Maps/SharedGridDraggingSystem.cs @@ -0,0 +1,29 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Maps; + +/// +/// Helper system to allow you to move grids with a mouse. +/// +public abstract class SharedGridDraggingSystem : EntitySystem +{ + public const string CommandName = "griddrag"; +} + + +/// +/// Raised on the client to request a grid move to a specific position. +/// +[Serializable, NetSerializable] +public sealed class GridDragRequestPosition : EntityEventArgs +{ + public EntityUid Grid; + public Vector2 WorldPosition; +} + +[Serializable, NetSerializable] +public sealed class GridDragVelocityRequest : EntityEventArgs +{ + public EntityUid Grid; + public Vector2 LinearVelocity; +} diff --git a/Resources/clientCommandPerms.yml b/Resources/clientCommandPerms.yml index 7805d0d24a..9f7ff9b6bd 100644 --- a/Resources/clientCommandPerms.yml +++ b/Resources/clientCommandPerms.yml @@ -17,6 +17,7 @@ - Flags: MAPPING Commands: + - griddrag - showmarkers - showsubfloor - showsubfloorforever