Devices with access restrictions list those restrictions in their examination description (#37712)
This commit is contained in:
@@ -54,7 +54,7 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
system.ClearDenyTags(reader);
|
system.ClearDenyTags(reader);
|
||||||
|
|
||||||
// test one list
|
// test one list
|
||||||
system.AddAccess(reader, "A");
|
system.TryAddAccess(reader, "A");
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
||||||
@@ -62,10 +62,10 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
||||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||||
});
|
});
|
||||||
system.ClearAccesses(reader);
|
system.TryClearAccesses(reader);
|
||||||
|
|
||||||
// test one list - two items
|
// test one list - two items
|
||||||
system.AddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A", "B" });
|
system.TryAddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A", "B" });
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.False);
|
||||||
@@ -73,14 +73,14 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
||||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||||
});
|
});
|
||||||
system.ClearAccesses(reader);
|
system.TryClearAccesses(reader);
|
||||||
|
|
||||||
// test two list
|
// test two list
|
||||||
var accesses = new List<HashSet<ProtoId<AccessLevelPrototype>>>() {
|
var accesses = new List<HashSet<ProtoId<AccessLevelPrototype>>>() {
|
||||||
new HashSet<ProtoId<AccessLevelPrototype>> () { "A" },
|
new HashSet<ProtoId<AccessLevelPrototype>> () { "A" },
|
||||||
new HashSet<ProtoId<AccessLevelPrototype>> () { "B", "C" }
|
new HashSet<ProtoId<AccessLevelPrototype>> () { "B", "C" }
|
||||||
};
|
};
|
||||||
system.AddAccesses(reader, accesses);
|
system.TryAddAccesses(reader, accesses);
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
||||||
@@ -90,10 +90,10 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "C", "B", "A" }, reader), Is.True);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "C", "B", "A" }, reader), Is.True);
|
||||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||||
});
|
});
|
||||||
system.ClearAccesses(reader);
|
system.TryClearAccesses(reader);
|
||||||
|
|
||||||
// test deny list
|
// test deny list
|
||||||
system.AddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
|
system.TryAddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
|
||||||
system.AddDenyTag(reader, "B");
|
system.AddDenyTag(reader, "B");
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
@@ -102,7 +102,7 @@ namespace Content.IntegrationTests.Tests.Access
|
|||||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.False);
|
||||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||||
});
|
});
|
||||||
system.ClearAccesses(reader);
|
system.TryClearAccesses(reader);
|
||||||
system.ClearDenyTags(reader);
|
system.ClearDenyTags(reader);
|
||||||
});
|
});
|
||||||
await pair.CleanReturnAsync();
|
await pair.CleanReturnAsync();
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
|||||||
_adminLogger.Add(LogType.Action, LogImpact.High,
|
_adminLogger.Add(LogType.Action, LogImpact.High,
|
||||||
$"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
|
$"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
|
||||||
|
|
||||||
_accessReader.SetAccesses(accessReaderEnt.Value, newAccessList);
|
_accessReader.TrySetAccesses(accessReaderEnt.Value, newAccessList);
|
||||||
|
|
||||||
var ev = new OnAccessOverriderAccessUpdatedEvent(player);
|
var ev = new OnAccessOverriderAccessUpdatedEvent(player);
|
||||||
RaiseLocalEvent(component.TargetAccessReaderId, ref ev);
|
RaiseLocalEvent(component.TargetAccessReaderId, ref ev);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public sealed class DoorElectronicsSystem : EntitySystem
|
|||||||
DoorElectronicsUpdateConfigurationMessage args)
|
DoorElectronicsUpdateConfigurationMessage args)
|
||||||
{
|
{
|
||||||
var accessReader = EnsureComp<AccessReaderComponent>(uid);
|
var accessReader = EnsureComp<AccessReaderComponent>(uid);
|
||||||
_accessReader.SetAccesses((uid, accessReader), args.AccessList);
|
_accessReader.TrySetAccesses((uid, accessReader), args.AccessList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAccessReaderChanged(
|
private void OnAccessReaderChanged(
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ public sealed partial class AccessReaderComponent : Component
|
|||||||
[DataField("access")]
|
[DataField("access")]
|
||||||
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists = new();
|
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An unmodified copy of the original list of the access groups that grant access to this reader.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If null, the access lists of this entity have not been modified yet.
|
||||||
|
/// </remarks>
|
||||||
|
[DataField]
|
||||||
|
public List<HashSet<ProtoId<AccessLevelPrototype>>>? AccessListsOriginal = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of <see cref="StationRecordKey"/>s that grant access. Only a single matching key is required to gain access.
|
/// A list of <see cref="StationRecordKey"/>s that grant access. Only a single matching key is required to gain access.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -76,6 +85,16 @@ public sealed partial class AccessReaderComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool BreakOnAccessBreaker = true;
|
public bool BreakOnAccessBreaker = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The examination text associated with this component.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The text can be supplied with the 'access' variable to populate it
|
||||||
|
/// with a comma separated list of the access levels contained in <see cref="AccessLists"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[DataField]
|
||||||
|
public LocId ExaminationText = "access-reader-examination";
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataDefinition, Serializable, NetSerializable]
|
[DataDefinition, Serializable, NetSerializable]
|
||||||
@@ -96,19 +115,36 @@ public sealed class AccessReaderComponentState : ComponentState
|
|||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags;
|
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags;
|
||||||
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists;
|
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists;
|
||||||
|
public List<HashSet<ProtoId<AccessLevelPrototype>>>? AccessListsOriginal;
|
||||||
public List<(NetEntity, uint)> AccessKeys;
|
public List<(NetEntity, uint)> AccessKeys;
|
||||||
public Queue<AccessRecord> AccessLog;
|
public Queue<AccessRecord> AccessLog;
|
||||||
public int AccessLogLimit;
|
public int AccessLogLimit;
|
||||||
|
|
||||||
public AccessReaderComponentState(bool enabled, HashSet<ProtoId<AccessLevelPrototype>> denyTags, List<HashSet<ProtoId<AccessLevelPrototype>>> accessLists, List<(NetEntity, uint)> accessKeys, Queue<AccessRecord> accessLog, int accessLogLimit)
|
public AccessReaderComponentState(
|
||||||
|
bool enabled,
|
||||||
|
HashSet<ProtoId<AccessLevelPrototype>> denyTags,
|
||||||
|
List<HashSet<ProtoId<AccessLevelPrototype>>> accessLists,
|
||||||
|
List<HashSet<ProtoId<AccessLevelPrototype>>>? accessListsOriginal,
|
||||||
|
List<(NetEntity, uint)> accessKeys,
|
||||||
|
Queue<AccessRecord> accessLog,
|
||||||
|
int accessLogLimit)
|
||||||
{
|
{
|
||||||
Enabled = enabled;
|
Enabled = enabled;
|
||||||
DenyTags = denyTags;
|
DenyTags = denyTags;
|
||||||
AccessLists = accessLists;
|
AccessLists = accessLists;
|
||||||
|
AccessListsOriginal = accessListsOriginal;
|
||||||
AccessKeys = accessKeys;
|
AccessKeys = accessKeys;
|
||||||
AccessLog = accessLog;
|
AccessLog = accessLog;
|
||||||
AccessLogLimit = accessLogLimit;
|
AccessLogLimit = accessLogLimit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised after the settings on the access reader are changed.
|
||||||
|
/// </summary>
|
||||||
public sealed class AccessReaderConfigurationChangedEvent : EntityEventArgs;
|
public sealed class AccessReaderConfigurationChangedEvent : EntityEventArgs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised before the settings on the access reader are changed. Can be cancelled.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AccessReaderConfigurationAttemptEvent : CancellableEntityEventArgs;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Access.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see whether an access reader's settings have been modified.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class ShowAccessReaderSettingsComponent : Component, IClothingSlots
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines from which equipment slots this entity can provide its benefits.
|
||||||
|
/// </summary>
|
||||||
|
public SlotFlags Slots { get; set; } = ~SlotFlags.POCKET;
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.DeviceLinking.Events;
|
using Content.Shared.DeviceLinking.Events;
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
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.NameIdentifier;
|
using Content.Shared.NameIdentifier;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.StationRecords;
|
using Content.Shared.StationRecords;
|
||||||
@@ -37,17 +40,74 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AccessReaderComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||||
|
SubscribeLocalEvent<AccessReaderComponent, AccessReaderConfigurationAttemptEvent>(OnConfigurationAttempt);
|
||||||
|
|
||||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnExamined(Entity<AccessReaderComponent> ent, ref ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (!GetMainAccessReader(ent, out var mainAccessReader))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mainAccessReader.Value.Comp.AccessListsOriginal ??= new(mainAccessReader.Value.Comp.AccessLists);
|
||||||
|
|
||||||
|
var accessHasBeenModified = mainAccessReader.Value.Comp.AccessLists.Count != mainAccessReader.Value.Comp.AccessListsOriginal.Count;
|
||||||
|
|
||||||
|
if (!accessHasBeenModified)
|
||||||
|
{
|
||||||
|
foreach (var accessSubgroup in mainAccessReader.Value.Comp.AccessLists)
|
||||||
|
{
|
||||||
|
if (!mainAccessReader.Value.Comp.AccessListsOriginal.Any(y => y.SetEquals(accessSubgroup)))
|
||||||
|
{
|
||||||
|
accessHasBeenModified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var canSeeAccessModification = accessHasBeenModified &&
|
||||||
|
(HasComp<ShowAccessReaderSettingsComponent>(ent) ||
|
||||||
|
_inventorySystem.TryGetInventoryEntity<ShowAccessReaderSettingsComponent>(args.Examiner, out _));
|
||||||
|
|
||||||
|
if (canSeeAccessModification)
|
||||||
|
{
|
||||||
|
var localizedCurrentNames = GetLocalizedAccessNames(mainAccessReader.Value.Comp.AccessLists);
|
||||||
|
var accessesFormatted = ContentLocalizationManager.FormatListToOr(localizedCurrentNames);
|
||||||
|
var currentSettingsMessage = localizedCurrentNames.Count > 0
|
||||||
|
? Loc.GetString("access-reader-access-settings-modified-message", ("access", accessesFormatted))
|
||||||
|
: Loc.GetString("access-reader-access-settings-removed-message");
|
||||||
|
|
||||||
|
args.PushMarkup(currentSettingsMessage);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localizedOriginalNames = GetLocalizedAccessNames(mainAccessReader.Value.Comp.AccessListsOriginal);
|
||||||
|
|
||||||
|
// If the string list is empty either there were no access restrictions or the localized names were invalid
|
||||||
|
if (localizedOriginalNames.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var originalAccessesFormatted = ContentLocalizationManager.FormatListToOr(localizedOriginalNames);
|
||||||
|
var originalSettingsMessage = Loc.GetString(mainAccessReader.Value.Comp.ExaminationText, ("access", originalAccessesFormatted));
|
||||||
|
args.PushMarkup(originalSettingsMessage);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
||||||
{
|
{
|
||||||
args.State = new AccessReaderComponentState(component.Enabled, component.DenyTags, component.AccessLists,
|
args.State = new AccessReaderComponentState(
|
||||||
_recordsSystem.Convert(component.AccessKeys), component.AccessLog, component.AccessLogLimit);
|
component.Enabled,
|
||||||
|
component.DenyTags,
|
||||||
|
component.AccessLists,
|
||||||
|
component.AccessListsOriginal,
|
||||||
|
_recordsSystem.Convert(component.AccessKeys),
|
||||||
|
component.AccessLog,
|
||||||
|
component.AccessLogLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
||||||
@@ -66,6 +126,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
component.AccessLists = new(state.AccessLists);
|
component.AccessLists = new(state.AccessLists);
|
||||||
|
component.AccessListsOriginal = state.AccessListsOriginal == null ? null : new(state.AccessListsOriginal);
|
||||||
component.DenyTags = new(state.DenyTags);
|
component.DenyTags = new(state.DenyTags);
|
||||||
component.AccessLog = new(state.AccessLog);
|
component.AccessLog = new(state.AccessLog);
|
||||||
component.AccessLogLimit = state.AccessLogLimit;
|
component.AccessLogLimit = state.AccessLogLimit;
|
||||||
@@ -100,6 +161,13 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
Dirty(uid, reader);
|
Dirty(uid, reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnConfigurationAttempt(Entity<AccessReaderComponent> ent, ref AccessReaderConfigurationAttemptEvent args)
|
||||||
|
{
|
||||||
|
// The first time that the access list of the reader is modified,
|
||||||
|
// make a copy of the original settings
|
||||||
|
ent.Comp.AccessListsOriginal ??= new(ent.Comp.AccessLists);
|
||||||
|
}
|
||||||
|
|
||||||
/// <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.
|
||||||
@@ -348,11 +416,23 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
|
|
||||||
#region: AccessLists API
|
#region: AccessLists API
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to clear the entity's <see cref="AccessReaderComponent.AccessLists"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity which is having its access permissions cleared.</param>
|
||||||
|
public void TryClearAccesses(Entity<AccessReaderComponent> ent)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
ClearAccesses(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the entity's <see cref="AccessReaderComponent.AccessLists"/>.
|
/// Clears the entity's <see cref="AccessReaderComponent.AccessLists"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity which is having its access permissions cleared.</param>
|
/// <param name="ent">The access reader entity which is having its access permissions cleared.</param>
|
||||||
public void ClearAccesses(Entity<AccessReaderComponent> ent)
|
private void ClearAccesses(Entity<AccessReaderComponent> ent)
|
||||||
{
|
{
|
||||||
ent.Comp.AccessLists.Clear();
|
ent.Comp.AccessLists.Clear();
|
||||||
|
|
||||||
@@ -360,32 +440,65 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to replace the access permissions in an entity's <see cref="AccessReaderComponent.AccessLists"/> with a supplied list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity which is having its list of access permissions replaced.</param>
|
||||||
|
/// <param name="accesses">The list of access permissions replacing the original one.</param>
|
||||||
|
public void TrySetAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
SetAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces the access permissions in an entity's <see cref="AccessReaderComponent.AccessLists"/> with a supplied list.
|
/// Replaces the access permissions in an entity's <see cref="AccessReaderComponent.AccessLists"/> with a supplied list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity which is having its list of access permissions replaced.</param>
|
/// <param name="ent">The access reader entity which is having its list of access permissions replaced.</param>
|
||||||
/// <param name="accesses">The list of access permissions replacing the original one.</param>
|
/// <param name="accesses">The list of access permissions replacing the original one.</param>
|
||||||
public void SetAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
private void SetAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
{
|
{
|
||||||
ent.Comp.AccessLists.Clear();
|
ent.Comp.AccessLists.Clear();
|
||||||
|
|
||||||
AddAccesses(ent, accesses);
|
AddAccesses(ent, accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref = "TrySetAccesses"/>
|
||||||
|
public void TrySetAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
SetAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref = "SetAccesses"/>
|
/// <inheritdoc cref = "SetAccesses"/>
|
||||||
public void SetAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
private void SetAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
{
|
{
|
||||||
ent.Comp.AccessLists.Clear();
|
ent.Comp.AccessLists.Clear();
|
||||||
|
|
||||||
AddAccesses(ent, accesses);
|
AddAccesses(ent, accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to add a collection of access permissions to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity to which the new access permissions are being added.</param>
|
||||||
|
/// <param name="accesses">The list of access permissions being added.</param>
|
||||||
|
public void TryAddAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
AddAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a collection of access permissions to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
/// Adds a collection of access permissions to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity to which the new access permissions are being added.</param>
|
/// <param name="ent">The access reader entity to which the new access permissions are being added.</param>
|
||||||
/// <param name="accesses">The list of access permissions being added.</param>
|
/// <param name="accesses">The list of access permissions being added.</param>
|
||||||
public void AddAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
private void AddAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
{
|
{
|
||||||
foreach (var access in accesses)
|
foreach (var access in accesses)
|
||||||
{
|
{
|
||||||
@@ -396,8 +509,17 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref = "TryAddAccesses"/>
|
||||||
|
public void TryAddAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
AddAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref = "AddAccesses"/>
|
/// <inheritdoc cref = "AddAccesses"/>
|
||||||
public void AddAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
private void AddAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
{
|
{
|
||||||
foreach (var access in accesses)
|
foreach (var access in accesses)
|
||||||
{
|
{
|
||||||
@@ -408,13 +530,27 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to add an access permission to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity to which the access permission is being added.</param>
|
||||||
|
/// <param name="access">The access permission being added.</param>
|
||||||
|
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
||||||
|
public void TryAddAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
AddAccess(ent, access);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an access permission to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
/// Adds an access permission to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity to which the access permission is being added.</param>
|
/// <param name="ent">The access reader entity to which the access permission is being added.</param>
|
||||||
/// <param name="access">The access permission being added.</param>
|
/// <param name="access">The access permission being added.</param>
|
||||||
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
||||||
public void AddAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
|
private void AddAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
|
||||||
{
|
{
|
||||||
ent.Comp.AccessLists.Add(access);
|
ent.Comp.AccessLists.Add(access);
|
||||||
|
|
||||||
@@ -425,18 +561,40 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref = "TryAddAccess"/>
|
||||||
|
public void TryAddAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
AddAccess(ent, access);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref = "AddAccess"/>
|
/// <inheritdoc cref = "AddAccess"/>
|
||||||
public void AddAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
|
private void AddAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
|
||||||
{
|
{
|
||||||
AddAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
|
AddAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to remove a collection of access permissions from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity from which the access permissions are being removed.</param>
|
||||||
|
/// <param name="accesses">The list of access permissions being removed.</param>
|
||||||
|
public void TryRemoveAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
RemoveAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a collection of access permissions from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
/// Removes a collection of access permissions from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity from which the access permissions are being removed.</param>
|
/// <param name="ent">The access reader entity from which the access permissions are being removed.</param>
|
||||||
/// <param name="accesses">The list of access permissions being removed.</param>
|
/// <param name="accesses">The list of access permissions being removed.</param>
|
||||||
public void RemoveAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
private void RemoveAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
|
||||||
{
|
{
|
||||||
foreach (var access in accesses)
|
foreach (var access in accesses)
|
||||||
{
|
{
|
||||||
@@ -447,8 +605,17 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref = "TryRemoveAccesses"/>
|
||||||
|
public void TryRemoveAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
RemoveAccesses(ent, accesses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref = "RemoveAccesses"/>
|
/// <inheritdoc cref = "RemoveAccesses"/>
|
||||||
public void RemoveAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
private void RemoveAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||||
{
|
{
|
||||||
foreach (var access in accesses)
|
foreach (var access in accesses)
|
||||||
{
|
{
|
||||||
@@ -459,13 +626,27 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to removes an access permission from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ent">The access reader entity from which the access permission is being removed.</param>
|
||||||
|
/// <param name="access">The access permission being removed.</param>
|
||||||
|
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
||||||
|
public void TryRemoveAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
RemoveAccess(ent, access);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes an access permission from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
/// Removes an access permission from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The access reader entity from which the access permission is being removed.</param>
|
/// <param name="ent">The access reader entity from which the access permission is being removed.</param>
|
||||||
/// <param name="access">The access permission being removed.</param>
|
/// <param name="access">The access permission being removed.</param>
|
||||||
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
|
||||||
public void RemoveAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
|
private void RemoveAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
|
||||||
{
|
{
|
||||||
for (int i = ent.Comp.AccessLists.Count - 1; i >= 0; i--)
|
for (int i = ent.Comp.AccessLists.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@@ -482,12 +663,29 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref = "TryRemoveAccess"/>
|
||||||
|
public void TryRemoveAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access)
|
||||||
|
{
|
||||||
|
if (CanConfigureAccessReader(ent))
|
||||||
|
{
|
||||||
|
RemoveAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref = "RemoveAccess"/>
|
/// <inheritdoc cref = "RemoveAccess"/>
|
||||||
public void RemoveAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
|
private void RemoveAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
|
||||||
{
|
{
|
||||||
RemoveAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
|
RemoveAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanConfigureAccessReader(Entity<AccessReaderComponent> ent)
|
||||||
|
{
|
||||||
|
var ev = new AccessReaderConfigurationAttemptEvent();
|
||||||
|
RaiseLocalEvent(ent, ev);
|
||||||
|
|
||||||
|
return !ev.Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region: AccessKeys API
|
#region: AccessKeys API
|
||||||
@@ -727,4 +925,38 @@ public sealed class AccessReaderSystem : EntitySystem
|
|||||||
|
|
||||||
Dirty(ent);
|
Dirty(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<string> GetLocalizedAccessNames(List<HashSet<ProtoId<AccessLevelPrototype>>> accessLists)
|
||||||
|
{
|
||||||
|
var localizedNames = new List<string>();
|
||||||
|
string? andSeparator = null;
|
||||||
|
|
||||||
|
foreach (var accessHashSet in accessLists)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var accessSubset = accessHashSet.ToList();
|
||||||
|
|
||||||
|
// Combine the names of all access levels in the subset into a single string
|
||||||
|
foreach (var access in accessSubset)
|
||||||
|
{
|
||||||
|
var accessName = Loc.GetString("access-reader-unknown-id");
|
||||||
|
|
||||||
|
if (_prototype.Resolve(access, out var accessProto) && !string.IsNullOrWhiteSpace(accessProto.Name))
|
||||||
|
accessName = Loc.GetString(accessProto.Name);
|
||||||
|
|
||||||
|
sb.Append(Loc.GetString("access-reader-access-label", ("access", accessName)));
|
||||||
|
|
||||||
|
if (accessSubset.IndexOf(access) < (accessSubset.Count - 1))
|
||||||
|
{
|
||||||
|
andSeparator ??= " " + Loc.GetString("generic-and") + " ";
|
||||||
|
sb.Append(andSeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this string to the list
|
||||||
|
localizedNames.Add(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return localizedNames;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace Content.Shared.Localizations
|
|||||||
<= 0 => string.Empty,
|
<= 0 => string.Empty,
|
||||||
1 => list[0],
|
1 => list[0],
|
||||||
2 => $"{list[0]} or {list[1]}",
|
2 => $"{list[0]} or {list[1]}",
|
||||||
_ => $"{string.Join(" or ", list)}"
|
_ => $"{string.Join(", ", list.GetRange(0, list.Count - 1))}, or {list[^1]}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
access-reader-unknown-id = Unknown
|
access-reader-unknown-id = Unknown
|
||||||
|
access-reader-access-label = [color=yellow]{$access}[/color]
|
||||||
|
access-reader-examination = Access is generally restricted to personnel with {$access} access.
|
||||||
|
access-reader-examination-functionality-restricted = {$access} access may be required to use certain functions.
|
||||||
|
access-reader-access-settings-modified-message = [italic]The access reader has been modified to accept personnel with {$access} access.[/italic]
|
||||||
|
access-reader-access-settings-removed-message = [italic]The settings on the access reader have been deleted.[/italic]
|
||||||
@@ -4,6 +4,9 @@ generic-not-available-shorthand = N/A
|
|||||||
generic-article-a = a
|
generic-article-a = a
|
||||||
generic-article-an = an
|
generic-article-an = an
|
||||||
|
|
||||||
|
generic-and = and
|
||||||
|
generic-or = or
|
||||||
|
|
||||||
generic-unknown = unknown
|
generic-unknown = unknown
|
||||||
generic-unknown-title = Unknown
|
generic-unknown-title = Unknown
|
||||||
generic-error = error
|
generic-error = error
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
damageContainers:
|
damageContainers:
|
||||||
- Inorganic
|
- Inorganic
|
||||||
- Silicon
|
- Silicon
|
||||||
|
- type: ShowAccessReaderSettings
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: [ClothingEyesBase, ShowMedicalIcons]
|
parent: [ClothingEyesBase, ShowMedicalIcons]
|
||||||
|
|||||||
@@ -132,6 +132,7 @@
|
|||||||
price: 150
|
price: 150
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering" ] ]
|
access: [ [ "Engineering" ] ]
|
||||||
|
examinationText: access-reader-examination-functionality-restricted
|
||||||
- type: PryUnpowered
|
- type: PryUnpowered
|
||||||
pryModifier: 0.5
|
pryModifier: 0.5
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
|
|||||||
@@ -76,6 +76,7 @@
|
|||||||
speakerVolume: Speak
|
speakerVolume: Speak
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [[ "Command" ]]
|
access: [[ "Command" ]]
|
||||||
|
examinationText: access-reader-examination-functionality-restricted
|
||||||
- type: ActivatableUI
|
- type: ActivatableUI
|
||||||
key: enum.HolopadUiKey.InteractionWindow
|
key: enum.HolopadUiKey.InteractionWindow
|
||||||
- type: ActivatableUIRequiresPower
|
- type: ActivatableUIRequiresPower
|
||||||
|
|||||||
@@ -416,6 +416,7 @@
|
|||||||
type: GenpopLockerBoundUserInterface
|
type: GenpopLockerBoundUserInterface
|
||||||
- type: AccessReader # note! this access is for the UI, not the door. door access is handled on GenpopLocker
|
- type: AccessReader # note! this access is for the UI, not the door. door access is handled on GenpopLocker
|
||||||
access: [["Security"]]
|
access: [["Security"]]
|
||||||
|
examinationText: access-reader-examination-functionality-restricted
|
||||||
- type: Lock
|
- type: Lock
|
||||||
locked: false
|
locked: false
|
||||||
useAccess: false
|
useAccess: false
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
breakOnAccessBreaker: false
|
breakOnAccessBreaker: false
|
||||||
access: [["Cryogenics"]]
|
access: [["Cryogenics"]]
|
||||||
|
examinationText: access-reader-examination-functionality-restricted
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Cryostorage
|
- type: Cryostorage
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
|
|||||||
Reference in New Issue
Block a user