diff --git a/Content.Client/Access/AccessOverlay.cs b/Content.Client/Access/AccessOverlay.cs index 3cb90158f3..59c9441036 100644 --- a/Content.Client/Access/AccessOverlay.cs +++ b/Content.Client/Access/AccessOverlay.cs @@ -9,20 +9,20 @@ namespace Content.Client.Access; public sealed class AccessOverlay : Overlay { + private const string TextFontPath = "/Fonts/NotoSans/NotoSans-Regular.ttf"; + private const int TextFontSize = 12; + private readonly IEntityManager _entityManager; - private readonly EntityLookupSystem _lookup; - private readonly SharedTransformSystem _xform; + private readonly SharedTransformSystem _transformSystem; private readonly Font _font; public override OverlaySpace Space => OverlaySpace.ScreenSpace; - public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup, SharedTransformSystem xform) + public AccessOverlay(IEntityManager entityManager, IResourceCache resourceCache, SharedTransformSystem transformSystem) { - _entityManager = entManager; - _lookup = lookup; - _xform = xform; - - _font = cache.GetFont("/Fonts/IBMPlexMono/IBMPlexMono-Regular.ttf", 12); + _entityManager = entityManager; + _transformSystem = transformSystem; + _font = resourceCache.GetFont(TextFontPath, TextFontSize); } protected override void Draw(in OverlayDrawArgs args) @@ -30,52 +30,65 @@ public sealed class AccessOverlay : Overlay if (args.ViewportControl == null) return; - var readerQuery = _entityManager.GetEntityQuery(); - var xformQuery = _entityManager.GetEntityQuery(); - - foreach (var ent in _lookup.GetEntitiesIntersecting(args.MapId, args.WorldAABB, - LookupFlags.Static | LookupFlags.Approximate)) + var textBuffer = new StringBuilder(); + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var accessReader, out var transform)) { - if (!readerQuery.TryGetComponent(ent, out var reader) || - !xformQuery.TryGetComponent(ent, out var xform)) + textBuffer.Clear(); + + var entityName = _entityManager.ToPrettyString(uid); + textBuffer.AppendLine(entityName.Prototype); + textBuffer.Append("UID: "); + textBuffer.Append(entityName.Uid.Id); + textBuffer.Append(", NUID: "); + textBuffer.Append(entityName.Nuid.Id); + textBuffer.AppendLine(); + + if (!accessReader.Enabled) { + textBuffer.AppendLine("-Disabled"); continue; } - var text = new StringBuilder(); - var index = 0; - var a = $"{_entityManager.ToPrettyString(ent)}"; - text.Append(a); - - foreach (var list in reader.AccessLists) + if (accessReader.AccessLists.Count > 0) { - a = $"Tag {index}"; - text.AppendLine(a); - - foreach (var entry in list) + var groupNumber = 0; + foreach (var accessList in accessReader.AccessLists) { - a = $"- {entry}"; - text.AppendLine(a); + groupNumber++; + foreach (var entry in accessList) + { + textBuffer.Append("+Set "); + textBuffer.Append(groupNumber); + textBuffer.Append(": "); + textBuffer.Append(entry.Id); + textBuffer.AppendLine(); + } } - - index++; - } - - string textStr; - - if (text.Length >= 2) - { - textStr = text.ToString(); - textStr = textStr[..^2]; } else { - textStr = ""; + textBuffer.AppendLine("+Unrestricted"); } - var screenPos = args.ViewportControl.WorldToScreen(_xform.GetWorldPosition(xform)); + foreach (var key in accessReader.AccessKeys) + { + textBuffer.Append("+Key "); + textBuffer.Append(key.OriginStation); + textBuffer.Append(": "); + textBuffer.Append(key.Id); + textBuffer.AppendLine(); + } - args.ScreenHandle.DrawString(_font, screenPos, textStr, Color.Gold); + foreach (var tag in accessReader.DenyTags) + { + textBuffer.Append("-Tag "); + textBuffer.AppendLine(tag.Id); + } + + var accessInfoText = textBuffer.ToString(); + var screenPos = args.ViewportControl.WorldToScreen(_transformSystem.GetWorldPosition(transform)); + args.ScreenHandle.DrawString(_font, screenPos, accessInfoText, Color.Gold); } } } diff --git a/Content.Client/Access/Commands/ShowAccessReadersCommand.cs b/Content.Client/Access/Commands/ShowAccessReadersCommand.cs index 7c804dd969..cb6cb6cf6b 100644 --- a/Content.Client/Access/Commands/ShowAccessReadersCommand.cs +++ b/Content.Client/Access/Commands/ShowAccessReadersCommand.cs @@ -7,8 +7,16 @@ namespace Content.Client.Access.Commands; public sealed class ShowAccessReadersCommand : IConsoleCommand { public string Command => "showaccessreaders"; - public string Description => "Shows all access readers in the viewport"; - public string Help => $"{Command}"; + + public string Description => "Toggles showing access reader permissions on the map"; + public string Help => """ + Overlay Info: + -Disabled | The access reader is disabled + +Unrestricted | The access reader has no restrictions + +Set [Index]: [Tag Name]| A tag in an access set (accessor needs all tags in the set to be allowed by the set) + +Key [StationUid]: [StationRecordKeyId] | A StationRecordKey that is allowed + -Tag [Tag Name] | A tag that is not allowed (takes priority over other allows) + """; public void Execute(IConsoleShell shell, string argStr, string[] args) { var collection = IoCManager.Instance; @@ -26,10 +34,9 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand var entManager = collection.Resolve(); var cache = collection.Resolve(); - var lookup = entManager.System(); var xform = entManager.System(); - overlay.AddOverlay(new AccessOverlay(entManager, cache, lookup, xform)); + overlay.AddOverlay(new AccessOverlay(entManager, cache, xform)); shell.WriteLine($"Set access reader debug overlay to true"); } } diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml b/Content.Client/Access/UI/AccessLevelControl.xaml new file mode 100644 index 0000000000..56968d8983 --- /dev/null +++ b/Content.Client/Access/UI/AccessLevelControl.xaml @@ -0,0 +1,4 @@ + + diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml.cs b/Content.Client/Access/UI/AccessLevelControl.xaml.cs new file mode 100644 index 0000000000..34db80b7af --- /dev/null +++ b/Content.Client/Access/UI/AccessLevelControl.xaml.cs @@ -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, Button> ButtonsList = new(); + + public AccessLevelControl() + { + RobustXamlLoader.Load(this); + } + + public void Populate(List> 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> pressedList, + List>? enabledList = null) + { + foreach (var (accessName, button) in ButtonsList) + { + button.Pressed = pressedList.Contains(accessName); + button.Disabled = !(enabledList?.Contains(accessName) ?? true); + } + } +} diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs index 0c23542f79..c1b63dc4d0 100644 --- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs +++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs @@ -64,7 +64,7 @@ namespace Content.Client.Access.UI _window?.UpdateState(castState); } - public void SubmitData(List newAccessList) + public void SubmitData(List> newAccessList) { SendMessage(new WriteToTargetAccessReaderIdMessage(newAccessList)); } diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs index 2fd0057121..6025c3b551 100644 --- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs +++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs @@ -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 _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(x.Key)).ToList()); } } } diff --git a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs index 95cc972b73..5bf31f631d 100644 --- a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs +++ b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs @@ -28,7 +28,6 @@ namespace Content.Client.Access.UI if (EntMan.TryGetComponent(Owner, out var idCard)) { accessLevels = idCard.AccessLevels; - accessLevels.Sort(); } else { @@ -70,7 +69,7 @@ namespace Content.Client.Access.UI public void SubmitData( string newFullName, string newJobTitle, - List newAccessList, + List> newAccessList, string newJobPrototype, string? newJobIcon) { diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml b/Content.Client/Access/UI/IdCardConsoleWindow.xaml index 47d63cf954..04dcd44806 100644 --- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml +++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml @@ -30,11 +30,7 @@