120 lines
4.1 KiB
C#
120 lines
4.1 KiB
C#
using CounterStrikeSharp.API;
|
|
using CounterStrikeSharp.API.Core;
|
|
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
|
using CounterStrikeSharp.API.Core.Capabilities;
|
|
using CounterStrikeSharp.API.Modules.Commands;
|
|
using CounterStrikeSharp.API.Modules.Entities;
|
|
using CounterStrikeSharp.API.ValveConstants.Protobuf;
|
|
using CS2_SimpleAdminApi;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace AdminStealth;
|
|
|
|
// Companion to CS2-SimpleAdmin's css_hide. When an admin hides, everyone else sees them leave the
|
|
// server, and nothing the hide does afterwards (the suicide, the team changes, their real
|
|
// disconnect later) is announced. Also blocks the status command for players, which would
|
|
// otherwise still list a hidden admin.
|
|
public class AdminStealth : BasePlugin
|
|
{
|
|
public override string ModuleName => "AdminStealth";
|
|
public override string ModuleVersion => "0.1.0";
|
|
public override string ModuleAuthor => "astra";
|
|
public override string ModuleDescription => "Makes CS2-SimpleAdmin's css_hide look like leaving the server";
|
|
|
|
private static readonly PluginCapability<ICS2_SimpleAdminApi> SimpleAdminCapability = new("simpleadmin:api");
|
|
private ICS2_SimpleAdminApi? _simpleAdmin;
|
|
|
|
public override void Load(bool hotReload)
|
|
{
|
|
AddCommandListener("status", OnStatus);
|
|
}
|
|
|
|
public override void OnAllPluginsLoaded(bool hotReload)
|
|
{
|
|
try
|
|
{
|
|
_simpleAdmin = SimpleAdminCapability.Get();
|
|
}
|
|
catch (KeyNotFoundException)
|
|
{
|
|
}
|
|
|
|
if (_simpleAdmin == null)
|
|
{
|
|
Logger.LogError("CS2-SimpleAdmin's API isn't available, so hiding won't look like leaving");
|
|
return;
|
|
}
|
|
_simpleAdmin.OnAdminToggleSilent += OnAdminToggleSilent;
|
|
}
|
|
|
|
public override void Unload(bool hotReload)
|
|
{
|
|
if (_simpleAdmin != null)
|
|
_simpleAdmin.OnAdminToggleSilent -= OnAdminToggleSilent;
|
|
}
|
|
|
|
// Players get nothing back. The server console and RCON still work.
|
|
private HookResult OnStatus(CCSPlayerController? player, CommandInfo command)
|
|
{
|
|
return player == null ? HookResult.Continue : HookResult.Stop;
|
|
}
|
|
|
|
private void OnAdminToggleSilent(int slot, bool hidden)
|
|
{
|
|
if (!hidden)
|
|
return;
|
|
|
|
var admin = Utilities.GetPlayerFromSlot(slot);
|
|
if (admin is not { IsValid: true, IsBot: false })
|
|
return;
|
|
|
|
// A fake player_disconnect, sent to each client rather than fired on the server, so no
|
|
// plugin (SimpleAdmin included) treats the admin as really gone.
|
|
var leave = new EventPlayerDisconnect(true)
|
|
{
|
|
Userid = admin,
|
|
Playerid = admin.Slot,
|
|
Name = admin.PlayerName,
|
|
Networkid = new SteamID(admin.SteamID).SteamId3,
|
|
Xuid = admin.SteamID,
|
|
Reason = (int)NetworkDisconnectionReason.NETWORK_DISCONNECT_DISCONNECT_BY_USER,
|
|
EverFullyConnected = true,
|
|
};
|
|
foreach (var player in Utilities.GetPlayers())
|
|
{
|
|
if (player is { IsValid: true, IsBot: false, IsHLTV: false } && player.Slot != slot)
|
|
leave.FireEventToClient(player);
|
|
}
|
|
leave.Free();
|
|
}
|
|
|
|
[GameEventHandler(HookMode.Pre)]
|
|
public HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info)
|
|
{
|
|
if (IsHidden(@event.Userid))
|
|
info.DontBroadcast = true;
|
|
return HookResult.Continue;
|
|
}
|
|
|
|
[GameEventHandler(HookMode.Pre)]
|
|
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
|
|
{
|
|
if (IsHidden(@event.Userid))
|
|
info.DontBroadcast = true;
|
|
return HookResult.Continue;
|
|
}
|
|
|
|
// Pre runs before SimpleAdmin's own handler forgets the player was hidden.
|
|
[GameEventHandler(HookMode.Pre)]
|
|
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
|
|
{
|
|
if (IsHidden(@event.Userid))
|
|
info.DontBroadcast = true;
|
|
return HookResult.Continue;
|
|
}
|
|
|
|
private bool IsHidden(CCSPlayerController? player)
|
|
{
|
|
return player is { IsValid: true, IsBot: false } && _simpleAdmin?.IsAdminSilent(player) == true;
|
|
}
|
|
}
|