Event based lock access (#40883)
* init * some bonus stuff * CheckForAnyReaders * reader * doc * review * fuck yaml * Me when I push changes myshelf --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ using Content.Shared.Hands.EntitySystems;
|
|||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Localizations;
|
using Content.Shared.Localizations;
|
||||||
|
using Content.Shared.Lock;
|
||||||
using Content.Shared.NameIdentifier;
|
using Content.Shared.NameIdentifier;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.StationRecords;
|
using Content.Shared.StationRecords;
|
||||||
@@ -44,6 +45,8 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, AccessReaderConfigurationAttemptEvent>(OnConfigurationAttempt);
|
SubscribeLocalEvent<AccessReaderComponent, AccessReaderConfigurationAttemptEvent>(OnConfigurationAttempt);
|
||||||
|
SubscribeLocalEvent<AccessReaderComponent, FindAvailableLocksEvent>(OnFindAvailableLocks);
|
||||||
|
SubscribeLocalEvent<AccessReaderComponent, CheckUserHasLockAccessEvent>(OnCheckLockAccess);
|
||||||
|
|
||||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||||
@@ -169,6 +172,22 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
ent.Comp.AccessListsOriginal ??= new(ent.Comp.AccessLists);
|
ent.Comp.AccessListsOriginal ??= new(ent.Comp.AccessLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnFindAvailableLocks(Entity<AccessReaderComponent> ent, ref FindAvailableLocksEvent args)
|
||||||
|
{
|
||||||
|
args.FoundReaders |= LockTypes.Access;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCheckLockAccess(Entity<AccessReaderComponent> ent, ref CheckUserHasLockAccessEvent args)
|
||||||
|
{
|
||||||
|
// Are we looking for an access lock?
|
||||||
|
if (!args.FoundReaders.HasFlag(LockTypes.Access))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the user has access to this lock, we pass it into the event.
|
||||||
|
if (IsAllowed(args.User, ent))
|
||||||
|
args.HasAccess |= LockTypes.Access;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Searches the source for access tags
|
/// Searches the source for access tags
|
||||||
/// then compares it with the all targets accesses to see if it is allowed.
|
/// then compares it with the all targets accesses to see if it is allowed.
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true, bool force = false)
|
private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true, bool force = false)
|
||||||
{
|
{
|
||||||
// Check fingerprint access if there is a reader on the mail
|
// Check fingerprint access if there is a reader on the mail
|
||||||
if (!force && TryComp<FingerprintReaderComponent>(ent, out var reader) && !_fingerprintReader.IsAllowed((ent, reader), user))
|
if (!force && !_fingerprintReader.IsAllowed(ent.Owner, user, out _))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
||||||
|
|||||||
@@ -20,16 +20,4 @@ public sealed partial class FingerprintReaderComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public bool IgnoreGloves;
|
public bool IgnoreGloves;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The popup to show when access is denied due to fingerprint mismatch.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public LocId? FailPopup;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The popup to show when access is denied due to wearing gloves.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public LocId? FailGlovesPopup;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.Forensics.Components;
|
using Content.Shared.Forensics.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Lock;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
@@ -12,15 +13,45 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<FingerprintReaderComponent, FindAvailableLocksEvent>(OnFindAvailableLocks);
|
||||||
|
SubscribeLocalEvent<FingerprintReaderComponent, CheckUserHasLockAccessEvent>(OnCheckLockAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFindAvailableLocks(Entity<FingerprintReaderComponent> ent, ref FindAvailableLocksEvent args)
|
||||||
|
{
|
||||||
|
args.FoundReaders |= LockTypes.Fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCheckLockAccess(Entity<FingerprintReaderComponent> 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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the given user has fingerprint access to the target entity.
|
/// Checks if the given user has fingerprint access to the target entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The target entity.</param>
|
/// <param name="target">The target entity.</param>
|
||||||
/// <param name="user">User trying to gain access.</param>
|
/// <param name="user">User trying to gain access.</param>
|
||||||
|
/// <param name="showPopup">Whether to display a popup with the reason you are not allowed to access this.</param>
|
||||||
|
/// <param name="denyReason">The reason why access was denied.</param>
|
||||||
/// <returns>True if access was granted, otherwise false.</returns>
|
/// <returns>True if access was granted, otherwise false.</returns>
|
||||||
|
// TODO: Remove showPopup, just keeping it here for backwards compatibility while I refactor mail
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool IsAllowed(Entity<FingerprintReaderComponent?> target, EntityUid user, bool showPopup = true)
|
public bool IsAllowed(Entity<FingerprintReaderComponent?> target, EntityUid user, [NotNullWhen(false)] out string? denyReason, bool showPopup = true)
|
||||||
{
|
{
|
||||||
|
denyReason = null;
|
||||||
if (!Resolve(target, ref target.Comp, false))
|
if (!Resolve(target, ref target.Comp, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -30,8 +61,11 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
// Check for gloves first
|
// Check for gloves first
|
||||||
if (!target.Comp.IgnoreGloves && TryGetBlockingGloves(user, out var gloves))
|
if (!target.Comp.IgnoreGloves && TryGetBlockingGloves(user, out var gloves))
|
||||||
{
|
{
|
||||||
if (target.Comp.FailGlovesPopup != null && showPopup)
|
denyReason = Loc.GetString("fingerprint-reader-fail-gloves", ("blocker", gloves));
|
||||||
_popup.PopupClient(Loc.GetString(target.Comp.FailGlovesPopup, ("blocker", gloves)), target, user);
|
|
||||||
|
if (showPopup)
|
||||||
|
_popup.PopupClient(denyReason, target, user);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +73,10 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
if (!TryComp<FingerprintComponent>(user, out var fingerprint) || fingerprint.Fingerprint == null ||
|
if (!TryComp<FingerprintComponent>(user, out var fingerprint) || fingerprint.Fingerprint == null ||
|
||||||
!target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint))
|
!target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint))
|
||||||
{
|
{
|
||||||
if (target.Comp.FailPopup != null && showPopup)
|
denyReason = Loc.GetString("fingerprint-reader-fail");
|
||||||
_popup.PopupClient(Loc.GetString(target.Comp.FailPopup), target, user);
|
|
||||||
|
if (showPopup)
|
||||||
|
_popup.PopupClient(denyReason, target, user);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Shared.Access.Components;
|
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -47,11 +46,37 @@ public sealed partial class LockComponent : Component
|
|||||||
public bool UnlockOnClick = true;
|
public bool UnlockOnClick = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the lock requires access validation through <see cref="AccessReaderComponent"/>
|
/// Whether or not the lock is locked when used it hand.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool LockInHand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the lock is unlocked when used in hand.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool UnlockInHand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether access requirements should be checked for this lock.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, AutoNetworkedField]
|
[DataField, AutoNetworkedField]
|
||||||
public bool UseAccess = true;
|
public bool UseAccess = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What readers should be checked to determine if an entity has access.
|
||||||
|
/// If null, all possible readers are checked.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public LockTypes? CheckedLocks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether any reader needs to be accessed to operate this lock.
|
||||||
|
/// By default, all readers need to be able to be accessed.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool CheckForAnyReaders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sound played when unlocked.
|
/// The sound played when unlocked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,6 +121,12 @@ public sealed partial class LockComponent : Component
|
|||||||
[DataField]
|
[DataField]
|
||||||
[AutoNetworkedField]
|
[AutoNetworkedField]
|
||||||
public TimeSpan UnlockTime;
|
public TimeSpan UnlockTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this lock can be locked again after being unlocked.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public bool AllowRepeatedLocking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Content.Shared.Access.Components;
|
|
||||||
using Content.Shared.Access.Systems;
|
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Construction.Components;
|
using Content.Shared.Construction.Components;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
@@ -7,6 +5,7 @@ using Content.Shared.Emag.Systems;
|
|||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Storage;
|
using Content.Shared.Storage;
|
||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
@@ -16,6 +15,7 @@ using Content.Shared.Wires;
|
|||||||
using Content.Shared.Item.ItemToggle.Components;
|
using Content.Shared.Item.ItemToggle.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Lock;
|
namespace Content.Shared.Lock;
|
||||||
@@ -26,7 +26,6 @@ namespace Content.Shared.Lock;
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class LockSystem : EntitySystem
|
public sealed class LockSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
[Dependency] private readonly EmagSystem _emag = default!;
|
[Dependency] private readonly EmagSystem _emag = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
@@ -35,6 +34,8 @@ public sealed class LockSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
||||||
|
|
||||||
|
private readonly LocId _defaultDenyReason = "lock-comp-has-user-access-fail";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -42,6 +43,7 @@ public sealed class LockSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<LockComponent, ComponentStartup>(OnStartup);
|
SubscribeLocalEvent<LockComponent, ComponentStartup>(OnStartup);
|
||||||
SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated, before: [typeof(ActivatableUISystem)]);
|
SubscribeLocalEvent<LockComponent, ActivateInWorldEvent>(OnActivated, before: [typeof(ActivatableUISystem)]);
|
||||||
|
SubscribeLocalEvent<LockComponent, UseInHandEvent>(OnUseInHand, before: [typeof(ActivatableUISystem)]);
|
||||||
SubscribeLocalEvent<LockComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
|
SubscribeLocalEvent<LockComponent, StorageOpenAttemptEvent>(OnStorageOpenAttempt);
|
||||||
SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<LockComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
|
SubscribeLocalEvent<LockComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleLockVerb);
|
||||||
@@ -84,6 +86,23 @@ public sealed class LockSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnUseInHand(EntityUid uid, LockComponent lockComp, UseInHandEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lockComp.Locked && lockComp.UnlockInHand)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
TryUnlock(uid, args.User, lockComp);
|
||||||
|
}
|
||||||
|
else if (!lockComp.Locked && lockComp.LockInHand)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
TryLock(uid, args.User, lockComp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnStorageOpenAttempt(EntityUid uid, LockComponent component, ref StorageOpenAttemptEvent args)
|
private void OnStorageOpenAttempt(EntityUid uid, LockComponent component, ref StorageOpenAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (!component.Locked)
|
if (!component.Locked)
|
||||||
@@ -125,7 +144,7 @@ public sealed class LockSystem : EntitySystem
|
|||||||
if (!CanToggleLock(uid, user, quiet: false))
|
if (!CanToggleLock(uid, user, quiet: false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (lockComp.UseAccess && !HasUserAccess(uid, user, quiet: false))
|
if (lockComp.UseAccess && !HasUserAccess(uid, user, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!skipDoAfter && lockComp.LockTime != TimeSpan.Zero)
|
if (!skipDoAfter && lockComp.LockTime != TimeSpan.Zero)
|
||||||
@@ -224,7 +243,7 @@ public sealed class LockSystem : EntitySystem
|
|||||||
if (!CanToggleLock(uid, user, quiet: false))
|
if (!CanToggleLock(uid, user, quiet: false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (lockComp.UseAccess && !HasUserAccess(uid, user, quiet: false))
|
if (lockComp.UseAccess && !HasUserAccess(uid, user, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!skipDoAfter && lockComp.UnlockTime != TimeSpan.Zero)
|
if (!skipDoAfter && lockComp.UnlockTime != TimeSpan.Zero)
|
||||||
@@ -273,33 +292,69 @@ public sealed class LockSystem : EntitySystem
|
|||||||
/// Raises an event for other components to check whether or not
|
/// Raises an event for other components to check whether or not
|
||||||
/// the entity can be locked in its current state.
|
/// the entity can be locked in its current state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanToggleLock(EntityUid uid, EntityUid user, bool quiet = true)
|
public bool CanToggleLock(Entity<LockComponent?> ent, EntityUid user, bool quiet = true)
|
||||||
{
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!_actionBlocker.CanComplexInteract(user))
|
if (!_actionBlocker.CanComplexInteract(user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!ent.Comp.Locked && !ent.Comp.AllowRepeatedLocking)
|
||||||
|
return false;
|
||||||
|
|
||||||
var ev = new LockToggleAttemptEvent(user, quiet);
|
var ev = new LockToggleAttemptEvent(user, quiet);
|
||||||
RaiseLocalEvent(uid, ref ev, true);
|
RaiseLocalEvent(ent, ref ev, true);
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var userEv = new UserLockToggleAttemptEvent(uid, quiet);
|
var userEv = new UserLockToggleAttemptEvent(ent, quiet);
|
||||||
RaiseLocalEvent(user, ref userEv, true);
|
RaiseLocalEvent(user, ref userEv, true);
|
||||||
return !userEv.Cancelled;
|
return !userEv.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this should be a helper on AccessReaderSystem since so many systems copy paste it
|
/// <summary>
|
||||||
private bool HasUserAccess(EntityUid uid, EntityUid user, AccessReaderComponent? reader = null, bool quiet = true)
|
/// Checks whether the user has access to locks on an entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The entity we check for locks.</param>
|
||||||
|
/// <param name="user">The user we check for access.</param>
|
||||||
|
/// <param name="quiet">Whether to display a popup if user has no access.</param>
|
||||||
|
/// <returns>True if the user has access, otherwise False.</returns>
|
||||||
|
[PublicAPI]
|
||||||
|
public bool HasUserAccess(Entity<LockComponent?> ent, EntityUid user, bool quiet = true)
|
||||||
{
|
{
|
||||||
// Not having an AccessComponent means you get free access. woo!
|
// Entity literally has no lock. Congratulations.
|
||||||
if (!Resolve(uid, ref reader, false))
|
if (!Resolve(ent, ref ent.Comp, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (_accessReader.IsAllowed(user, uid, reader))
|
var checkedReaders = LockTypes.None;
|
||||||
|
if (ent.Comp.CheckedLocks is null)
|
||||||
|
{
|
||||||
|
var lockEv = new FindAvailableLocksEvent(user);
|
||||||
|
RaiseLocalEvent(ent, ref lockEv);
|
||||||
|
checkedReaders = lockEv.FoundReaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no locks are found, you have access. Woo!
|
||||||
|
if (checkedReaders == LockTypes.None)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var accessEv = new CheckUserHasLockAccessEvent(user, checkedReaders);
|
||||||
|
RaiseLocalEvent(ent, ref accessEv);
|
||||||
|
|
||||||
|
// If we check for any, as long as user has access to any of the locks we grant access.
|
||||||
|
if (accessEv.HasAccess != LockTypes.None && ent.Comp.CheckForAnyReaders)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (accessEv.HasAccess == checkedReaders)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-has-user-access-fail"), uid, user);
|
{
|
||||||
|
var denyReason = accessEv.DenyReason ?? _defaultDenyReason;
|
||||||
|
_sharedPopupSystem.PopupClient(denyReason, ent, user);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,3 +521,35 @@ public sealed class LockSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity to check whether it has any readers that can prevent it from being opened.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="User">The person attempting to open the entity.</param>
|
||||||
|
/// <param name="FoundReaders">What readers were found. This should not be set when raising the event.</param>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct FindAvailableLocksEvent(EntityUid User, LockTypes FoundReaders = LockTypes.None);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity to check if the user has access (ID, Fingerprint, etc) to said entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="User">The user we are checking.</param>
|
||||||
|
/// <param name="FoundReaders">What readers we are attempting to verify access for.</param>
|
||||||
|
/// <param name="HasAccess">Which readers the user has access to. This should not be set when raising the event.</param>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct CheckUserHasLockAccessEvent(EntityUid User, LockTypes FoundReaders = LockTypes.None, LockTypes HasAccess = LockTypes.None, string? DenyReason = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enum of all readers a lock can be "locked" by.
|
||||||
|
/// Used to determine what you need in order to access the lock.
|
||||||
|
/// For example, an entity with <see cref="AccessReaderComponent"/> will have the Access type, which is gathered by an event and handled by the respective system.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum LockTypes : byte
|
||||||
|
{
|
||||||
|
None, // Default state, means the lock is not restricted.
|
||||||
|
Access, // Means there is an AccessReader currently present.
|
||||||
|
Fingerprint, // Means there is a FingerprintReader currently present.
|
||||||
|
All = Access | Fingerprint,
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
- type: Label
|
- type: Label
|
||||||
examinable: false
|
examinable: false
|
||||||
- type: FingerprintReader
|
- type: FingerprintReader
|
||||||
failPopup: fingerprint-reader-fail
|
|
||||||
failGlovesPopup: fingerprint-reader-fail-gloves
|
|
||||||
- type: Delivery
|
- type: Delivery
|
||||||
- type: DeliveryRandomMultiplier
|
- type: DeliveryRandomMultiplier
|
||||||
- type: ContainerContainer
|
- type: ContainerContainer
|
||||||
|
|||||||
Reference in New Issue
Block a user