diff --git a/Content.Omu.Server/Toolshed/Errors/EntityNotOnAGridError.cs b/Content.Omu.Server/Toolshed/Errors/EntityNotOnAGridError.cs new file mode 100644 index 00000000000..cf7bc818518 --- /dev/null +++ b/Content.Omu.Server/Toolshed/Errors/EntityNotOnAGridError.cs @@ -0,0 +1,21 @@ +using System.Diagnostics; +using Robust.Shared.Toolshed.Errors; +using Robust.Shared.Utility; + +namespace Content.Omu.Server.Toolshed.Errors; + +[Virtual] +public class EntityNotOnAGridError(EntityUid triggeringEnt) : IConError +{ + protected readonly EntityUid TriggeringEnt = triggeringEnt; + + public virtual FormattedMessage DescribeInner() + { + return FormattedMessage.FromUnformatted( + $"The entity {PrettyPrint.PrintUserFacingWithType(TriggeringEnt, out var _)} is not on a grid!"); + } + + public string? Expression { get; set; } + public Vector2i? IssueSpan { get; set; } + public StackTrace? Trace { get; set; } +} diff --git a/Content.Omu.Server/Toolshed/Errors/NoAttachedEntityError.cs b/Content.Omu.Server/Toolshed/Errors/NoAttachedEntityError.cs new file mode 100644 index 00000000000..4ed620d6a75 --- /dev/null +++ b/Content.Omu.Server/Toolshed/Errors/NoAttachedEntityError.cs @@ -0,0 +1,18 @@ +using System.Diagnostics; +using Robust.Shared.Toolshed.Errors; +using Robust.Shared.Utility; + +namespace Content.Omu.Server.Toolshed.Errors; + +public sealed class NoAttachedEntityError : IConError +{ + public FormattedMessage DescribeInner() + { + return FormattedMessage.FromUnformatted( + "You must be attached to an entity to use this."); + } + + public string? Expression { get; set; } + public Vector2i? IssueSpan { get; set; } + public StackTrace? Trace { get; set; } +} diff --git a/Content.Omu.Server/Toolshed/Errors/YouAreNotOnAGridError.cs b/Content.Omu.Server/Toolshed/Errors/YouAreNotOnAGridError.cs new file mode 100644 index 00000000000..4e3d881e246 --- /dev/null +++ b/Content.Omu.Server/Toolshed/Errors/YouAreNotOnAGridError.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Utility; + +namespace Content.Omu.Server.Toolshed.Errors; + +public sealed class YouAreNotOnAGridError(EntityUid you) : EntityNotOnAGridError(you) +{ + public override FormattedMessage DescribeInner() + { + return FormattedMessage.FromUnformatted($"You ({PrettyPrint.PrintUserFacingWithType(TriggeringEnt, out var _)}) are not on a grid!!"); + } +} diff --git a/Content.Omu.Server/Toolshed/OnCommand.cs b/Content.Omu.Server/Toolshed/OnCommand.cs new file mode 100644 index 00000000000..074021b1227 --- /dev/null +++ b/Content.Omu.Server/Toolshed/OnCommand.cs @@ -0,0 +1,85 @@ +using System.Linq; +using Content.Omu.Server.Toolshed.Errors; +using Robust.Shared.Map; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Errors; + +namespace Content.Omu.Server.Toolshed; + +[ToolshedCommand] +public sealed class OnCommand : ToolshedCommand +{ + [CommandImplementation("grid")] + public IEnumerable OnGrid([PipedArgument] IEnumerable ents, EntityUid grid , [CommandInverted] bool inverted) + { + return FilterGrid(ents, grid, inverted); + } + + [CommandImplementation("thisgrid")] + public IEnumerable OnThisGrid(IInvocationContext ctx, [PipedArgument] IEnumerable ents, [CommandInverted] bool inverted) + { + return Outer_OnThisX(ctx, ents, inverted, (ents, inverted, invoker) + => (Transform(invoker).GridUid is { } filter_grid) + ? FilterGrid(ents, filter_grid, inverted) + : ReportErrorAndBail(ctx, new YouAreNotOnAGridError(invoker)) + ); + } + + [CommandImplementation("gridof")] + public IEnumerable OnGridOf(IInvocationContext ctx, [PipedArgument] IEnumerable ents, EntityUid other_ent, [CommandInverted] bool inverted) + { + return (Transform(other_ent).GridUid is { } filter_grid) + ? FilterGrid(ents, filter_grid, inverted) + : ReportErrorAndBail(ctx, new EntityNotOnAGridError(other_ent)) + ; + } + + [CommandImplementation("map")] + public IEnumerable OnMap([PipedArgument] IEnumerable ents, int map, [CommandInverted] bool inverted) + { + return FilterMap(ents, new MapId(map), inverted); + } + + [CommandImplementation("thismap")] + public IEnumerable OnThisMap(IInvocationContext ctx, [PipedArgument] IEnumerable ents, [CommandInverted] bool inverted) + { + return Outer_OnThisX(ctx, ents, inverted, (ents, inverted, invoker) => FilterMap(ents, Transform(invoker).MapID, inverted)); + } + + [CommandImplementation("mapof")] + public IEnumerable OnMapOf([PipedArgument] IEnumerable ents, EntityUid other_ent, [CommandInverted] bool inverted) + { + return FilterMap(ents, Transform(other_ent).MapID, inverted); + } + + private IEnumerable Outer_OnThisX(IInvocationContext ctx, IEnumerable ents, bool inverted, Func, bool, EntityUid, IEnumerable> inner) + { + if (ctx.Session is null) return ReportErrorAndBail(ctx, new NotForServerConsoleError()); + if (ctx.Session.AttachedEntity is { } invoker) + { + return inner(ents, inverted, invoker); + } + else return ReportErrorAndBail(ctx, new NoAttachedEntityError()); + } + + private IEnumerable FilterMap(IEnumerable ents, MapId map, bool inverted) + { + return FilterX(ents, e => Transform(e).MapID == map, inverted); + } + + private IEnumerable FilterGrid(IEnumerable ents, EntityUid grid, bool inverted) + { + return FilterX(ents, e => Transform(e).GridUid == grid, inverted); + } + + private IEnumerable FilterX(IEnumerable ents, Func cond, bool inverted) + { + return ents.Where(e => cond(e) ^ inverted); + } + + private IEnumerable ReportErrorAndBail(IInvocationContext ctx, IConError e) + { + ctx.ReportError(e); + return default!; + } +} diff --git a/Content.Omu.Server/Toolshed/ThisCommand.cs b/Content.Omu.Server/Toolshed/ThisCommand.cs new file mode 100644 index 00000000000..851de7ed604 --- /dev/null +++ b/Content.Omu.Server/Toolshed/ThisCommand.cs @@ -0,0 +1,39 @@ +using Robust.Shared.Map; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Errors; + +namespace Content.Omu.Server.Toolshed; + +[ToolshedCommand] +public sealed class ThisCommand : ToolshedCommand +{ + [CommandImplementation("grid")] + public EntityUid? ThisGrid(IInvocationContext ctx) + { + return CheckCommonPitfalls(ctx, null, invoker => Transform(invoker).GridUid); + } + + [CommandImplementation("map")] + public int ThisMap(IInvocationContext ctx) + { + return CheckCommonPitfalls(ctx, (int) MapId.Nullspace, invoker => (int) Transform(invoker).MapID); + } + + private T CheckCommonPitfalls(IInvocationContext ctx, T fail_value, Func and_then_do_this) + { + if (ctx.Session is null) + { + ctx.ReportError(new NotForServerConsoleError()); + return fail_value; + } + + if (ctx.Session.AttachedEntity is { } invoker) + { + return and_then_do_this(invoker); + } + else + { + return fail_value; + } + } +} diff --git a/Resources/Locale/en-US/_Omu/commands/toolshed-commands.ftl b/Resources/Locale/en-US/_Omu/commands/toolshed-commands.ftl new file mode 100644 index 00000000000..fb0ad6be62b --- /dev/null +++ b/Resources/Locale/en-US/_Omu/commands/toolshed-commands.ftl @@ -0,0 +1,9 @@ +command-description-on-grid = Filters the input entities by whether or not they are on the grid with the given ID. +command-description-on-thisgrid = Filters the input entities by whether or not they are on the grid you are currently on. +command-description-on-gridof = Filters the input entities by whether or not they are on the same grid as the given entity. +command-description-on-map = Filters the input entities by whether or not they are on the map with the given ID. +command-description-on-thismap = Filters the input entities by whether or not they are on the map you are currently on. +command-description-on-mapof = Filters the input entities by whether or not they are on the same map as the given entity. + +command-description-this-grid = Returns the grid you are on. +command-description-this-map = Returns the ID of the map you are on. diff --git a/Resources/toolshedEngineCommandPerms.yml b/Resources/toolshedEngineCommandPerms.yml index 7305d19e93f..94c3d14cd35 100644 --- a/Resources/toolshedEngineCommandPerms.yml +++ b/Resources/toolshedEngineCommandPerms.yml @@ -70,6 +70,8 @@ - contains - isnull - isempty + - on + - this - cd - ls - stopwatch