using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Numerics; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Player; using Robust.Shared.Utility; namespace Robust.Shared.Console.Commands; internal sealed class TeleportCommand : LocalizedEntityCommands { [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; public override string Command => "tp"; public override bool RequireServerOrSingleplayer => true; public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (shell.Player is not { AttachedEntity: { } entity }) return; if (args.Length < 2 || !float.TryParse(args[0], out var posX) || !float.TryParse(args[1], out var posY)) { shell.WriteError(Help); return; } var transform = _entityManager.GetComponent(entity); var position = new Vector2(posX, posY); _transform.AttachToGridOrMap(entity, transform); MapId mapId; if (args.Length == 3 && int.TryParse(args[2], out var intMapId)) mapId = new MapId(intMapId); else mapId = transform.MapID; if (!_map.MapExists(mapId)) { shell.WriteError($"Map {mapId} doesn't exist!"); return; } if (_map.TryFindGridAt(mapId, position, out var gridUid, out var grid)) { var gridPos = Vector2.Transform(position, _transform.GetInvWorldMatrix(gridUid)); _transform.SetCoordinates(entity, transform, new EntityCoordinates(gridUid, gridPos)); } else { var mapEnt = _map.GetMapEntityIdOrThrow(mapId); _transform.SetWorldPosition((entity, transform), position); _transform.SetParent(entity, transform, mapEnt); } shell.WriteLine($"Teleported {shell.Player} to {mapId}:{posX},{posY}."); } } public sealed class TeleportToCommand : LocalizedEntityCommands { [Dependency] private readonly ISharedPlayerManager _players = default!; [Dependency] private readonly IEntityManager _entities = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; public override string Command => "tpto"; public override bool RequireServerOrSingleplayer => true; public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0) return; var target = args[0]; if (!TryGetTransformFromUidOrUsername(target, shell, out var targetUid, out _)) return; var targetCoords = new EntityCoordinates(targetUid.Value, Vector2.Zero); if (_entities.TryGetComponent(targetUid, out PhysicsComponent? targetPhysics)) { targetCoords = targetCoords.Offset(targetPhysics.LocalCenter); } var victims = new List<(EntityUid Entity, TransformComponent Transform)>(); if (args.Length == 1) { var ent = shell.Player?.AttachedEntity; if (!_entities.TryGetComponent(ent, out TransformComponent? playerTransform)) { shell.WriteError(Loc.GetString("cmd-failure-no-attached-entity")); return; } victims.Add((ent.Value, playerTransform)); } else { foreach (var victim in args) { if (victim == target) continue; if (!TryGetTransformFromUidOrUsername(victim, shell, out var uid, out var victimTransform)) continue; victims.Add((uid.Value, victimTransform)); } } foreach (var victim in victims) { _transform.SetCoordinates(victim.Entity, targetCoords); _transform.AttachToGridOrMap(victim.Entity, victim.Transform); } } private bool TryGetTransformFromUidOrUsername( string str, IConsoleShell shell, [NotNullWhen(true)] out EntityUid? victimUid, [NotNullWhen(true)] out TransformComponent? transform) { if (NetEntity.TryParse(str, out var uidNet) && _entities.TryGetEntity(uidNet, out var uid) && _entities.TryGetComponent(uid, out transform) && !_entities.HasComponent(uid)) { victimUid = uid; return true; } if (_players.Sessions.TryFirstOrDefault(x => x.Channel.UserName == str, out var session) && _entities.TryGetComponent(session.AttachedEntity, out transform)) { victimUid = session.AttachedEntity; return true; } shell.WriteError(Loc.GetString("cmd-tpto-parse-error", ("str",str))); transform = null; victimUid = default; return false; } public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) { if (args.Length == 0) return CompletionResult.Empty; var last = args[^1]; var users = _players.Sessions .Select(x => x.Name ?? string.Empty) .Where(x => !string.IsNullOrWhiteSpace(x) && x.StartsWith(last, StringComparison.CurrentCultureIgnoreCase)); var hint = args.Length == 1 ? "cmd-tpto-destination-hint" : "cmd-tpto-victim-hint"; hint = Loc.GetString(hint); return CompletionResult.FromHintOptions(users, hint); } } sealed class LocationCommand : LocalizedEntityCommands { [Dependency] private readonly IEntityManager _ent = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; public override string Command => "loc"; public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (shell.Player is not { AttachedEntity: { } entity }) return; var pt = _ent.GetComponent(entity); var pos = pt.Coordinates; var mapId = _transform.GetMapId(pos); var gridUid = _transform.GetGrid(pos); shell.WriteLine($"MapID:{mapId} GridUid:{gridUid} X:{pos.X:N2} Y:{pos.Y:N2}"); } } sealed class TpGridCommand : LocalizedEntityCommands { [Dependency] private readonly IEntityManager _ent = default!; [Dependency] private readonly SharedMapSystem _map = default!; public override string Command => "tpgrid"; public override bool RequireServerOrSingleplayer => true; public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length is < 3 or > 4) { shell.WriteError(Loc.GetString("cmd-invalid-arg-number-error")); return; } if (!NetEntity.TryParse(args[0], out var gridIdNet)) { shell.WriteError(Loc.GetString("cmd-parse-failure-uid", ("arg", args[0]))); return; } if (!_ent.TryGetEntity(gridIdNet, out var uid) || !_ent.HasComponent(uid) || _ent.HasComponent(uid)) { shell.WriteError(Loc.GetString("cmd-parse-failure-grid", ("arg", args[0]))); return; } var xPos = float.Parse(args[1], CultureInfo.InvariantCulture); var yPos = float.Parse(args[2], CultureInfo.InvariantCulture); var gridXform = _ent.GetComponent(uid.Value); var mapId = gridXform.MapID; if (args.Length > 3) { if (!int.TryParse(args[3], out var map)) { shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", args[3]))); return; } mapId = new MapId(map); } var id = _map.GetMap(mapId); if (id == EntityUid.Invalid) { shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", mapId.Value))); return; } var pos = new EntityCoordinates(id, new Vector2(xPos, yPos)); _ent.System().SetCoordinates(uid.Value, pos); } public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) { return args.Length switch { 1 => CompletionResult.FromHintOptions(CompletionHelper.Components(args[^1], _ent), ""), 2 => CompletionResult.FromHint(""), 3 => CompletionResult.FromHint(""), 4 => CompletionResult.FromHintOptions(CompletionHelper.MapIds(_ent), "[MapId]"), _ => CompletionResult.Empty }; } }