Add access configurator (#18638)

The access configurator programs the access levels of any access reader. To use the access configurator, players must:

- Insert an ID card
- Click a nearby entity with an access reader with the access configurator in hand
- Change the access list

Note that players only need one of the access levels listed on the device to lock/unlock it, but will only be able to alter access settings when they all of the access levels listed on the device

For example, an airlock which has 'Science' and 'Engineering' access listed can be opened by any player with either 'Science' or 'Engineering' access. However, to change the access settings on this airlock, a player must have both 'Science' and 'Engineering' access. This is to prevent people from easily breaking into secure areas with this tool, by adding one of their own access levels to the target device

Obviously, the most useful ID card to use with this tool is one with all access, since it can change the settings of any device. Removing all access requirements from a device will make it useable by anyone.

---------

Co-authored-by: Kevin Zheng <kevinz5000@gmail.com>
This commit is contained in:
chromiumboy
2023-08-08 13:30:46 -05:00
committed by GitHub
parent 4509312eea
commit 2df70799f8
16 changed files with 783 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
using Content.Shared.Access.Systems;
using Content.Shared.Containers.ItemSlots;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Access.Components;
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedAccessOverriderSystem))]
public sealed class AccessOverriderComponent : Component
{
public static string PrivilegedIdCardSlotId = "AccessOverrider-privilegedId";
[DataField("privilegedIdSlot")]
public ItemSlot PrivilegedIdSlot = new();
[ViewVariables(VVAccess.ReadWrite)]
[DataField("denialSound")]
public SoundSpecifier? DenialSound;
public EntityUid TargetAccessReaderId = new();
[Serializable, NetSerializable]
public sealed class WriteToTargetAccessReaderIdMessage : BoundUserInterfaceMessage
{
public readonly List<string> AccessList;
public WriteToTargetAccessReaderIdMessage(List<string> accessList)
{
AccessList = accessList;
}
}
[DataField("accessLevels", customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
public List<string> AccessLevels = new();
[ViewVariables(VVAccess.ReadWrite)]
[DataField("doAfter")]
public float DoAfterTime = 0f;
[Serializable, NetSerializable]
public sealed class AccessOverriderBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly string TargetLabel;
public readonly Color TargetLabelColor;
public readonly string PrivilegedIdName;
public readonly bool IsPrivilegedIdPresent;
public readonly bool IsPrivilegedIdAuthorized;
public readonly string[]? TargetAccessReaderIdAccessList;
public readonly string[]? AllowedModifyAccessList;
public readonly string[]? MissingPrivilegesList;
public AccessOverriderBoundUserInterfaceState(bool isPrivilegedIdPresent,
bool isPrivilegedIdAuthorized,
string[]? targetAccessReaderIdAccessList,
string[]? allowedModifyAccessList,
string[]? missingPrivilegesList,
string privilegedIdName,
string targetLabel,
Color targetLabelColor)
{
IsPrivilegedIdPresent = isPrivilegedIdPresent;
IsPrivilegedIdAuthorized = isPrivilegedIdAuthorized;
TargetAccessReaderIdAccessList = targetAccessReaderIdAccessList;
AllowedModifyAccessList = allowedModifyAccessList;
MissingPrivilegesList = missingPrivilegesList;
PrivilegedIdName = privilegedIdName;
TargetLabel = targetLabel;
TargetLabelColor = targetLabelColor;
}
}
[Serializable, NetSerializable]
public enum AccessOverriderUiKey : byte
{
Key,
}
}

View File

@@ -0,0 +1,72 @@
using Content.Shared.Access.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.DoAfter;
using JetBrains.Annotations;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Access.Systems
{
[UsedImplicitly]
public abstract class SharedAccessOverriderSystem : EntitySystem
{
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly ILogManager _log = default!;
public const string Sawmill = "accessoverrider";
protected ISawmill _sawmill = default!;
public override void Initialize()
{
base.Initialize();
_sawmill = _log.GetSawmill(Sawmill);
SubscribeLocalEvent<AccessOverriderComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<AccessOverriderComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<AccessOverriderComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<AccessOverriderComponent, ComponentHandleState>(OnHandleState);
}
private void OnHandleState(EntityUid uid, AccessOverriderComponent component, ref ComponentHandleState args)
{
if (args.Current is not AccessOverriderComponentState state) return;
component.AccessLevels = state.AccessLevels;
}
private void OnGetState(EntityUid uid, AccessOverriderComponent component, ref ComponentGetState args)
{
args.State = new AccessOverriderComponentState(component.AccessLevels);
}
private void OnComponentInit(EntityUid uid, AccessOverriderComponent component, ComponentInit args)
{
_itemSlotsSystem.AddItemSlot(uid, AccessOverriderComponent.PrivilegedIdCardSlotId, component.PrivilegedIdSlot);
}
private void OnComponentRemove(EntityUid uid, AccessOverriderComponent component, ComponentRemove args)
{
_itemSlotsSystem.RemoveItemSlot(uid, component.PrivilegedIdSlot);
}
[Serializable, NetSerializable]
private sealed class AccessOverriderComponentState : ComponentState
{
public List<string> AccessLevels;
public AccessOverriderComponentState(List<string> accessLevels)
{
AccessLevels = accessLevels;
}
}
[Serializable, NetSerializable]
public sealed class AccessOverriderDoAfterEvent : DoAfterEvent
{
public AccessOverriderDoAfterEvent()
{
}
public override DoAfterEvent Clone() => this;
}
}
}