diff --git a/Content.IntegrationTests/Tests/BuckleTest.cs b/Content.IntegrationTests/Tests/BuckleTest.cs index 652950d600bb..1de145d50978 100644 --- a/Content.IntegrationTests/Tests/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/BuckleTest.cs @@ -146,6 +146,22 @@ public async Task Test() Assert.True(ActionBlockerSystem.CanMove(human)); Assert.True(ActionBlockerSystem.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); + + // Re-buckle + Assert.True(buckle.TryBuckle(human, chair)); + + // Move away from the chair + human.Transform.WorldPosition += (1, 0); + }); + + server.RunTicks(1); + + server.Assert(() => + { + // No longer buckled + Assert.False(buckle.Buckled); + Assert.Null(buckle.BuckledTo); + Assert.IsEmpty(strap.BuckledEntities); }); await server.WaitIdleAsync(); diff --git a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs index 4914e7f9a976..61f5db1fe5b7 100644 --- a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs +++ b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs @@ -3,7 +3,6 @@ using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Strap; -using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Server.Mobs; using Content.Server.Utility; @@ -18,12 +17,13 @@ using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; -using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -38,6 +38,7 @@ public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop [Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; #pragma warning restore 649 private int _size; @@ -90,6 +91,13 @@ private set [ViewVariables] private bool ContainerChanged { get; set; } + /// + /// True if the entity was forcefully moved while buckled and should + /// unbuckle next update, false otherwise + /// + [ViewVariables] + private bool Moved { get; set; } + /// /// The amount of space that this entity occupies in a /// . @@ -275,6 +283,8 @@ public bool TryBuckle(IEntity user, IEntity to) SendMessage(new BuckleMessage(Owner, to)); + Owner.EntityManager.EventBus.SubscribeEvent(EventSource.Local, this, MoveEvent); + return true; } @@ -359,6 +369,8 @@ public bool TryUnbuckle(IEntity user, bool force = false) SendMessage(new UnbuckleMessage(Owner, oldBuckledTo.Owner)); + Owner.EntityManager.EventBus.UnsubscribeEvent(EventSource.Local, this); + return true; } @@ -386,6 +398,33 @@ public bool ToggleBuckle(IEntity user, IEntity to, bool force = false) return TryBuckle(user, to); } + /// + /// Checks if a buckled entity should be unbuckled from moving + /// too far from its strap. + /// + /// The move event of a buckled entity. + private void MoveEvent(MoveEvent moveEvent) + { + if (moveEvent.Sender != Owner) + { + return; + } + + if (BuckledTo == null || !BuckleOffset.HasValue) + { + return; + } + + var bucklePosition = BuckledTo.Owner.Transform.GridPosition.Offset(BuckleOffset.Value); + + if (moveEvent.NewPosition.InRange(_mapManager, bucklePosition, 0.2f)) + { + return; + } + + Moved = true; + } + /// /// Called when the owner is inserted or removed from a container, /// to synchronize the state of buckling. @@ -409,7 +448,18 @@ private void InsertIntoContainer(ContainerModifiedMessage message) /// public void Update() { - if (!ContainerChanged || BuckledTo == null) + if (BuckledTo == null) + { + return; + } + + if (Moved) + { + TryUnbuckle(Owner, true); + return; + } + + if (!ContainerChanged) { return; } diff --git a/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs b/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs index 2b9712f6d141..0f5719d500a7 100644 --- a/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs @@ -13,34 +13,6 @@ namespace Content.Server.GameObjects.EntitySystems [UsedImplicitly] public class BuckleSystem : EntitySystem { -#pragma warning disable 649 - [Dependency] private readonly IMapManager _mapManager; -#pragma warning restore 649 - - /// - /// Checks if a buckled entity should be unbuckled from moving - /// too far from its strap. - /// - /// The move event of a buckled entity. - private void MoveEvent(MoveEvent moveEvent) - { - if (!moveEvent.Sender.TryGetComponent(out BuckleComponent buckle) || - buckle.BuckledTo == null || - !buckle.BuckleOffset.HasValue) - { - return; - } - - var bucklePosition = buckle.BuckledTo.Owner.Transform.GridPosition.Offset(buckle.BuckleOffset.Value); - - if (moveEvent.NewPosition.InRange(_mapManager, bucklePosition, 0.2f)) - { - return; - } - - buckle.TryUnbuckle(buckle.Owner, true); - } - public override void Initialize() { base.Initialize(); @@ -49,8 +21,6 @@ public override void Initialize() UpdatesAfter.Add(typeof(InteractionSystem)); UpdatesAfter.Add(typeof(InputSystem)); - - SubscribeLocalEvent(MoveEvent); } public override void Update(float frameTime)