diff --git a/Content.Server/Doors/Systems/DoorSystem.cs b/Content.Server/Doors/Systems/DoorSystem.cs index a690d7a3ba..f2491310ee 100644 --- a/Content.Server/Doors/Systems/DoorSystem.cs +++ b/Content.Server/Doors/Systems/DoorSystem.cs @@ -331,7 +331,7 @@ public sealed class DoorSystem : SharedDoorSystem { if (component.BumpOpen) { - foreach (var other in PhysicsSystem.GetCollidingEntities(body)) + foreach (var other in PhysicsSystem.GetContactingEntities(body, approximate: true)) { if (Tags.HasTag(other.Owner, "DoorBumpOpener") && TryOpen(component.Owner, component, other.Owner, false, quiet: true)) break; diff --git a/Content.Shared/Movement/Components/SlowContactsComponent.cs b/Content.Shared/Movement/Components/SlowContactsComponent.cs index ef4151935a..5175fe95df 100644 --- a/Content.Shared/Movement/Components/SlowContactsComponent.cs +++ b/Content.Shared/Movement/Components/SlowContactsComponent.cs @@ -1,4 +1,5 @@ using Robust.Shared.GameStates; +using Robust.Shared.Serialization; namespace Content.Shared.Movement.Components; @@ -6,8 +7,22 @@ namespace Content.Shared.Movement.Components; public sealed class SlowContactsComponent : Component { [ViewVariables, DataField("walkSpeedModifier")] - public float WalkSpeedModifier { get; private set; } = 1.0f; + public float WalkSpeedModifier { get; set; } = 1.0f; [ViewVariables, DataField("sprintSpeedModifier")] - public float SprintSpeedModifier { get; private set; } = 1.0f; + public float SprintSpeedModifier { get; set; } = 1.0f; +} + +[Serializable, NetSerializable] +public sealed class SlowContactsComponentState : ComponentState +{ + public readonly float WalkSpeedModifier; + + public readonly float SprintSpeedModifier; + + public SlowContactsComponentState(float walkSpeedModifier, float sprintSpeedModifier) + { + WalkSpeedModifier = walkSpeedModifier; + SprintSpeedModifier = sprintSpeedModifier; + } } diff --git a/Content.Shared/Movement/Components/SlowedByContactComponent.cs b/Content.Shared/Movement/Components/SlowedByContactComponent.cs new file mode 100644 index 0000000000..d2065a9b41 --- /dev/null +++ b/Content.Shared/Movement/Components/SlowedByContactComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Movement.Components; + +/// +/// Exists just to listen to a single event. What a life. +/// +[NetworkedComponent, RegisterComponent] // must be networked to properly predict adding & removal +public sealed class SlowedByContactComponent : Component +{ +} diff --git a/Content.Shared/Movement/Components/SlowsOnContactComponent.cs b/Content.Shared/Movement/Components/SlowsOnContactComponent.cs deleted file mode 100644 index 92a406b4d5..0000000000 --- a/Content.Shared/Movement/Components/SlowsOnContactComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Movement.Components; - -/// -/// Exists just to listen to a single event. What a life. -/// -[NetworkedComponent, RegisterComponent] -public sealed class SlowsOnContactComponent : Component -{ -} diff --git a/Content.Shared/Movement/Systems/SlowContactsSystem.cs b/Content.Shared/Movement/Systems/SlowContactsSystem.cs index fb7010a2d0..c036379bc0 100644 --- a/Content.Shared/Movement/Systems/SlowContactsSystem.cs +++ b/Content.Shared/Movement/Systems/SlowContactsSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Movement.Components; +using Robust.Shared.GameStates; using Robust.Shared.Physics.Dynamics; namespace Content.Shared.Movement.Systems; @@ -8,65 +9,96 @@ public sealed class SlowContactsSystem : EntitySystem [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly MovementSpeedModifierSystem _speedModifierSystem = default!; - private readonly Dictionary _statusCapableInContact = new(); + private HashSet _toUpdate = new(); + private HashSet _toRemove = new(); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnEntityEnter); SubscribeLocalEvent(OnEntityExit); - SubscribeLocalEvent(MovementSpeedCheck); + SubscribeLocalEvent(MovementSpeedCheck); + + SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnGetState); + + UpdatesAfter.Add(typeof(SharedPhysicsSystem)); } - private void MovementSpeedCheck(EntityUid uid, SlowsOnContactComponent component, RefreshMovementSpeedModifiersEvent args) + public override void Update(float frameTime) { - if (!_statusCapableInContact.ContainsKey(uid) || _statusCapableInContact[uid] <= 0) + base.Update(frameTime); + + _toRemove.Clear(); + + foreach (var ent in _toUpdate) + { + _speedModifierSystem.RefreshMovementSpeedModifiers(ent); + } + + foreach (var ent in _toRemove) + { + RemComp(ent); + } + + _toUpdate.Clear(); + } + + private void OnGetState(EntityUid uid, SlowContactsComponent component, ref ComponentGetState args) + { + args.State = new SlowContactsComponentState(component.WalkSpeedModifier, component.SprintSpeedModifier); + } + + private void OnHandleState(EntityUid uid, SlowContactsComponent component, ref ComponentHandleState args) + { + if (args.Current is not SlowContactsComponentState state) return; + component.WalkSpeedModifier = state.WalkSpeedModifier; + component.SprintSpeedModifier = state.SprintSpeedModifier; + } + + private void MovementSpeedCheck(EntityUid uid, SlowedByContactComponent component, RefreshMovementSpeedModifiersEvent args) + { if (!EntityManager.TryGetComponent(uid, out var physicsComponent)) return; var walkSpeed = 1.0f; var sprintSpeed = 1.0f; - foreach (var colliding in _physics.GetCollidingEntities(physicsComponent)) + bool remove = true; + foreach (var colliding in _physics.GetContactingEntities(physicsComponent)) { var ent = colliding.Owner; - if (!EntityManager.TryGetComponent(ent, out var slowContactsComponent)) + if (!TryComp(ent, out var slowContactsComponent)) continue; walkSpeed = Math.Min(walkSpeed, slowContactsComponent.WalkSpeedModifier); sprintSpeed = Math.Min(sprintSpeed, slowContactsComponent.SprintSpeedModifier); + remove = false; } args.ModifySpeed(walkSpeed, sprintSpeed); + + // no longer colliding with anything + if (remove) + _toRemove.Add(uid); } private void OnEntityExit(EntityUid uid, SlowContactsComponent component, EndCollideEvent args) { var otherUid = args.OtherFixture.Body.Owner; - if (!EntityManager.HasComponent(otherUid) - || !EntityManager.HasComponent(otherUid)) - return; - if (!_statusCapableInContact.ContainsKey(otherUid)) - Logger.ErrorS("slowscontacts", $"The entity {otherUid} left a body ({uid}) it was never in."); - _statusCapableInContact[otherUid]--; - if (_statusCapableInContact[otherUid] == 0) - EntityManager.RemoveComponentDeferred(otherUid); - _speedModifierSystem.RefreshMovementSpeedModifiers(otherUid); - + if (HasComp(otherUid)) + _toUpdate.Add(otherUid); } private void OnEntityEnter(EntityUid uid, SlowContactsComponent component, StartCollideEvent args) { var otherUid = args.OtherFixture.Body.Owner; - if (!EntityManager.HasComponent(otherUid)) + if (!HasComp(otherUid)) return; - if (!_statusCapableInContact.ContainsKey(otherUid)) - _statusCapableInContact[otherUid] = 0; - _statusCapableInContact[otherUid]++; - EnsureComp(otherUid); - _speedModifierSystem.RefreshMovementSpeedModifiers(otherUid); + EnsureComp(otherUid); + _toUpdate.Add(otherUid); } }