diff --git a/Content.Server/Body/BodyComponent.cs b/Content.Server/Body/BodyComponent.cs index d1940ff73a..916943f667 100644 --- a/Content.Server/Body/BodyComponent.cs +++ b/Content.Server/Body/BodyComponent.cs @@ -1,21 +1,15 @@ -using Content.Server.GameTicking; using Content.Server.Ghost; -using Content.Server.Mind.Components; using Content.Shared.Audio; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Body.Slot; -using Content.Shared.MobState; -using Content.Shared.Movement.Components; using Content.Shared.Random.Helpers; using Content.Shared.Sound; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Serialization.Manager.Attributes; namespace Content.Server.Body @@ -23,7 +17,7 @@ namespace Content.Server.Body [RegisterComponent] [ComponentReference(typeof(SharedBodyComponent))] [ComponentReference(typeof(IGhostOnMove))] - public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove + public class BodyComponent : SharedBodyComponent, IGhostOnMove { private Container _partContainer = default!; @@ -89,17 +83,6 @@ namespace Content.Server.Body } } - void IRelayMoveInput.MoveInputPressed(ICommonSession session) - { - if (Owner.TryGetComponent(out IMobStateComponent? mobState) && - mobState.IsDead() && - Owner.TryGetComponent(out MindComponent? mind) && - mind.HasMind) - { - EntitySystem.Get().OnGhostAttempt(mind.Mind!, true); - } - } - public override void Gib(bool gibParts = false) { base.Gib(gibParts); diff --git a/Content.Server/Body/BodySystem.cs b/Content.Server/Body/BodySystem.cs new file mode 100644 index 0000000000..ad0d586059 --- /dev/null +++ b/Content.Server/Body/BodySystem.cs @@ -0,0 +1,32 @@ +using Content.Server.GameTicking; +using Content.Server.Mind.Components; +using Content.Shared.MobState; +using Content.Shared.MobState.State; +using Content.Shared.Movement.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.Body +{ + public sealed class BodySystem : EntitySystem + { + [Dependency] private readonly GameTicker _ticker = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRelayMoveInput); + } + + private void OnRelayMoveInput(EntityUid uid, BodyComponent component, RelayMoveInputEvent args) + { + if (ComponentManager.TryGetComponent(uid, out var mobState) && + mobState.IsDead() && + ComponentManager.TryGetComponent(uid, out var mind) && + mind.HasMind) + { + _ticker.OnGhostAttempt(mind.Mind!, true); + } + } + } +} diff --git a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs index 7427057ba3..6e5840106f 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs +++ b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs @@ -4,14 +4,11 @@ using Content.Server.Construction.Components; using Content.Server.Disposal.Unit.Components; using Content.Shared.Acts; using Content.Shared.Disposal.Components; -using Content.Shared.Movement; -using Content.Shared.Notification; using Content.Shared.Notification.Managers; using Content.Shared.Sound; using Content.Shared.Verbs; using Robust.Server.Console; using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -19,7 +16,6 @@ using Robust.Shared.Localization; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Player; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Timing; using Robust.Shared.ViewVariables; @@ -28,16 +24,14 @@ namespace Content.Server.Disposal.Tube.Components { public abstract class DisposalTubeComponent : Component, IDisposalTubeComponent, IBreakAct { - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IMapManager _mapManager = default!; - private static readonly TimeSpan ClangDelay = TimeSpan.FromSeconds(0.5); - private TimeSpan _lastClang; + public static readonly TimeSpan ClangDelay = TimeSpan.FromSeconds(0.5); + public TimeSpan LastClang; private bool _connected; private bool _broken; - [DataField("clangSound")] - private SoundSpecifier _clangSound = new SoundPathSpecifier("/Audio/Effects/clang.ogg"); + [DataField("clangSound")] public SoundSpecifier ClangSound = new SoundPathSpecifier("/Audio/Effects/clang.ogg"); /// /// Container of entities that are currently inside this tube @@ -253,24 +247,6 @@ namespace Content.Server.Disposal.Tube.Components Disconnect(); } - public override void HandleMessage(ComponentMessage message, IComponent? component) - { - base.HandleMessage(message, component); - - switch (message) - { - case RelayMovementEntityMessage _: - if (_gameTiming.CurTime < _lastClang + ClangDelay) - { - break; - } - - _lastClang = _gameTiming.CurTime; - SoundSystem.Play(Filter.Pvs(Owner), _clangSound.GetSound(), Owner); - break; - } - } - void IBreakAct.OnBreak(BreakageEventArgs eventArgs) { _broken = true; // TODO: Repair diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 8cae9e5b9e..4d0697ae6b 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -1,15 +1,35 @@ using Content.Server.Disposal.Tube.Components; +using Content.Shared.Movement; +using Robust.Shared.Audio; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Player; +using Robust.Shared.Timing; namespace Content.Server.Disposal.Tube { public sealed class DisposalTubeSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(BodyTypeChanged); + SubscribeLocalEvent(OnRelayMovement); + } + + private void OnRelayMovement(EntityUid uid, DisposalTubeComponent component, RelayMovementEntityEvent args) + { + if (_gameTiming.CurTime < component.LastClang + DisposalTubeComponent.ClangDelay) + { + return; + } + + var entity = EntityManager.GetEntity(uid); + component.LastClang = _gameTiming.CurTime; + SoundSystem.Play(Filter.Pvs(entity), component.ClangSound.GetSound(), entity); } private static void BodyTypeChanged( diff --git a/Content.Server/Ghost/Components/GhostOnMoveComponent.cs b/Content.Server/Ghost/Components/GhostOnMoveComponent.cs index 1496d0d6bf..04c3a3384a 100644 --- a/Content.Server/Ghost/Components/GhostOnMoveComponent.cs +++ b/Content.Server/Ghost/Components/GhostOnMoveComponent.cs @@ -10,19 +10,10 @@ namespace Content.Server.Ghost.Components { [RegisterComponent] [ComponentReference(typeof(IGhostOnMove))] - public class GhostOnMoveComponent : Component, IRelayMoveInput, IGhostOnMove + public class GhostOnMoveComponent : Component,IGhostOnMove { public override string Name => "GhostOnMove"; [DataField("canReturn")] public bool CanReturn { get; set; } = true; - - void IRelayMoveInput.MoveInputPressed(ICommonSession session) - { - // Let's not ghost if our mind is visiting... - if (Owner.HasComponent()) return; - if (!Owner.TryGetComponent(out MindComponent? mind) || !mind.HasMind || mind.Mind!.IsVisitingEntity) return; - - EntitySystem.Get().OnGhostAttempt(mind.Mind!, CanReturn); - } } } diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 5523ba9b78..6cac372421 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Content.Server.GameTicking; using Content.Server.Ghost.Components; using Content.Server.Mind.Components; using Content.Server.Players; @@ -7,6 +8,7 @@ using Content.Server.Visible; using Content.Server.Warps; using Content.Shared.Examine; using Content.Shared.Ghost; +using Content.Shared.Movement.EntitySystems; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -23,6 +25,7 @@ namespace Content.Server.Ghost { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly GameTicker _ticker = default!; public override void Initialize() { @@ -36,12 +39,23 @@ namespace Content.Server.Ghost SubscribeLocalEvent(OnMindRemovedMessage); SubscribeLocalEvent(OnMindUnvisitedMessage); + SubscribeLocalEvent(OnRelayMoveInput); + SubscribeNetworkEvent(OnGhostWarpsRequest); SubscribeNetworkEvent(OnGhostReturnToBodyRequest); SubscribeNetworkEvent(OnGhostWarpToLocationRequest); SubscribeNetworkEvent(OnGhostWarpToTargetRequest); } + private void OnRelayMoveInput(EntityUid uid, GhostOnMoveComponent component, RelayMoveInputEvent args) + { + // Let's not ghost if our mind is visiting... + if (ComponentManager.HasComponent(uid)) return; + if (!ComponentManager.TryGetComponent(uid, out var mind) || !mind.HasMind || mind.Mind!.IsVisitingEntity) return; + + _ticker.OnGhostAttempt(mind.Mind!, component.CanReturn); + } + private void OnGhostStartup(EntityUid uid, GhostComponent component, ComponentStartup args) { // Allow this entity to be seen by other ghosts. diff --git a/Content.Server/Medical/Components/MedicalScannerComponent.cs b/Content.Server/Medical/Components/MedicalScannerComponent.cs index 04c69c164b..16b5ee5993 100644 --- a/Content.Server/Medical/Components/MedicalScannerComponent.cs +++ b/Content.Server/Medical/Components/MedicalScannerComponent.cs @@ -36,11 +36,9 @@ namespace Content.Server.Medical.Components public class MedicalScannerComponent : SharedMedicalScannerComponent, IActivate, IDestroyAct { [Dependency] private readonly IServerPreferencesManager _prefsManager = null!; - [Dependency] private readonly IPlayerManager _playerManager = null!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - private static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); - private TimeSpan _lastInternalOpenAttempt; + public static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); + public TimeSpan LastInternalOpenAttempt; private ContainerSlot _bodyContainer = default!; private readonly Vector2 _ejectOffset = new(0f, 0f); @@ -70,31 +68,6 @@ namespace Content.Server.Medical.Components UpdateUserInterface(); } - /// - public override void HandleMessage(ComponentMessage message, IComponent? component) - { - base.HandleMessage(message, component); - - switch (message) - { - case RelayMovementEntityMessage msg: - { - if (EntitySystem.Get().CanInteract(msg.Entity)) - { - if (_gameTiming.CurTime < - _lastInternalOpenAttempt + InternalOpenAttemptDelay) - { - break; - } - - _lastInternalOpenAttempt = _gameTiming.CurTime; - EjectBody(); - } - break; - } - } - } - private static readonly MedicalScannerBoundUserInterfaceState EmptyUIState = new( null, diff --git a/Content.Server/Medical/MedicalScannerSystem.cs b/Content.Server/Medical/MedicalScannerSystem.cs index 93758edeba..5df903b79c 100644 --- a/Content.Server/Medical/MedicalScannerSystem.cs +++ b/Content.Server/Medical/MedicalScannerSystem.cs @@ -1,12 +1,39 @@ using Content.Server.Medical.Components; +using Content.Shared.ActionBlocker; +using Content.Shared.Movement; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Timing; namespace Content.Server.Medical { [UsedImplicitly] internal sealed class MedicalScannerSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRelayMovement); + } + + private void OnRelayMovement(EntityUid uid, MedicalScannerComponent component, RelayMovementEntityEvent args) + { + if (_blocker.CanInteract(args.Entity)) + { + if (_gameTiming.CurTime < + component.LastInternalOpenAttempt + MedicalScannerComponent.InternalOpenAttemptDelay) + { + return; + } + + component.LastInternalOpenAttempt = _gameTiming.CurTime; + component.EjectBody(); + } + } public override void Update(float frameTime) { diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs index 542a7dc6db..a94d1e8434 100644 --- a/Content.Server/Storage/Components/EntityStorageComponent.cs +++ b/Content.Server/Storage/Components/EntityStorageComponent.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Content.Server.Hands.Components; using Content.Server.Tools.Components; using Content.Shared.ActionBlocker; using Content.Shared.Acts; using Content.Shared.Body.Components; using Content.Shared.Interaction; using Content.Shared.Item; -using Content.Shared.Movement; using Content.Shared.Notification.Managers; using Content.Shared.Physics; using Content.Shared.Placeable; @@ -27,7 +25,6 @@ using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Player; using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Timing; using Robust.Shared.ViewVariables; namespace Content.Server.Storage.Components @@ -37,14 +34,12 @@ namespace Content.Server.Storage.Components [ComponentReference(typeof(IStorageComponent))] public class EntityStorageComponent : Component, IActivate, IStorageComponent, IInteractUsing, IDestroyAct, IActionBlocker, IExAct { - [Dependency] private readonly IGameTiming _gameTiming = default!; - public override string Name => "EntityStorage"; private const float MaxSize = 1.0f; // maximum width or height of an entity allowed inside the storage. - private static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); - private TimeSpan _lastInternalOpenAttempt; + public static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); + public TimeSpan LastInternalOpenAttempt; private const int OpenMask = (int) ( CollisionGroup.MobImpassable | @@ -227,7 +222,7 @@ namespace Content.Server.Storage.Components ModifyComponents(); SoundSystem.Play(Filter.Pvs(Owner), _closeSound.GetSound(), Owner); - _lastInternalOpenAttempt = default; + LastInternalOpenAttempt = default; } protected virtual void OpenStorage() @@ -313,29 +308,6 @@ namespace Content.Server.Storage.Components } } - /// - public override void HandleMessage(ComponentMessage message, IComponent? component) - { - base.HandleMessage(message, component); - - switch (message) - { - case RelayMovementEntityMessage msg: - if (msg.Entity.HasComponent()) - { - if (_gameTiming.CurTime < - _lastInternalOpenAttempt + InternalOpenAttemptDelay) - { - break; - } - - _lastInternalOpenAttempt = _gameTiming.CurTime; - TryOpenStorage(msg.Entity); - } - break; - } - } - public virtual bool TryOpenStorage(IEntity user) { if (!CanOpen(user)) return false; diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs index bafc86ae47..e5e7bee2fa 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs @@ -1,16 +1,22 @@ using System.Collections.Generic; +using Content.Server.Hands.Components; using Content.Server.Interaction; using Content.Server.Storage.Components; +using Content.Shared.Movement; using JetBrains.Annotations; using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Timing; namespace Content.Server.Storage.EntitySystems { [UsedImplicitly] internal sealed class StorageSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; + private readonly List _sessionCache = new(); /// @@ -20,6 +26,22 @@ namespace Content.Server.Storage.EntitySystems SubscribeLocalEvent(HandleEntityRemovedFromContainer); SubscribeLocalEvent(HandleEntityInsertedIntoContainer); + SubscribeLocalEvent(OnRelayMovement); + } + + private void OnRelayMovement(EntityUid uid, EntityStorageComponent component, RelayMovementEntityEvent args) + { + if (ComponentManager.HasComponent(uid)) + { + if (_gameTiming.CurTime < + component.LastInternalOpenAttempt + EntityStorageComponent.InternalOpenAttemptDelay) + { + return; + } + + component.LastInternalOpenAttempt = _gameTiming.CurTime; + component.TryOpenStorage(args.Entity); + } } /// diff --git a/Content.Shared/Movement/Components/IRelayMoveInput.cs b/Content.Shared/Movement/Components/IRelayMoveInput.cs deleted file mode 100644 index cd93814028..0000000000 --- a/Content.Shared/Movement/Components/IRelayMoveInput.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.Players; - -namespace Content.Shared.Movement.Components -{ - public interface IRelayMoveInput - { - void MoveInputPressed(ICommonSession session); - } -} diff --git a/Content.Shared/Movement/EntitySystems/SharedMoverSystem.cs b/Content.Shared/Movement/EntitySystems/SharedMoverSystem.cs index 9ab8e4a474..11469b89c5 100644 --- a/Content.Shared/Movement/EntitySystems/SharedMoverSystem.cs +++ b/Content.Shared/Movement/EntitySystems/SharedMoverSystem.cs @@ -41,7 +41,7 @@ namespace Content.Shared.Movement.EntitySystems base.Shutdown(); } - private static void HandleDirChange(ICommonSession? session, Direction dir, ushort subTick, bool state) + private void HandleDirChange(ICommonSession? session, Direction dir, ushort subTick, bool state) { if (!TryGetAttachedComponent(session, out var moverComp)) return; @@ -50,19 +50,13 @@ namespace Content.Shared.Movement.EntitySystems if (owner != null && session != null) { - foreach (var comp in owner.GetAllComponents().ToArray()) - { - comp.MoveInputPressed(session); - } + EntityManager.EventBus.RaiseLocalEvent(owner.Uid, new RelayMoveInputEvent(session)); // For stuff like "Moving out of locker" or the likes if (owner.IsInContainer() && (!owner.TryGetComponent(out IMobStateComponent? mobState) || mobState.IsAlive())) { - var relayEntityMoveMessage = new RelayMovementEntityMessage(owner); - owner.Transform.Parent!.Owner.SendMessage(owner.Transform, relayEntityMoveMessage); - var relayMoveEvent = new RelayMovementEntityEvent(owner); owner.EntityManager.EventBus.RaiseLocalEvent(owner.Transform.ParentUid, relayMoveEvent); } @@ -114,7 +108,7 @@ namespace Content.Shared.Movement.EntitySystems return false; } - HandleDirChange(session, _dir, message.SubTick, full.State == BoundKeyState.Down); + Get().HandleDirChange(session, _dir, message.SubTick, full.State == BoundKeyState.Down); return false; } } @@ -133,4 +127,14 @@ namespace Content.Shared.Movement.EntitySystems } } } + + public sealed class RelayMoveInputEvent : EntityEventArgs + { + public ICommonSession Session { get; } + + public RelayMoveInputEvent(ICommonSession session) + { + Session = session; + } + } } diff --git a/Content.Shared/Movement/RelayMovementEntityEvent.cs b/Content.Shared/Movement/RelayMovementEntityEvent.cs new file mode 100644 index 0000000000..79021d816f --- /dev/null +++ b/Content.Shared/Movement/RelayMovementEntityEvent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.Movement +{ + public sealed class RelayMovementEntityEvent : EntityEventArgs + { + public IEntity Entity { get; } + + public RelayMovementEntityEvent(IEntity entity) + { + Entity = entity; + } + } +} diff --git a/Content.Shared/Movement/RelayMovementEntityMessage.cs b/Content.Shared/Movement/RelayMovementEntityMessage.cs deleted file mode 100644 index cc7ed3ad0e..0000000000 --- a/Content.Shared/Movement/RelayMovementEntityMessage.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using JetBrains.Annotations; -using Robust.Shared.GameObjects; - -namespace Content.Shared.Movement -{ - [Obsolete("Component Messages are deprecated, use Entity Events instead.")] - public class RelayMovementEntityMessage : ComponentMessage - { - [PublicAPI] - public readonly IEntity Entity; - - public RelayMovementEntityMessage(IEntity entity) - { - Entity = entity; - } - } - - public sealed class RelayMovementEntityEvent : EntityEventArgs - { - public IEntity Entity { get; } - - public RelayMovementEntityEvent(IEntity entity) - { - Entity = entity; - } - } -} diff --git a/Content.Shared/Pulling/Components/SharedPullableComponent.cs b/Content.Shared/Pulling/Components/SharedPullableComponent.cs index 50d5d9dbf6..e7b87b8c53 100644 --- a/Content.Shared/Pulling/Components/SharedPullableComponent.cs +++ b/Content.Shared/Pulling/Components/SharedPullableComponent.cs @@ -1,8 +1,4 @@ using System; -using Content.Shared.ActionBlocker; -using Content.Shared.Alert; -using Content.Shared.Movement; -using Content.Shared.Movement.Components; using Content.Shared.Physics.Pull; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -17,7 +13,7 @@ using Robust.Shared.Serialization; namespace Content.Shared.Pulling.Components { [NetworkedComponent()] - public abstract class SharedPullableComponent : Component, IRelayMoveInput + public abstract class SharedPullableComponent : Component { public override string Name => "Pullable"; @@ -348,14 +344,6 @@ namespace Content.Shared.Pulling.Components base.OnRemove(); } - - // TODO: Need a component bus relay so all entities can use this and not just players - void IRelayMoveInput.MoveInputPressed(ICommonSession session) - { - var entity = session.AttachedEntity; - if (entity == null || !EntitySystem.Get().CanMove(entity)) return; - TryStopPull(); - } } [Serializable, NetSerializable] diff --git a/Content.Shared/Pulling/Systems/SharedPullableSystem.cs b/Content.Shared/Pulling/Systems/SharedPullableSystem.cs new file mode 100644 index 0000000000..554138452c --- /dev/null +++ b/Content.Shared/Pulling/Systems/SharedPullableSystem.cs @@ -0,0 +1,26 @@ +using Content.Shared.ActionBlocker; +using Content.Shared.Movement.EntitySystems; +using Content.Shared.Pulling.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Shared.Pulling.Systems +{ + public class SharedPullableSystem : EntitySystem + { + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnRelayMoveInput); + } + + private void OnRelayMoveInput(EntityUid uid, SharedPullableComponent component, RelayMoveInputEvent args) + { + var entity = args.Session.AttachedEntity; + if (entity == null || !_blocker.CanMove(entity)) return; + component.TryStopPull(); + } + } +}