diff --git a/Content.Shared/FingerprintReader/FingerprintReaderComponent.cs b/Content.Shared/FingerprintReader/FingerprintReaderComponent.cs new file mode 100644 index 0000000000..166551cfe7 --- /dev/null +++ b/Content.Shared/FingerprintReader/FingerprintReaderComponent.cs @@ -0,0 +1,35 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.FingerprintReader; + +/// +/// Component for checking if a user's fingerprint matches allowed fingerprints +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(FingerprintReaderSystem))] +public sealed partial class FingerprintReaderComponent : Component +{ + /// + /// The fingerprints that are allowed to access this entity. + /// + [DataField, AutoNetworkedField] + public HashSet AllowedFingerprints = new(); + + /// + /// Whether to ignore gloves when checking fingerprints. + /// + [DataField, AutoNetworkedField] + public bool IgnoreGloves; + + /// + /// The popup to show when access is denied due to fingerprint mismatch. + /// + [DataField] + public LocId? FailPopup; + + /// + /// The popup to show when access is denied due to wearing gloves. + /// + [DataField] + public LocId? FailGlovesPopup; +} diff --git a/Content.Shared/FingerprintReader/FingerprintReaderSystem.cs b/Content.Shared/FingerprintReader/FingerprintReaderSystem.cs new file mode 100644 index 0000000000..f3944be9cd --- /dev/null +++ b/Content.Shared/FingerprintReader/FingerprintReaderSystem.cs @@ -0,0 +1,100 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Forensics.Components; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using JetBrains.Annotations; + +namespace Content.Shared.FingerprintReader; + +// TODO: This has a lot of overlap with the AccessReaderSystem, maybe merge them in the future? +public sealed class FingerprintReaderSystem : EntitySystem +{ + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + /// + /// Checks if the given user has fingerprint access to the target entity. + /// + /// The target entity. + /// User trying to gain access. + /// True if access was granted, otherwise false. + [PublicAPI] + public bool IsAllowed(Entity target, EntityUid user) + { + if (!Resolve(target, ref target.Comp, false)) + return true; + + if (target.Comp.AllowedFingerprints.Count == 0) + return true; + + // Check for gloves first + if (!target.Comp.IgnoreGloves && TryGetBlockingGloves(user, out var gloves)) + { + if (target.Comp.FailGlovesPopup != null) + _popup.PopupEntity(Loc.GetString(target.Comp.FailGlovesPopup, ("blocker", gloves)), target, user); + return false; + } + + // Check fingerprint match + if (!TryComp(user, out var fingerprint) || fingerprint.Fingerprint == null || + !target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint)) + { + if (target.Comp.FailPopup != null) + _popup.PopupEntity(Loc.GetString(target.Comp.FailPopup), target, user); + + return false; + } + + return true; + } + + /// + /// Gets the blocking gloves of a user. Gloves count as blocking if they hide fingerprints. + /// + /// Entity wearing the gloves. + /// The returned gloves, if they exist. + /// True if blocking gloves were found, otherwise False. + [PublicAPI] + public bool TryGetBlockingGloves(EntityUid user, [NotNullWhen(true)] out EntityUid? blocker) + { + blocker = null; + + if (_inventory.TryGetSlotEntity(user, "gloves", out var gloves) && HasComp(gloves)) + { + blocker = gloves; + return true; + } + + return false; + } + + /// + /// Sets the allowed fingerprints for a fingerprint reader + /// + [PublicAPI] + public void SetAllowedFingerprints(Entity target, HashSet fingerprints) + { + target.Comp.AllowedFingerprints = fingerprints; + Dirty(target); + } + + /// + /// Adds an allowed fingerprint to a fingerprint reader + /// + [PublicAPI] + public void AddAllowedFingerprint(Entity target, string fingerprint) + { + target.Comp.AllowedFingerprints.Add(fingerprint); + Dirty(target); + } + + /// + /// Removes an allowed fingerprint from a fingerprint reader + /// + [PublicAPI] + public void RemoveAllowedFingerprint(Entity target, string fingerprint) + { + target.Comp.AllowedFingerprints.Remove(fingerprint); + Dirty(target); + } +} diff --git a/Resources/Locale/en-US/fingerprint-reader/fingerprint-reader.ftl b/Resources/Locale/en-US/fingerprint-reader/fingerprint-reader.ftl new file mode 100644 index 0000000000..b8d7807882 --- /dev/null +++ b/Resources/Locale/en-US/fingerprint-reader/fingerprint-reader.ftl @@ -0,0 +1,2 @@ +fingerprint-reader-fail = Your fingerprint does not match! +fingerprint-reader-fail-gloves = The fingerprint reader cannot read through your {$blocker}!