mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
187 lines
6.6 KiB
C#
187 lines
6.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Robust.Shared.Console;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Reflection;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Toolshed.Invocation;
|
|
using Robust.Shared.Toolshed.Syntax;
|
|
using Robust.Shared.Toolshed.TypeParsers;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Robust.Shared.Toolshed;
|
|
|
|
/// <summary>
|
|
/// The overarching controller for Toolshed, providing invocation, reflection, commands, parsing, and other tools used by the language.
|
|
/// <see href="https://docs.spacestation14.io/">External documentation</see> has a more in-depth look.
|
|
/// </summary>
|
|
/// <seealso cref="ToolshedCommand"/>
|
|
/// <seealso cref="IInvocationContext"/>
|
|
public sealed partial class ToolshedManager
|
|
{
|
|
[Dependency] private readonly IDynamicTypeFactoryInternal _typeFactory = default!;
|
|
[Dependency] private readonly IEntityManager _entity = default!;
|
|
[Dependency] private readonly IReflectionManager _reflection = default!;
|
|
[Dependency] private readonly ILogManager _logManager = default!;
|
|
[Dependency] private readonly INetManager _net = default!;
|
|
|
|
private ISawmill _log = default!;
|
|
|
|
/// <summary>
|
|
/// If you're not an engine developer, you probably shouldn't call this.
|
|
/// </summary>
|
|
public void Initialize()
|
|
{
|
|
_log = _logManager.GetSawmill("toolshed");
|
|
|
|
InitializeParser();
|
|
}
|
|
|
|
private Dictionary<NetUserId, IInvocationContext> _contexts = new();
|
|
|
|
/// <summary>
|
|
/// Invokes a command as the given user.
|
|
/// </summary>
|
|
/// <param name="session">User to run as.</param>
|
|
/// <param name="command">Command to invoke.</param>
|
|
/// <param name="input">An input value to use, if any.</param>
|
|
/// <param name="result">The resulting value, if any.</param>
|
|
/// <returns>Invocation success.</returns>
|
|
/// <example><code>
|
|
/// ToolshedManager toolshed = ...;
|
|
/// ICommonSession ctx = ...;
|
|
/// // Now run some user provided command and get a result!
|
|
/// toolshed.InvokeCommand(ctx, userCommand, "my input value", out var result);
|
|
/// </code></example>
|
|
/// <remarks>
|
|
/// This will use the same IInvocationContext as the one used by the user for debug console commands.
|
|
/// </remarks>
|
|
public bool InvokeCommand(ICommonSession session, string command, object? input, out object? result)
|
|
{
|
|
if (!_contexts.TryGetValue(session.UserId, out var ctx))
|
|
{
|
|
// Can't get a shell here.
|
|
result = null;
|
|
return false;
|
|
}
|
|
|
|
ctx.ClearErrors();
|
|
|
|
return InvokeCommand(ctx, command, input, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes a command as the given user.
|
|
/// </summary>
|
|
/// <param name="session">User to run as.</param>
|
|
/// <param name="command">Command to invoke.</param>
|
|
/// <param name="input">An input value to use, if any.</param>
|
|
/// <param name="result">The resulting value, if any.</param>
|
|
/// <returns>Invocation success.</returns>
|
|
/// <example><code>
|
|
/// ToolshedManager toolshed = ...;
|
|
/// IConsoleShell ctx = ...;
|
|
/// // Now run some user provided command and get a result!
|
|
/// toolshed.InvokeCommand(ctx, userCommand, "my input value", out var result);
|
|
/// </code></example>
|
|
/// <remarks>
|
|
/// This will use the same IInvocationContext as the one used by the user for debug console commands.
|
|
/// </remarks>
|
|
public bool InvokeCommand(IConsoleShell session, string command, object? input, out object? result, out IInvocationContext ctx)
|
|
{
|
|
var idx = session.Player?.UserId ?? new NetUserId();
|
|
if (!_contexts.TryGetValue(idx, out var ourCtx))
|
|
{
|
|
ourCtx = new OldShellInvocationContext(session);
|
|
_contexts[idx] = ourCtx;
|
|
}
|
|
|
|
ourCtx.ClearErrors();
|
|
ctx = ourCtx;
|
|
|
|
return InvokeCommand(ctx, command, input, out result);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Invokes a command with the given context.
|
|
/// </summary>
|
|
/// <param name="ctx">The context to run in.</param>
|
|
/// <param name="command">Command to invoke.</param>
|
|
/// <param name="input">An input value to use, if any.</param>
|
|
/// <param name="result">The resulting value, if any.</param>
|
|
/// <returns>Invocation success.</returns>
|
|
/// <example><code>
|
|
/// ToolshedManager toolshed = ...;
|
|
/// IInvocationContext ctx = ...;
|
|
/// // Now run some user provided command and get a result!
|
|
/// toolshed.InvokeCommand(ctx, userCommand, "my input value", out var result);
|
|
/// </code></example>
|
|
public bool InvokeCommand(IInvocationContext ctx, string command, object? input, out object? result)
|
|
{
|
|
ctx.ClearErrors();
|
|
|
|
var parser = new ParserContext(command, this, ctx.Environment);
|
|
if (!CommandRun.TryParse(false, parser, input?.GetType(), null, false, out var expr, out _, out var err) || parser.Index < parser.MaxIndex)
|
|
{
|
|
|
|
if (err is not null)
|
|
ctx.ReportError(err);
|
|
|
|
result = null;
|
|
return false;
|
|
}
|
|
|
|
result = expr.Invoke(input, ctx);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A command specification, containing both the command object and the selected subcommand if any.
|
|
/// </summary>
|
|
/// <param name="Cmd">Command object.</param>
|
|
/// <param name="SubCommand">Subcommand, if any.</param>
|
|
public readonly record struct CommandSpec(ToolshedCommand Cmd, string? SubCommand) : IAsType<ToolshedCommand>
|
|
{
|
|
/// <inheritdoc/>
|
|
public ToolshedCommand AsType()
|
|
{
|
|
return Cmd;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a completion option for this command, for use in autocomplete.
|
|
/// </summary>
|
|
public CompletionOption AsCompletion()
|
|
{
|
|
return new CompletionOption(
|
|
$"{Cmd.Name}{(SubCommand is not null ? ":" + SubCommand : "")}",
|
|
Cmd.Description(SubCommand)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the full name of the command.
|
|
/// </summary>
|
|
public string FullName() => $"{Cmd.Name}{(SubCommand is not null ? ":" + SubCommand : "")}";
|
|
|
|
/// <summary>
|
|
/// Returns the localization string for the description of this command.
|
|
/// </summary>
|
|
public string DescLocStr() => Cmd.UnlocalizedDescription(SubCommand);
|
|
|
|
/// <inheritdoc/>
|
|
public override string ToString()
|
|
{
|
|
return Cmd.GetHelp(SubCommand);
|
|
}
|
|
}
|