From 6dc681683c3d174f628e890cab28d83e9a1367d1 Mon Sep 17 00:00:00 2001
From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Date: Fri, 25 Feb 2022 19:32:35 +1300
Subject: [PATCH] Prevent non-airlock doors from closing on people. (#6882)
---
Content.Shared/Doors/Components/DoorComponent.cs | 11 +++++++++--
Content.Shared/Doors/DoorEvents.cs | 15 +++++++++++----
.../Doors/Systems/SharedAirlockSystem.cs | 4 ++--
Content.Shared/Doors/Systems/SharedDoorSystem.cs | 10 ++++++----
4 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs
index 7a86117a2a..c44f14ce31 100644
--- a/Content.Shared/Doors/Components/DoorComponent.cs
+++ b/Content.Shared/Doors/Components/DoorComponent.cs
@@ -130,12 +130,19 @@ public sealed class DoorComponent : Component, ISerializationHooks
public DamageSpecifier? CrushDamage;
///
- /// If false, this door is incapable of crushing entities. Note that this differs from the airlock's "safety"
- /// feature that checks for colliding entities.
+ /// If false, this door is incapable of crushing entities. This just determines whether it will apply damage and
+ /// stun, not whether it can close despite entities being in the way.
///
[DataField("canCrush")]
public readonly bool CanCrush = true;
+ ///
+ /// Whether to check for colliding entities before closing. This may be overridden by other system by subscribing to
+ /// . For example, hacked airlocks will set this to false.
+ ///
+ [DataField("performCollisionCheck")]
+ public readonly bool PerformCollisionCheck = true;
+
///
/// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen().
///
diff --git a/Content.Shared/Doors/DoorEvents.cs b/Content.Shared/Doors/DoorEvents.cs
index cb5f4f3166..953a694602 100644
--- a/Content.Shared/Doors/DoorEvents.cs
+++ b/Content.Shared/Doors/DoorEvents.cs
@@ -25,16 +25,23 @@ namespace Content.Shared.Doors
}
///
- /// Raised when the door is determining whether it is able to close.
- /// Cancel to stop the door from being closed.
+ /// Raised when the door is determining whether it is able to close. If the event is canceled, the door will not
+ /// close. Additionally this event also has a bool that determines whether or not the door should perform a
+ /// safety/collision check before closing. This check has to be proactively disabled by things like hacked airlocks.
///
///
/// This event is raised both when the door is initially closed, and when it is just about to become "partially"
- /// closed (opaque & collidable). If canceled while partially closing, it will start opening again. Useful for
- /// things like airlock anti-crush safety features.
+ /// closed (opaque & collidable). If canceled while partially closing, it will start opening again. Useful in case
+ /// an entity entered the door just as it was about to become "solid".
///
public sealed class BeforeDoorClosedEvent : CancellableEntityEventArgs
{
+ public bool PerformCollisionCheck;
+
+ public BeforeDoorClosedEvent(bool performCollisionCheck)
+ {
+ PerformCollisionCheck = performCollisionCheck;
+ }
}
///
diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs
index a6c0e559db..fed0e32093 100644
--- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs
+++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs
@@ -35,8 +35,8 @@ public abstract class SharedAirlockSystem : EntitySystem
protected virtual void OnBeforeDoorClosed(EntityUid uid, SharedAirlockComponent airlock, BeforeDoorClosedEvent args)
{
- if (airlock.Safety && DoorSystem.GetColliding(uid).Any())
- args.Cancel();
+ if (!airlock.Safety)
+ args.PerformCollisionCheck = false;
}
diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs
index 2e901dcc52..1229db9685 100644
--- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs
+++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs
@@ -309,12 +309,15 @@ public abstract class SharedDoorSystem : EntitySystem
if (!Resolve(uid, ref door))
return false;
- var ev = new BeforeDoorClosedEvent();
+ var ev = new BeforeDoorClosedEvent(door.PerformCollisionCheck);
RaiseLocalEvent(uid, ev, false);
if (ev.Cancelled)
return false;
- return HasAccess(uid, user);
+ if (!HasAccess(uid, user))
+ return false;
+
+ return !ev.PerformCollisionCheck || !GetColliding(uid).Any();
}
public virtual void StartClosing(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false)
@@ -387,11 +390,10 @@ public abstract class SharedDoorSystem : EntitySystem
if (!Resolve(uid, ref door))
return;
- // is this door capable of crushing? NOT the same as an airlock safety check. The door will still close.
if (!door.CanCrush)
return;
- // Crush
+ // Find entities and apply curshing effects
var stunTime = door.DoorStunTime + door.OpenTimeOne;
foreach (var entity in GetColliding(uid, physics))
{