diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 6e781970bd..6bcf4b5872 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -302,7 +302,7 @@ namespace Content.IntegrationTests.Tests.Buckle human.Transform.LocalPosition += (100, 0); }); - await WaitUntil(server, () => !buckle.Buckled, maxTicks: 10); + await WaitUntil(server, () => !buckle.Buckled, 10); Assert.False(buckle.Buckled); diff --git a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs index 7e956d89de..0eb0ffebea 100644 --- a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs +++ b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs @@ -15,21 +15,16 @@ using Content.Shared.GameObjects.Verbs; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Utility; -using NFluidsynth; using Robust.Server.GameObjects; -using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.ComponentDependencies; -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.Log; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -39,8 +34,6 @@ namespace Content.Server.GameObjects.Components.Buckle [RegisterComponent] public class BuckleComponent : SharedBuckleComponent, IInteractHand { - [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [ComponentDependency] public readonly AppearanceComponent? AppearanceComponent = null; @@ -69,7 +62,10 @@ namespace Content.Server.GameObjects.Components.Buckle [ViewVariables] private TimeSpan _buckleTime; - public Vector2? BuckleOffset { get; private set; } + /// + /// The position offset that is being applied to this entity if buckled. + /// + public Vector2 BuckleOffset { get; private set; } private StrapComponent? _buckledTo; @@ -91,20 +87,6 @@ namespace Content.Server.GameObjects.Components.Buckle [ViewVariables] public override bool Buckled => BuckledTo != null; - /// - /// True if the entity was inserted or removed from a container - /// before updating, false otherwise. - /// - [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 /// . @@ -116,18 +98,20 @@ namespace Content.Server.GameObjects.Components.Buckle /// Shows or hides the buckled status effect depending on if the /// entity is buckled or not. /// - private void BuckleStatus() + private void UpdateBuckleStatus() { - if (_serverStatusEffectsComponent != null) + if (_serverStatusEffectsComponent == null) { - if (Buckled) - { - _serverStatusEffectsComponent.ChangeStatusEffectIcon(StatusEffect.Buckled, BuckledTo!.BuckledIcon); - } - else - { - _serverStatusEffectsComponent.RemoveStatusEffect(StatusEffect.Buckled); - } + return; + } + + if (Buckled) + { + _serverStatusEffectsComponent.ChangeStatusEffectIcon(StatusEffect.Buckled, BuckledTo!.BuckledIcon); + } + else + { + _serverStatusEffectsComponent.RemoveStatusEffect(StatusEffect.Buckled); } } @@ -135,7 +119,7 @@ namespace Content.Server.GameObjects.Components.Buckle /// Reattaches this entity to the strap, modifying its position and rotation. /// /// The strap to reattach to. - private void ReAttach(StrapComponent strap) + public void ReAttach(StrapComponent strap) { var ownTransform = Owner.Transform; var strapTransform = strap.Owner.Transform; @@ -161,7 +145,7 @@ namespace Content.Server.GameObjects.Components.Buckle if (strapTransform.WorldRotation.GetCardinalDir() == Direction.North) { BuckleOffset = (0, 0.15f); - ownTransform.WorldPosition = strapTransform.WorldPosition + BuckleOffset!.Value; + ownTransform.WorldPosition = strapTransform.WorldPosition + BuckleOffset; } else { @@ -266,8 +250,7 @@ namespace Content.Server.GameObjects.Components.Buckle return false; } - _entitySystem.GetEntitySystem() - .PlayFromEntity(strap.BuckleSound, Owner); + EntitySystem.Get().PlayFromEntity(strap.BuckleSound, Owner); if (!strap.TryAdd(this)) { @@ -283,7 +266,7 @@ namespace Content.Server.GameObjects.Components.Buckle BuckledTo = strap; ReAttach(strap); - BuckleStatus(); + UpdateBuckleStatus(); SendMessage(new BuckleMessage(Owner, to)); @@ -312,12 +295,12 @@ namespace Content.Server.GameObjects.Components.Buckle /// public bool TryUnbuckle(IEntity user, bool force = false) { - if (!Buckled) + if (BuckledTo == null) { return false; } - StrapComponent oldBuckledTo = BuckledTo!; + var oldBuckledTo = BuckledTo; if (!force) { @@ -357,16 +340,12 @@ namespace Content.Server.GameObjects.Components.Buckle EntitySystem.Get().Standing(Owner); } - if (_mobStateManagerComponent != null) - { - _mobStateManagerComponent.CurrentMobState.EnterState(Owner); - } + _mobStateManagerComponent?.CurrentMobState.EnterState(Owner); - BuckleStatus(); + UpdateBuckleStatus(); oldBuckledTo.Remove(this); - _entitySystem.GetEntitySystem() - .PlayFromEntity(oldBuckledTo.UnbuckleSound, Owner); + EntitySystem.Get().PlayFromEntity(oldBuckledTo.UnbuckleSound, Owner); SendMessage(new UnbuckleMessage(Owner, oldBuckledTo.Owner)); @@ -397,90 +376,6 @@ namespace Content.Server.GameObjects.Components.Buckle 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. - public void OnMoveEvent(MoveEvent moveEvent) - { - if (moveEvent.Sender != Owner) - { - return; - } - - if (BuckledTo == null || !BuckleOffset.HasValue) - { - return; - } - - var bucklePosition = BuckledTo.Owner.Transform.Coordinates.Offset(BuckleOffset.Value); - - if (moveEvent.NewPosition.InRange(_entityManager, bucklePosition, 0.2f)) - { - return; - } - - Moved = true; - } - - /// - /// Called when the owner is inserted or removed from a container, - /// to synchronize the state of buckling. - /// - /// The message received - private void InsertIntoContainer(ContainerModifiedMessage message) - { - if (message.Entity != Owner) - { - return; - } - - ContainerChanged = true; - } - - /// - /// Synchronizes the state of buckling depending on whether the entity - /// was inserted or removed from a container, and whether or not - /// its current strap (if there is one) has also been put into or removed - /// from the same container as well. - /// - public void Update() - { - if (BuckledTo == null) - { - return; - } - - if (Moved) - { - TryUnbuckle(Owner, true); - Moved = false; - return; - } - - if (!ContainerChanged) - { - return; - } - - var contained = ContainerHelpers.TryGetContainer(Owner, out var ownContainer); - var strapContained = ContainerHelpers.TryGetContainer(BuckledTo.Owner, out var strapContainer); - - if (contained != strapContained || ownContainer != strapContainer) - { - TryUnbuckle(Owner, true); - return; - } - - if (!contained && !strapContained) - { - ReAttach(BuckledTo); - } - - ContainerChanged = false; - } - public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); @@ -494,32 +389,21 @@ namespace Content.Server.GameObjects.Components.Buckle _unbuckleDelay = TimeSpan.FromSeconds(seconds); } - public override void Initialize() - { - base.Initialize(); - - _entityManager.EventBus.SubscribeEvent(EventSource.Local, this, InsertIntoContainer); - _entityManager.EventBus.SubscribeEvent(EventSource.Local, this, InsertIntoContainer); - } - protected override void Startup() { base.Startup(); - BuckleStatus(); + UpdateBuckleStatus(); } public override void OnRemove() { base.OnRemove(); - _entityManager.EventBus.UnsubscribeEvents(this); - BuckledTo?.Remove(this); - TryUnbuckle(Owner, true); _buckleTime = default; - BuckleStatus(); + UpdateBuckleStatus(); } public override ComponentState GetComponentState() diff --git a/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs b/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs index 8e2f0c2422..c6bcb65591 100644 --- a/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/BuckleSystem.cs @@ -1,8 +1,11 @@ -using Content.Server.GameObjects.Components.Buckle; +#nullable enable +using Content.Server.GameObjects.Components.Buckle; +using Content.Server.GameObjects.Components.Strap; using Content.Server.GameObjects.EntitySystems.Click; using JetBrains.Annotations; +using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Server.GameObjects.EntitySystems; -using Robust.Shared.GameObjects; +using Robust.Shared.Containers; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Systems; @@ -17,7 +20,10 @@ namespace Content.Server.GameObjects.EntitySystems UpdatesAfter.Add(typeof(InteractionSystem)); UpdatesAfter.Add(typeof(InputSystem)); + SubscribeLocalEvent(MoveEvent); + SubscribeLocalEvent(ContainerModified); + SubscribeLocalEvent(ContainerModified); } public override void Shutdown() @@ -29,17 +35,69 @@ namespace Content.Server.GameObjects.EntitySystems private void MoveEvent(MoveEvent ev) { - if (ev.Sender.TryGetComponent(out BuckleComponent buckle)) + if (!ev.Sender.TryGetComponent(out BuckleComponent? buckle)) { - buckle.OnMoveEvent(ev); + return; + } + + var strap = buckle.BuckledTo; + + if (strap == null) + { + return; + } + + var strapPosition = strap.Owner.Transform.Coordinates.Offset(buckle.BuckleOffset); + + if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f)) + { + return; + } + + buckle.TryUnbuckle(buckle.Owner, true); + } + + private void ContainerModified(ContainerModifiedMessage message) + { + // Not returning is necessary in case an entity has both a buckle and strap component + if (message.Entity.TryGetComponent(out BuckleComponent? buckle)) + { + ContainerModifiedReAttach(buckle, buckle.BuckledTo); + } + + if (message.Entity.TryGetComponent(out StrapComponent? strap)) + { + foreach (var buckledEntity in strap.BuckledEntities) + { + if (!buckledEntity.TryGetComponent(out BuckleComponent? buckled)) + { + continue; + } + + ContainerModifiedReAttach(buckled, strap); + } } } - public override void Update(float frameTime) + private void ContainerModifiedReAttach(BuckleComponent buckle, StrapComponent? strap) { - foreach (var buckle in ComponentManager.EntityQuery()) + if (strap == null) { - buckle.Update(); + return; + } + + var contained = ContainerHelpers.TryGetContainer(buckle.Owner, out var ownContainer); + var strapContained = ContainerHelpers.TryGetContainer(strap.Owner, out var strapContainer); + + if (contained != strapContained || ownContainer != strapContainer) + { + buckle.TryUnbuckle(buckle.Owner, true); + return; + } + + if (!contained) + { + buckle.ReAttach(strap); } } }