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)