Initial commit

This commit is contained in:
daffyyyy
2023-12-02 22:44:11 +01:00
parent 7ec9d5b9c0
commit 6bcb10c5cf
11 changed files with 586 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
bin/
obj/
.vs/
.git

67
BanManager.cs Normal file
View File

@@ -0,0 +1,67 @@
using CounterStrikeSharp.API.Core;
using Dapper;
using MySqlConnector;
using System.Data;
namespace CS2_SimpleAdmin
{
internal class BanManager
{
private readonly IDbConnection _dbConnection;
public BanManager(string connectionString)
{
_dbConnection = new MySqlConnection(connectionString);
}
public void BanPlayer(CCSPlayerController? player, CCSPlayerController? issuer, string reason, int time = 0)
{
_dbConnection.Open();
if (player == null || !player.IsValid || player.AuthorizedSteamID == null) return;
DateTime now = DateTime.Now;
DateTime futureTime = now.AddMinutes(time);
var sql = "INSERT INTO `sa_bans` (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `duration`, `ends`, `created`) " +
"VALUES (@playerSteamid, @playerName, @adminSteamid, @adminName, @duration, @ends, @created)";
_dbConnection.Execute(sql, new
{
playerSteamid = player.AuthorizedSteamID.SteamId64.ToString(),
playerName = player.PlayerName,
adminSteamid = issuer == null ? "Console" : issuer?.AuthorizedSteamID?.SteamId64.ToString(),
adminName = issuer == null ? "Console" : issuer.PlayerName,
duration = time,
ends = futureTime,
created = now
});
_dbConnection.Close();
}
public bool IsPlayerBanned(string steamId)
{
_dbConnection.Open();
DateTime now = DateTime.Now;
string sql = "SELECT COUNT(*) FROM sa_bans WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)";
int banCount = _dbConnection.ExecuteScalar<int>(sql, new { PlayerSteamID = steamId, CurrentTime = now });
_dbConnection.Close();
return banCount > 0;
}
public void ExpireOldBans()
{
_dbConnection.Open();
string sql = "UPDATE sa_bans SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime";
int affectedRows = _dbConnection.Execute(sql, new { CurrentTime = DateTime.Now });
_dbConnection.Close();
}
}
}

187
CS2-SimpleAdmin.cs Normal file
View File

@@ -0,0 +1,187 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using MySqlConnector;
using static System.Net.Mime.MediaTypeNames;
namespace CS2_SimpleAdmin;
public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdminConfig>
{
internal string dbConnectionString = string.Empty;
public override string ModuleName => "CS2-SimpleAdmin";
public override string ModuleDescription => "";
public override string ModuleAuthor => "daffyy";
public override string ModuleVersion => "1.0.0";
public CS2_SimpleAdminConfig Config { get; set; } = new();
public override void Load(bool hotReload)
{
registerEvents();
if (hotReload)
{
OnMapStart(string.Empty);
}
}
public void OnConfigParsed(CS2_SimpleAdminConfig config)
{
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{
throw new Exception("[CS2-SimpleAdmin] You need to setup Database credentials in config!");
}
MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder
{
Server = config.DatabaseHost,
Database = config.DatabaseName,
UserID = config.DatabaseUser,
Password = config.DatabasePassword,
Port = (uint)config.DatabasePort,
};
dbConnectionString = builder.ConnectionString;
try
{
using (var connection = new MySqlConnection(dbConnectionString))
{
connection.Open();
connection.Close();
}
}
catch (MySqlException ex)
{
throw new Exception("[CS2-SimpleAdmin] Unable to connect to Database!" + ex.Message);
}
Config = config;
}
[ConsoleCommand("css_kick")]
[RequiresPermissions("@css/kick")]
[CommandHelper(minArgs: 1, usage: "<#userid or name> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
public void OnKickCommand(CCSPlayerController? caller, CommandInfo command)
{
if (!GetTarget(command, out var player))
return;
player!.Pawn.Value!.Freeze();
string reason = "Brak powodu";
if (command.ArgCount >= 2)
reason = command.GetArg(2);
if (command.ArgCount >= 2)
{
player!.PrintToCenter($"{Config.Messages.PlayerKickMessage}".Replace("{REASON}", reason).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName));
AddTimer(10.0f, () => Helper.KickPlayer(player!.UserId, reason));
}
else
{
AddTimer(10.0f, () => Helper.KickPlayer(player!.UserId));
}
Server.PrintToChatAll(Helper.ReplaceTags($" {Config.Prefix} {Config.Messages.AdminKickMessage}".Replace("{REASON}", reason).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName).Replace("{PLAYER}", player.PlayerName)));
}
[ConsoleCommand("css_ban")]
[RequiresPermissions("@css/ban")]
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
public void OnBanCommand(CCSPlayerController? caller, CommandInfo command)
{
if (!GetTarget(command, out var player))
return;
if (command.ArgCount < 2)
return;
int time = 0;
string reason = "Unknown";
player!.Pawn.Value!.Freeze();
BanManager _banManager = new(dbConnectionString);
int.TryParse(command.GetArg(2), out time);
if (command.ArgCount >= 3)
reason = command.GetArg(3);
_banManager.BanPlayer(player, caller, reason, time);
if (time == 0)
{
player!.PrintToCenter($"{Config.Messages.PlayerBanMessagePerm}".Replace("{REASON}", reason).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName));
Server.PrintToChatAll(Helper.ReplaceTags($" {Config.Prefix} {Config.Messages.AdminBanMessagePerm}".Replace("{REASON}", reason).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName).Replace("{PLAYER}", player.PlayerName)));
}
else
{
player!.PrintToCenter($"{Config.Messages.PlayerBanMessageTime}".Replace("{REASON}", reason).Replace("{TIME}", time.ToString()).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName));
Server.PrintToChatAll(Helper.ReplaceTags($" {Config.Prefix} {Config.Messages.AdminBanMessageTime}".Replace("{REASON}", reason).Replace("{TIME}", time.ToString()).Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName).Replace("{PLAYER}", player.PlayerName)));
}
AddTimer(10.0f, () => Helper.KickPlayer(player!.UserId));
}
[ConsoleCommand("css_slay")]
[RequiresPermissions("@css/slay")]
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
public void OnSlayCommand(CCSPlayerController? caller, CommandInfo command)
{
if (!GetTarget(command, out CCSPlayerController? player))
return;
if (!player!.PawnIsAlive)
return;
player!.CommitSuicide(false, true);
Server.PrintToChatAll(Helper.ReplaceTags($" {Config.Prefix} {Config.Messages.AdminSlayMessage}".Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName).Replace("{PLAYER}", player.PlayerName)));
}
[ConsoleCommand("css_slap")]
[RequiresPermissions("@css/slay")]
[CommandHelper(minArgs: 1, usage: "<#userid or name> [damage]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
public void OnSlapCommand(CCSPlayerController? caller, CommandInfo command)
{
if (!GetTarget(command, out CCSPlayerController? player))
return;
if (!player!.PawnIsAlive)
return;
int damage = 0;
if (command.ArgCount >= 2)
{
int.TryParse(command.GetArg(2), out damage);
}
player!.Pawn.Value!.Slap(damage);
Server.PrintToChatAll(Helper.ReplaceTags($" {Config.Prefix} {Config.Messages.AdminSlapMessage}".Replace("{ADMIN}", caller?.PlayerName == null ? "Console" : caller.PlayerName).Replace("{PLAYER}", player.PlayerName)));
}
private static bool GetTarget(CommandInfo info, out CCSPlayerController? player)
{
var matches = Helper.GetTarget(info.GetArg(1), out player);
switch (matches)
{
case TargetResult.None:
info.ReplyToCommand($"Target {info.GetArg(1)} not found.");
return false;
case TargetResult.Multiple:
info.ReplyToCommand($"Multiple targets found for \"{info.GetArg(1)}\".");
return false;
}
return true;
}
}

17
CS2-SimpleAdmin.csproj Normal file
View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>CS2_SimpleAdmin</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.90" />
<PackageReference Include="Dapper" Version="2.1.24" />
<PackageReference Include="MySqlConnector" Version="2.3.1" />
</ItemGroup>
</Project>

25
CS2-SimpleAdmin.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34309.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2-SimpleAdmin", "CS2-SimpleAdmin.csproj", "{0DB90496-262F-4BF9-9B55-1490EBF4D49F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {86114444-059F-4DB8-9A55-E6D1BB76238D}
EndGlobalSection
EndGlobal

53
Config.cs Normal file
View File

@@ -0,0 +1,53 @@
using CounterStrikeSharp.API.Core;
using System.Text.Json.Serialization;
namespace CS2_SimpleAdmin
{
public class Messages
{
[JsonPropertyName("PlayerBanMessageTime")]
public string PlayerBanMessageTime { get; set; } = "You have been banned for {REASON} for {TIME} minutes by {ADMIN}!";
[JsonPropertyName("PlayerBanMessagePerm")]
public string PlayerBanMessagePerm { get; set; } = "You have been banned permanently for {REASON} by {ADMIN}!";
[JsonPropertyName("PlayerKickMessage")]
public string PlayerKickMessage { get; set; } = "You have been kicked for {REASON} by {ADMIN}!";
[JsonPropertyName("AdminBanMessageTime")]
public string AdminBanMessageTime { get; set; } = "Admin {ADMIN} banned {PLAYER} for {REASON} for {TIME} minutes!";
[JsonPropertyName("AdminBanMessagePerm")]
public string AdminBanMessagePerm { get; set; } = "Admin {ADMIN} banned {PLAYER} permanently for {REASON}";
[JsonPropertyName("AdminKickMessage")]
public string AdminKickMessage { get; set; } = "Admin {ADMIN} kicked {PLAYER} for {REASON}!";
[JsonPropertyName("AdminSlayMessage")]
public string AdminSlayMessage { get; set; } = "Admin {ADMIN} slayed {PLAYER}!";
[JsonPropertyName("AdminSlapMessage")]
public string AdminSlapMessage { get; set; } = "Admin {ADMIN} slapped {PLAYER}!";
}
public class CS2_SimpleAdminConfig : BasePluginConfig
{
public override int Version { get; set; } = 1;
[JsonPropertyName("DatabaseHost")]
public string DatabaseHost { get; set; } = "";
[JsonPropertyName("DatabasePort")]
public int DatabasePort { get; set; } = 3306;
[JsonPropertyName("DatabaseUser")]
public string DatabaseUser { get; set; } = "";
[JsonPropertyName("DatabasePassword")]
public string DatabasePassword { get; set; } = "";
[JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; } = "";
[JsonPropertyName("Prefix")]
public string Prefix { get; set; } = "{GREEN}[SimpleAdmin]";
[JsonPropertyName("Messages")]
public Messages Messages { get; set; } = new Messages();
}
}

48
Events.cs Normal file
View File

@@ -0,0 +1,48 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities;
namespace CS2_SimpleAdmin
{
public partial class CS2_SimpleAdmin
{
private void registerEvents()
{
RegisterListener<Listeners.OnClientAuthorized>(OnClientAuthorized);
RegisterListener<Listeners.OnMapStart>(OnMapStart);
}
private void OnClientAuthorized(int playerSlot, SteamID steamID)
{
int playerIndex = playerSlot + 1;
CCSPlayerController? player = Utilities.GetPlayerFromIndex(playerIndex);
if (player.AuthorizedSteamID == null)
{
AddTimer(3.0f, () =>
{
OnClientAuthorized(playerSlot, steamID);
});
return;
}
BanManager _banManager = new(dbConnectionString);
bool isBanned = _banManager.IsPlayerBanned(player.AuthorizedSteamID.SteamId64.ToString());
if (isBanned)
{
Helper.KickPlayer(player.UserId, "Banned");
}
}
private void OnMapStart(string mapName)
{
AddTimer(120.0f, () =>
{
BanManager _banManager = new(dbConnectionString);
_banManager.ExpireOldBans();
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
}
}

63
Helper.cs Normal file
View File

@@ -0,0 +1,63 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API;
using MySqlConnector;
using CounterStrikeSharp.API.Modules.Utils;
using System.Reflection;
namespace CS2_SimpleAdmin
{
internal class Helper
{
internal static CS2_SimpleAdminConfig? Config { get; set; }
public static List<CCSPlayerController> GetPlayerFromName(string name)
{
return Utilities.GetPlayers().FindAll(x => x.PlayerName.Contains(name, StringComparison.OrdinalIgnoreCase));
}
public static TargetResult GetTarget(string target, out CCSPlayerController? player)
{
player = null;
if (target.StartsWith("#") && int.TryParse(target.AsSpan(1), out var userid))
{
player = Utilities.GetPlayerFromUserid(userid);
}
else
{
var matches = GetPlayerFromName(target);
if (matches.Count > 1)
return TargetResult.Multiple;
player = matches.FirstOrDefault();
}
return player?.IsValid == true ? TargetResult.Single : TargetResult.None;
}
public static void KickPlayer(int? userId, string? reason = null)
{
Server.ExecuteCommand($"kickid {userId} {reason}");
}
internal static string ReplaceTags(string message)
{
if (message.Contains('{'))
{
string modifiedValue = message;
foreach (FieldInfo field in typeof(ChatColors).GetFields())
{
string pattern = $"{{{field.Name}}}";
if (message.Contains(pattern, StringComparison.OrdinalIgnoreCase))
{
modifiedValue = modifiedValue.Replace(pattern, field.GetValue(null)!.ToString(), StringComparison.OrdinalIgnoreCase);
}
}
return modifiedValue;
}
return message;
}
}
}

71
PlayerUtils.cs Normal file
View File

@@ -0,0 +1,71 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
namespace CS2_SimpleAdmin;
public static class PlayerUtils
{
public static void Slap(this CBasePlayerPawn pawn, int damage = 0)
{
PerformSlap(pawn, damage);
}
public static void Bury(this CBasePlayerPawn pawn, float depth = 10f)
{
var newPos = new Vector(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
pawn.AbsOrigin!.Z - depth);
pawn.Teleport(newPos, pawn.AbsRotation!, pawn.AbsVelocity);
}
public static void Unbury(this CBasePlayerPawn pawn, float depth = 15f)
{
var newPos = new Vector(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
pawn.AbsOrigin!.Z + depth);
pawn.Teleport(newPos, pawn.AbsRotation!, pawn.AbsVelocity);
}
public static void Freeze(this CBasePlayerPawn pawn)
{
pawn.MoveType = MoveType_t.MOVETYPE_NONE;
}
public static void Unfreeze(this CBasePlayerPawn pawn)
{
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
}
public static void ToggleNoclip(this CBasePlayerPawn pawn)
{
if (pawn.MoveType == MoveType_t.MOVETYPE_NOCLIP)
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
else
pawn.MoveType = MoveType_t.MOVETYPE_NOCLIP;
}
private static void PerformSlap(CBasePlayerPawn pawn, int damage = 0)
{
if (pawn.LifeState != (int)LifeState_t.LIFE_ALIVE)
return;
/* Teleport in a random direction - thank you, Mani!*/
/* Thank you AM & al!*/
var random = new Random();
var vel = new Vector(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z);
vel.X += ((random.Next(180) + 50) * ((random.Next(2) == 1) ? -1 : 1));
vel.Y += ((random.Next(180) + 50) * ((random.Next(2) == 1) ? -1 : 1));
vel.Z += random.Next(200) + 100;
pawn.Teleport(pawn.AbsOrigin!, pawn.AbsRotation!, vel);
if (damage <= 0)
return;
pawn.Health -= damage;
if (pawn.Health <= 0)
pawn.CommitSuicide(true, true);
}
}

43
README.md Normal file
View File

@@ -0,0 +1,43 @@
# CS2-SimpleAdmin
### Description
Manage your Counter-Strike 2 server by simple commands :)
### Info
It's only plugin base, I don't have much time for more extensive development, so if you want to help, do it :)
### Commands
- css_ban <#userid or name> [time in minutes/0 perm] [reason] - Ban player
- css_kick <#userid or name> [reason] - Kick player
- css_slay <#userid or name> - Kill player
- css_slap <#userid or name> [damage] - Slap player
### Requirments
[CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on v90**
### Configuration
After first launch, u need to configure plugin in addons/counterstrikesharp/configs/plugins/CS2-SimpleAdmin/CS2-SimpleAdmin.json
### Colors
```
public static char Default = '\x01';
public static char White = '\x01';
public static char Darkred = '\x02';
public static char Green = '\x04';
public static char LightYellow = '\x03';
public static char LightBlue = '\x03';
public static char Olive = '\x05';
public static char Lime = '\x06';
public static char Red = '\x07';
public static char Purple = '\x03';
public static char Grey = '\x08';
public static char Yellow = '\x09';
public static char Gold = '\x10';
public static char Silver = '\x0A';
public static char Blue = '\x0B';
public static char DarkBlue = '\x0C';
public static char BlueGrey = '\x0D';
public static char Magenta = '\x0E';
public static char LightRed = '\x0F';
```
Use color name for e.g. {LightRed}

8
TargetResult.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace CS2_SimpleAdmin;
internal enum TargetResult
{
None,
Multiple,
Single
}