GhostKickManager.cs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. using Content.Server.Administration;
  2. using Content.Shared.Administration;
  3. using Content.Shared.GhostKick;
  4. using Robust.Server.Player;
  5. using Robust.Shared.Console;
  6. using Robust.Shared.Network;
  7. using Robust.Shared.Timing;
  8. namespace Content.Server.GhostKick;
  9. // Handles logic for "ghost kicking".
  10. // Basically we boot the client off the server without telling them, so the game shits itself.
  11. // Hilariously isn't it?
  12. public sealed class GhostKickManager
  13. {
  14. [Dependency] private readonly IServerNetManager _netManager = default!;
  15. public void Initialize()
  16. {
  17. _netManager.RegisterNetMessage<MsgGhostKick>();
  18. }
  19. public void DoDisconnect(INetChannel channel, string reason)
  20. {
  21. Timer.Spawn(TimeSpan.FromMilliseconds(100), () =>
  22. {
  23. if (!channel.IsConnected)
  24. return;
  25. // We do this so the client can set net.fakeloss 1 before getting ghosted.
  26. // This avoids it spamming messages at the server that cause warnings due to unconnected client.
  27. channel.SendMessage(new MsgGhostKick());
  28. Timer.Spawn(TimeSpan.FromMilliseconds(100), () =>
  29. {
  30. if (!channel.IsConnected)
  31. return;
  32. // Actually just remove the client entirely.
  33. channel.Disconnect(reason, false);
  34. });
  35. });
  36. }
  37. }
  38. [AdminCommand(AdminFlags.Moderator)]
  39. public sealed class GhostKickCommand : IConsoleCommand
  40. {
  41. public string Command => "ghostkick";
  42. public string Description => "Kick a client from the server as if their network just dropped.";
  43. public string Help => "Usage: ghostkick <Player> [Reason]";
  44. public void Execute(IConsoleShell shell, string argStr, string[] args)
  45. {
  46. if (args.Length < 1)
  47. {
  48. shell.WriteError("Need at least one argument");
  49. return;
  50. }
  51. var playerName = args[0];
  52. var reason = args.Length > 1 ? args[1] : "Ghost kicked by console";
  53. var players = IoCManager.Resolve<IPlayerManager>();
  54. var ghostKick = IoCManager.Resolve<GhostKickManager>();
  55. if (!players.TryGetSessionByUsername(playerName, out var player))
  56. {
  57. shell.WriteError($"Unable to find player: '{playerName}'.");
  58. return;
  59. }
  60. ghostKick.DoDisconnect(player.Channel, reason);
  61. }
  62. }