Prevent non-airlock doors from closing on people. (#6882)

This commit is contained in:
Leon Friedrich
2022-02-25 19:32:35 +13:00
committed by GitHub
parent 49ae383f06
commit 6dc681683c
4 changed files with 28 additions and 12 deletions

View File

@@ -130,12 +130,19 @@ public sealed class DoorComponent : Component, ISerializationHooks
public DamageSpecifier? CrushDamage; public DamageSpecifier? CrushDamage;
/// <summary> /// <summary>
/// If false, this door is incapable of crushing entities. Note that this differs from the airlock's "safety" /// If false, this door is incapable of crushing entities. This just determines whether it will apply damage and
/// feature that checks for colliding entities. /// stun, not whether it can close despite entities being in the way.
/// </summary> /// </summary>
[DataField("canCrush")] [DataField("canCrush")]
public readonly bool CanCrush = true; public readonly bool CanCrush = true;
/// <summary>
/// Whether to check for colliding entities before closing. This may be overridden by other system by subscribing to
/// <see cref="BeforeDoorClosedEvent"/>. For example, hacked airlocks will set this to false.
/// </summary>
[DataField("performCollisionCheck")]
public readonly bool PerformCollisionCheck = true;
/// <summary> /// <summary>
/// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen(). /// List of EntityUids of entities we're currently crushing. Cleared in OnPartialOpen().
/// </summary> /// </summary>

View File

@@ -25,16 +25,23 @@ namespace Content.Shared.Doors
} }
/// <summary> /// <summary>
/// Raised when the door is determining whether it is able to close. /// Raised when the door is determining whether it is able to close. If the event is canceled, the door will not
/// Cancel to stop the door from being closed. /// 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.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This event is raised both when the door is initially closed, and when it is just about to become "partially" /// 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 /// closed (opaque & collidable). If canceled while partially closing, it will start opening again. Useful in case
/// things like airlock anti-crush safety features. /// an entity entered the door just as it was about to become "solid".
/// </remarks> /// </remarks>
public sealed class BeforeDoorClosedEvent : CancellableEntityEventArgs public sealed class BeforeDoorClosedEvent : CancellableEntityEventArgs
{ {
public bool PerformCollisionCheck;
public BeforeDoorClosedEvent(bool performCollisionCheck)
{
PerformCollisionCheck = performCollisionCheck;
}
} }
/// <summary> /// <summary>

View File

@@ -35,8 +35,8 @@ public abstract class SharedAirlockSystem : EntitySystem
protected virtual void OnBeforeDoorClosed(EntityUid uid, SharedAirlockComponent airlock, BeforeDoorClosedEvent args) protected virtual void OnBeforeDoorClosed(EntityUid uid, SharedAirlockComponent airlock, BeforeDoorClosedEvent args)
{ {
if (airlock.Safety && DoorSystem.GetColliding(uid).Any()) if (!airlock.Safety)
args.Cancel(); args.PerformCollisionCheck = false;
} }

View File

@@ -309,12 +309,15 @@ public abstract class SharedDoorSystem : EntitySystem
if (!Resolve(uid, ref door)) if (!Resolve(uid, ref door))
return false; return false;
var ev = new BeforeDoorClosedEvent(); var ev = new BeforeDoorClosedEvent(door.PerformCollisionCheck);
RaiseLocalEvent(uid, ev, false); RaiseLocalEvent(uid, ev, false);
if (ev.Cancelled) if (ev.Cancelled)
return false; 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) 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)) if (!Resolve(uid, ref door))
return; return;
// is this door capable of crushing? NOT the same as an airlock safety check. The door will still close.
if (!door.CanCrush) if (!door.CanCrush)
return; return;
// Crush // Find entities and apply curshing effects
var stunTime = door.DoorStunTime + door.OpenTimeOne; var stunTime = door.DoorStunTime + door.OpenTimeOne;
foreach (var entity in GetColliding(uid, physics)) foreach (var entity in GetColliding(uid, physics))
{ {