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);
}
}