diff --git a/Content.Client/GameObjects/EntitySystems/PullingSystem.cs b/Content.Client/GameObjects/EntitySystems/PullingSystem.cs new file mode 100644 index 0000000000..40064daf22 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/PullingSystem.cs @@ -0,0 +1,30 @@ +using Content.Client.GameObjects.Components.Pulling; +using Content.Shared.GameObjects.EntitySystemMessages.Pulling; +using Content.Shared.GameObjects.EntitySystems; +using JetBrains.Annotations; +using Robust.Client.Physics; + +namespace Content.Client.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class PullingSystem : SharedPullingSystem + { + public override void Initialize() + { + base.Initialize(); + + UpdatesAfter.Add(typeof(PhysicsSystem)); + + SubscribeLocalEvent(OnPullableMove); + SubscribeLocalEvent(OnPullableStopMove); + } + + public override void Shutdown() + { + base.Shutdown(); + + UnsubscribeLocalEvent(OnPullableMove); + UnsubscribeLocalEvent(OnPullableStopMove); + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/PullingSystem.cs b/Content.Server/GameObjects/EntitySystems/PullingSystem.cs new file mode 100644 index 0000000000..63a2c1d42c --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/PullingSystem.cs @@ -0,0 +1,30 @@ +using Content.Server.GameObjects.Components.Pulling; +using Content.Shared.GameObjects.EntitySystemMessages.Pulling; +using Content.Shared.GameObjects.EntitySystems; +using JetBrains.Annotations; +using Robust.Server.GameObjects; + +namespace Content.Server.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class PullingSystem : SharedPullingSystem + { + public override void Initialize() + { + base.Initialize(); + + UpdatesAfter.Add(typeof(PhysicsSystem)); + + SubscribeLocalEvent(OnPullableMove); + SubscribeLocalEvent(OnPullableStopMove); + } + + public override void Shutdown() + { + base.Shutdown(); + + UnsubscribeLocalEvent(OnPullableMove); + UnsubscribeLocalEvent(OnPullableStopMove); + } + } +} diff --git a/Content.Server/Physics/Controllers/PullController.cs b/Content.Server/Physics/Controllers/PullController.cs new file mode 100644 index 0000000000..fcc9c724b2 --- /dev/null +++ b/Content.Server/Physics/Controllers/PullController.cs @@ -0,0 +1,78 @@ +#nullable enable +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Controllers; +using Robust.Shared.Utility; + +namespace Content.Server.Physics.Controllers +{ + public class PullController : VirtualController + { + private const int ImpulseModifier = 20; + + private SharedPullingSystem _pullableSystem = default!; + + public override List UpdatesAfter => new() {typeof(MoverController)}; + + public override void Initialize() + { + base.Initialize(); + + _pullableSystem = EntitySystem.Get(); + } + + public override void UpdateBeforeSolve(bool prediction, float frameTime) + { + base.UpdateBeforeSolve(prediction, frameTime); + + foreach (var pullable in _pullableSystem.Moving) + { + if (pullable.Deleted) + { + continue; + } + + if (pullable.MovingTo == null) + { + continue; + } + + DebugTools.AssertNotNull(pullable.Puller); + + var pullerPosition = pullable.Puller!.Transform.MapPosition; + if (pullable.MovingTo.Value.MapId != pullerPosition.MapId) + { + pullable.MovingTo = null; + continue; + } + + if (!pullable.Owner.TryGetComponent(out var physics) || + physics.BodyType == BodyType.Static || + pullable.MovingTo.Value.MapId != pullable.Owner.Transform.MapID) + { + pullable.MovingTo = null; + continue; + } + + var movingPosition = pullable.MovingTo.Value.Position; + var ownerPosition = pullable.Owner.Transform.MapPosition.Position; + + if (movingPosition.EqualsApprox(ownerPosition, 0.01)) + { + pullable.MovingTo = null; + continue; + } + + var diff = movingPosition - ownerPosition; + var diffLength = diff.Length; + var multiplier = diffLength < 1 ? ImpulseModifier * diffLength : ImpulseModifier; + var impulse = diff.Normalized * multiplier; + + physics.ApplyLinearImpulse(impulse); + } + } + } +} diff --git a/Content.Shared/GameObjects/Components/Pulling/SharedPullableComponent.cs b/Content.Shared/GameObjects/Components/Pulling/SharedPullableComponent.cs index 4b9d3f1603..6f434fffee 100644 --- a/Content.Shared/GameObjects/Components/Pulling/SharedPullableComponent.cs +++ b/Content.Shared/GameObjects/Components/Pulling/SharedPullableComponent.cs @@ -3,7 +3,7 @@ using System; using Content.Shared.Alert; using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Movement; -using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.GameObjects.EntitySystemMessages.Pulling; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Physics; using Content.Shared.Physics.Pull; @@ -12,8 +12,8 @@ using Robust.Shared.GameObjects; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Physics; -using Robust.Shared.Players; using Robust.Shared.Physics.Dynamics.Joints; +using Robust.Shared.Players; using Robust.Shared.Serialization; namespace Content.Shared.GameObjects.Components.Pulling @@ -29,11 +29,15 @@ namespace Content.Shared.GameObjects.Components.Pulling /// Only set in Puller->set! Only set in unison with _pullerPhysics! /// private IEntity? _puller; - private IPhysBody? _pullerPhysics; - public IPhysBody? PullerPhysics => _pullerPhysics; + + public IPhysBody? PullerPhysics { get; private set; } private DistanceJoint? _pullJoint; + public float? MaxDistance => _pullJoint?.MaxLength; + + private MapCoordinates? _movingTo; + /// /// The current entity pulling this component. /// Setting this performs the entire setup process for pulling. @@ -52,11 +56,11 @@ namespace Content.Shared.GameObjects.Components.Pulling if (_puller != null) { var oldPuller = _puller; - var oldPullerPhysics = _pullerPhysics; + var oldPullerPhysics = PullerPhysics; _puller = null; Dirty(); - _pullerPhysics = null; + PullerPhysics = null; if (_physics != null && oldPullerPhysics != null) { @@ -78,7 +82,11 @@ namespace Content.Shared.GameObjects.Components.Pulling return; } - if (value != null) + if (value == null) + { + MovingTo = null; + } + else { // Pulling a new object : Perform sanity checks. @@ -137,16 +145,16 @@ namespace Content.Shared.GameObjects.Components.Pulling _puller = value; Dirty(); - _pullerPhysics = pullerPhysics; + PullerPhysics = pullerPhysics; - var message = new PullStartedMessage(_pullerPhysics, _physics); + var message = new PullStartedMessage(PullerPhysics, _physics); _puller.SendMessage(null, message); Owner.SendMessage(null, message); _puller.EntityManager.EventBus.RaiseEvent(EventSource.Local, message); - var union = _pullerPhysics.GetWorldAABB().Union(_physics.GetWorldAABB()); + var union = PullerPhysics.GetWorldAABB().Union(_physics.GetWorldAABB()); var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f; _physics.WakeBody(); @@ -162,6 +170,29 @@ namespace Content.Shared.GameObjects.Components.Pulling public bool BeingPulled => Puller != null; + public MapCoordinates? MovingTo + { + get => _movingTo; + set + { + if (_movingTo == value) + { + return; + } + + _movingTo = value; + + if (value == null) + { + Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PullableStopMovingMessage()); + } + else + { + Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PullableMoveMessage()); + } + } + } + /// /// Sanity-check pull. This is called from Puller setter, so it will never deny a pull that's valid by setting Puller. /// It might allow an impossible pull (i.e: puller has no PhysicsComponent somehow). @@ -251,7 +282,7 @@ namespace Content.Shared.GameObjects.Components.Pulling return TryStartPull(puller); } - public bool TryMoveTo(EntityCoordinates to) + public bool TryMoveTo(MapCoordinates to) { if (Puller == null) { @@ -263,16 +294,8 @@ namespace Content.Shared.GameObjects.Components.Pulling return false; } - /* - if (!_physics.TryGetController(out PullController controller)) - { - return false; - } - */ - + MovingTo = to; return true; - - //return controller.TryMoveTo(Puller.Transform.Coordinates, to); } public override ComponentState GetComponentState(ICommonSession player) @@ -314,21 +337,15 @@ namespace Content.Shared.GameObjects.Components.Pulling return; } - SharedAlertsComponent? pulledStatus = Owner.GetComponentOrNull(); + var pulledStatus = Owner.GetComponentOrNull(); switch (message) { - case PullStartedMessage msg: - if (pulledStatus != null) - { - pulledStatus.ShowAlert(AlertType.Pulled); - } + case PullStartedMessage: + pulledStatus?.ShowAlert(AlertType.Pulled); break; - case PullStoppedMessage msg: - if (pulledStatus != null) - { - pulledStatus.ClearAlert(AlertType.Pulled); - } + case PullStoppedMessage: + pulledStatus?.ClearAlert(AlertType.Pulled); break; } } @@ -336,6 +353,7 @@ namespace Content.Shared.GameObjects.Components.Pulling public override void OnRemove() { TryStopPull(); + MovingTo = null; base.OnRemove(); } diff --git a/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableMoveMessage.cs b/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableMoveMessage.cs new file mode 100644 index 0000000000..40588bc23a --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableMoveMessage.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.EntitySystemMessages.Pulling +{ + public class PullableMoveMessage : EntityEventArgs + { + } +} diff --git a/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableStopMovingMessage.cs b/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableStopMovingMessage.cs new file mode 100644 index 0000000000..562fc7f8c2 --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/Pulling/PullableStopMovingMessage.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.EntitySystemMessages.Pulling +{ + public class PullableStopMovingMessage : EntityEventArgs + { + } +} diff --git a/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs index 00b1180aed..c89d510046 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Content.Shared.GameObjects.Components.Pulling; +using Content.Shared.GameObjects.EntitySystemMessages.Pulling; +using Content.Shared.GameTicking; using Content.Shared.Input; using Content.Shared.Physics.Pull; using JetBrains.Annotations; @@ -16,7 +18,7 @@ using Robust.Shared.Players; namespace Content.Shared.GameObjects.EntitySystems { [UsedImplicitly] - public class SharedPullingSystem : EntitySystem + public abstract class SharedPullingSystem : EntitySystem, IResettingEntitySystem { /// /// A mapping of pullers to the entity that they are pulling. @@ -24,6 +26,11 @@ namespace Content.Shared.GameObjects.EntitySystems private readonly Dictionary _pullers = new(); + private readonly HashSet _moving = new(); + private readonly HashSet _stoppedMoving = new(); + + public IReadOnlySet Moving => _moving; + public override void Initialize() { base.Initialize(); @@ -39,6 +46,21 @@ namespace Content.Shared.GameObjects.EntitySystems .Register(); } + public override void Update(float frameTime) + { + base.Update(frameTime); + + _moving.ExceptWith(_stoppedMoving); + _stoppedMoving.Clear(); + } + + public void Reset() + { + _pullers.Clear(); + _moving.Clear(); + _stoppedMoving.Clear(); + } + private void OnPullStarted(PullStartedMessage message) { if (_pullers.TryGetValue(message.Puller.Owner, out var pulled) && @@ -55,6 +77,16 @@ namespace Content.Shared.GameObjects.EntitySystems RemovePuller(message.Puller.Owner); } + protected void OnPullableMove(EntityUid uid, SharedPullableComponent component, PullableMoveMessage args) + { + _moving.Add(component); + } + + protected void OnPullableStopMove(EntityUid uid, SharedPullableComponent component, PullableStopMovingMessage args) + { + _stoppedMoving.Add(component); + } + private void PullerMoved(MoveEvent ev) { if (!TryGetPulled(ev.Sender, out var pulled)) @@ -68,6 +100,11 @@ namespace Content.Shared.GameObjects.EntitySystems } physics.WakeBody(); + + if (pulled.TryGetComponent(out SharedPullableComponent? pullable)) + { + pullable.MovingTo = null; + } } // TODO: When Joint networking is less shitcodey fix this to use a dedicated joints message. @@ -110,7 +147,7 @@ namespace Content.Shared.GameObjects.EntitySystems return false; } - pullable.TryMoveTo(coords); + pullable.TryMoveTo(coords.ToMap(EntityManager)); return false; } diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 43ca8e4818..171ae04e43 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -95,6 +95,7 @@ True True True + True True True True