using Content.Client.Popups; using Content.Client.UserInterface.Controls; using Content.Shared.RCD; using Content.Shared.RCD.Components; using Content.Shared.RCD.Systems; using JetBrains.Annotations; using Robust.Client.UserInterface; using Robust.Shared.Collections; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client.RCD; [UsedImplicitly] public sealed partial class RCDMenuBoundUserInterface : BoundUserInterface { [Dependency] private IPrototypeManager _prototypeManager = default!; [Dependency] private ISharedPlayerManager _playerManager = default!; [Dependency] private PopupSystem _popup = default!; [Dependency] private RCDSystem _rcd = default!; private const string TopLevelActionCategory = "Main"; private static readonly Dictionary PrototypesGroupingInfo = new() { ["WallsAndFlooring"] = ("rcd-component-walls-and-flooring", 0, new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/walls_and_flooring.png"))), ["WindowsAndGrilles"] = ("rcd-component-windows-and-grilles", 1, new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/windows_and_grilles.png"))), ["Airlocks"] = ("rcd-component-airlocks", 2, new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/airlocks.png"))), ["Electrical"] = ("rcd-component-electrical", 3, new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/multicoil.png"))), ["Lighting"] = ("rcd-component-lighting", 4, new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Radial/RCD/lighting.png"))), }; private SimpleRadialMenu? _menu; public RCDMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } protected override void Open() { base.Open(); if (!EntMan.TryGetComponent(Owner, out var rcd)) return; _menu = this.CreateWindow(); _menu.Track(Owner); var models = ConvertToButtons(rcd.AvailablePrototypes); _menu.SetButtons(models); _menu.OpenOverMouseScreenPosition(); } private IEnumerable ConvertToButtons(HashSet> prototypes) { Dictionary> buttonsByCategory = new(); ValueList topLevelActions = new(); foreach (var protoId in prototypes) { var prototype = _prototypeManager.Index(protoId); if (prototype.Category == TopLevelActionCategory) { var topLevelActionOption = new RadialMenuActionOption(HandleMenuOptionClick, prototype) { IconSpecifier = RadialMenuIconSpecifier.With(prototype.Sprite), ToolTip = GetTooltip(prototype), Order = prototype.MenuOrder, }; topLevelActions.Add(topLevelActionOption); continue; } if (!PrototypesGroupingInfo.TryGetValue(prototype.Category, out var groupInfo)) continue; if (!buttonsByCategory.TryGetValue(prototype.Category, out var list)) { list = new List(); buttonsByCategory.Add(prototype.Category, list); } var actionOption = new RadialMenuActionOption(HandleMenuOptionClick, prototype) { IconSpecifier = RadialMenuIconSpecifier.With(prototype.Sprite), ToolTip = GetTooltip(prototype), Order = prototype.MenuOrder, }; list.Add(actionOption); } var models = new RadialMenuOptionBase[buttonsByCategory.Count + topLevelActions.Count]; var i = 0; foreach (var (key, list) in buttonsByCategory) { var groupInfo = PrototypesGroupingInfo[key]; models[i] = new RadialMenuNestedLayerOption(list) { IconSpecifier = RadialMenuIconSpecifier.With(groupInfo.Sprite), ToolTip = Loc.GetString(groupInfo.Tooltip), Order = groupInfo.Order, }; i++; } foreach (var action in topLevelActions) { models[i] = action; i++; } return models; } private void HandleMenuOptionClick(RCDPrototype proto) { // A predicted message cannot be used here as the RCD UI is closed immediately // after this message is sent, which will stop the server from receiving it SendMessage(new RCDSystemMessage(proto.ID)); if (_playerManager.LocalSession?.AttachedEntity == null) return; var rcdName = _rcd.GetPrototypeName(proto); var msg = Loc.GetString("rcd-component-change-mode", ("mode", rcdName)); if (proto.Mode is RcdMode.ConstructTile or RcdMode.ConstructObject) msg = Loc.GetString("rcd-component-change-build-mode", ("name", rcdName)); // Popup message _popup.PopupEntity(msg, Owner); } private string GetTooltip(RCDPrototype proto) { var tooltip = _rcd.GetPrototypeName(proto); tooltip = OopsConcat(char.ToUpper(tooltip[0]).ToString(), tooltip.Remove(0, 1)); return tooltip; } private static string OopsConcat(string a, string b) { // This exists to prevent Roslyn being clever and compiling something that fails sandbox checks. return a + b; } }