Legally distinct gravity gun (#8114)

This commit is contained in:
metalgearsloth
2022-05-13 12:24:34 +10:00
committed by GitHub
parent 194c5d6842
commit c3adf24557
6 changed files with 306 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
using Robust.Shared.Console;
namespace Content.Client.Weapons.Ranged;
public sealed class TetherGunCommand : IConsoleCommand
{
public string Command => "tethergun";
public string Description => "Allows you to drag mobs around with your mouse.";
public string Help => $"{Command}";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<TetherGunSystem>().Enabled ^= true;
}
}

View File

@@ -0,0 +1,107 @@
using Content.Client.Clickable;
using Content.Shared.Weapons.Ranged;
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.Weapons.Ranged;
public sealed class TetherGunSystem : SharedTetherGunSystem
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
public bool Enabled { get; set; }
/// <summary>
/// The entity being dragged around.
/// </summary>
private EntityUid? _dragging;
private MapCoordinates? _lastMousePosition;
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)
{
var bodyQuery = GetEntityQuery<PhysicsComponent>();
var lowest = new List<(int DrawDepth, EntityUid Entity)>();
foreach (var ent in _lookup.GetEntitiesIntersecting(mousePos))
{
if (!bodyQuery.HasComponent(ent) ||
!TryComp<ClickableComponent>(ent, out var clickable) ||
!clickable.CheckClick(mousePos.Position, out var drawDepth, out _)) continue;
lowest.Add((drawDepth, ent));
}
lowest.Sort((x, y) => y.DrawDepth.CompareTo(x.DrawDepth));
foreach (var ent in lowest)
{
StartDragging(ent.Entity, mousePos);
break;
}
if (_dragging == null) return;
}
if (!TryComp<TransformComponent>(_dragging!.Value, out var xform) ||
_lastMousePosition!.Value.MapId != xform.MapID)
{
StopDragging();
return;
}
if (_lastMousePosition.Value.Position.EqualsApprox(mousePos.Position)) return;
_lastMousePosition = mousePos;
RaiseNetworkEvent(new TetherMoveEvent()
{
Coordinates = _lastMousePosition!.Value,
});
}
private void StopDragging()
{
if (_dragging == null) return;
RaiseNetworkEvent(new StopTetherEvent());
_dragging = null;
_lastMousePosition = null;
}
private void StartDragging(EntityUid uid, MapCoordinates coordinates)
{
_dragging = uid;
_lastMousePosition = coordinates;
RaiseNetworkEvent(new StartTetherEvent()
{
Entity = _dragging!.Value,
Coordinates = coordinates,
});
}
}

View File

@@ -0,0 +1,153 @@
using Content.Shared.Administration;
using Content.Shared.Weapons.Ranged;
using Robust.Server.Console;
using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics.Joints;
using Robust.Shared.Players;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Weapon.Ranged;
public sealed class TetherGunSystem : SharedTetherGunSystem
{
[Dependency] private readonly IConGroupController _admin = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedJointSystem _joints = default!;
private Dictionary<ICommonSession, (EntityUid Entity, EntityUid Tether, Joint Joint)> _tethered = new();
private const string JointId = "tether-joint";
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<StartTetherEvent>(OnStartTether);
SubscribeNetworkEvent<StopTetherEvent>(OnStopTether);
SubscribeNetworkEvent<TetherMoveEvent>(OnMoveTether);
_playerManager.PlayerStatusChanged += OnStatusChange;
}
private void OnStatusChange(object? sender, SessionStatusEventArgs e)
{
StopTether(e.Session);
}
public override void Shutdown()
{
base.Shutdown();
_playerManager.PlayerStatusChanged -= OnStatusChange;
}
private void OnStartTether(StartTetherEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession is not IPlayerSession playerSession ||
!_admin.CanCommand(playerSession, CommandName) ||
!Exists(msg.Entity) ||
Deleted(msg.Entity) ||
msg.Coordinates == MapCoordinates.Nullspace ||
_tethered.ContainsKey(args.SenderSession) ||
_container.IsEntityInContainer(msg.Entity)) return;
var tether = Spawn("TetherEntity", msg.Coordinates);
if (!TryComp<PhysicsComponent>(tether, out var bodyA) ||
!TryComp<PhysicsComponent>(msg.Entity, out var bodyB))
{
Del(tether);
return;
}
EnsureComp<AdminFrozenComponent>(msg.Entity);
if (TryComp<TransformComponent>(msg.Entity, out var xform))
{
xform.Anchored = false;
}
if (TryComp<PhysicsComponent>(msg.Entity, out var body))
{
body.BodyStatus = BodyStatus.InAir;
}
var joint = _joints.CreateMouseJoint(bodyA.Owner, bodyB.Owner, id: JointId);
SharedJointSystem.LinearStiffness(5f, 0.7f, bodyA.Mass, bodyB.Mass, out var stiffness, out var damping);
joint.Stiffness = stiffness;
joint.Damping = damping;
joint.MaxForce = 5000f * bodyB.Mass;
_tethered.Add(playerSession, (msg.Entity, tether, joint));
}
private void OnStopTether(StopTetherEvent msg, EntitySessionEventArgs args)
{
StopTether(args.SenderSession);
}
private void StopTether(ICommonSession session)
{
if (!_tethered.TryGetValue(session, out var weh))
return;
RemComp<AdminFrozenComponent>(weh.Entity);
if (TryComp<PhysicsComponent>(weh.Entity, out var body))
{
Timer.Spawn(1000, () =>
{
if (Deleted(body.Owner)) return;
body.BodyStatus = BodyStatus.OnGround;
});
}
_joints.RemoveJoint(weh.Joint);
Del(weh.Tether);
_tethered.Remove(session);
}
private void OnMoveTether(TetherMoveEvent msg, EntitySessionEventArgs args)
{
if (!_tethered.TryGetValue(args.SenderSession, out var tether) ||
!TryComp<TransformComponent>(tether.Tether, out var xform) ||
xform.MapID != msg.Coordinates.MapId) return;
xform.WorldPosition = msg.Coordinates.Position;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var toRemove = new RemQueue<ICommonSession>();
var bodyQuery = GetEntityQuery<PhysicsComponent>();
foreach (var (session, entity) in _tethered)
{
if (Deleted(entity.Entity) ||
Deleted(entity.Tether) ||
!entity.Joint.Enabled)
{
toRemove.Add(session);
continue;
}
// Force it awake, always
if (bodyQuery.TryGetComponent(entity.Entity, out var body))
{
body.WakeBody();
}
}
foreach (var session in toRemove)
{
StopTether(session);
}
}
}

View File

@@ -0,0 +1,25 @@
using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Shared.Weapons.Ranged;
public abstract class SharedTetherGunSystem : EntitySystem
{
public const string CommandName = "tethergun";
}
[Serializable, NetSerializable]
public sealed class StartTetherEvent : EntityEventArgs
{
public EntityUid Entity;
public MapCoordinates Coordinates;
}
[Serializable, NetSerializable]
public sealed class StopTetherEvent : EntityEventArgs {}
[Serializable, NetSerializable]
public sealed class TetherMoveEvent : EntityEventArgs
{
public MapCoordinates Coordinates;
}

View File

@@ -0,0 +1,6 @@
- type: entity
id: TetherEntity
noSpawn: true
components:
- type: Physics
- type: Fixtures

View File

@@ -17,6 +17,7 @@
- Flags: MAPPING
Commands:
- tethergun
- griddrag
- showmarkers
- showsubfloor