]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Allow for respawn and erase verb to be used on offline players. Also minor rewrite...
authornikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com>
Sat, 31 Aug 2024 11:38:03 +0000 (11:38 +0000)
committerGitHub <noreply@github.com>
Sat, 31 Aug 2024 11:38:03 +0000 (21:38 +1000)
* Localize respawn command, allow for it to use userids, and make it use [Dependency] attributes

* Make respawn verb available for offline players

* Make erase available for offline players

A thousand admins rejoice

* Reorder verbs in code

* Add erase command

* Fix localisation for erase command

* Address reviews and add completion to respawn command

* Complete reviews which I forgor

Content.Server/Administration/BanPanelEui.cs
Content.Server/Administration/Commands/EraseCommand.cs [new file with mode: 0644]
Content.Server/Administration/Systems/AdminSystem.cs
Content.Server/Administration/Systems/AdminVerbSystem.cs
Content.Server/Chat/Managers/ChatManager.cs
Content.Server/Chat/Managers/IChatManager.cs
Content.Server/GameTicking/Commands/RespawnCommand.cs
Resources/Locale/en-US/administration/commands/erase.ftl [new file with mode: 0644]
Resources/Locale/en-US/administration/commands/respawn.ftl [new file with mode: 0644]

index aa6bd8d4bfaf4600f630b4f9f6fdef102905ebdd..b3253f0d0cc6650d4c19bf14e08eb8b34f63cfc5 100644 (file)
@@ -132,13 +132,12 @@ public sealed class BanPanelEui : BaseEui
         }
 
         if (erase &&
-            targetUid != null &&
-            _playerManager.TryGetSessionById(targetUid.Value, out var targetPlayer))
+            targetUid != null)
         {
             try
             {
                 if (_entities.TrySystem(out AdminSystem? adminSystem))
-                    adminSystem.Erase(targetPlayer);
+                    adminSystem.Erase(targetUid.Value);
             }
             catch (Exception e)
             {
diff --git a/Content.Server/Administration/Commands/EraseCommand.cs b/Content.Server/Administration/Commands/EraseCommand.cs
new file mode 100644 (file)
index 0000000..cb01d74
--- /dev/null
@@ -0,0 +1,47 @@
+using System.Linq;
+using Content.Server.Administration.Systems;
+using Content.Shared.Administration;
+using Robust.Server.Player;
+using Robust.Shared.Console;
+
+namespace Content.Server.Administration.Commands;
+
+[AdminCommand(AdminFlags.Admin)]
+public sealed class EraseCommand : LocalizedEntityCommands
+{
+    [Dependency] private readonly IPlayerLocator _locator = default!;
+    [Dependency] private readonly IPlayerManager _players = default!;
+    [Dependency] private readonly AdminSystem _admin = default!;
+
+    public override string Command => "erase";
+
+    public override async void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        if (args.Length != 1)
+        {
+            shell.WriteError(Loc.GetString("cmd-erase-invalid-args"));
+            shell.WriteLine(Help);
+            return;
+        }
+
+        var located = await _locator.LookupIdByNameOrIdAsync(args[0]);
+
+        if (located == null)
+        {
+            shell.WriteError(Loc.GetString("cmd-erase-player-not-found"));
+            return;
+        }
+
+        _admin.Erase(located.UserId);
+    }
+
+    public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
+    {
+        if (args.Length != 1)
+            return CompletionResult.Empty;
+
+        var options = _players.Sessions.OrderBy(c => c.Name).Select(c => c.Name).ToArray();
+
+        return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-erase-player-completion"));
+    }
+}
index db22c41520d76ea20b869ca58d616502a35cc790..99551c714c48c5ecf98cbc707345f655c2ee6425 100644 (file)
@@ -15,7 +15,9 @@ using Content.Shared.GameTicking;
 using Content.Shared.Hands.Components;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Inventory;
+using Content.Shared.Mind;
 using Content.Shared.PDA;
+using Content.Shared.Players;
 using Content.Shared.Players.PlayTimeTracking;
 using Content.Shared.Popups;
 using Content.Shared.Roles;
@@ -377,30 +379,32 @@ public sealed class AdminSystem : EntitySystem
         }
     }
 
-    /// <summary>
-    ///     Erases a player from the round.
-    ///     This removes them and any trace of them from the round, deleting their
-    ///     chat messages and showing a popup to other players.
-    ///     Their items are dropped on the ground.
-    /// </summary>
-    public void Erase(ICommonSession player)
-    {
-        var entity = player.AttachedEntity;
-        _chat.DeleteMessagesBy(player);
-
-        if (entity != null && !TerminatingOrDeleted(entity.Value))
+        /// <summary>
+        ///     Erases a player from the round.
+        ///     This removes them and any trace of them from the round, deleting their
+        ///     chat messages and showing a popup to other players.
+        ///     Their items are dropped on the ground.
+        /// </summary>
+        public void Erase(NetUserId uid)
         {
-            if (TryComp(entity.Value, out TransformComponent? transform))
+            _chat.DeleteMessagesBy(uid);
+
+            if (!_minds.TryGetMind(uid, out var mindId, out var mind) || mind.OwnedEntity == null || TerminatingOrDeleted(mind.OwnedEntity.Value))
+                return;
+
+            var entity = mind.OwnedEntity.Value;
+
+            if (TryComp(entity, out TransformComponent? transform))
             {
-                var coordinates = _transform.GetMoverCoordinates(entity.Value, transform);
-                var name = Identity.Entity(entity.Value, EntityManager);
+                var coordinates = _transform.GetMoverCoordinates(entity, transform);
+                var name = Identity.Entity(entity, EntityManager);
                 _popup.PopupCoordinates(Loc.GetString("admin-erase-popup", ("user", name)), coordinates, PopupType.LargeCaution);
                 var filter = Filter.Pvs(coordinates, 1, EntityManager, _playerManager);
                 var audioParams = new AudioParams().WithVolume(3);
                 _audio.PlayStatic("/Audio/Effects/pop_high.ogg", filter, coordinates, true, audioParams);
             }
 
-            foreach (var item in _inventory.GetHandOrInventoryEntities(entity.Value))
+            foreach (var item in _inventory.GetHandOrInventoryEntities(entity))
             {
                 if (TryComp(item, out PdaComponent? pda) &&
                     TryComp(pda.ContainedId, out StationRecordKeyStorageComponent? keyStorage) &&
@@ -424,29 +428,29 @@ public sealed class AdminSystem : EntitySystem
                 }
             }
 
-            if (_inventory.TryGetContainerSlotEnumerator(entity.Value, out var enumerator))
+            if (_inventory.TryGetContainerSlotEnumerator(entity, out var enumerator))
             {
                 while (enumerator.NextItem(out var item, out var slot))
                 {
-                    if (_inventory.TryUnequip(entity.Value, entity.Value, slot.Name, true, true))
+                    if (_inventory.TryUnequip(entity, entity, slot.Name, true, true))
                         _physics.ApplyAngularImpulse(item, ThrowingSystem.ThrowAngularImpulse);
                 }
             }
 
-            if (TryComp(entity.Value, out HandsComponent? hands))
+            if (TryComp(entity, out HandsComponent? hands))
             {
-                foreach (var hand in _hands.EnumerateHands(entity.Value, hands))
+                foreach (var hand in _hands.EnumerateHands(entity, hands))
                 {
-                    _hands.TryDrop(entity.Value, hand, checkActionBlocker: false, doDropInteraction: false, handsComp: hands);
+                    _hands.TryDrop(entity, hand, checkActionBlocker: false, doDropInteraction: false, handsComp: hands);
                 }
             }
-        }
 
-        _minds.WipeMind(player);
-        QueueDel(entity);
+            _minds.WipeMind(mindId, mind);
+            QueueDel(entity);
 
-        _gameTicker.SpawnObserver(player);
-    }
+            if (_playerManager.TryGetSessionById(uid, out var session))
+                _gameTicker.SpawnObserver(session);
+        }
 
     private void OnSessionPlayTimeUpdated(ICommonSession session)
     {
index 308a679846ccf9703458acdf3b87a2f010969eb3..5aa05ce28b701428d507dec3bb69f0b9d7bb72ff 100644 (file)
@@ -34,11 +34,11 @@ using Robust.Shared.Timing;
 using Robust.Shared.Toolshed;
 using Robust.Shared.Utility;
 using System.Linq;
-using System.Numerics;
 using Content.Server.Silicons.Laws;
 using Content.Shared.Silicons.Laws;
 using Content.Shared.Silicons.Laws.Components;
 using Robust.Server.Player;
+using Content.Shared.Mind;
 using Robust.Shared.Physics.Components;
 using static Content.Shared.Configurable.ConfigurationComponent;
 
@@ -137,34 +137,6 @@ namespace Content.Server.Administration.Systems
                     prayerVerb.Impact = LogImpact.Low;
                     args.Verbs.Add(prayerVerb);
 
-                    // Erase
-                    args.Verbs.Add(new Verb
-                    {
-                        Text = Loc.GetString("admin-verbs-erase"),
-                        Message = Loc.GetString("admin-verbs-erase-description"),
-                        Category = VerbCategory.Admin,
-                        Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
-                        Act = () =>
-                        {
-                            _adminSystem.Erase(targetActor.PlayerSession);
-                        },
-                        Impact = LogImpact.Extreme,
-                        ConfirmationPopup = true
-                    });
-
-                // Respawn
-                    args.Verbs.Add(new Verb()
-                    {
-                        Text = Loc.GetString("admin-player-actions-respawn"),
-                        Category = VerbCategory.Admin,
-                        Act = () =>
-                        {
-                            _console.ExecuteCommand(player, $"respawn {targetActor.PlayerSession.Name}");
-                        },
-                        ConfirmationPopup = true,
-                        // No logimpact as the command does it internally.
-                    });
-
                     // Spawn - Like respawn but on the spot.
                     args.Verbs.Add(new Verb()
                     {
@@ -225,6 +197,38 @@ namespace Content.Server.Administration.Systems
                     });
                 }
 
+                if (_mindSystem.TryGetMind(args.Target, out _, out var mind) && mind.UserId != null)
+                {
+                    // Erase
+                    args.Verbs.Add(new Verb
+                    {
+                        Text = Loc.GetString("admin-verbs-erase"),
+                        Message = Loc.GetString("admin-verbs-erase-description"),
+                        Category = VerbCategory.Admin,
+                        Icon = new SpriteSpecifier.Texture(
+                            new("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
+                        Act = () =>
+                        {
+                            _adminSystem.Erase(mind.UserId.Value);
+                        },
+                        Impact = LogImpact.Extreme,
+                        ConfirmationPopup = true
+                    });
+
+                    // Respawn
+                    args.Verbs.Add(new Verb
+                    {
+                        Text = Loc.GetString("admin-player-actions-respawn"),
+                        Category = VerbCategory.Admin,
+                        Act = () =>
+                        {
+                            _console.ExecuteCommand(player, $"respawn \"{mind.UserId}\"");
+                        },
+                        ConfirmationPopup = true,
+                        // No logimpact as the command does it internally.
+                    });
+                }
+
                 // Freeze
                 var frozen = TryComp<AdminFrozenComponent>(args.Target, out var frozenComp);
                 var frozenAndMuted = frozenComp?.Muted ?? false;
index 6fb7bbba8e8debf08da6c4ed59649427c199a069..02f718daef0e6ee5af351704634a31b59820d989 100644 (file)
@@ -81,10 +81,10 @@ internal sealed partial class ChatManager : IChatManager
         DispatchServerAnnouncement(Loc.GetString(val ? "chat-manager-admin-ooc-chat-enabled-message" : "chat-manager-admin-ooc-chat-disabled-message"));
     }
 
-    public void DeleteMessagesBy(ICommonSession player)
-    {
-        if (!_players.TryGetValue(player.UserId, out var user))
-            return;
+        public void DeleteMessagesBy(NetUserId uid)
+        {
+            if (!_players.TryGetValue(uid, out var user))
+                return;
 
         var msg = new MsgDeleteChatMessagesBy { Key = user.Key, Entities = user.Entities };
         _netManager.ServerSendToAll(msg);
index 15d1288ee2357ded917a5895e4d26131887793f3..76fa91d847411e89ef3540e406b15f3033552785 100644 (file)
@@ -41,7 +41,7 @@ namespace Content.Server.Chat.Managers
 
         bool MessageCharacterLimit(ICommonSession player, string message);
 
-        void DeleteMessagesBy(ICommonSession player);
+        void DeleteMessagesBy(NetUserId uid);
 
         [return: NotNullIfNotNull(nameof(author))]
         ChatUser? EnsurePlayer(NetUserId? author);
index 4f101d0939ad65cc78d5ec3daf8120a4847608e1..f7ea11baf16307f96c92fed95d8beb1cf691f10d 100644 (file)
@@ -1,4 +1,6 @@
-using Content.Shared.Mind;
+using System.Linq;
+using Content.Server.Administration;
+using Content.Server.Mind;
 using Content.Shared.Players;
 using Robust.Server.Player;
 using Robust.Shared.Console;
@@ -6,57 +8,72 @@ using Robust.Shared.Network;
 
 namespace Content.Server.GameTicking.Commands
 {
-    sealed class RespawnCommand : IConsoleCommand
+    sealed class RespawnCommand : LocalizedEntityCommands
     {
-        public string Command => "respawn";
-        public string Description => "Respawns a player, kicking them back to the lobby.";
-        public string Help => "respawn [player]";
+        [Dependency] private readonly IPlayerManager _player = default!;
+        [Dependency] private readonly IPlayerLocator _locator = default!;
+        [Dependency] private readonly GameTicker _gameTicker = default!;
+        [Dependency] private readonly MindSystem _mind = default!;
 
-        public void Execute(IConsoleShell shell, string argStr, string[] args)
+        public override string Command => "respawn";
+
+        public override async void Execute(IConsoleShell shell, string argStr, string[] args)
         {
             var player = shell.Player;
             if (args.Length > 1)
             {
-                shell.WriteLine("Must provide <= 1 argument.");
+                shell.WriteError(Loc.GetString("cmd-respawn-invalid-args"));
                 return;
             }
 
-            var playerMgr = IoCManager.Resolve<IPlayerManager>();
-            var sysMan = IoCManager.Resolve<IEntitySystemManager>();
-            var ticker = sysMan.GetEntitySystem<GameTicker>();
-            var mind = sysMan.GetEntitySystem<SharedMindSystem>();
-
             NetUserId userId;
             if (args.Length == 0)
             {
                 if (player == null)
                 {
-                    shell.WriteLine("If not a player, an argument must be given.");
+                    shell.WriteError(Loc.GetString("cmd-respawn-no-player"));
                     return;
                 }
 
                 userId = player.UserId;
             }
-            else if (!playerMgr.TryGetUserId(args[0], out userId))
+            else
             {
-                shell.WriteLine("Unknown player");
-                return;
+                var located = await _locator.LookupIdByNameOrIdAsync(args[0]);
+
+                if (located == null)
+                {
+                    shell.WriteError(Loc.GetString("cmd-respawn-unknown-player"));
+                    return;
+                }
+
+                userId = located.UserId;
             }
 
-            if (!playerMgr.TryGetSessionById(userId, out var targetPlayer))
+            if (!_player.TryGetSessionById(userId, out var targetPlayer))
             {
-                if (!playerMgr.TryGetPlayerData(userId, out var data))
+                if (!_player.TryGetPlayerData(userId, out var data))
                 {
-                    shell.WriteLine("Unknown player");
+                    shell.WriteError(Loc.GetString("cmd-respawn-unknown-player"));
                     return;
                 }
 
-                mind.WipeMind(data.ContentData()?.Mind);
-                shell.WriteLine("Player is not currently online, but they will respawn if they come back online");
+                _mind.WipeMind(data.ContentData()?.Mind);
+                shell.WriteError(Loc.GetString("cmd-respawn-player-not-online"));
                 return;
             }
 
-            ticker.Respawn(targetPlayer);
+            _gameTicker.Respawn(targetPlayer);
+        }
+
+      public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
+        {
+            if (args.Length != 1)
+                return CompletionResult.Empty;
+
+            var options = _player.Sessions.OrderBy(c => c.Name).Select(c => c.Name).ToArray();
+
+            return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-respawn-player-completion"));
         }
     }
 }
diff --git a/Resources/Locale/en-US/administration/commands/erase.ftl b/Resources/Locale/en-US/administration/commands/erase.ftl
new file mode 100644 (file)
index 0000000..e9f995f
--- /dev/null
@@ -0,0 +1,7 @@
+# erase
+cmd-erase-desc = Erase a player's entity if it exists and all their chat messages
+cmd-erase-help = erase <Username of User Id>
+cmd-erase-invalid-args = Invalid number of arguments
+cmd-erase-player-not-found = Player not found
+
+cmd-erase-player-completion = <Username>
diff --git a/Resources/Locale/en-US/administration/commands/respawn.ftl b/Resources/Locale/en-US/administration/commands/respawn.ftl
new file mode 100644 (file)
index 0000000..6aab854
--- /dev/null
@@ -0,0 +1,9 @@
+cmd-respawn-desc = Respawns a player, kicking them back to the lobby.
+cmd-respawn-help = respawn [player or UserId]
+
+cmd-respawn-invalid-args = Must provide <= 1 argument.
+cmd-respawn-no-player = If not a player, an argument must be given.
+cmd-respawn-unknown-player = Unknown player
+cmd-respawn-player-not-online = Player is not currently online, but they will respawn if they come back online
+
+cmd-respawn-player-completion = <Username>