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)) {