diff --git a/Content.Client/Bql/BqlResultsEui.cs b/Content.Client/Bql/BqlResultsEui.cs new file mode 100644 index 0000000000..3e9bda57ff --- /dev/null +++ b/Content.Client/Bql/BqlResultsEui.cs @@ -0,0 +1,45 @@ +using Content.Client.Eui; +using Content.Shared.Bql; +using Content.Shared.Eui; +using JetBrains.Annotations; +using Robust.Client.Console; + +namespace Content.Client.Bql; + +[UsedImplicitly] +public sealed class BqlResultsEui : BaseEui +{ + private readonly BqlResultsWindow _window; + + public BqlResultsEui() + { + _window = new BqlResultsWindow( + IoCManager.Resolve(), + IoCManager.Resolve() + ); + + _window.OnClose += () => SendMessage(new CloseEuiMessage()); + } + + public override void HandleState(EuiStateBase state) + { + if (state is not BqlResultsEuiState castState) + return; + + _window.Update(castState.Entities); + } + + public override void Closed() + { + base.Closed(); + + _window.Close(); + } + + public override void Opened() + { + base.Opened(); + + _window.OpenCentered(); + } +} diff --git a/Content.Client/Bql/BqlResultsWindow.xaml b/Content.Client/Bql/BqlResultsWindow.xaml new file mode 100644 index 0000000000..9affbf2181 --- /dev/null +++ b/Content.Client/Bql/BqlResultsWindow.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/Content.Client/Bql/BqlResultsWindow.xaml.cs b/Content.Client/Bql/BqlResultsWindow.xaml.cs new file mode 100644 index 0000000000..7adceb5d77 --- /dev/null +++ b/Content.Client/Bql/BqlResultsWindow.xaml.cs @@ -0,0 +1,48 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.Console; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Bql; + +[GenerateTypedNameReferences] +internal sealed partial class BqlResultsWindow : DefaultWindow +{ + private readonly IClientConsoleHost _console; + private readonly ILocalizationManager _loc; + + public BqlResultsWindow(IClientConsoleHost console, ILocalizationManager loc) + { + _console = console; + _loc = loc; + + RobustXamlLoader.Load(this); + } + + protected override Vector2 ContentsMinimumSize => (500, 700); + + public void Update((string name, EntityUid entity)[] entities) + { + StatusLabel.Text = _loc.GetString("ui-bql-results-status", ("count", entities.Length)); + ItemList.RemoveAllChildren(); + + foreach (var (name, entity) in entities) + { + var nameLabel = new Label { Text = name, HorizontalExpand = true }; + var tpButton = new Button { Text = _loc.GetString("ui-bql-results-tp") }; + tpButton.OnPressed += _ => _console.ExecuteCommand($"tpto {entity}"); + tpButton.ToolTip = _loc.GetString("ui-bql-results-tp-tooltip"); + + var vvButton = new Button { Text = _loc.GetString("ui-bql-results-vv") }; + vvButton.ToolTip = _loc.GetString("ui-bql-results-vv-tooltip"); + vvButton.OnPressed += _ => _console.ExecuteCommand($"vv {entity}"); + + ItemList.AddChild(new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal, + Children = { nameLabel, tpButton, vvButton } + }); + } + } +} diff --git a/Content.Server/Bql/BqlSelectCommand.cs b/Content.Server/Bql/BqlSelectCommand.cs new file mode 100644 index 0000000000..bcb658bfe7 --- /dev/null +++ b/Content.Server/Bql/BqlSelectCommand.cs @@ -0,0 +1,56 @@ +using System.Linq; +using Content.Server.Administration; +using Content.Server.EUI; +using Content.Shared.Administration; +using Content.Shared.Bql; +using Content.Shared.Eui; +using Robust.Server.Bql; +using Robust.Server.Player; +using Robust.Shared.Console; + +namespace Content.Server.Bql; + +[AdminCommand(AdminFlags.Query)] +public sealed class BqlSelectCommand : LocalizedCommands +{ + [Dependency] private readonly IBqlQueryManager _bql = default!; + [Dependency] private readonly EuiManager _euiManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + public override string Command => "bql_select"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (shell.Player == null) + { + shell.WriteError(LocalizationManager.GetString("cmd-bql_select-err-server-shell")); + return; + } + + var (entities, rest) = _bql.SimpleParseAndExecute(argStr["bql_select".Length..]); + + if (!string.IsNullOrWhiteSpace(rest)) + shell.WriteLine(LocalizationManager.GetString("cmd-bql_select-err-rest", ("rest", rest))); + + var ui = new BqlResultsEui( + entities.Select(e => (_entityManager.GetComponent(e).EntityName, e)).ToArray() + ); + _euiManager.OpenEui(ui, (IPlayerSession) shell.Player); + _euiManager.QueueStateUpdate(ui); + } +} + +internal sealed class BqlResultsEui : BaseEui +{ + private readonly (string name, EntityUid entity)[] _entities; + + public BqlResultsEui((string name, EntityUid entity)[] entities) + { + _entities = entities; + } + + public override EuiStateBase GetNewState() + { + return new BqlResultsEuiState(_entities); + } +} diff --git a/Content.Shared/Bql/BqlResultsEuiState.cs b/Content.Shared/Bql/BqlResultsEuiState.cs new file mode 100644 index 0000000000..cd298fa814 --- /dev/null +++ b/Content.Shared/Bql/BqlResultsEuiState.cs @@ -0,0 +1,15 @@ +using Content.Shared.Eui; +using Robust.Shared.Serialization; + +namespace Content.Shared.Bql; + +[Serializable, NetSerializable] +public sealed class BqlResultsEuiState : EuiStateBase +{ + public readonly (string name, EntityUid entity)[] Entities; + + public BqlResultsEuiState((string name, EntityUid entity)[] entities) + { + Entities = entities; + } +} diff --git a/Resources/Locale/en-US/bql/bql-select.ftl b/Resources/Locale/en-US/bql/bql-select.ftl new file mode 100644 index 0000000000..8d508ff14d --- /dev/null +++ b/Resources/Locale/en-US/bql/bql-select.ftl @@ -0,0 +1,13 @@ +cmd-bql_select-desc = Show results of a BQL query in a client-side window +cmd-bql_select-help = Usage: bql_select + The opened window allows you to teleport to or view variables the resulting entities. + +cmd-bql_select-err-server-shell = Cannot be executed from server shell +cmd-bql_select-err-rest = Warning: unused part after BQL query: "{ $rest }" + +ui-bql-results-title = BQL results +ui-bql-results-vv = VV +ui-bql-results-tp = TP +ui-bql-results-vv-tooltip = View entity variables +ui-bql-results-tp-tooltip = Teleport to entity +ui-bql-results-status = { $count } entities