using System.Diagnostics.CodeAnalysis; using Content.Shared.Forensics.Components; using Content.Shared.Inventory; using Content.Shared.Lock; 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!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnFindAvailableLocks); SubscribeLocalEvent(OnCheckLockAccess); } private void OnFindAvailableLocks(Entity ent, ref FindAvailableLocksEvent args) { args.FoundReaders |= LockTypes.Fingerprint; } private void OnCheckLockAccess(Entity ent, ref CheckUserHasLockAccessEvent args) { // Are we looking for a fingerprint lock? if (!args.FoundReaders.HasFlag(LockTypes.Fingerprint)) return; // If the user has access to this lock, we pass it into the event. if (IsAllowed(ent.Owner, args.User, out var denyReason)) args.HasAccess |= LockTypes.Fingerprint; else args.DenyReason = denyReason; } /// /// Checks if the given user has fingerprint access to the target entity. /// /// The target entity. /// User trying to gain access. /// Whether to display a popup with the reason you are not allowed to access this. /// The reason why access was denied. /// True if access was granted, otherwise false. // TODO: Remove showPopup, just keeping it here for backwards compatibility while I refactor mail [PublicAPI] public bool IsAllowed(Entity target, EntityUid user, [NotNullWhen(false)] out string? denyReason, bool showPopup = true) { denyReason = null; 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)) { denyReason = Loc.GetString("fingerprint-reader-fail-gloves", ("blocker", gloves)); if (showPopup) _popup.PopupClient(denyReason, target, user); return false; } // Check fingerprint match if (!TryComp(user, out var fingerprint) || fingerprint.Fingerprint == null || !target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint)) { denyReason = Loc.GetString("fingerprint-reader-fail"); if (showPopup) _popup.PopupClient(denyReason, 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); } }