]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Security barriers take 5 seconds to (un)lock (#24637)
authorPieter-Jan Briers <pieterjan.briers+git@gmail.com>
Sun, 28 Jan 2024 00:28:02 +0000 (01:28 +0100)
committerGitHub <noreply@github.com>
Sun, 28 Jan 2024 00:28:02 +0000 (11:28 +1100)
People are using these as unhackable and hard-to-tailgate airlocks into sec. They should not be trivial for security officers to move through.

Made LockComponent have configurable lock times to implement this.

Content.Shared/Lock/LockComponent.cs
Content.Shared/Lock/LockSystem.cs
Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml

index 174818c4e81de808a55727965bf614380b577fd2..b3c46597498ad21ccf64de784aee18e340872935 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.DoAfter;
 using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
 using Robust.Shared.Serialization;
@@ -50,6 +51,26 @@ public sealed partial class LockComponent : Component
     [DataField("breakOnEmag")]
     [AutoNetworkedField]
     public bool BreakOnEmag = true;
+
+    /// <summary>
+    /// Amount of do-after time needed to lock the entity.
+    /// </summary>
+    /// <remarks>
+    /// If set to zero, no do-after will be used.
+    /// </remarks>
+    [DataField]
+    [AutoNetworkedField]
+    public TimeSpan LockTime;
+
+    /// <summary>
+    /// Amount of do-after time needed to unlock the entity.
+    /// </summary>
+    /// <remarks>
+    /// If set to zero, no do-after will be used.
+    /// </remarks>
+    [DataField]
+    [AutoNetworkedField]
+    public TimeSpan UnlockTime;
 }
 
 /// <summary>
@@ -64,3 +85,31 @@ public record struct LockToggleAttemptEvent(EntityUid User, bool Silent = false,
 /// </summary>
 [ByRefEvent]
 public readonly record struct LockToggledEvent(bool Locked);
+
+/// <summary>
+/// Used to lock a lockable entity that has a lock time configured.
+/// </summary>
+/// <seealso cref="LockComponent"/>
+/// <seealso cref="LockSystem"/>
+[Serializable, NetSerializable]
+public sealed partial class LockDoAfter : DoAfterEvent
+{
+    public override DoAfterEvent Clone()
+    {
+        return this;
+    }
+}
+
+/// <summary>
+/// Used to unlock a lockable entity that has an unlock time configured.
+/// </summary>
+/// <seealso cref="LockComponent"/>
+/// <seealso cref="LockSystem"/>
+[Serializable, NetSerializable]
+public sealed partial class UnlockDoAfter : DoAfterEvent
+{
+    public override DoAfterEvent Clone()
+    {
+        return this;
+    }
+}
index 7babc6a9c0cb590545051c00b3fe73818445edbb..e5f53b4080e96670fb9ded19a3c524bdfbdd1bc2 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Access.Components;
 using Content.Shared.Access.Systems;
+using Content.Shared.DoAfter;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Hands.Components;
@@ -26,6 +27,7 @@ public sealed class LockSystem : EntitySystem
     [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
+    [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
 
     /// <inheritdoc />
     public override void Initialize()
@@ -38,6 +40,8 @@ public sealed class LockSystem : EntitySystem
         SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
         SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
         SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
+        SubscribeLocalEvent<LockComponent, LockDoAfter>(OnDoAfterLock);
+        SubscribeLocalEvent<LockComponent, UnlockDoAfter>(OnDoAfterUnlock);
     }
 
     private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
@@ -86,11 +90,15 @@ public sealed class LockSystem : EntitySystem
     /// <summary>
     /// Attmempts to lock a given entity
     /// </summary>
+    /// <remarks>
+    /// If the lock is set to require a do-after, a true return value only indicates that the do-after started.
+    /// </remarks>
     /// <param name="uid">The entity with the lock</param>
     /// <param name="user">The person trying to lock it</param>
     /// <param name="lockComp"></param>
+    /// <param name="skipDoAfter">If true, skip the required do-after if one is configured.</param>
     /// <returns>If locking was successful</returns>
-    public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+    public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null, bool skipDoAfter = false)
     {
         if (!Resolve(uid, ref lockComp))
             return false;
@@ -101,6 +109,16 @@ public sealed class LockSystem : EntitySystem
         if (!HasUserAccess(uid, user, quiet: false))
             return false;
 
+        if (!skipDoAfter && lockComp.LockTime != TimeSpan.Zero)
+        {
+            return _doAfter.TryStartDoAfter(
+                new DoAfterArgs(EntityManager, user, lockComp.LockTime, new LockDoAfter(), uid, uid)
+                {
+                    BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, RequireCanInteract = true,
+                    NeedHand = true
+                });
+        }
+
         _sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
                 ("entityName", Identity.Name(uid, EntityManager))), uid, user);
         _audio.PlayPredicted(lockComp.LockSound, uid, user);
@@ -117,6 +135,9 @@ public sealed class LockSystem : EntitySystem
     /// <summary>
     /// Forces a given entity to be unlocked
     /// </summary>
+    /// <remarks>
+    /// This does not process do-after times.
+    /// </remarks>
     /// <param name="uid">The entity with the lock</param>
     /// <param name="user">The person unlocking it. Can be null</param>
     /// <param name="lockComp"></param>
@@ -145,11 +166,15 @@ public sealed class LockSystem : EntitySystem
     /// <summary>
     /// Attmempts to unlock a given entity
     /// </summary>
+    /// <remarks>
+    /// If the lock is set to require a do-after, a true return value only indicates that the do-after started.
+    /// </remarks>
     /// <param name="uid">The entity with the lock</param>
     /// <param name="user">The person trying to unlock it</param>
     /// <param name="lockComp"></param>
+    /// <param name="skipDoAfter">If true, skip the required do-after if one is configured.</param>
     /// <returns>If locking was successful</returns>
-    public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+    public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null, bool skipDoAfter = false)
     {
         if (!Resolve(uid, ref lockComp))
             return false;
@@ -160,6 +185,16 @@ public sealed class LockSystem : EntitySystem
         if (!HasUserAccess(uid, user, quiet: false))
             return false;
 
+        if (!skipDoAfter && lockComp.UnlockTime != TimeSpan.Zero)
+        {
+            return _doAfter.TryStartDoAfter(
+                new DoAfterArgs(EntityManager, user, lockComp.LockTime, new UnlockDoAfter(), uid, uid)
+                {
+                    BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, RequireCanInteract = true,
+                    NeedHand = true
+                });
+        }
+
         Unlock(uid, user, lockComp);
         return true;
     }
@@ -219,5 +254,21 @@ public sealed class LockSystem : EntitySystem
         RemComp<LockComponent>(uid); //Literally destroys the lock as a tell it was emagged
         args.Handled = true;
     }
+
+    private void OnDoAfterLock(EntityUid uid, LockComponent component, LockDoAfter args)
+    {
+        if (args.Cancelled)
+            return;
+
+        TryLock(uid, args.User, skipDoAfter: true);
+    }
+
+    private void OnDoAfterUnlock(EntityUid uid, LockComponent component, UnlockDoAfter args)
+    {
+        if (args.Cancelled)
+            return;
+
+        TryUnlock(uid, args.User, skipDoAfter: true);
+    }
 }
 
index 035185487de85f2e8dbba49649c5010755c7769f..3a31edf7f149389263ccc6dd1a91175be1b11555 100644 (file)
@@ -45,6 +45,8 @@
   - type: Lock
     locked: false
     lockOnClick: true # toggle lock just by clicking on barrier
+    lockTime: 5
+    unlockTime: 5
   - type: Damageable
     damageContainer: Inorganic
     damageModifierSet: Metallic