Add door electronics access configuration menu (#17778)
* Add door electronics configuration menu * Use file-scoped namespaces Signed-off-by: c4llv07e <kseandi@gmail.com> * Open door electronics configuration menu only with network configurator Signed-off-by: c4llv07e <kseandi@gmail.com> * Doors will now try to move their AccessReaderComponent to their door electronics when the map is initialized Signed-off-by: c4llv07e <kseandi@gmail.com> * Make the access list in the id card computer a separate control Signed-off-by: c4llv07e <kseandi@gmail.com> * Fix merge conflict Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove DoorElectronics tag Signed-off-by: c4llv07e <kseandi@gmail.com> * Integrate doors with #17927 Signed-off-by: c4llv07e <kseandi@gmail.com> * Move door electornics ui stuff to the right place Signed-off-by: c4llv07e <kseandi@gmail.com> * Some review fixes Signed-off-by: c4llv07e <kseandi@gmail.com> * More fixes Signed-off-by: c4llv07e <kseandi@gmail.com> * review fix Signed-off-by: c4llv07e <kseandi@gmail.com> * move all accesses from airlock prototypes to door electronics Signed-off-by: c4llv07e <kseandi@gmail.com> * rework door electronics config access list Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove Linq from the door electronics user interface * [WIP] Add EntityWhitelist to the activatable ui component Signed-off-by: c4llv07e <kseandi@gmail.com> * Better interaction system Signed-off-by: c4llv07e <kseandi@gmail.com> * Refactor Signed-off-by: c4llv07e <kseandi@gmail.com> * Fix some door electronics not working without AccessReaderComponent Signed-off-by: c4llv07e <kseandi@gmail.com> * Move AccessReaderComponent update code to the AccessReaderSystem Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove unnecesary newlines in the door access prototypes Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove unused variables in access level control Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove unnecessary method from the door electronics configuration menu Signed-off-by: c4llv07e <kseandi@gmail.com> * [WIP] change access type from string to ProtoId<AccessLevelPrototype> Signed-off-by: c4llv07e <kseandi@gmail.com> * Remove unused methods Signed-off-by: c4llv07e <kseandi@gmail.com> * Newline fix Signed-off-by: c4llv07e <kseandi@gmail.com> * Restored to a functional state Signed-off-by: c4llv07e <kseandi@gmail.com> * Fix access configurator not working with door electronics AccessReaderComponent Signed-off-by: c4llv07e <kseandi@gmail.com> * Replace all string access fields with ProtoId Signed-off-by: c4llv07e <kseandi@gmail.com> * move access level control initialization into Populate method Signed-off-by: c4llv07e <kseandi@gmail.com> * Review --------- Signed-off-by: c4llv07e <kseandi@gmail.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
4
Content.Client/Access/UI/AccessLevelControl.xaml
Normal file
4
Content.Client/Access/UI/AccessLevelControl.xaml
Normal file
@@ -0,0 +1,4 @@
|
||||
<GridContainer xmlns="https://spacestation14.io"
|
||||
Columns="5"
|
||||
HorizontalAlignment="Center">
|
||||
</GridContainer>
|
||||
52
Content.Client/Access/UI/AccessLevelControl.xaml.cs
Normal file
52
Content.Client/Access/UI/AccessLevelControl.xaml.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Systems;
|
||||
|
||||
namespace Content.Client.Access.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AccessLevelControl : GridContainer
|
||||
{
|
||||
public readonly Dictionary<ProtoId<AccessLevelPrototype>, Button> ButtonsList = new();
|
||||
|
||||
public AccessLevelControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void Populate(List<ProtoId<AccessLevelPrototype>> accessLevels, IPrototypeManager prototypeManager)
|
||||
{
|
||||
foreach (var access in accessLevels)
|
||||
{
|
||||
if (!prototypeManager.TryIndex(access, out var accessLevel))
|
||||
{
|
||||
Logger.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var newButton = new Button
|
||||
{
|
||||
Text = accessLevel.GetAccessLevelName(),
|
||||
ToggleMode = true,
|
||||
};
|
||||
AddChild(newButton);
|
||||
ButtonsList.Add(accessLevel.ID, newButton);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateState(
|
||||
List<ProtoId<AccessLevelPrototype>> pressedList,
|
||||
List<ProtoId<AccessLevelPrototype>>? enabledList = null)
|
||||
{
|
||||
foreach (var (accessName, button) in ButtonsList)
|
||||
{
|
||||
button.Pressed = pressedList.Contains(accessName);
|
||||
button.Disabled = !(enabledList?.Contains(accessName) ?? true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace Content.Client.Access.UI
|
||||
_window?.UpdateState(castState);
|
||||
}
|
||||
|
||||
public void SubmitData(List<string> newAccessList)
|
||||
public void SubmitData(List<ProtoId<AccessLevelPrototype>> newAccessList)
|
||||
{
|
||||
SendMessage(new WriteToTargetAccessReaderIdMessage(newAccessList));
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Content.Client.Access.UI
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private readonly ISawmill _logMill = default!;
|
||||
private readonly AccessOverriderBoundUserInterface _owner;
|
||||
private readonly Dictionary<string, Button> _accessButtons = new();
|
||||
|
||||
@@ -25,7 +24,7 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill);
|
||||
var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill);
|
||||
|
||||
_owner = owner;
|
||||
|
||||
@@ -33,13 +32,13 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
if (!prototypeManager.TryIndex(access, out var accessLevel))
|
||||
{
|
||||
_logMill.Error($"Unable to find accesslevel for {access}");
|
||||
logMill.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var newButton = new Button
|
||||
{
|
||||
Text = GetAccessLevelName(accessLevel),
|
||||
Text = accessLevel.GetAccessLevelName(),
|
||||
ToggleMode = true,
|
||||
};
|
||||
|
||||
@@ -49,14 +48,6 @@ namespace Content.Client.Access.UI
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetAccessLevelName(AccessLevelPrototype prototype)
|
||||
{
|
||||
if (prototype.Name is { } name)
|
||||
return Loc.GetString(name);
|
||||
|
||||
return prototype.ID;
|
||||
}
|
||||
|
||||
public void UpdateState(AccessOverriderBoundUserInterfaceState state)
|
||||
{
|
||||
PrivilegedIdLabel.Text = state.PrivilegedIdName;
|
||||
@@ -105,7 +96,7 @@ namespace Content.Client.Access.UI
|
||||
_owner.SubmitData(
|
||||
|
||||
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
|
||||
_accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
|
||||
_accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId<AccessLevelPrototype>(x.Key)).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.CrewManifest;
|
||||
@@ -28,7 +29,6 @@ namespace Content.Client.Access.UI
|
||||
if (EntMan.TryGetComponent<IdCardConsoleComponent>(Owner, out var idCard))
|
||||
{
|
||||
accessLevels = idCard.AccessLevels;
|
||||
accessLevels.Sort();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -65,7 +65,7 @@ namespace Content.Client.Access.UI
|
||||
_window?.UpdateState(castState);
|
||||
}
|
||||
|
||||
public void SubmitData(string newFullName, string newJobTitle, List<string> newAccessList, string newJobPrototype)
|
||||
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, string newJobPrototype)
|
||||
{
|
||||
if (newFullName.Length > MaxFullNameLength)
|
||||
newFullName = newFullName[..MaxFullNameLength];
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
<Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
|
||||
<OptionButton Name="JobPresetOptionButton" />
|
||||
</GridContainer>
|
||||
<GridContainer Name="AccessLevelGrid" Columns="5" HorizontalAlignment="Center">
|
||||
|
||||
<!-- Access level buttons are added here by the C# code -->
|
||||
|
||||
</GridContainer>
|
||||
<Control Name="AccessLevelControlContainer" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Content.Client.Access.UI
|
||||
|
||||
private readonly IdCardConsoleBoundUserInterface _owner;
|
||||
|
||||
private readonly Dictionary<string, Button> _accessButtons = new();
|
||||
private AccessLevelControl _accessButtons = new();
|
||||
private readonly List<string> _jobPrototypeIds = new();
|
||||
|
||||
private string? _lastFullName;
|
||||
@@ -66,36 +66,18 @@ namespace Content.Client.Access.UI
|
||||
|
||||
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
|
||||
|
||||
foreach (var access in accessLevels)
|
||||
{
|
||||
if (!prototypeManager.TryIndex<AccessLevelPrototype>(access, out var accessLevel))
|
||||
{
|
||||
_logMill.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
_accessButtons.Populate(accessLevels, prototypeManager);
|
||||
AccessLevelControlContainer.AddChild(_accessButtons);
|
||||
|
||||
var newButton = new Button
|
||||
foreach (var (id, button) in _accessButtons.ButtonsList)
|
||||
{
|
||||
Text = GetAccessLevelName(accessLevel),
|
||||
ToggleMode = true,
|
||||
};
|
||||
AccessLevelGrid.AddChild(newButton);
|
||||
_accessButtons.Add(accessLevel.ID, newButton);
|
||||
newButton.OnPressed += _ => SubmitData();
|
||||
button.OnPressed += _ => SubmitData();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetAccessLevelName(AccessLevelPrototype prototype)
|
||||
{
|
||||
if (prototype.Name is { } name)
|
||||
return Loc.GetString(name);
|
||||
|
||||
return prototype.ID;
|
||||
}
|
||||
|
||||
private void ClearAllAccess()
|
||||
{
|
||||
foreach (var button in _accessButtons.Values)
|
||||
foreach (var button in _accessButtons.ButtonsList.Values)
|
||||
{
|
||||
if (button.Pressed)
|
||||
{
|
||||
@@ -119,7 +101,7 @@ namespace Content.Client.Access.UI
|
||||
// this is a sussy way to do this
|
||||
foreach (var access in job.Access)
|
||||
{
|
||||
if (_accessButtons.TryGetValue(access, out var button) && !button.Disabled)
|
||||
if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
|
||||
{
|
||||
button.Pressed = true;
|
||||
}
|
||||
@@ -134,7 +116,7 @@ namespace Content.Client.Access.UI
|
||||
|
||||
foreach (var access in groupPrototype.Tags)
|
||||
{
|
||||
if (_accessButtons.TryGetValue(access, out var button) && !button.Disabled)
|
||||
if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
|
||||
{
|
||||
button.Pressed = true;
|
||||
}
|
||||
@@ -184,15 +166,10 @@ namespace Content.Client.Access.UI
|
||||
|
||||
JobPresetOptionButton.Disabled = !interfaceEnabled;
|
||||
|
||||
foreach (var (accessName, button) in _accessButtons)
|
||||
{
|
||||
button.Disabled = !interfaceEnabled;
|
||||
if (interfaceEnabled)
|
||||
{
|
||||
button.Pressed = state.TargetIdAccessList?.Contains(accessName) ?? false;
|
||||
button.Disabled = (!state.AllowedModifyAccessList?.Contains(accessName)) ?? true;
|
||||
}
|
||||
}
|
||||
_accessButtons.UpdateState(state.TargetIdAccessList?.ToList() ??
|
||||
new List<ProtoId<AccessLevelPrototype>>(),
|
||||
state.AllowedModifyAccessList?.ToList() ??
|
||||
new List<ProtoId<AccessLevelPrototype>>());
|
||||
|
||||
var jobIndex = _jobPrototypeIds.IndexOf(state.TargetIdJobPrototype);
|
||||
if (jobIndex >= 0)
|
||||
@@ -215,7 +192,7 @@ namespace Content.Client.Access.UI
|
||||
FullNameLineEdit.Text,
|
||||
JobTitleLineEdit.Text,
|
||||
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
|
||||
_accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList(),
|
||||
_accessButtons.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList(),
|
||||
jobProtoDirty ? _jobPrototypeIds[JobPresetOptionButton.SelectedId] : string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Doors.Electronics;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Doors.Electronics;
|
||||
|
||||
public sealed class DoorElectronicsBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private DoorElectronicsConfigurationMenu? _window;
|
||||
|
||||
public DoorElectronicsBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
List<ProtoId<AccessLevelPrototype>> accessLevels = new();
|
||||
|
||||
foreach (var accessLevel in _prototypeManager.EnumeratePrototypes<AccessLevelPrototype>())
|
||||
{
|
||||
if (accessLevel.Name != null)
|
||||
{
|
||||
accessLevels.Add(accessLevel.ID);
|
||||
}
|
||||
}
|
||||
|
||||
accessLevels.Sort();
|
||||
|
||||
_window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager);
|
||||
_window.OnClose += Close;
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
var castState = (DoorElectronicsConfigurationState) state;
|
||||
|
||||
_window?.UpdateState(castState);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
|
||||
public void UpdateConfiguration(List<ProtoId<AccessLevelPrototype>> newAccessList)
|
||||
{
|
||||
SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<Control Name="AccessLevelControlContainer" />
|
||||
|
||||
</controls:FancyWindow>
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Client.Access.UI;
|
||||
using Content.Client.Doors.Electronics;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Doors.Electronics;
|
||||
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
|
||||
|
||||
namespace Content.Client.Doors.Electronics;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow
|
||||
{
|
||||
private readonly DoorElectronicsBoundUserInterface _owner;
|
||||
private AccessLevelControl _buttonsList = new();
|
||||
|
||||
public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List<ProtoId<AccessLevelPrototype>> accessLevels, IPrototypeManager prototypeManager)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_owner = ui;
|
||||
|
||||
_buttonsList.Populate(accessLevels, prototypeManager);
|
||||
AccessLevelControlContainer.AddChild(_buttonsList);
|
||||
|
||||
foreach (var (id, button) in _buttonsList.ButtonsList)
|
||||
{
|
||||
button.OnPressed += _ => _owner.UpdateConfiguration(
|
||||
_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateState(DoorElectronicsConfigurationState state)
|
||||
{
|
||||
_buttonsList.UpdateState(state.AccessList);
|
||||
}
|
||||
}
|
||||
@@ -57,9 +57,9 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
var reader = new AccessReaderComponent();
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "Foo" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "Bar" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "Foo" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "Bar" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.True);
|
||||
});
|
||||
|
||||
// test deny
|
||||
@@ -67,58 +67,58 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
reader.DenyTags.Add("A");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "Foo" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A", "Foo" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "Foo" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "Foo" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.True);
|
||||
});
|
||||
|
||||
// test one list
|
||||
reader = new AccessReaderComponent();
|
||||
reader.AccessLists.Add(new HashSet<string> { "A" });
|
||||
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||
});
|
||||
|
||||
// test one list - two items
|
||||
reader = new AccessReaderComponent();
|
||||
reader.AccessLists.Add(new HashSet<string> { "A", "B" });
|
||||
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A", "B" });
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
|
||||
});
|
||||
|
||||
// test two list
|
||||
reader = new AccessReaderComponent();
|
||||
reader.AccessLists.Add(new HashSet<string> { "A" });
|
||||
reader.AccessLists.Add(new HashSet<string> { "B", "C" });
|
||||
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
|
||||
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "B", "C" });
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "C", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "C", "B", "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "C", "B" }, 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);
|
||||
});
|
||||
|
||||
// test deny list
|
||||
reader = new AccessReaderComponent();
|
||||
reader.AccessLists.Add(new HashSet<string> { "A" });
|
||||
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
|
||||
reader.DenyTags.Add("B");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new[] { "A", "B" }, reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(Array.Empty<string>(), reader), Is.False);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
|
||||
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "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);
|
||||
});
|
||||
});
|
||||
await pair.CleanReturnAsync();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
@@ -12,6 +13,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.Access.Components.AccessOverriderComponent;
|
||||
|
||||
namespace Content.Server.Access.Systems;
|
||||
@@ -26,6 +28,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -108,17 +111,20 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
var targetLabel = Loc.GetString("access-overrider-window-no-target");
|
||||
var targetLabelColor = Color.Red;
|
||||
|
||||
string[]? possibleAccess = null;
|
||||
string[]? currentAccess = null;
|
||||
string[]? missingAccess = null;
|
||||
ProtoId<AccessLevelPrototype>[]? possibleAccess = null;
|
||||
ProtoId<AccessLevelPrototype>[]? currentAccess = null;
|
||||
ProtoId<AccessLevelPrototype>[]? missingAccess = null;
|
||||
|
||||
if (component.TargetAccessReaderId is { Valid: true } accessReader)
|
||||
{
|
||||
targetLabel = Loc.GetString("access-overrider-window-target-label") + " " + EntityManager.GetComponent<MetaDataComponent>(component.TargetAccessReaderId).EntityName;
|
||||
targetLabelColor = Color.White;
|
||||
|
||||
List<HashSet<string>> currentAccessHashsets = EntityManager.GetComponent<AccessReaderComponent>(accessReader).AccessLists;
|
||||
currentAccess = ConvertAccessHashSetsToList(currentAccessHashsets)?.ToArray();
|
||||
if (!_accessReader.GetMainAccessReader(accessReader, out var accessReaderComponent))
|
||||
return;
|
||||
|
||||
var currentAccessHashsets = accessReaderComponent.AccessLists;
|
||||
currentAccess = ConvertAccessHashSetsToList(currentAccessHashsets).ToArray();
|
||||
}
|
||||
|
||||
if (component.PrivilegedIdSlot.Item is { Valid: true } idCard)
|
||||
@@ -151,15 +157,15 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
_userInterface.TrySetUiState(uid, AccessOverriderUiKey.Key, newState);
|
||||
}
|
||||
|
||||
private List<string> ConvertAccessHashSetsToList(List<HashSet<string>> accessHashsets)
|
||||
private List<ProtoId<AccessLevelPrototype>> ConvertAccessHashSetsToList(List<HashSet<ProtoId<AccessLevelPrototype>>> accessHashsets)
|
||||
{
|
||||
List<string> accessList = new List<string>();
|
||||
List<ProtoId<AccessLevelPrototype>> accessList = new List<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
if (accessHashsets != null && accessHashsets.Any())
|
||||
{
|
||||
foreach (HashSet<string> hashSet in accessHashsets)
|
||||
foreach (HashSet<ProtoId<AccessLevelPrototype>> hashSet in accessHashsets)
|
||||
{
|
||||
foreach (string hash in hashSet.ToArray())
|
||||
foreach (ProtoId<AccessLevelPrototype> hash in hashSet.ToArray())
|
||||
{
|
||||
accessList.Add(hash);
|
||||
}
|
||||
@@ -169,15 +175,15 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
return accessList;
|
||||
}
|
||||
|
||||
private List<HashSet<string>> ConvertAccessListToHashSet(List<string> accessList)
|
||||
private List<HashSet<ProtoId<AccessLevelPrototype>>> ConvertAccessListToHashSet(List<ProtoId<AccessLevelPrototype>> accessList)
|
||||
{
|
||||
List<HashSet<string>> accessHashsets = new List<HashSet<string>>();
|
||||
List<HashSet<ProtoId<AccessLevelPrototype>>> accessHashsets = new List<HashSet<ProtoId<AccessLevelPrototype>>>();
|
||||
|
||||
if (accessList != null && accessList.Any())
|
||||
{
|
||||
foreach (string access in accessList)
|
||||
foreach (ProtoId<AccessLevelPrototype> access in accessList)
|
||||
{
|
||||
accessHashsets.Add(new HashSet<string>() { access });
|
||||
accessHashsets.Add(new HashSet<ProtoId<AccessLevelPrototype>>() { access });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +194,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
/// Called whenever an access button is pressed, adding or removing that access requirement from the target access reader.
|
||||
/// </summary>
|
||||
private void TryWriteToTargetAccessReaderId(EntityUid uid,
|
||||
List<string> newAccessList,
|
||||
List<ProtoId<AccessLevelPrototype>> newAccessList,
|
||||
EntityUid player,
|
||||
AccessOverriderComponent? component = null)
|
||||
{
|
||||
@@ -211,9 +217,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
return;
|
||||
}
|
||||
|
||||
TryComp(component.TargetAccessReaderId, out AccessReaderComponent? accessReader);
|
||||
|
||||
if (accessReader == null)
|
||||
if (!_accessReader.GetMainAccessReader(component.TargetAccessReaderId, out var accessReader))
|
||||
return;
|
||||
|
||||
var oldTags = ConvertAccessHashSetsToList(accessReader.AccessLists);
|
||||
@@ -262,10 +266,10 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return true;
|
||||
|
||||
if (!EntityManager.TryGetComponent<AccessReaderComponent>(uid, out var reader))
|
||||
if (_accessReader.GetMainAccessReader(uid, out var accessReader))
|
||||
return true;
|
||||
|
||||
var privilegedId = component.PrivilegedIdSlot.Item;
|
||||
return privilegedId != null && _accessReader.IsAllowed(privilegedId.Value, uid, reader);
|
||||
return privilegedId != null && _accessReader.IsAllowed(privilegedId.Value, uid, accessReader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
using static Content.Shared.Access.Components.IdCardConsoleComponent;
|
||||
using Content.Shared.Access;
|
||||
|
||||
namespace Content.Server.Access.Systems;
|
||||
|
||||
@@ -54,11 +55,11 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
return;
|
||||
|
||||
var privilegedIdName = string.Empty;
|
||||
string[]? possibleAccess = null;
|
||||
List<ProtoId<AccessLevelPrototype>>? possibleAccess = null;
|
||||
if (component.PrivilegedIdSlot.Item is { Valid: true } item)
|
||||
{
|
||||
privilegedIdName = EntityManager.GetComponent<MetaDataComponent>(item).EntityName;
|
||||
possibleAccess = _accessReader.FindAccessTags(item).ToArray();
|
||||
possibleAccess = _accessReader.FindAccessTags(item).ToList();
|
||||
}
|
||||
|
||||
IdCardConsoleBoundUserInterfaceState newState;
|
||||
@@ -82,7 +83,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
var targetIdComponent = EntityManager.GetComponent<IdCardComponent>(targetId);
|
||||
var targetAccessComponent = EntityManager.GetComponent<AccessComponent>(targetId);
|
||||
|
||||
var jobProto = string.Empty;
|
||||
var jobProto = new ProtoId<AccessLevelPrototype>(string.Empty);
|
||||
if (TryComp<StationRecordKeyStorageComponent>(targetId, out var keyStorage)
|
||||
&& keyStorage.Key is {} key
|
||||
&& _record.TryGetRecord<GeneralStationRecord>(key, out var record))
|
||||
@@ -96,7 +97,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
true,
|
||||
targetIdComponent.FullName,
|
||||
targetIdComponent.JobTitle,
|
||||
targetAccessComponent.Tags.ToArray(),
|
||||
targetAccessComponent.Tags.ToList(),
|
||||
possibleAccess,
|
||||
jobProto,
|
||||
privilegedIdName,
|
||||
@@ -113,8 +114,8 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
private void TryWriteToTargetId(EntityUid uid,
|
||||
string newFullName,
|
||||
string newJobTitle,
|
||||
List<string> newAccessList,
|
||||
string newJobProto,
|
||||
List<ProtoId<AccessLevelPrototype>> newAccessList,
|
||||
ProtoId<AccessLevelPrototype> newJobProto,
|
||||
EntityUid player,
|
||||
IdCardConsoleComponent? component = null)
|
||||
{
|
||||
@@ -140,7 +141,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var oldTags = _access.TryGetTags(targetId) ?? new List<string>();
|
||||
var oldTags = _access.TryGetTags(targetId) ?? new List<ProtoId<AccessLevelPrototype>>();
|
||||
oldTags = oldTags.ToList();
|
||||
|
||||
var privilegedId = component.PrivilegedIdSlot.Item;
|
||||
@@ -189,7 +190,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
return privilegedId != null && _accessReader.IsAllowed(privilegedId.Value, uid, reader);
|
||||
}
|
||||
|
||||
private void UpdateStationRecord(EntityUid uid, EntityUid targetId, string newFullName, string newJobTitle, JobPrototype? newJobProto)
|
||||
private void UpdateStationRecord(EntityUid uid, EntityUid targetId, string newFullName, ProtoId<AccessLevelPrototype> newJobTitle, JobPrototype? newJobProto)
|
||||
{
|
||||
if (!TryComp<StationRecordKeyStorageComponent>(targetId, out var keyStorage)
|
||||
|| keyStorage.Key is not { } key
|
||||
|
||||
@@ -35,6 +35,7 @@ using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Systems;
|
||||
@@ -844,14 +845,14 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
var allAccess = _prototypeManager
|
||||
.EnumeratePrototypes<AccessLevelPrototype>()
|
||||
.Select(p => p.ID).ToArray();
|
||||
.Select(p => new ProtoId<AccessLevelPrototype>(p.ID)).ToArray();
|
||||
|
||||
_accessSystem.TrySetTags(entity, allAccess);
|
||||
}
|
||||
|
||||
private void RevokeAllAccess(EntityUid entity)
|
||||
{
|
||||
_accessSystem.TrySetTags(entity, Array.Empty<string>());
|
||||
_accessSystem.TrySetTags(entity, new List<ProtoId<AccessLevelPrototype>>());
|
||||
}
|
||||
|
||||
public enum TricksVerbPriorities
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Doors.Electronics;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.DeviceNetwork.Components;
|
||||
using Content.Shared.Doors.Electronics;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Doors.Electronics;
|
||||
|
||||
public sealed class DoorElectronicsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DoorElectronicsComponent, DoorElectronicsUpdateConfigurationMessage>(OnChangeConfiguration);
|
||||
SubscribeLocalEvent<DoorElectronicsComponent, AccessReaderConfigurationChangedEvent>(OnAccessReaderChanged);
|
||||
SubscribeLocalEvent<DoorElectronicsComponent, BoundUIOpenedEvent>(OnBoundUIOpened);
|
||||
}
|
||||
|
||||
public void UpdateUserInterface(EntityUid uid, DoorElectronicsComponent component)
|
||||
{
|
||||
var accesses = new List<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
if (TryComp<AccessReaderComponent>(uid, out var accessReader))
|
||||
{
|
||||
foreach (var accessList in accessReader.AccessLists)
|
||||
{
|
||||
var access = accessList.FirstOrDefault();
|
||||
accesses.Add(access);
|
||||
}
|
||||
}
|
||||
|
||||
var state = new DoorElectronicsConfigurationState(accesses);
|
||||
_uiSystem.TrySetUiState(uid, DoorElectronicsConfigurationUiKey.Key, state);
|
||||
}
|
||||
|
||||
private void OnChangeConfiguration(
|
||||
EntityUid uid,
|
||||
DoorElectronicsComponent component,
|
||||
DoorElectronicsUpdateConfigurationMessage args)
|
||||
{
|
||||
var accessReader = EnsureComp<AccessReaderComponent>(uid);
|
||||
_accessReader.SetAccesses(uid, accessReader, args.AccessList);
|
||||
}
|
||||
|
||||
private void OnAccessReaderChanged(
|
||||
EntityUid uid,
|
||||
DoorElectronicsComponent component,
|
||||
AccessReaderConfigurationChangedEvent args)
|
||||
{
|
||||
UpdateUserInterface(uid, component);
|
||||
}
|
||||
|
||||
private void OnBoundUIOpened(
|
||||
EntityUid uid,
|
||||
DoorElectronicsComponent component,
|
||||
BoundUIOpenedEvent args)
|
||||
{
|
||||
UpdateUserInterface(uid, component);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using Robust.Server.Placement;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Sandbox
|
||||
{
|
||||
@@ -121,7 +122,7 @@ namespace Content.Server.Sandbox
|
||||
|
||||
var allAccess = PrototypeManager
|
||||
.EnumeratePrototypes<AccessLevelPrototype>()
|
||||
.Select(p => p.ID).ToArray();
|
||||
.Select(p => new ProtoId<AccessLevelPrototype>(p.ID)).ToList();
|
||||
|
||||
if (_inventory.TryGetSlotEntity(attached, "id", out var slotEntity))
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Resist;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Coordinates;
|
||||
using Content.Shared.DoAfter;
|
||||
@@ -14,6 +15,7 @@ using Content.Shared.Tools.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Storage.EntitySystems;
|
||||
|
||||
@@ -138,7 +140,7 @@ public sealed class BluespaceLockerSystem : EntitySystem
|
||||
}
|
||||
|
||||
/// <returns>True if any HashSet in <paramref name="a"/> would grant access to <paramref name="b"/></returns>
|
||||
private bool AccessMatch(IReadOnlyCollection<HashSet<string>>? a, IReadOnlyCollection<HashSet<string>>? b)
|
||||
private bool AccessMatch(IReadOnlyCollection<HashSet<ProtoId<AccessLevelPrototype>>>? a, IReadOnlyCollection<HashSet<ProtoId<AccessLevelPrototype>>>? b)
|
||||
{
|
||||
if ((a == null || a.Count == 0) && (b == null || b.Count == 0))
|
||||
return true;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
|
||||
@@ -34,12 +37,19 @@ namespace Content.Server.UserInterface
|
||||
[DataField]
|
||||
public bool RequireHands = true;
|
||||
|
||||
/// <summary>
|
||||
/// Entities that are required to open this UI.
|
||||
/// </summary>
|
||||
[DataField("allowedItems")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public EntityWhitelist? AllowedItems = null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether you can activate this ui with activateinhand or not
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool rightClickOnly = false;
|
||||
public bool RightClickOnly;
|
||||
|
||||
/// <summary>
|
||||
/// Whether spectators (non-admin ghosts) should be allowed to view this UI.
|
||||
@@ -63,4 +73,3 @@ namespace Content.Server.UserInterface
|
||||
public ICommonSession? CurrentSingleUser;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
||||
|
||||
SubscribeLocalEvent<ActivatableUIComponent, ActivateInWorldEvent>(OnActivate);
|
||||
SubscribeLocalEvent<ActivatableUIComponent, UseInHandEvent>(OnUseInHand);
|
||||
SubscribeLocalEvent<ActivatableUIComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<ActivatableUIComponent, HandDeselectedEvent>(OnHandDeselected);
|
||||
SubscribeLocalEvent<ActivatableUIComponent, GotUnequippedHandEvent>((uid, aui, _) => CloseAll(uid, aui));
|
||||
// *THIS IS A BLATANT WORKAROUND!* RATIONALE: Microwaves need it
|
||||
@@ -100,12 +101,20 @@ public sealed partial class ActivatableUISystem : EntitySystem
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (component.rightClickOnly)
|
||||
if (component.RightClickOnly)
|
||||
return;
|
||||
|
||||
args.Handled = InteractUI(args.User, uid, component);
|
||||
}
|
||||
|
||||
private void OnInteractUsing(EntityUid uid, ActivatableUIComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
if (component.AllowedItems == null) return;
|
||||
if (!component.AllowedItems.IsValid(args.Used, EntityManager)) return;
|
||||
args.Handled = InteractUI(args.User, uid, component);
|
||||
}
|
||||
|
||||
private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntParentChangedMessage args)
|
||||
{
|
||||
CloseAll(uid, aui);
|
||||
|
||||
@@ -14,6 +14,6 @@ public sealed partial class AccessGroupPrototype : IPrototype
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("tags", required: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
public HashSet<string> Tags = default!;
|
||||
[DataField("tags", required: true)]
|
||||
public HashSet<ProtoId<AccessLevelPrototype>> Tags = default!;
|
||||
}
|
||||
|
||||
@@ -17,5 +17,13 @@ namespace Content.Shared.Access
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string GetAccessLevelName()
|
||||
{
|
||||
if (Name is { } name)
|
||||
return Loc.GetString(name);
|
||||
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,17 +20,17 @@ public sealed partial class AccessComponent : Component
|
||||
[AutoNetworkedField]
|
||||
public bool Enabled = true;
|
||||
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
[DataField]
|
||||
[Access(typeof(SharedAccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
[AutoNetworkedField]
|
||||
public HashSet<string> Tags = new();
|
||||
public HashSet<ProtoId<AccessLevelPrototype>> Tags = new();
|
||||
|
||||
/// <summary>
|
||||
/// Access Groups. These are added to the tags during map init. After map init this will have no effect.
|
||||
/// </summary>
|
||||
[DataField(readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessGroupPrototype>))]
|
||||
[DataField(readOnly: true)]
|
||||
[AutoNetworkedField]
|
||||
public HashSet<string> Groups = new();
|
||||
public HashSet<ProtoId<AccessGroupPrototype>> Groups = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,9 +47,9 @@ public struct GetAdditionalAccessEvent
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct GetAccessTagsEvent(HashSet<string> Tags, IPrototypeManager PrototypeManager)
|
||||
public record struct GetAccessTagsEvent(HashSet<ProtoId<AccessLevelPrototype>> Tags, IPrototypeManager PrototypeManager)
|
||||
{
|
||||
public void AddGroup(string group)
|
||||
public void AddGroup(ProtoId<AccessGroupPrototype> group)
|
||||
{
|
||||
if (!PrototypeManager.TryIndex<AccessGroupPrototype>(group, out var groupPrototype))
|
||||
return;
|
||||
|
||||
@@ -25,9 +25,9 @@ public sealed partial class AccessOverriderComponent : Component
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class WriteToTargetAccessReaderIdMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly List<string> AccessList;
|
||||
public readonly List<ProtoId<AccessLevelPrototype>> AccessList;
|
||||
|
||||
public WriteToTargetAccessReaderIdMessage(List<string> accessList)
|
||||
public WriteToTargetAccessReaderIdMessage(List<ProtoId<AccessLevelPrototype>> accessList)
|
||||
{
|
||||
AccessList = accessList;
|
||||
}
|
||||
@@ -48,15 +48,15 @@ public sealed partial class AccessOverriderComponent : Component
|
||||
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 readonly ProtoId<AccessLevelPrototype>[]? TargetAccessReaderIdAccessList;
|
||||
public readonly ProtoId<AccessLevelPrototype>[]? AllowedModifyAccessList;
|
||||
public readonly ProtoId<AccessLevelPrototype>[]? MissingPrivilegesList;
|
||||
|
||||
public AccessOverriderBoundUserInterfaceState(bool isPrivilegedIdPresent,
|
||||
bool isPrivilegedIdAuthorized,
|
||||
string[]? targetAccessReaderIdAccessList,
|
||||
string[]? allowedModifyAccessList,
|
||||
string[]? missingPrivilegesList,
|
||||
ProtoId<AccessLevelPrototype>[]? targetAccessReaderIdAccessList,
|
||||
ProtoId<AccessLevelPrototype>[]? allowedModifyAccessList,
|
||||
ProtoId<AccessLevelPrototype>[]? missingPrivilegesList,
|
||||
string privilegedIdName,
|
||||
string targetLabel,
|
||||
Color targetLabelColor)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
||||
|
||||
@@ -23,15 +24,15 @@ public sealed partial class AccessReaderComponent : Component
|
||||
/// The set of tags that will automatically deny an allowed check, if any of them are present.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
public HashSet<string> DenyTags = new();
|
||||
[DataField]
|
||||
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags = new();
|
||||
|
||||
/// <summary>
|
||||
/// List of access groups that grant access to this reader. Only a single matching group is required to gain access.
|
||||
/// A group matches if it is a subset of the set being checked against.
|
||||
/// </summary>
|
||||
[DataField("access")] [ViewVariables(VVAccess.ReadWrite)]
|
||||
public List<HashSet<string>> AccessLists = new();
|
||||
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists = new();
|
||||
|
||||
/// <summary>
|
||||
/// A list of <see cref="StationRecordKey"/>s that grant access. Only a single matching key is required to gain
|
||||
@@ -88,9 +89,9 @@ public sealed class AccessReaderComponentState : ComponentState
|
||||
{
|
||||
public bool Enabled;
|
||||
|
||||
public HashSet<string> DenyTags;
|
||||
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags;
|
||||
|
||||
public List<HashSet<string>> AccessLists;
|
||||
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists;
|
||||
|
||||
public List<(NetEntity, uint)> AccessKeys;
|
||||
|
||||
@@ -98,7 +99,7 @@ public sealed class AccessReaderComponentState : ComponentState
|
||||
|
||||
public int AccessLogLimit;
|
||||
|
||||
public AccessReaderComponentState(bool enabled, HashSet<string> denyTags, List<HashSet<string>> accessLists, List<(NetEntity, uint)> accessKeys, Queue<AccessRecord> accessLog, int accessLogLimit)
|
||||
public AccessReaderComponentState(bool enabled, HashSet<ProtoId<AccessLevelPrototype>> denyTags, List<HashSet<ProtoId<AccessLevelPrototype>>> accessLists, List<(NetEntity, uint)> accessKeys, Queue<AccessRecord> accessLog, int accessLogLimit)
|
||||
{
|
||||
Enabled = enabled;
|
||||
DenyTags = denyTags;
|
||||
@@ -108,3 +109,10 @@ public sealed class AccessReaderComponentState : ComponentState
|
||||
AccessLogLimit = accessLogLimit;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AccessReaderConfigurationChangedEvent : EntityEventArgs
|
||||
{
|
||||
public AccessReaderConfigurationChangedEvent()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ using Content.Shared.Containers.ItemSlots;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Access.Components;
|
||||
|
||||
@@ -27,10 +29,10 @@ public sealed partial class IdCardConsoleComponent : Component
|
||||
{
|
||||
public readonly string FullName;
|
||||
public readonly string JobTitle;
|
||||
public readonly List<string> AccessList;
|
||||
public readonly string JobPrototype;
|
||||
public readonly List<ProtoId<AccessLevelPrototype>> AccessList;
|
||||
public readonly ProtoId<AccessLevelPrototype> JobPrototype;
|
||||
|
||||
public WriteToTargetIdMessage(string fullName, string jobTitle, List<string> accessList, string jobPrototype)
|
||||
public WriteToTargetIdMessage(string fullName, string jobTitle, List<ProtoId<AccessLevelPrototype>> accessList, ProtoId<AccessLevelPrototype> jobPrototype)
|
||||
{
|
||||
FullName = fullName;
|
||||
JobTitle = jobTitle;
|
||||
@@ -86,18 +88,18 @@ public sealed partial class IdCardConsoleComponent : Component
|
||||
public readonly string TargetIdName;
|
||||
public readonly string? TargetIdFullName;
|
||||
public readonly string? TargetIdJobTitle;
|
||||
public readonly string[]? TargetIdAccessList;
|
||||
public readonly string[]? AllowedModifyAccessList;
|
||||
public readonly string TargetIdJobPrototype;
|
||||
public readonly List<ProtoId<AccessLevelPrototype>>? TargetIdAccessList;
|
||||
public readonly List<ProtoId<AccessLevelPrototype>>? AllowedModifyAccessList;
|
||||
public readonly ProtoId<AccessLevelPrototype> TargetIdJobPrototype;
|
||||
|
||||
public IdCardConsoleBoundUserInterfaceState(bool isPrivilegedIdPresent,
|
||||
bool isPrivilegedIdAuthorized,
|
||||
bool isTargetIdPresent,
|
||||
string? targetIdFullName,
|
||||
string? targetIdJobTitle,
|
||||
string[]? targetIdAccessList,
|
||||
string[]? allowedModifyAccessList,
|
||||
string targetIdJobPrototype,
|
||||
List<ProtoId<AccessLevelPrototype>>? targetIdAccessList,
|
||||
List<ProtoId<AccessLevelPrototype>>? allowedModifyAccessList,
|
||||
ProtoId<AccessLevelPrototype> targetIdJobPrototype,
|
||||
string privilegedIdName,
|
||||
string targetIdName)
|
||||
{
|
||||
|
||||
@@ -112,11 +112,36 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool GetMainAccessReader(EntityUid uid, [NotNullWhen(true)] out AccessReaderComponent? component)
|
||||
{
|
||||
component = null;
|
||||
if (!TryComp(uid, out AccessReaderComponent? accessReader))
|
||||
return false;
|
||||
|
||||
component = accessReader;
|
||||
|
||||
if (component.ContainerAccessProvider == null)
|
||||
return true;
|
||||
|
||||
if (!_containerSystem.TryGetContainer(uid, component.ContainerAccessProvider, out var container))
|
||||
return true;
|
||||
|
||||
foreach (var entity in container.ContainedEntities)
|
||||
{
|
||||
if (TryComp(entity, out AccessReaderComponent? containedReader))
|
||||
{
|
||||
component = containedReader;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the given access permissions satisfy an access reader's requirements.
|
||||
/// </summary>
|
||||
public bool IsAllowed(
|
||||
ICollection<string> access,
|
||||
ICollection<ProtoId<AccessLevelPrototype>> access,
|
||||
ICollection<StationRecordKey> stationKeys,
|
||||
EntityUid target,
|
||||
AccessReaderComponent reader)
|
||||
@@ -142,7 +167,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsAllowedInternal(ICollection<string> access, ICollection<StationRecordKey> stationKeys, AccessReaderComponent reader)
|
||||
private bool IsAllowedInternal(ICollection<ProtoId<AccessLevelPrototype>> access, ICollection<StationRecordKey> stationKeys, AccessReaderComponent reader)
|
||||
{
|
||||
return !reader.Enabled
|
||||
|| AreAccessTagsAllowed(access, reader)
|
||||
@@ -154,7 +179,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
/// </summary>
|
||||
/// <param name="accessTags">A list of access tags</param>
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool AreAccessTagsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
public bool AreAccessTagsAllowed(ICollection<ProtoId<AccessLevelPrototype>> accessTags, AccessReaderComponent reader)
|
||||
{
|
||||
if (reader.DenyTags.Overlaps(accessTags))
|
||||
{
|
||||
@@ -218,9 +243,9 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</param>
|
||||
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
|
||||
public ICollection<string> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
public ICollection<ProtoId<AccessLevelPrototype>> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
{
|
||||
HashSet<string>? tags = null;
|
||||
HashSet<ProtoId<AccessLevelPrototype>>? tags = null;
|
||||
var owned = false;
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
@@ -230,7 +255,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
FindAccessTagsItem(ent, ref tags, ref owned);
|
||||
}
|
||||
|
||||
return (ICollection<string>?) tags ?? Array.Empty<string>();
|
||||
return (ICollection<ProtoId<AccessLevelPrototype>>?) tags ?? Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -260,7 +285,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
/// This version merges into a set or replaces the set.
|
||||
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
|
||||
/// </summary>
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<string>? tags, ref bool owned)
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<ProtoId<AccessLevelPrototype>>? tags, ref bool owned)
|
||||
{
|
||||
if (!FindAccessTagsItem(uid, out var targetTags))
|
||||
{
|
||||
@@ -286,6 +311,16 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAccesses(EntityUid uid, AccessReaderComponent component, List<ProtoId<AccessLevelPrototype>> accesses)
|
||||
{
|
||||
component.AccessLists.Clear();
|
||||
foreach (var access in accesses)
|
||||
{
|
||||
component.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>>(){access});
|
||||
}
|
||||
RaiseLocalEvent(uid, new AccessReaderConfigurationChangedEvent());
|
||||
}
|
||||
|
||||
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
|
||||
{
|
||||
items = new();
|
||||
@@ -308,7 +343,7 @@ public sealed class AccessReaderSystem : EntitySystem
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindAccessTagsItem(EntityUid uid, out HashSet<string> tags)
|
||||
private bool FindAccessTagsItem(EntityUid uid, out HashSet<ProtoId<AccessLevelPrototype>> tags)
|
||||
{
|
||||
tags = new();
|
||||
var ev = new GetAccessTagsEvent(tags, _prototype);
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Content.Shared.Access.Systems
|
||||
/// Replaces the set of access tags we have with the provided set.
|
||||
/// </summary>
|
||||
/// <param name="access">The new access tags</param>
|
||||
public bool TrySetTags(EntityUid uid, IEnumerable<string> newTags, AccessComponent? access = null)
|
||||
public bool TrySetTags(EntityUid uid, IEnumerable<ProtoId<AccessLevelPrototype>> newTags, AccessComponent? access = null)
|
||||
{
|
||||
if (!Resolve(uid, ref access))
|
||||
return false;
|
||||
@@ -67,12 +67,12 @@ namespace Content.Shared.Access.Systems
|
||||
/// Gets the set of access tags.
|
||||
/// </summary>
|
||||
/// <param name="access">The new access tags</param>
|
||||
public IEnumerable<string>? TryGetTags(EntityUid uid, AccessComponent? access = null)
|
||||
public IEnumerable<ProtoId<AccessLevelPrototype>>? TryGetTags(EntityUid uid, AccessComponent? access = null)
|
||||
{
|
||||
return !Resolve(uid, ref access) ? null : access.Tags;
|
||||
}
|
||||
|
||||
public bool TryAddGroups(EntityUid uid, IEnumerable<string> newGroups, AccessComponent? access = null)
|
||||
public bool TryAddGroups(EntityUid uid, IEnumerable<ProtoId<AccessGroupPrototype>> newGroups, AccessComponent? access = null)
|
||||
{
|
||||
if (!Resolve(uid, ref access))
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Access.Systems
|
||||
{
|
||||
@@ -33,5 +36,16 @@ namespace Content.Shared.Access.Systems
|
||||
_itemSlotsSystem.RemoveItemSlot(uid, component.PrivilegedIdSlot);
|
||||
_itemSlotsSystem.RemoveItemSlot(uid, component.TargetIdSlot);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
private sealed class IdCardConsoleComponentState : ComponentState
|
||||
{
|
||||
public List<string> AccessLevels;
|
||||
|
||||
public IdCardConsoleComponentState(List<string> accessLevels)
|
||||
{
|
||||
AccessLevels = accessLevels;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
Content.Shared/Doors/Electronics/DoorElectronicsComponent.cs
Normal file
42
Content.Shared/Doors/Electronics/DoorElectronicsComponent.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Access;
|
||||
|
||||
namespace Content.Shared.Doors.Electronics;
|
||||
|
||||
/// <summary>
|
||||
/// Allows an entity's AccessReader to be configured via UI.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DoorElectronicsComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class DoorElectronicsUpdateConfigurationMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public List<ProtoId<AccessLevelPrototype>> AccessList;
|
||||
|
||||
public DoorElectronicsUpdateConfigurationMessage(List<ProtoId<AccessLevelPrototype>> accessList)
|
||||
{
|
||||
AccessList = accessList;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class DoorElectronicsConfigurationState : BoundUserInterfaceState
|
||||
{
|
||||
public List<ProtoId<AccessLevelPrototype>> AccessList;
|
||||
|
||||
public DoorElectronicsConfigurationState(List<ProtoId<AccessLevelPrototype>> accessList)
|
||||
{
|
||||
AccessList = accessList;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum DoorElectronicsConfigurationUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
@@ -116,8 +116,8 @@ public sealed partial class NearbyAccessRule : RulesRule
|
||||
[DataField("count")]
|
||||
public int Count = 1;
|
||||
|
||||
[DataField("access", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
|
||||
public List<string> Access = new();
|
||||
[DataField("access", required: true)]
|
||||
public List<ProtoId<AccessLevelPrototype>> Access = new();
|
||||
|
||||
[DataField("range")]
|
||||
public float Range = 10f;
|
||||
|
||||
@@ -105,17 +105,17 @@ namespace Content.Shared.Roles
|
||||
[DataField("special", serverOnly: true)]
|
||||
public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
|
||||
|
||||
[DataField("access", customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
|
||||
public IReadOnlyCollection<string> Access { get; private set; } = Array.Empty<string>();
|
||||
[DataField("access")]
|
||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
[DataField("accessGroups", customTypeSerializer: typeof(PrototypeIdListSerializer<AccessGroupPrototype>))]
|
||||
public IReadOnlyCollection<string> AccessGroups { get; private set; } = Array.Empty<string>();
|
||||
[DataField("accessGroups")]
|
||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||
|
||||
[DataField("extendedAccess", customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
|
||||
public IReadOnlyCollection<string> ExtendedAccess { get; private set; } = Array.Empty<string>();
|
||||
[DataField("extendedAccess")]
|
||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
[DataField("extendedAccessGroups", customTypeSerializer: typeof(PrototypeIdListSerializer<AccessGroupPrototype>))]
|
||||
public IReadOnlyCollection<string> ExtendedAccessGroups { get; private set; } = Array.Empty<string>();
|
||||
[DataField("extendedAccessGroups")]
|
||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,9 +7,19 @@
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/module.rsi
|
||||
state: door_electronics
|
||||
- type: AccessReader
|
||||
- type: Tag
|
||||
tags:
|
||||
- DoorElectronics
|
||||
- type: DoorElectronics
|
||||
- type: StaticPrice
|
||||
price: 55
|
||||
- type: AccessReader
|
||||
- type: ActivatableUI
|
||||
key: enum.DoorElectronicsConfigurationUiKey.Key
|
||||
allowedItems:
|
||||
tags:
|
||||
- Multitool
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.DoorElectronicsConfigurationUiKey.Key
|
||||
type: DoorElectronicsBoundUserInterface
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsService
|
||||
suffix: Service, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Service"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsTheatre
|
||||
suffix: Theatre, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Theatre"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsChapel
|
||||
suffix: Chapel, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Chapel"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsJanitor
|
||||
suffix: Janitor, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Janitor"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsKitchen
|
||||
suffix: Kitchen, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Kitchen"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsBar
|
||||
suffix: Bar, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Bar"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsHydroponics
|
||||
suffix: Hydroponics, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Hydroponics"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsCaptain
|
||||
suffix: Captain, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Captain"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsExternal
|
||||
suffix: External, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["External"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsCargo
|
||||
suffix: Cargo, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Cargo"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsEngineering
|
||||
suffix: Engineering, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Engineering"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsAtmospherics
|
||||
suffix: Atmospherics, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Atmospherics"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsFreezer
|
||||
suffix: Freezer, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Kitchen"], ["Hydroponics"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsSalvage
|
||||
suffix: Salvage, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Salvage"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsMedical
|
||||
suffix: Medical, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Medical"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsChemistry
|
||||
suffix: Chemistry, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Chemistry"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsResearch
|
||||
suffix: Research, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Research"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsScience
|
||||
suffix: Science, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Research"], ["Medical"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsCommand
|
||||
suffix: Command, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Command"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsChiefMedicalOfficer
|
||||
suffix: ChiefMedicalOfficer, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["ChiefMedicalOfficer"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsChiefEngineer
|
||||
suffix: ChiefEngineer, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["ChiefEngineer"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsHeadOfSecurity
|
||||
suffix: HeadOfSecurity, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["HeadOfSecurity"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsResearchDirector
|
||||
suffix: ResearchDirector, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["ResearchDirector"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsHeadOfPersonnel
|
||||
suffix: HeadOfPersonnel, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["HeadOfPersonnel"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsQuartermaster
|
||||
suffix: Quartermaster, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Quartermaster"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsSecurity
|
||||
suffix: Security, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Security"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsDetective
|
||||
suffix: Detective, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Detective"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsBrig
|
||||
suffix: Brig, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Brig"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsArmory
|
||||
suffix: Armory, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Armory"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsVault
|
||||
suffix: Vault, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Security", "Command"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsMaintenance
|
||||
suffix: Maintenance, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Maintenance"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsSyndicateAgent
|
||||
suffix: SyndicateAgent, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["SyndicateAgent"]]
|
||||
|
||||
- type: entity
|
||||
parent: DoorElectronics
|
||||
id: DoorElectronicsRnDMed
|
||||
suffix: Medical/Science, Locked
|
||||
components:
|
||||
- type: AccessReader
|
||||
access: [["Research"], ["Medical"]]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,8 @@
|
||||
- type: ContainerFill
|
||||
containers:
|
||||
board: [ DoorElectronics ]
|
||||
- type: AccessReader
|
||||
containerAccessProvider: board
|
||||
- type: Door
|
||||
crushDamage:
|
||||
types:
|
||||
@@ -140,7 +142,6 @@
|
||||
- type: PaintableAirlock
|
||||
group: Standard
|
||||
department: Civilian
|
||||
- type: AccessReader
|
||||
- type: StaticPrice
|
||||
price: 150
|
||||
- type: LightningTarget
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
- type: NavMapDoor
|
||||
- type: DoorBolt
|
||||
- type: AccessReader
|
||||
containerAccessProvider: board
|
||||
- type: Appearance
|
||||
- type: WiresVisuals
|
||||
- type: ApcPowerReceiver
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
conditions:
|
||||
- !type:EntityAnchored {}
|
||||
steps:
|
||||
- tag: DoorElectronics
|
||||
- component: DoorElectronics
|
||||
store: board
|
||||
name: "door electronics circuit board"
|
||||
icon:
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
- !type:EntityAnchored
|
||||
anchored: true
|
||||
steps:
|
||||
- tag: DoorElectronics
|
||||
- component: DoorElectronics
|
||||
name: Door Electronics
|
||||
icon:
|
||||
sprite: "Objects/Misc/module.rsi"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
conditions:
|
||||
- !type:EntityAnchored {}
|
||||
steps:
|
||||
- tag: DoorElectronics
|
||||
- component: DoorElectronics
|
||||
store: board
|
||||
name: "door electronics circuit board"
|
||||
icon:
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
conditions:
|
||||
- !type:EntityAnchored {}
|
||||
steps:
|
||||
- tag: DoorElectronics
|
||||
- component: DoorElectronics
|
||||
store: board
|
||||
name: "door electronics circuit board"
|
||||
icon:
|
||||
@@ -378,7 +378,7 @@
|
||||
conditions:
|
||||
- !type:EntityAnchored { }
|
||||
steps:
|
||||
- tag: DoorElectronics
|
||||
- component: DoorElectronics
|
||||
store: board
|
||||
name: "door electronics circuit board"
|
||||
icon:
|
||||
|
||||
Reference in New Issue
Block a user