mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-09-27 20:17:04 +02:00
upstream ~ v1.7.7-alpha
This commit is contained in:
commit
c586dd700c
43 changed files with 928 additions and 337 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,5 +4,6 @@ obj/
|
|||
.git
|
||||
.vscode/
|
||||
.idea/
|
||||
Modules/CS2-SimpleAdmin_PlayTimeModule
|
||||
CS2-SimpleAdmin.sln.DotSettings.user
|
||||
Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdmin_ExampleModule.sln.DotSettings.user
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
||||
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
||||
public override string ModuleAuthor => "daffyy & Dliix66";
|
||||
public override string ModuleVersion => "1.7.5a";
|
||||
public override string ModuleVersion => "1.7.7-alpha";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
|
|
@ -31,6 +31,8 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||
{
|
||||
ServerLoaded = false;
|
||||
_serverLoading = false;
|
||||
|
||||
CacheManager = new CacheManager();
|
||||
OnGameServerSteamAPIActivated();
|
||||
OnMapStart(string.Empty);
|
||||
|
||||
|
|
@ -40,10 +42,10 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||
|
||||
var playerManager = new PlayerManager();
|
||||
|
||||
Helper.GetValidPlayers().ForEach(player =>
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
playerManager.LoadPlayerData(player);
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
_cBasePlayerControllerSetPawnFunc = new MemoryFunctionVoid<CBasePlayerController, CCSPlayerPawn, bool, bool>(GameData.GetSignature("CBasePlayerController_SetPawn"));
|
||||
|
|
@ -58,7 +60,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||
|
||||
public override void OnAllPluginsLoaded(bool hotReload)
|
||||
{
|
||||
AddTimer(3.0f, () => ReloadAdmins(null));
|
||||
AddTimer(5.0f, () => ReloadAdmins(null));
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -151,4 +153,10 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||
command.ReplyToCommand($"Multiple targets found for \"{command.GetArg(1)}\".");
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
CacheManager?.Dispose();
|
||||
CacheManager = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,11 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.305" />
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.318" />
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="*" />
|
||||
<PackageReference Include="ZLinq" Version="1.4.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -25,6 +26,12 @@
|
|||
<None Update="Database\Migrations\010_CreateWarnsTable.sql">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Database\Migrations\012_AddUpdatedAtColumnToSaBansTable.sql">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Database\Migrations\013_AddNameColumnToSaPlayerIpsTable.sql">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public static class RegisterCommands
|
|||
new CommandMapping("css_addgroup", CS2_SimpleAdmin.Instance.OnAddGroup),
|
||||
new CommandMapping("css_delgroup", CS2_SimpleAdmin.Instance.OnDelGroupCommand),
|
||||
new CommandMapping("css_reloadadmins", CS2_SimpleAdmin.Instance.OnRelAdminCommand),
|
||||
new CommandMapping("css_reloadbans", CS2_SimpleAdmin.Instance.OnRelBans),
|
||||
new CommandMapping("css_hide", CS2_SimpleAdmin.Instance.OnHideCommand),
|
||||
new CommandMapping("css_hidecomms", CS2_SimpleAdmin.Instance.OnHideCommsCommand),
|
||||
new CommandMapping("css_who", CS2_SimpleAdmin.Instance.OnWhoCommand),
|
||||
|
|
@ -122,6 +123,7 @@ public static class RegisterCommands
|
|||
{ "css_addgroup", new Command { Aliases = ["css_addgroup"] } },
|
||||
{ "css_delgroup", new Command { Aliases = ["css_delgroup"] } },
|
||||
{ "css_reloadadmins", new Command { Aliases = ["css_reloadadmins"] } },
|
||||
{ "css_reloadbans", new Command { Aliases = ["css_reloadbans"] } },
|
||||
{ "css_hide", new Command { Aliases = ["css_hide", "css_stealth"] } },
|
||||
{ "css_hidecomms", new Command { Aliases = ["css_hidecomms"] } },
|
||||
{ "css_who", new Command { Aliases = ["css_who"] } },
|
||||
|
|
|
|||
|
|
@ -73,12 +73,6 @@ public partial class CS2_SimpleAdmin
|
|||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time, penaltyId);
|
||||
});
|
||||
|
||||
// Update banned players list
|
||||
if (playerInfo.IpAddress != null && !BannedPlayers.Contains(playerInfo.IpAddress))
|
||||
BannedPlayers.Add(playerInfo.IpAddress);
|
||||
if (!BannedPlayers.Contains(player.SteamID.ToString()))
|
||||
BannedPlayers.Add(player.SteamID.ToString());
|
||||
|
||||
// Determine message keys and arguments based on ban time
|
||||
var (messageKey, activityMessageKey, centerArgs, adminActivityArgs) = time == 0
|
||||
? ("sa_player_ban_message_perm", "sa_admin_ban_message_perm",
|
||||
|
|
@ -129,8 +123,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -184,8 +177,7 @@ public partial class CS2_SimpleAdmin
|
|||
? PlayersInfo[caller.UserId.Value]
|
||||
: null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid);
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -247,8 +239,7 @@ public partial class CS2_SimpleAdmin
|
|||
? PlayersInfo[caller.UserId.Value]
|
||||
: null;
|
||||
|
||||
var matches = Helper.GetPlayerFromIp(ipAddress);
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromIp(ipAddress);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -366,10 +357,10 @@ public partial class CS2_SimpleAdmin
|
|||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
// Freeze player pawn if alive
|
||||
if (player.PawnIsAlive)
|
||||
if (player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
player.Pawn.Value?.Freeze();
|
||||
AddTimer(5.0f, () => player.Pawn.Value?.Unfreeze(), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
player.PlayerPawn?.Value?.Freeze();
|
||||
AddTimer(5.0f, () => player.PlayerPawn?.Value?.Unfreeze(), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
// Get player and admin information
|
||||
|
|
@ -442,8 +433,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ public partial class CS2_SimpleAdmin
|
|||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
Helper.PrintToCenterAll(utf8String.ReplaceColorTags());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -387,19 +387,20 @@ public partial class CS2_SimpleAdmin
|
|||
command.ReplyToCommand("Reloaded sql admins and groups");
|
||||
}
|
||||
|
||||
public void ReloadAdmins(CCSPlayerController? caller)
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnRelBans(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
|
||||
for (var index = 0; index < PermissionManager.AdminCache.Keys.ToList().Count; index++)
|
||||
{
|
||||
var steamId = PermissionManager.AdminCache.Keys.ToList()[index];
|
||||
if (!PermissionManager.AdminCache.TryRemove(steamId, out _)) continue;
|
||||
|
||||
AdminManager.ClearPlayerPermissions(steamId);
|
||||
AdminManager.RemovePlayerAdminData(steamId);
|
||||
_ = Instance.CacheManager?.ForceReInitializeCacheAsync();
|
||||
command.ReplyToCommand("Reloaded bans");
|
||||
}
|
||||
|
||||
public void ReloadAdmins(CCSPlayerController? caller)
|
||||
{
|
||||
if (Database == null) return;
|
||||
|
||||
if(!Config.IsCSSPanel)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
|
|
@ -413,11 +414,11 @@ public partial class CS2_SimpleAdmin
|
|||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(1.8f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
AddTimer(1.3f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
if (!string.IsNullOrEmpty(groupsFile))
|
||||
AddTimer(2.5f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json"));
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(3.0f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
AddTimer(3.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
|
||||
_logger?.LogInformation("Loaded admins!");
|
||||
});
|
||||
|
|
@ -445,8 +446,8 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
Server.ExecuteCommand("sv_disable_teamselect_menu 1");
|
||||
|
||||
if (caller.PlayerPawn.Value != null && caller.PawnIsAlive)
|
||||
caller.PlayerPawn.Value.CommitSuicide(true, false);
|
||||
if (caller.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
caller.PlayerPawn.Value?.CommitSuicide(true, false);
|
||||
|
||||
AddTimer(1.0f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.Spectator)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
AddTimer(1.4f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.None)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
|
@ -520,6 +521,10 @@ public partial class CS2_SimpleAdmin
|
|||
printMethod($"• Total Mutes: \"{playerInfo.TotalMutes}\"");
|
||||
printMethod($"• Total Silences: \"{playerInfo.TotalSilences}\"");
|
||||
printMethod($"• Total Warns: \"{playerInfo.TotalWarns}\"");
|
||||
|
||||
var chunkedAccounts = playerInfo.AccountsAssociated.ChunkBy(3).ToList();
|
||||
foreach (var chunk in chunkedAccounts)
|
||||
printMethod($"• Associated Accounts: \"{string.Join(", ", chunk.Select(a => $"{a.PlayerName} ({a.SteamId})"))}\"");
|
||||
}
|
||||
|
||||
printMethod($"--------- END INFO ABOUT \"{player.PlayerName}\" ---------");
|
||||
|
|
@ -661,7 +666,6 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsBot: false }).ToList();
|
||||
|
||||
if (playersToTarget.Count > 1)
|
||||
return;
|
||||
|
||||
|
|
@ -719,20 +723,20 @@ public partial class CS2_SimpleAdmin
|
|||
if (caller != null)
|
||||
{
|
||||
caller.PrintToConsole("--------- PLAYER LIST ---------");
|
||||
playersToTarget.ForEach(player =>
|
||||
foreach (var player in playersToTarget)
|
||||
{
|
||||
caller.PrintToConsole(
|
||||
$"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{(AdminManager.PlayerHasPermissions(new SteamID(caller.SteamID), "@css/showip") ? player.IpAddress?.Split(":")[0] : "Unknown")}\" SteamID64: \"{player.SteamID}\")");
|
||||
});
|
||||
};
|
||||
caller.PrintToConsole("--------- END PLAYER LIST ---------");
|
||||
}
|
||||
else
|
||||
{
|
||||
Server.PrintToConsole("--------- PLAYER LIST ---------");
|
||||
playersToTarget.ForEach(player =>
|
||||
foreach (var player in playersToTarget)
|
||||
{
|
||||
Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")");
|
||||
});
|
||||
};
|
||||
Server.PrintToConsole("--------- END PLAYER LIST ---------");
|
||||
}
|
||||
}
|
||||
|
|
@ -800,6 +804,8 @@ public partial class CS2_SimpleAdmin
|
|||
Kick(caller, player, reason, callerName, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
public void Kick(CCSPlayerController? caller, CCSPlayerController player, string? reason = "Unknown", string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -839,8 +845,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command and send Discord notification
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_kick {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {reason}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason, -1, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,8 +114,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -173,8 +172,7 @@ public partial class CS2_SimpleAdmin
|
|||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid);
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -230,8 +228,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -407,8 +404,7 @@ public partial class CS2_SimpleAdmin
|
|||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid);
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -448,8 +444,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -499,8 +494,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -681,8 +675,7 @@ public partial class CS2_SimpleAdmin
|
|||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid);
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -722,8 +715,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -773,8 +765,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = matches.Count == 1 ? matches.FirstOrDefault() : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public partial class CS2_SimpleAdmin
|
|||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player.IsValid &&
|
||||
player is { PawnIsAlive: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList();
|
||||
player is { IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -27,6 +27,8 @@ public partial class CS2_SimpleAdmin
|
|||
NoClip(caller, player, callerName);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void NoClip(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -53,14 +55,8 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
// Log the command
|
||||
if (command == null)
|
||||
{
|
||||
Helper.LogCommand(caller, $"css_noclip {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
}
|
||||
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
|
|
@ -70,7 +66,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is {IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -82,6 +78,8 @@ public partial class CS2_SimpleAdmin
|
|||
God(caller, player, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void God(CCSPlayerController? caller, CCSPlayerController player, CommandInfo? command = null)
|
||||
|
|
@ -100,8 +98,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_god {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message key and arguments for the god mode notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -124,7 +120,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -133,6 +129,8 @@ public partial class CS2_SimpleAdmin
|
|||
Freeze(caller, player, time, callerName, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name> [size]")]
|
||||
|
|
@ -144,7 +142,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -206,8 +204,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command and send Discord notification
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_freeze {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {time}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
|
|
@ -218,12 +214,14 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
Unfreeze(caller, player, callerName, command);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void Unfreeze(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -251,7 +249,5 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command and send Discord notification
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_unfreeze {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,12 +22,14 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is {IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
Slay(caller, player, callerName, command);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void Slay(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -55,8 +57,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command and send Discord notification
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_slay {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
|
|
@ -67,7 +67,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
var weaponName = command.GetArg(2);
|
||||
|
||||
// check if item is typed
|
||||
|
|
@ -94,6 +94,8 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
GiveWeapon(caller, player, weaponName, callerName, command);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
private static void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -122,8 +124,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_giveweapon {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {weaponName}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the weapon give notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -150,8 +150,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_giveweapon {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {weapon.ToString()}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the weapon give notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -173,7 +171,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -182,6 +180,8 @@ public partial class CS2_SimpleAdmin
|
|||
StripWeapons(caller, player, callerName, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void StripWeapons(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -192,7 +192,7 @@ public partial class CS2_SimpleAdmin
|
|||
callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console";
|
||||
|
||||
// Check if player is valid, alive, and connected
|
||||
if (!player.IsValid || !player.PawnIsAlive || player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
if (!player.IsValid || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE || player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
// Strip weapons from the player
|
||||
|
|
@ -201,8 +201,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_strip {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the weapon strip notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -225,7 +223,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -234,6 +232,8 @@ public partial class CS2_SimpleAdmin
|
|||
SetHp(caller, player, health, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void SetHp(CCSPlayerController? caller, CCSPlayerController player, int health, CommandInfo? command = null)
|
||||
|
|
@ -250,8 +250,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_hp {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {health}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the HP set notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -274,7 +272,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -286,6 +284,8 @@ public partial class CS2_SimpleAdmin
|
|||
SetSpeed(caller, player, speed, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void SetSpeed(CCSPlayerController? caller, CCSPlayerController player, float speed, CommandInfo? command = null)
|
||||
|
|
@ -306,8 +306,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_speed {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {speed}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the speed set notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -330,7 +328,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -342,6 +340,8 @@ public partial class CS2_SimpleAdmin
|
|||
SetGravity(caller, player, gravity, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void SetGravity(CCSPlayerController? caller, CCSPlayerController player, float gravity, CommandInfo? command = null)
|
||||
|
|
@ -362,8 +362,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_gravity {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {gravity}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the gravity set notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -387,7 +385,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
|
|
@ -399,6 +397,8 @@ public partial class CS2_SimpleAdmin
|
|||
SetMoney(caller, player, money, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void SetMoney(CCSPlayerController? caller, CCSPlayerController player, int money, CommandInfo? command = null)
|
||||
|
|
@ -414,8 +414,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_money {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {money}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message keys and arguments for the money set notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -438,7 +436,7 @@ public partial class CS2_SimpleAdmin
|
|||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
if (command.ArgCount >= 2)
|
||||
{
|
||||
|
|
@ -455,6 +453,8 @@ public partial class CS2_SimpleAdmin
|
|||
Slap(caller, player, damage, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void Slap(CCSPlayerController? caller, CCSPlayerController player, int damage, CommandInfo? command = null)
|
||||
|
|
@ -470,8 +470,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_slap {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {damage}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message key and arguments for the slap notification
|
||||
var (activityMessageKey, adminActivityArgs) =
|
||||
|
|
@ -532,6 +530,8 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
ChangeTeam(caller, player, _teamName, teamNum, kill, command);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void ChangeTeam(CCSPlayerController? caller, CCSPlayerController player, string teamName, CsTeam teamNum, bool kill, CommandInfo? command = null)
|
||||
|
|
@ -549,7 +549,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Change team based on the provided teamName and conditions
|
||||
if (!teamName.Equals("swap", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (player.PawnIsAlive && teamNum != CsTeam.Spectator && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1)
|
||||
if (player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && teamNum != CsTeam.Spectator && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1)
|
||||
player.SwitchTeam(teamNum);
|
||||
else
|
||||
player.ChangeTeam(teamNum);
|
||||
|
|
@ -560,7 +560,7 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
var _teamNum = (CsTeam)player.TeamNum == CsTeam.Terrorist ? CsTeam.CounterTerrorist : CsTeam.Terrorist;
|
||||
teamName = _teamNum == CsTeam.Terrorist ? "TT" : "CT";
|
||||
if (player.PawnIsAlive && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1)
|
||||
if (player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1)
|
||||
player.SwitchTeam(_teamNum);
|
||||
else
|
||||
player.ChangeTeam(_teamNum);
|
||||
|
|
@ -570,8 +570,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_team {player.PlayerName} {teamName}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message key and arguments for the team change notification
|
||||
var activityMessageKey = "sa_admin_team_message";
|
||||
|
|
@ -698,6 +696,8 @@ public partial class CS2_SimpleAdmin
|
|||
Respawn(caller, player, callerName, command);
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
internal static void Respawn(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
|
|
@ -722,8 +722,6 @@ public partial class CS2_SimpleAdmin
|
|||
// Log the command
|
||||
if (command == null)
|
||||
Helper.LogCommand(caller, $"css_respawn {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
else
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Determine message key and arguments for the respawn notification
|
||||
var activityMessageKey = "sa_admin_respawn_message";
|
||||
|
|
@ -740,7 +738,7 @@ public partial class CS2_SimpleAdmin
|
|||
public void OnGotoCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
// Check if the caller is valid and has a live pawn
|
||||
if (caller == null || !caller.PawnIsAlive) return;
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
// Get the target players
|
||||
var targets = GetTarget(command);
|
||||
|
|
@ -754,7 +752,7 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Process each player to teleport
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true }).Where(caller.CanTarget))
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).Where(caller.CanTarget))
|
||||
{
|
||||
if (caller.PlayerPawn.Value == null || player.PlayerPawn.Value == null)
|
||||
continue;
|
||||
|
|
@ -778,7 +776,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Set a timer to toggle collision back after 4 seconds
|
||||
AddTimer(4, () =>
|
||||
{
|
||||
if (!caller.IsValid || !caller.PawnIsAlive)
|
||||
if (!caller.IsValid || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
|
@ -811,7 +809,8 @@ public partial class CS2_SimpleAdmin
|
|||
public void OnBringCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
// Check if the caller is valid and has a live pawn
|
||||
if (caller == null || !caller.PawnIsAlive) return;
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
// Get the target players
|
||||
var targets = GetTarget(command);
|
||||
|
|
@ -825,7 +824,7 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Process each player to teleport
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true }).Where(caller.CanTarget))
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).Where(caller.CanTarget))
|
||||
{
|
||||
if (caller.PlayerPawn.Value == null || player.PlayerPawn.Value == null)
|
||||
continue;
|
||||
|
|
@ -849,7 +848,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Set a timer to toggle collision back after 4 seconds
|
||||
AddTimer(4, () =>
|
||||
{
|
||||
if (!player.IsValid || !player.PawnIsAlive)
|
||||
if (!player.IsValid || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,17 @@ public class Discord
|
|||
new DiscordPenaltySetting { Name = "Footer", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "Time", Value = "{relative}" },
|
||||
];
|
||||
|
||||
[JsonPropertyName("DiscordAssociatedAccountsSettings")]
|
||||
public DiscordPenaltySetting[] DiscordAssociatedAccountsSettings { get; set; } =
|
||||
[
|
||||
new DiscordPenaltySetting { Name = "Color", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "Webhook", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "ThumbnailUrl", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "ImageUrl", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "Footer", Value = "" },
|
||||
new DiscordPenaltySetting { Name = "Time", Value = "{relative}" },
|
||||
];
|
||||
}
|
||||
|
||||
public class ChatLog
|
||||
|
|
@ -248,6 +259,9 @@ public class OtherSettings
|
|||
|
||||
[JsonPropertyName("HideStealthPlayersFromSpecList")]
|
||||
public bool HideStealthPlayersFromSpecList { get; set; } = false;
|
||||
|
||||
[JsonPropertyName("IgnoredIps")]
|
||||
public List<string> IgnoredIps { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CS2_SimpleAdminConfig : BasePluginConfig
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `sa_bans` ADD COLUMN `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER `status`;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
UPDATE `sa_players_ips` SET `address` = INET_ATON(address);
|
||||
ALTER TABLE `sa_players_ips` CHANGE `address` `address` INT UNSIGNED NOT NULL;
|
||||
ALTER TABLE `sa_players_ips` ADD `name` VARCHAR(64) NULL DEFAULT NULL AFTER `steamid`;
|
||||
ALTER TABLE `sa_players_ips` ADD INDEX(`used_at`);
|
||||
|
|
@ -150,13 +150,21 @@ public partial class CS2_SimpleAdmin
|
|||
if (player.UserId.HasValue)
|
||||
PlayersInfo.TryRemove(player.UserId.Value, out _);
|
||||
|
||||
var authorizedSteamId = player.AuthorizedSteamID;
|
||||
if (authorizedSteamId == null || !PermissionManager.AdminCache.TryGetValue(authorizedSteamId,
|
||||
out var expirationTime)
|
||||
|| !(expirationTime <= Time.ActualDateTime())) return HookResult.Continue;
|
||||
if (!PermissionManager.AdminCache.TryGetValue(steamId, out var data)
|
||||
|| !(data.ExpirationTime <= Time.ActualDateTime()))
|
||||
{
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
AdminManager.ClearPlayerPermissions(authorizedSteamId);
|
||||
AdminManager.RemovePlayerAdminData(authorizedSteamId);
|
||||
AdminManager.RemovePlayerPermissions(steamId, PermissionManager.AdminCache[steamId].Flags.ToArray());
|
||||
AdminManager.RemovePlayerFromGroup(steamId, true, PermissionManager.AdminCache[steamId].Flags.ToArray());
|
||||
var adminData = AdminManager.GetPlayerAdminData(steamId);
|
||||
|
||||
if (adminData == null || data.Flags.ToList().Count != 0 && adminData.Groups.ToList().Count != 0)
|
||||
return HookResult.Continue;
|
||||
|
||||
AdminManager.ClearPlayerPermissions(steamId);
|
||||
AdminManager.RemovePlayerAdminData(steamId);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
|
@ -172,7 +180,10 @@ public partial class CS2_SimpleAdmin
|
|||
#if DEBUG
|
||||
Logger.LogCritical("[OnClientConnect]");
|
||||
#endif
|
||||
if (!CS2_SimpleAdmin.BannedPlayers.Contains(ipaddress.Split(":")[0]))
|
||||
if (Config.OtherSettings.BanType == 0)
|
||||
return;
|
||||
|
||||
if (Instance.CacheManager != null && !Instance.CacheManager.IsPlayerBanned(null, ipaddress.Split(":")[0]))
|
||||
return;
|
||||
|
||||
Server.NextFrame((() =>
|
||||
|
|
@ -263,12 +274,25 @@ public partial class CS2_SimpleAdmin
|
|||
!PlayerPenaltyManager.IsPenalized(author.Slot, PenaltyType.Silence, out endDateTime))
|
||||
return HookResult.Continue;
|
||||
|
||||
if (_localizer != null && endDateTime is not null)
|
||||
var message = um.ReadString("param2");
|
||||
|
||||
if (_localizer == null || endDateTime is null) return HookResult.Continue;
|
||||
|
||||
if (CoreConfig.PublicChatTrigger.Concat(CoreConfig.SilentChatTrigger).Any(trigger => message.StartsWith(trigger)))
|
||||
{
|
||||
foreach (var recipient in um.Recipients)
|
||||
{
|
||||
if (recipient == author)
|
||||
continue;
|
||||
|
||||
um.Recipients.Remove(recipient);
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
author.SendLocalizedMessage(_localizer, "sa_player_penalty_chat_active", endDateTime.Value.ToString("g", author.GetLanguage()));
|
||||
return HookResult.Stop;
|
||||
|
||||
// um.Recipients.Clear();
|
||||
|
||||
}
|
||||
|
||||
private HookResult ComamndListenerHandler(CCSPlayerController? player, CommandInfo info)
|
||||
|
|
@ -448,9 +472,9 @@ public partial class CS2_SimpleAdmin
|
|||
private void OnMapStart(string mapName)
|
||||
{
|
||||
if (Config.OtherSettings.ReloadAdminsEveryMapChange && ServerLoaded && ServerId != null)
|
||||
AddTimer(3.0f, () => ReloadAdmins(null));
|
||||
AddTimer(5.0f, () => ReloadAdmins(null));
|
||||
|
||||
AddTimer(1.0f, () => new ServerManager().CheckHibernationStatus());
|
||||
AddTimer(1.0f, () => ServerManager.CheckHibernationStatus());
|
||||
|
||||
// AddTimer(34, () =>
|
||||
// {
|
||||
|
|
@ -471,10 +495,9 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
var player = @event.Userid;
|
||||
|
||||
if (player is null || @event.Attacker is null || !player.PawnIsAlive || player.PlayerPawn.Value == null)
|
||||
if (player is null || @event.Attacker is null || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE || player.PlayerPawn.Value == null)
|
||||
return HookResult.Continue;
|
||||
|
||||
|
||||
if (SpeedPlayers.TryGetValue(player.Slot, out var speedPlayer))
|
||||
AddTimer(0.15f, () => player.SetSpeed(speedPlayer));
|
||||
|
||||
|
|
|
|||
12
CS2-SimpleAdmin/Extensions/EnumerableExtensions.cs
Normal file
12
CS2-SimpleAdmin/Extensions/EnumerableExtensions.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
public static IEnumerable<IEnumerable<T>> ChunkBy<T>(this IEnumerable<T> source, int chunkSize)
|
||||
{
|
||||
return source
|
||||
.Select((x, i) => new { Index = i, Value = x })
|
||||
.GroupBy(x => x.Index / chunkSize)
|
||||
.Select(x => x.Select(v => v.Value));
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ public static class PlayerExtensions
|
|||
public static void SetHp(this CCSPlayerController? controller, int health = 100)
|
||||
{
|
||||
if (controller == null) return;
|
||||
if ((health <= 0 || !controller.PawnIsAlive || controller.PlayerPawn.Value == null)) return;
|
||||
if (health <= 0 || controller.PlayerPawn.Value == null || controller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
controller.PlayerPawn.Value.Health = health;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ using CounterStrikeSharp.API.Core.Plugin.Host;
|
|||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CS2_SimpleAdmin.Managers;
|
||||
using MenuManager;
|
||||
using ZLinq;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
|
|
@ -78,34 +79,30 @@ internal static class Helper
|
|||
return Utilities.GetPlayers().FindAll(x => x.PlayerName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetPlayerFromSteamid64(string steamid)
|
||||
public static CCSPlayerController? GetPlayerFromSteamid64(string steamid)
|
||||
{
|
||||
return GetValidPlayers().FindAll(x =>
|
||||
x.SteamID.ToString().Equals(steamid, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
return GetValidPlayers().FirstOrDefault(x => x.SteamID.ToString().Equals(steamid, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetPlayerFromIp(string ipAddress)
|
||||
public static CCSPlayerController? GetPlayerFromIp(string ipAddress)
|
||||
{
|
||||
return GetValidPlayers().FindAll(x =>
|
||||
x.IpAddress != null &&
|
||||
x.IpAddress.Split(":")[0].Equals(ipAddress)
|
||||
);
|
||||
return GetValidPlayers().FirstOrDefault(x => x.IpAddress != null && x.IpAddress.Split(":")[0].Equals(ipAddress));
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetValidPlayers()
|
||||
{
|
||||
return Utilities.GetPlayers().FindAll(p => p is
|
||||
{ IsValid: true, IsBot: false, Connected: PlayerConnectedState.PlayerConnected });
|
||||
return Utilities.GetPlayers().AsValueEnumerable()
|
||||
.Where(p => p is { IsValid: true, IsBot: false, Connected: PlayerConnectedState.PlayerConnected })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<CCSPlayerController?> GetValidPlayersWithBots()
|
||||
public static List<CCSPlayerController> GetValidPlayersWithBots()
|
||||
{
|
||||
return Utilities.GetPlayers().FindAll(p =>
|
||||
p is { IsValid: true, IsBot: false, IsHLTV: false } or { IsValid: true, IsBot: true, IsHLTV: false }
|
||||
);
|
||||
return Utilities.GetPlayers().AsValueEnumerable()
|
||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList();
|
||||
}
|
||||
|
||||
|
||||
// public static bool IsValidSteamId64(string input)
|
||||
// {
|
||||
// const string pattern = @"^\d{17}$";
|
||||
|
|
@ -699,7 +696,6 @@ internal static class Helper
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log or handle the exception
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
|
|
@ -827,6 +823,7 @@ internal static class Helper
|
|||
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PluginInfo
|
||||
|
|
@ -1000,3 +997,35 @@ public static class WeaponHelper
|
|||
return filteredWeapons; // Return all relevant matches for the partial input
|
||||
}
|
||||
}
|
||||
|
||||
public static class IpHelper
|
||||
{
|
||||
public static uint IpToUint(string ipAddress)
|
||||
{
|
||||
return (uint)BitConverter.ToInt32(System.Net.IPAddress.Parse(ipAddress).GetAddressBytes().Reverse().ToArray(),
|
||||
0);
|
||||
}
|
||||
|
||||
public static bool TryConvertIpToUint(string ipString, out uint ipUint)
|
||||
{
|
||||
ipUint = 0;
|
||||
if (string.IsNullOrWhiteSpace(ipString))
|
||||
return false;
|
||||
|
||||
if (!System.Net.IPAddress.TryParse(ipString, out var ipAddress))
|
||||
return false;
|
||||
|
||||
var bytes = ipAddress.GetAddressBytes();
|
||||
if (bytes.Length != 4)
|
||||
return false;
|
||||
|
||||
ipUint = IpToUint(ipString);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string UintToIp(uint ipAddress)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(ipAddress).Reverse().ToArray();
|
||||
return new System.Net.IPAddress(bytes).ToString();
|
||||
}
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ internal class BanManager(Database.Database? database)
|
|||
{
|
||||
string sql;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp)
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp && !CS2_SimpleAdmin.Instance.Config.OtherSettings.IgnoredIps.Contains(player.IpAddress))
|
||||
{
|
||||
sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode ? """
|
||||
SELECT COALESCE((
|
||||
|
|
@ -232,7 +232,8 @@ internal class BanManager(Database.Database? database)
|
|||
{
|
||||
PlayerSteamID = player.SteamId.SteamId64.ToString(),
|
||||
PlayerIP = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 ||
|
||||
string.IsNullOrEmpty(player.IpAddress)
|
||||
string.IsNullOrEmpty(player.IpAddress) ||
|
||||
CS2_SimpleAdmin.Instance.Config.OtherSettings.IgnoredIps.Contains(player.IpAddress)
|
||||
? null
|
||||
: player.IpAddress,
|
||||
PlayerName = !string.IsNullOrEmpty(player.Name) ? player.Name : string.Empty,
|
||||
|
|
@ -393,7 +394,7 @@ internal class BanManager(Database.Database? database)
|
|||
{
|
||||
SteamIDs = steamIds,
|
||||
IpAddresses = checkIpBans ? ipAddresses : [],
|
||||
ServerId = CS2_SimpleAdmin.ServerId
|
||||
CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
|
||||
var valueTuples = bannedPlayers.ToList();
|
||||
|
|
|
|||
397
CS2-SimpleAdmin/Managers/CacheManager.cs
Normal file
397
CS2-SimpleAdmin/Managers/CacheManager.cs
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
using System.Collections.Concurrent;
|
||||
using CS2_SimpleAdmin.Models;
|
||||
using Dapper;
|
||||
using ZLinq;
|
||||
|
||||
namespace CS2_SimpleAdmin.Managers;
|
||||
|
||||
internal class CacheManager: IDisposable
|
||||
{
|
||||
private readonly ConcurrentDictionary<int, BanRecord> _banCache = [];
|
||||
private readonly ConcurrentDictionary<string, List<BanRecord>> _steamIdIndex = [];
|
||||
private readonly ConcurrentDictionary<uint, List<BanRecord>> _ipIndex = [];
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, HashSet<IpRecord>> _playerIpsCache = [];
|
||||
private HashSet<uint> _cachedIgnoredIps = [];
|
||||
|
||||
private DateTime _lastUpdateTime = DateTime.MinValue;
|
||||
private bool _isInitialized;
|
||||
private bool _disposed;
|
||||
|
||||
public async Task InitializeCacheAsync()
|
||||
{
|
||||
if (CS2_SimpleAdmin.Database == null) return;
|
||||
if (!CS2_SimpleAdmin.ServerLoaded) return;
|
||||
if (_isInitialized) return;
|
||||
|
||||
try
|
||||
{
|
||||
Clear();
|
||||
_cachedIgnoredIps = new HashSet<uint>(
|
||||
CS2_SimpleAdmin.Instance.Config.OtherSettings.IgnoredIps
|
||||
.Select(IpHelper.IpToUint));
|
||||
|
||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||
List<BanRecord> bans;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
bans = (await connection.QueryAsync<BanRecord>(
|
||||
"""
|
||||
SELECT
|
||||
id AS Id,
|
||||
player_steamid AS PlayerSteamId,
|
||||
player_ip AS PlayerIp,
|
||||
status AS Status
|
||||
FROM sa_bans
|
||||
""")).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
bans = (await connection.QueryAsync<BanRecord>(
|
||||
"""
|
||||
SELECT
|
||||
id AS Id,
|
||||
player_steamid AS PlayerSteamId,
|
||||
player_ip AS PlayerIp,
|
||||
status AS Status
|
||||
FROM sa_bans
|
||||
WHERE server_id = @serverId
|
||||
""", new {serverId = CS2_SimpleAdmin.ServerId})).ToList();
|
||||
}
|
||||
|
||||
var ipHistory =
|
||||
await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
||||
"SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC");
|
||||
|
||||
foreach (var ban in bans)
|
||||
{
|
||||
_banCache.TryAdd(ban.Id, ban);
|
||||
}
|
||||
|
||||
foreach (var group in ipHistory.AsValueEnumerable().GroupBy(x => x.steamid))
|
||||
{
|
||||
var ipSet = new HashSet<IpRecord>(
|
||||
group
|
||||
.GroupBy(x => x.address)
|
||||
.Select(g =>
|
||||
{
|
||||
var latest = g.MaxBy(x => x.used_at);
|
||||
return new IpRecord(
|
||||
g.Key,
|
||||
latest.used_at,
|
||||
!string.IsNullOrEmpty(latest.name)
|
||||
? latest.name
|
||||
: CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"
|
||||
);
|
||||
}),
|
||||
new IpRecordComparer()
|
||||
);
|
||||
|
||||
_playerIpsCache.AddOrUpdate(
|
||||
group.Key,
|
||||
_ => ipSet,
|
||||
(_, existingSet) =>
|
||||
{
|
||||
foreach (var ip in ipSet)
|
||||
{
|
||||
existingSet.Remove(ip);
|
||||
existingSet.Add(ip);
|
||||
}
|
||||
|
||||
return existingSet;
|
||||
});
|
||||
}
|
||||
|
||||
RebuildIndexes();
|
||||
|
||||
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
||||
_isInitialized = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ForceReInitializeCacheAsync()
|
||||
{
|
||||
_isInitialized = false;
|
||||
|
||||
_banCache.Clear();
|
||||
_playerIpsCache.Clear();
|
||||
_cachedIgnoredIps.Clear();
|
||||
_lastUpdateTime = DateTime.MinValue;
|
||||
|
||||
await InitializeCacheAsync();
|
||||
}
|
||||
|
||||
public async Task RefreshCacheAsync()
|
||||
{
|
||||
if (CS2_SimpleAdmin.Database == null) return;
|
||||
if (!_isInitialized) return;
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||
List<BanRecord> updatedBans;
|
||||
|
||||
var allIds = (await connection.QueryAsync<int>("SELECT id FROM sa_bans")).ToHashSet();
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
updatedBans = (await connection.QueryAsync<BanRecord>(
|
||||
"""
|
||||
SELECT id AS Id,
|
||||
player_steamid AS PlayerSteamId,
|
||||
player_ip AS PlayerIp,
|
||||
status AS Status
|
||||
FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC
|
||||
""",
|
||||
new { lastUpdate = _lastUpdateTime }
|
||||
)).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
updatedBans = (await connection.QueryAsync<BanRecord>(
|
||||
"""
|
||||
SELECT id AS Id,
|
||||
player_steamid AS PlayerSteamId,
|
||||
player_ip AS PlayerIp,
|
||||
status AS Status
|
||||
FROM `sa_bans` WHERE (updated_at > @lastUpdate OR created > @lastUpdate) AND server_id = @serverId ORDER BY updated_at DESC
|
||||
""",
|
||||
new { lastUpdate = _lastUpdateTime, serverId = CS2_SimpleAdmin.ServerId }
|
||||
)).ToList();
|
||||
}
|
||||
|
||||
foreach (var id in _banCache.Keys)
|
||||
{
|
||||
if (allIds.Contains(id) || !_banCache.TryRemove(id, out var ban)) continue;
|
||||
|
||||
// Remove from steamIdIndex
|
||||
if (!string.IsNullOrWhiteSpace(ban.PlayerSteamId) &&
|
||||
_steamIdIndex.TryGetValue(ban.PlayerSteamId, out var steamBans))
|
||||
{
|
||||
steamBans.RemoveAll(b => b.Id == id);
|
||||
if (steamBans.Count == 0)
|
||||
_steamIdIndex.TryRemove(ban.PlayerSteamId, out _);
|
||||
}
|
||||
|
||||
// Remove from ipIndex
|
||||
if (!string.IsNullOrWhiteSpace(ban.PlayerIp) &&
|
||||
IpHelper.TryConvertIpToUint(ban.PlayerIp, out var ipUInt) &&
|
||||
_ipIndex.TryGetValue(ipUInt, out var ipBans))
|
||||
{
|
||||
ipBans.RemoveAll(b => b.Id == id);
|
||||
if (ipBans.Count == 0)
|
||||
_ipIndex.TryRemove(ipUInt, out _);
|
||||
}
|
||||
}
|
||||
|
||||
var ipHistory = (await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
||||
"SELECT steamid, name, address, used_at FROM sa_players_ips WHERE used_at >= @lastUpdate ORDER BY used_at DESC LIMIT 300", new {lastUpdate = _lastUpdateTime})).ToList();
|
||||
|
||||
foreach (var group in ipHistory.AsValueEnumerable().GroupBy(x => x.steamid))
|
||||
{
|
||||
var ipSet = new HashSet<IpRecord>(
|
||||
group
|
||||
.GroupBy(x => x.address)
|
||||
.Select(g =>
|
||||
{
|
||||
var latest = g.MaxBy(x => x.used_at);
|
||||
return new IpRecord(
|
||||
g.Key,
|
||||
latest.used_at,
|
||||
!string.IsNullOrEmpty(latest.name)
|
||||
? latest.name
|
||||
: CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"
|
||||
);
|
||||
}),
|
||||
new IpRecordComparer()
|
||||
);
|
||||
|
||||
_playerIpsCache.AddOrUpdate(
|
||||
group.Key,
|
||||
_ => ipSet,
|
||||
(_, existingSet) =>
|
||||
{
|
||||
foreach (var newEntry in ipSet)
|
||||
{
|
||||
existingSet.Remove(newEntry);
|
||||
existingSet.Add(newEntry);
|
||||
}
|
||||
return existingSet;
|
||||
});
|
||||
}
|
||||
|
||||
if (updatedBans.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var ban in updatedBans)
|
||||
{
|
||||
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
||||
}
|
||||
|
||||
RebuildIndexes();
|
||||
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildIndexes()
|
||||
{
|
||||
_steamIdIndex.Clear();
|
||||
_ipIndex.Clear();
|
||||
|
||||
foreach (var ban in _banCache.Values)
|
||||
{
|
||||
if (ban.Status != "ACTIVE")
|
||||
continue;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ban.PlayerSteamId))
|
||||
{
|
||||
var steamId = ban.PlayerSteamId;
|
||||
_steamIdIndex.AddOrUpdate(
|
||||
steamId,
|
||||
key => [ban],
|
||||
(key, list) =>
|
||||
{
|
||||
list.Add(ban);
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
if (ban.PlayerIp != null &&
|
||||
IpHelper.TryConvertIpToUint(ban.PlayerIp, out var ipUInt))
|
||||
{
|
||||
_ipIndex.AddOrUpdate(
|
||||
ipUInt,
|
||||
key => [ban],
|
||||
(key, list) =>
|
||||
{
|
||||
list.Add(ban);
|
||||
return list;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BanRecord> GetAllBans() => _banCache.Values.ToList();
|
||||
public List<BanRecord> GetActiveBans() => _banCache.Values.Where(b => b.Status == "ACTIVE").ToList();
|
||||
public List<BanRecord> GetPlayerBansBySteamId(string steamId) => _steamIdIndex.TryGetValue(steamId, out var bans) ? bans : [];
|
||||
public List<(ulong SteamId, DateTime UsedAt, string PlayerName)> GetAccountsByIp(string ipAddress)
|
||||
{
|
||||
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
||||
|
||||
return _playerIpsCache.AsValueEnumerable()
|
||||
.SelectMany(kvp => kvp.Value
|
||||
.Where(entry => entry.Ip == ipAsUint)
|
||||
.Select(entry => (kvp.Key, entry.UsedAt, entry.PlayerName)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool IsIpBanned(string ipAddress)
|
||||
{
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||
var ipUInt = IpHelper.IpToUint(ipAddress);
|
||||
return !_cachedIgnoredIps.Contains(ipUInt) && _ipIndex.ContainsKey(ipUInt);
|
||||
}
|
||||
|
||||
|
||||
public bool IsPlayerBanned(string? steamId, string? ipAddress)
|
||||
{
|
||||
if (steamId != null && _steamIdIndex.ContainsKey(steamId))
|
||||
return true;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||
|
||||
if (ipAddress == null)
|
||||
return false;
|
||||
|
||||
if (!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt))
|
||||
return false;
|
||||
|
||||
return !_cachedIgnoredIps.Contains(ipUInt) &&
|
||||
_ipIndex.ContainsKey(ipUInt);
|
||||
}
|
||||
|
||||
public bool IsPlayerOrAnyIpBanned(ulong steamId, string? ipAddress)
|
||||
{
|
||||
var steamIdStr = steamId.ToString();
|
||||
|
||||
if (_steamIdIndex.ContainsKey(steamIdStr))
|
||||
return true;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||
|
||||
if (!_playerIpsCache.TryGetValue(steamId, out var ipData))
|
||||
return false;
|
||||
|
||||
var now = DateTime.Now;
|
||||
var cutoff = now.AddDays(-7);
|
||||
|
||||
if (ipAddress != null)
|
||||
{
|
||||
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
||||
|
||||
if (!_cachedIgnoredIps.Contains(ipAsUint))
|
||||
{
|
||||
ipData.Add(new IpRecord(
|
||||
ipAsUint,
|
||||
now.AddSeconds(-2), // artificially recent
|
||||
CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var ipRecord in ipData)
|
||||
{
|
||||
if (ipRecord.UsedAt < cutoff || _cachedIgnoredIps.Contains(ipRecord.Ip))
|
||||
continue;
|
||||
|
||||
if (_ipIndex.ContainsKey(ipRecord.Ip))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasIpForPlayer(ulong steamId, string ipAddress)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ipAddress))
|
||||
return false;
|
||||
|
||||
return _playerIpsCache.TryGetValue(steamId, out var ipData)
|
||||
&& ipData.Any(x => x.Ip == IpHelper.IpToUint(ipAddress));
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
_steamIdIndex.Clear();
|
||||
_ipIndex.Clear();
|
||||
|
||||
_banCache.Clear();
|
||||
_playerIpsCache.Clear();
|
||||
_cachedIgnoredIps.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
Clear();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class IpRecordComparer : IEqualityComparer<IpRecord>
|
||||
{
|
||||
public bool Equals(IpRecord x, IpRecord y)
|
||||
=> x.Ip == y.Ip;
|
||||
|
||||
public int GetHashCode(IpRecord obj)
|
||||
=> obj.Ip.GetHashCode();
|
||||
}
|
||||
|
|
@ -187,13 +187,13 @@ internal class MuteManager(Database.Database? database)
|
|||
}
|
||||
}
|
||||
|
||||
public async Task CheckOnlineModeMutes(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
|
||||
public async Task CheckOnlineModeMutes(List<(ulong SteamID, int? UserId, int Slot)> players)
|
||||
{
|
||||
if (database == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
var batchSize = 10;
|
||||
const int batchSize = 20;
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
|
|
@ -205,7 +205,7 @@ internal class MuteManager(Database.Database? database)
|
|||
var batch = players.Skip(i).Take(batchSize);
|
||||
var parametersList = new List<object>();
|
||||
|
||||
foreach (var (_, steamId, _, _) in batch)
|
||||
foreach (var (steamId, _, _) in batch)
|
||||
{
|
||||
parametersList.Add(new { PlayerSteamID = steamId, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ internal class MuteManager(Database.Database? database)
|
|||
: "SELECT * FROM `sa_mutes` WHERE player_steamid = @PlayerSteamID AND passed >= duration AND duration > 0 AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
|
||||
|
||||
foreach (var (_, steamId, _, slot) in players)
|
||||
foreach (var (steamId, _, slot) in players)
|
||||
{
|
||||
var muteRecords = await connection.QueryAsync(sql, new { PlayerSteamID = steamId, serverid = CS2_SimpleAdmin.ServerId });
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
|
|||
using MySqlConnector;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Concurrent;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
|
||||
namespace CS2_SimpleAdmin.Managers;
|
||||
|
||||
|
|
@ -13,7 +14,8 @@ public class PermissionManager(Database.Database? database)
|
|||
{
|
||||
// Unused for now
|
||||
//public static readonly ConcurrentDictionary<string, ConcurrentBag<string>> _adminCache = new ConcurrentDictionary<string, ConcurrentBag<string>>();
|
||||
public static readonly ConcurrentDictionary<SteamID, DateTime?> AdminCache = new();
|
||||
// public static readonly ConcurrentDictionary<SteamID, DateTime?> AdminCache = new();
|
||||
public static readonly ConcurrentDictionary<SteamID, (DateTime? ExpirationTime, List<string> Flags)> AdminCache = new();
|
||||
|
||||
// Get the relevant server groups from the sa_servers_groups table by searching if the serverId is in the servers set column
|
||||
public async Task<List<string>> GetServerGroups()
|
||||
|
|
@ -236,7 +238,7 @@ public class PermissionManager(Database.Database? database)
|
|||
{
|
||||
if (!AdminCache.ContainsKey(steamId))
|
||||
{
|
||||
AdminCache.TryAdd(steamId, ends);
|
||||
AdminCache.TryAdd(steamId, (ends, flags));
|
||||
//_adminCacheTimestamps.Add(steamId, ends);
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +402,7 @@ public class PermissionManager(Database.Database? database)
|
|||
.GroupBy(player => player.name) // Group by player name
|
||||
.ToDictionary(
|
||||
group => group.Key, // Use the player name as the key
|
||||
group =>
|
||||
object (group) =>
|
||||
{
|
||||
// Consolidate data for players with the same name
|
||||
var consolidatedData = group.Aggregate(
|
||||
|
|
@ -432,16 +434,76 @@ public class PermissionManager(Database.Database? database)
|
|||
return acc;
|
||||
});
|
||||
|
||||
foreach (var player in group)
|
||||
Server.NextFrameAsync(() =>
|
||||
{
|
||||
SteamID.TryParse(player.identity, out var steamId);
|
||||
if (steamId != null && !AdminCache.ContainsKey(steamId))
|
||||
var keysToRemove = new List<SteamID>();
|
||||
|
||||
foreach (var steamId in AdminCache.Keys.ToList())
|
||||
{
|
||||
AdminCache.TryAdd(steamId, player.ends);
|
||||
}
|
||||
var data = AdminManager.GetPlayerAdminData(steamId);
|
||||
if (data != null)
|
||||
{
|
||||
var flagsArray = AdminCache[steamId].Flags.ToArray();
|
||||
AdminManager.RemovePlayerPermissions(steamId, flagsArray);
|
||||
AdminManager.RemovePlayerFromGroup(steamId, true, flagsArray);
|
||||
}
|
||||
|
||||
return (object)consolidatedData;
|
||||
keysToRemove.Add(steamId);
|
||||
}
|
||||
|
||||
foreach (var steamId in keysToRemove)
|
||||
{
|
||||
if (!AdminCache.TryRemove(steamId, out _)) continue;
|
||||
|
||||
var data = AdminManager.GetPlayerAdminData(steamId);
|
||||
if (data == null) continue;
|
||||
if (data.Flags.Count != 0 && data.Groups.Count != 0) continue;
|
||||
|
||||
AdminManager.ClearPlayerPermissions(steamId);
|
||||
AdminManager.RemovePlayerAdminData(steamId);
|
||||
}
|
||||
|
||||
foreach (var player in group)
|
||||
{
|
||||
if (SteamID.TryParse(player.identity, out var steamId) && steamId != null)
|
||||
{
|
||||
AdminCache.TryAdd(steamId, (player.ends, player.flags));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Server.NextFrameAsync(() =>
|
||||
// {
|
||||
// for (var index = 0; index < AdminCache.Keys.ToList().Count; index++)
|
||||
// {
|
||||
// var steamId = AdminCache.Keys.ToList()[index];
|
||||
//
|
||||
// var data = AdminManager.GetPlayerAdminData(steamId);
|
||||
// if (data != null)
|
||||
// {
|
||||
// AdminManager.RemovePlayerPermissions(steamId, AdminCache[steamId].Flags.ToArray());
|
||||
// AdminManager.RemovePlayerFromGroup(steamId, true, AdminCache[steamId].Flags.ToArray());
|
||||
// }
|
||||
//
|
||||
// if (!AdminCache.TryRemove(steamId, out _)) continue;
|
||||
//
|
||||
// if (data == null) continue;
|
||||
// if (data.Flags.ToList().Count != 0 && data.Groups.ToList().Count != 0)
|
||||
// continue;
|
||||
//
|
||||
// AdminManager.ClearPlayerPermissions(steamId);
|
||||
// AdminManager.RemovePlayerAdminData(steamId);
|
||||
// }
|
||||
//
|
||||
// foreach (var player in group)
|
||||
// {
|
||||
// SteamID.TryParse(player.identity, out var steamId);
|
||||
// if (steamId == null) continue;
|
||||
// AdminCache.TryAdd(steamId, (player.ends, player.flags));
|
||||
// }
|
||||
// });
|
||||
|
||||
return consolidatedData;
|
||||
});
|
||||
|
||||
var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using CounterStrikeSharp.API.ValveConstants.Protobuf;
|
|||
using CS2_SimpleAdminApi;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ZLinq;
|
||||
|
||||
namespace CS2_SimpleAdmin.Managers;
|
||||
|
||||
|
|
@ -26,10 +27,10 @@ public class PlayerManager
|
|||
}
|
||||
|
||||
var ipAddress = player.IpAddress?.Split(":")[0];
|
||||
|
||||
CS2_SimpleAdmin.PlayersInfo[player.UserId.Value] =
|
||||
new PlayerInfo(player.UserId.Value, player.Slot, new SteamID(player.SteamID), player.PlayerName, ipAddress);
|
||||
|
||||
|
||||
// if (!player.UserId.HasValue)
|
||||
// {
|
||||
// Helper.KickPlayer(player, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION);
|
||||
|
|
@ -37,31 +38,69 @@ public class PlayerManager
|
|||
// }
|
||||
|
||||
var userId = player.UserId.Value;
|
||||
|
||||
// Check if the player's IP or SteamID is in the bannedPlayers list
|
||||
if (_config.OtherSettings.BanType > 0 && CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress) ||
|
||||
CS2_SimpleAdmin.BannedPlayers.Contains(player.SteamID.ToString()))
|
||||
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(userId))
|
||||
{
|
||||
// Kick the player if banned
|
||||
Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
||||
return;
|
||||
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION);
|
||||
}
|
||||
|
||||
var steamId64 = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64;
|
||||
var steamId = steamId64.ToString();
|
||||
|
||||
if (CS2_SimpleAdmin.Database == null) return;
|
||||
|
||||
// Perform asynchronous database operations within a single method
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (_config.OtherSettings.CheckMultiAccountsByIp)
|
||||
var isBanned = CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
||||
{
|
||||
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, null),
|
||||
_ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp
|
||||
? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(steamId64, ipAddress)
|
||||
: CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, ipAddress)
|
||||
};
|
||||
|
||||
if (isBanned)
|
||||
{
|
||||
// Kick the player if banned
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
if (!player.UserId.HasValue) return;
|
||||
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.CacheManager.HasIpForPlayer(
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, ipAddress))
|
||||
{
|
||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||
const string selectQuery = "SELECT COUNT(*) FROM `sa_players_ips` WHERE steamid = @SteamID AND address = @IPAddress;";
|
||||
|
||||
const string updateQuery = """
|
||||
UPDATE `sa_players_ips`
|
||||
SET used_at = CURRENT_TIMESTAMP
|
||||
WHERE steamid = @SteamID AND address = @IPAddress;
|
||||
""";
|
||||
await connection.ExecuteAsync(updateQuery, new
|
||||
{
|
||||
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
|
||||
IPAddress = IpHelper.IpToUint(ipAddress)
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||
|
||||
const string selectQuery =
|
||||
"SELECT COUNT(*) FROM `sa_players_ips` WHERE steamid = @SteamID AND address = @IPAddress;";
|
||||
var recordExists = await connection.ExecuteScalarAsync<int>(selectQuery, new
|
||||
{
|
||||
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
|
||||
IPAddress = ipAddress
|
||||
IPAddress = IpHelper.IpToUint(ipAddress)
|
||||
});
|
||||
|
||||
if (recordExists > 0)
|
||||
|
|
@ -74,7 +113,7 @@ public class PlayerManager
|
|||
await connection.ExecuteAsync(updateQuery, new
|
||||
{
|
||||
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
|
||||
IPAddress = ipAddress
|
||||
IPAddress = IpHelper.IpToUint(ipAddress)
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
@ -86,55 +125,31 @@ public class PlayerManager
|
|||
await connection.ExecuteAsync(insertQuery, new
|
||||
{
|
||||
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
|
||||
IPAddress = ipAddress
|
||||
IPAddress = IpHelper.IpToUint(ipAddress)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(
|
||||
$"Unable to save ip address for {CS2_SimpleAdmin.PlayersInfo[userId].Name} ({ipAddress}) {ex.Message}");
|
||||
}
|
||||
|
||||
// Get all accounts associated to the player (ip address)
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].AccountsAssociated =
|
||||
CS2_SimpleAdmin.Instance.CacheManager?.GetAccountsByIp(ipAddress).AsValueEnumerable().Select(x => (x.SteamId, x.PlayerName)).ToList() ?? [];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(userId))
|
||||
{
|
||||
await Server.NextFrameAsync(() => Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION));
|
||||
}
|
||||
|
||||
// Check if the player is banned
|
||||
var isBanned = await CS2_SimpleAdmin.Instance.BanManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId]);
|
||||
|
||||
if (isBanned)
|
||||
{
|
||||
// Add player's IP and SteamID to bannedPlayers list if not already present
|
||||
if (_config.OtherSettings.BanType > 0 && ipAddress != null &&
|
||||
!CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress))
|
||||
{
|
||||
CS2_SimpleAdmin.BannedPlayers.Add(ipAddress);
|
||||
}
|
||||
|
||||
if (!CS2_SimpleAdmin.BannedPlayers.Contains(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()))
|
||||
{
|
||||
CS2_SimpleAdmin.BannedPlayers.Add(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString());
|
||||
}
|
||||
|
||||
// Kick the player if banned
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
var victim = Utilities.GetPlayerFromUserid(userId);
|
||||
if (victim == null || !victim.UserId.HasValue) return;
|
||||
|
||||
if (CS2_SimpleAdmin.UnlockedCommands && _config.BanIDBan)
|
||||
Server.ExecuteCommand($"banid 1 {userId}");
|
||||
|
||||
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
// var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0
|
||||
// ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(
|
||||
// CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString(), null)
|
||||
// : CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp
|
||||
// ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(CS2_SimpleAdmin
|
||||
// .PlayersInfo[userId].SteamId.SteamId64)
|
||||
// : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString(), ipAddress);
|
||||
|
||||
if (fullConnect || !fullConnect) // Temp skip
|
||||
{
|
||||
|
|
@ -142,8 +157,7 @@ public class PlayerManager
|
|||
var (totalMutes, totalGags, totalSilences) =
|
||||
await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]);
|
||||
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans =
|
||||
await CS2_SimpleAdmin.Instance.BanManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]);
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = CS2_SimpleAdmin.Instance.CacheManager?.GetPlayerBansBySteamId(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()).Count ?? 0;
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes;
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags;
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences;
|
||||
|
|
@ -192,6 +206,8 @@ public class PlayerManager
|
|||
|
||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect && fullConnect)
|
||||
{
|
||||
var associatedAcccountsChunks = CS2_SimpleAdmin.PlayersInfo[userId].AccountsAssociated.ChunkBy(5).ToList();
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
foreach (var admin in Helper.GetValidPlayers()
|
||||
|
|
@ -199,9 +215,8 @@ public class PlayerManager
|
|||
AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/ban")) &&
|
||||
p.Connected == PlayerConnectedState.PlayerConnected && !CS2_SimpleAdmin.AdminDisabledJoinComms.Contains(p.SteamID)))
|
||||
{
|
||||
if (CS2_SimpleAdmin._localizer != null && admin != player
|
||||
&& (CS2_SimpleAdmin.PlayersInfo[userId].TotalBans > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalGags > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns > 0)
|
||||
)
|
||||
if (CS2_SimpleAdmin._localizer != null && admin != player)
|
||||
{
|
||||
admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_penalty_info",
|
||||
player.PlayerName,
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans,
|
||||
|
|
@ -210,6 +225,16 @@ public class PlayerManager
|
|||
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences,
|
||||
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns
|
||||
);
|
||||
|
||||
foreach (var chunk in associatedAcccountsChunks)
|
||||
{
|
||||
admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_associated_accounts",
|
||||
player.PlayerName,
|
||||
string.Join(", ",
|
||||
chunk.Select(a => $"{a.PlayerName} ({a.SteamId})"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -232,12 +257,9 @@ public class PlayerManager
|
|||
{
|
||||
if (CS2_SimpleAdmin.GravityPlayers.Count <= 0) return;
|
||||
|
||||
foreach (var value in CS2_SimpleAdmin.GravityPlayers)
|
||||
foreach (var value in CS2_SimpleAdmin.GravityPlayers.Where(value => value.Key is
|
||||
{ IsValid: true, Connected: PlayerConnectedState.PlayerConnected } || value.Key.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE))
|
||||
{
|
||||
if (value.Key is not
|
||||
{ IsValid: true, Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true })
|
||||
continue;
|
||||
|
||||
value.Key.SetGravity(value.Value);
|
||||
}
|
||||
}, TimerFlags.REPEAT);
|
||||
|
|
@ -250,79 +272,70 @@ public class PlayerManager
|
|||
if (CS2_SimpleAdmin.Database == null)
|
||||
return;
|
||||
|
||||
var players = Helper.GetValidPlayers();
|
||||
var onlinePlayers = new List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)>();
|
||||
// var onlinePlayers = players
|
||||
// .Where(player => player.IpAddress != null)
|
||||
// .Select(player => (player.IpAddress, player.SteamID, player.UserId, player.Slot))
|
||||
// .ToList();
|
||||
|
||||
foreach (var player in players)
|
||||
var tempPlayers = Helper.GetValidPlayers()
|
||||
.Select(p => new
|
||||
{
|
||||
if (player.IpAddress != null)
|
||||
onlinePlayers.Add((player.IpAddress, player.SteamID, player.UserId, player.Slot));
|
||||
}
|
||||
p.SteamID, p.IpAddress, p.UserId, p.Slot,
|
||||
})
|
||||
.ToList();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var expireTasks = new[]
|
||||
var expireTasks = new Task[]
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.BanManager.ExpireOldBans(),
|
||||
CS2_SimpleAdmin.Instance.MuteManager.ExpireOldMutes(),
|
||||
CS2_SimpleAdmin.Instance.WarnManager.ExpireOldWarns(),
|
||||
CS2_SimpleAdmin.Instance.CacheManager?.RefreshCacheAsync() ?? Task.CompletedTask,
|
||||
CS2_SimpleAdmin.Instance.PermissionManager.DeleteOldAdmins()
|
||||
};
|
||||
|
||||
Task.WhenAll(expireTasks).ContinueWith(t =>
|
||||
{
|
||||
if (t is not { IsFaulted: true, Exception: not null }) return;
|
||||
|
||||
foreach (var ex in t.Exception.InnerExceptions)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Error expiring penalties: {ex.Message}");
|
||||
}
|
||||
});
|
||||
await Task.WhenAll(expireTasks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError("Unexpected error: {exception}", ex.Message);
|
||||
CS2_SimpleAdmin._logger?.LogError($"Error processing players timer tasks: {ex.Message}");
|
||||
|
||||
if (ex is AggregateException aggregate)
|
||||
{
|
||||
foreach (var inner in aggregate.InnerExceptions)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Inner exception: {inner.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CS2_SimpleAdmin.BannedPlayers.Clear();
|
||||
var bannedPlayers = tempPlayers.AsValueEnumerable()
|
||||
.Where(player =>
|
||||
{
|
||||
return CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
||||
{
|
||||
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null),
|
||||
_ =>
|
||||
CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress?.Split(":")[0])
|
||||
};
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (onlinePlayers.Count > 0)
|
||||
foreach (var player in bannedPlayers)
|
||||
{
|
||||
try
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await CS2_SimpleAdmin.Instance.BanManager.CheckOnlinePlayers(onlinePlayers);
|
||||
if (player.UserId.HasValue)
|
||||
await Server.NextFrameAsync(() => Helper.KickPlayer((int)player.UserId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED));
|
||||
}
|
||||
|
||||
var onlinePlayers = tempPlayers.AsValueEnumerable().Select(player => (player.SteamID, player.UserId, player.Slot)).ToList();
|
||||
if (tempPlayers.Count == 0 || onlinePlayers.Count == 0) return;
|
||||
if (_config.OtherSettings.TimeMode == 0)
|
||||
{
|
||||
await CS2_SimpleAdmin.Instance.MuteManager.CheckOnlineModeMutes(onlinePlayers);
|
||||
}
|
||||
}).ContinueWith(t =>
|
||||
{
|
||||
if (t is not { IsFaulted: true, Exception: not null }) return;
|
||||
|
||||
foreach (var ex in t.Exception.InnerExceptions)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Error checking online players: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Unexpected error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (onlinePlayers.Count <= 0) return;
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
var players = Helper.GetValidPlayers();
|
||||
var penalizedSlots = players
|
||||
.Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot))
|
||||
.Select(player => new
|
||||
|
|
@ -350,8 +363,7 @@ public class PlayerManager
|
|||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Unable to remove old penalties: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT);
|
||||
}, TimerFlags.REPEAT);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,9 @@ public class ServerManager
|
|||
{
|
||||
private int _getIpTryCount;
|
||||
|
||||
public void CheckHibernationStatus()
|
||||
public static void CheckHibernationStatus()
|
||||
{
|
||||
ConVar? convar = ConVar.Find("sv_hibernate_when_empty");
|
||||
var convar = ConVar.Find("sv_hibernate_when_empty");
|
||||
|
||||
if (convar == null || !convar.GetPrimitiveValue<bool>())
|
||||
return;
|
||||
|
|
@ -96,12 +96,16 @@ public class ServerManager
|
|||
|
||||
CS2_SimpleAdmin.ServerId = serverId;
|
||||
|
||||
CS2_SimpleAdmin._logger?.LogInformation("Loaded server with ip {ip}", ipAddress);
|
||||
|
||||
if (CS2_SimpleAdmin.ServerId != null)
|
||||
{
|
||||
await Server.NextWorldUpdateAsync(() => CS2_SimpleAdmin.Instance.ReloadAdmins(null));
|
||||
}
|
||||
|
||||
CS2_SimpleAdmin.ServerLoaded = true;
|
||||
if (CS2_SimpleAdmin.Instance.CacheManager != null)
|
||||
await CS2_SimpleAdmin.Instance.CacheManager.InitializeCacheAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ public static class PlayersMenu
|
|||
|
||||
public static void OpenAliveMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
{
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.PawnIsAlive);
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE);
|
||||
}
|
||||
|
||||
public static void OpenDeadMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController?, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
{
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.PawnIsAlive == false);
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE);
|
||||
}
|
||||
|
||||
public static void OpenMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
|
|
|
|||
18
CS2-SimpleAdmin/Models/BanRecord.cs
Normal file
18
CS2-SimpleAdmin/Models/BanRecord.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace CS2_SimpleAdmin.Models;
|
||||
|
||||
public record BanRecord
|
||||
{
|
||||
[Column("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("player_steamid")]
|
||||
public string? PlayerSteamId { get; set; }
|
||||
|
||||
[Column("player_ip")]
|
||||
public string? PlayerIp { get; set; }
|
||||
|
||||
[Column("status")]
|
||||
public string Status { get; set; }
|
||||
}
|
||||
3
CS2-SimpleAdmin/Models/IpRecord.cs
Normal file
3
CS2-SimpleAdmin/Models/IpRecord.cs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
namespace CS2_SimpleAdmin.Models;
|
||||
|
||||
public readonly record struct IpRecord(uint Ip, DateTime UsedAt, string PlayerName);
|
||||
|
|
@ -1 +1 @@
|
|||
1.7.5a
|
||||
1.7.7-alpha
|
||||
|
|
@ -32,14 +32,13 @@ public partial class CS2_SimpleAdmin
|
|||
// Command and Server Settings
|
||||
public static readonly bool UnlockedCommands = CoreConfig.UnlockConCommands;
|
||||
internal static string IpAddress = string.Empty;
|
||||
public static bool ServerLoaded;
|
||||
public static int? ServerId = null;
|
||||
internal static bool ServerLoaded;
|
||||
internal static int? ServerId = null;
|
||||
internal static readonly HashSet<ulong> AdminDisabledJoinComms = [];
|
||||
|
||||
// Player Management
|
||||
private static readonly HashSet<int> GodPlayers = [];
|
||||
internal static readonly HashSet<int> SilentPlayers = [];
|
||||
internal static readonly ConcurrentBag<string?> BannedPlayers = [];
|
||||
internal static readonly Dictionary<ulong, string> RenamedPlayers = [];
|
||||
internal static readonly ConcurrentDictionary<int, PlayerInfo> PlayersInfo = [];
|
||||
private static readonly List<DisconnectedPlayer> DisconnectedPlayers = [];
|
||||
|
|
@ -69,6 +68,7 @@ public partial class CS2_SimpleAdmin
|
|||
internal BanManager BanManager = new(Database);
|
||||
internal MuteManager MuteManager = new(Database);
|
||||
internal WarnManager WarnManager = new(Database);
|
||||
internal CacheManager? CacheManager = new();
|
||||
internal ChatManager ChatManager = new();
|
||||
|
||||
static string firstMessage = "";
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nعقوبات اللاعبين لـ {lightred}{0}{default},\nعدد الحظر: {lightred}{1}{default}, عدد الصمت: {lightred}{2}{default}, عدد الكتم: {lightred}{3}{default}, عدد السكوت: {lightred}{4}{default}, عدد التحذيرات: {lightred}{5}{default}\nالعقوبات النشطة:\n{6}\nالتحذيرات النشطة:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}عقوبات اللاعبين لـ {lightred}{0}{grey}, حظر: {lightred}{1}{grey}, صمت: {lightred}{2}{grey}, كتم: {lightred}{3}{grey}, سكوت: {lightred}{4}{grey}, تحذيرات: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}الحسابات المرتبطة باللاعب {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "تم حظرك لمدة {lightred}{0}{default} لمدة {lightred}{1}{default} دقيقة من قبل {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "تم حظرك بشكل دائم لمدة {lightred}{0}{default} من قبل {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "تم طردك لمدة {lightred}{0}{default} من قبل {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nSpielerstrafe für {lightred}{0}{default},\nAnzahl der Sperren: {lightred}{1}{default}, Anzahl der Mundtot: {lightred}{2}{default}, Anzahl der Stummschaltungen: {lightred}{3}{default}, Anzahl der Stille: {lightred}{4}{default}, Anzahl der Warnungen: {lightred}{5}{default}\nAktive Strafen:\n{6}\nAktive Warnungen:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Spielerstrafe für {lightred}{0}{grey}, Sperren: {lightred}{1}{grey}, Mundtot: {lightred}{2}{grey}, Stummschaltungen: {lightred}{3}{grey}, Stille: {lightred}{4}{grey}, Warnungen: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Verknüpfte Konten des Spielers {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Du wurdest wegen {lightred}{0}{default} für {lightred}{1}{default} Minuten von {lightred}{2}{default} gebannt!",
|
||||
"sa_player_ban_message_perm": "Du wurdest wegen {lightred}{0}{default} von {lightred}{1}{default} permanent gebannt!",
|
||||
"sa_player_kick_message": "Du wurdest wegen {lightred}{0}{default} von {lightred}{1}{default} gekickt!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nPlayer penalties for {lightred}{0}{default},\nNumber of bans: {lightred}{1}{default}, Number of gags: {lightred}{2}{default}, Number of mutes: {lightred}{3}{default}, Number of silences: {lightred}{4}{default}, Number of warnings: {lightred}{5}{default}\nActive penalties:\n{6}\nActive warnings:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Player penalties for {lightred}{0}{grey}, Bans: {lightred}{1}{grey}, Gags: {lightred}{2}{grey}, Mutes: {lightred}{3}{grey}, Silences: {lightred}{4}{grey}, Warns: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Associated accounts of player {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "You have been banned for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "You have been banned permanently for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "You have been kicked for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nPenalizaciones del jugador para {lightred}{0}{default},\nNúmero de prohibiciones: {lightred}{1}{default}, Número de boqueos: {lightred}{2}{default}, Número de silenciamientos: {lightred}{3}{default}, Número de silencios: {lightred}{4}{default}, Número de advertencias: {lightred}{5}{default}\nPenalizaciones activas:\n{6}\nAdvertencias activas:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Penalizaciones del jugador para {lightred}{0}{grey}, Prohibiciones: {lightred}{1}{grey}, Boqueos: {lightred}{2}{grey}, Silenciamientos: {lightred}{3}{grey}, Silencios: {lightred}{4}{grey}, Advertencias: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Cuentas asociadas del jugador {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Has sido baneado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Has sido baneado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Has sido expulsado por {lightred}{0}{default} durante {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nتنبیهات بازیکن برای {lightred}{0}{default},\nتعداد مسدودیتها: {lightred}{1}{default}, تعداد سکوتها: {lightred}{2}{default}, تعداد بیصدا کردنها: {lightred}{3}{default}, تعداد سکوتها: {lightred}{4}{default}, تعداد هشدارها: {lightred}{5}{default}\nتنبیهات فعال:\n{6}\nهشدارهای فعال:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}تنبیهات بازیکن برای {lightred}{0}{grey}, مسدودیتها: {lightred}{1}{grey}, سکوتها: {lightred}{2}{grey}, بیصدا کردنها: {lightred}{3}{grey}, سکوتها: {lightred}{4}{grey}, هشدارها: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}حسابهای مرتبط با بازیکن {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "شما توسط {lightred}{2}{default} برای {lightred}{1}{default} دقیقه به دلیل {lightred}{0}{default} مسدود شدهاید!",
|
||||
"sa_player_ban_message_perm": "شما توسط {lightred}{1}{default} به دلیل {lightred}{0}{default} برای همیشه مسدود شدهاید!",
|
||||
"sa_player_kick_message": "شما توسط {lightred}{1}{default} به دلیل {lightred}{0}{default} اخراج شدهاید!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nPénalités du joueur pour {lightred}{0}{default},\nNombre de bannissements: {lightred}{1}{default}, Nombre de gag: {lightred}{2}{default}, Nombre de mutes: {lightred}{3}{default}, Nombre de silences: {lightred}{4}{default}, Nombre d’avertissements: {lightred}{5}{default}\nPénalités actives:\n{6}\nAvertissements actifs:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Pénalités du joueur pour {lightred}{0}{grey}, Bannissements: {lightred}{1}{grey}, Gags: {lightred}{2}{grey}, Mutes: {lightred}{3}{grey}, Silences: {lightred}{4}{grey}, Avertissements: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Comptes associés du joueur {lightred}{0}{grey} : {1}",
|
||||
"sa_player_ban_message_time": "Vous avez été banni pour {lightred}{0}{default} pendant {lightred}{1}{default} minutes par {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Vous avez été banni définitivement pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Vous avez été expulsé pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nSpēlētāja sods priekš {lightred}{0}{default},\nAizliegumu skaits: {lightred}{1}{default}, Klusumu skaits: {lightred}{2}{default}, Izslēgšanas skaits: {lightred}{3}{default}, Klusēšanas skaits: {lightred}{4}{default}, Brīdinājumu skaits: {lightred}{5}{default}\nAktīvie sodi:\n{6}\nAktīvie brīdinājumi:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Spēlētāja sods priekš {lightred}{0}{grey}, Aizliegumi: {lightred}{1}{grey}, Klusumi: {lightred}{2}{grey}, Izslēgšana: {lightred}{3}{grey}, Klusēšana: {lightred}{4}{grey}, Brīdinājumi: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Spēlētāja {lightred}{0}{grey} saistītie konti: {1}",
|
||||
"sa_player_ban_message_time": "Tu esi nobanots uz {lightred}{0}{default} uz {lightred}{1}{default} minūtēm, iemesls: {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Tevis bans ir uz mūžu, iemesls: {lightred}{0}{default}, Admins: {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Tu esi izmests, iemesls: {lightred}{0}{default}, Admins: {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nBlokady gracza {lightred}{0}{default},\nIlość banów: {lightred}{1}{default}, Ilość zakneblowań: {lightred}{2}{default}, Ilość wyciszeń: {lightred}{3}{default}, Ilość uciszeń: {lightred}{4}{default}Ilość ostrzeżeń: {lightred}{5}{default}\nAktywne blokady:\n{6}\nAktywne ostrzeżenia:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Blokady gracza {lightred}{0}{grey} - bany: {lightred}{1}{grey}, zakneblowania: {lightred}{2}{grey}, wyciszenia: {lightred}{3}{grey}, uciszenia: {lightred}{4}{grey}, ostrzeżenia: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Powiązane konta gracza {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Zostałeś zbanowany za {lightred}{0}{default} na {lightred}{1}{default} minut przez {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Zostałeś zbanowany na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Zostałeś wyrzucony za {lightred}{0}{default} przez {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nPenalidades do jogador para {lightred}{0}{default},\nNúmero de banimentos: {lightred}{1}{default}, Número de gags: {lightred}{2}{default}, Número de mutes: {lightred}{3}{default}, Número de silêncios: {lightred}{4}{default}, Número de avisos: {lightred}{5}{default}\nPenalidades ativas:\n{6}\nAvisos ativos:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Penalidades do jogador para {lightred}{0}{grey}, Banimentos: {lightred}{1}{grey}, Gags: {lightred}{2}{grey}, Mutes: {lightred}{3}{grey}, Silêncios: {lightred}{4}{grey}, Avisos: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Contas associadas do jogador {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Você foi banido por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Você foi banido permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Você foi expulso por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nPenalidades do jogador para {lightred}{0}{default},\nNúmero de banimentos: {lightred}{1}{default}, Número de gags: {lightred}{2}{default}, Número de mutes: {lightred}{3}{default}, Número de silêncios: {lightred}{4}{default}, Número de avisos: {lightred}{5}{default}\nPenalidades ativas:\n{6}\nAvisos ativos:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Penalidades do jogador para {lightred}{0}{grey}, Banimentos: {lightred}{1}{grey}, Gags: {lightred}{2}{grey}, Mutes: {lightred}{3}{grey}, Silêncios: {lightred}{4}{grey}, Avisos: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Contas associadas do jogador {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Foste banido pelo administrador {lightred}{0}{default} durante {lightred}{1}{default} minutos. Motivo: {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Foste banido permanentemente pelo administrador {lightred}{0}{default}. Motivo: {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Foste expulso pelo administrador {lightred}{0}{default}. Motivo: {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nШтрафы игрока для {lightred}{0}{default},\nКоличество банов: {lightred}{1}{default}, Количество гэгов: {lightred}{2}{default}, Количество мутов: {lightred}{3}{default}, Количество тишин: {lightred}{4}{default}, Количество предупреждений: {lightred}{5}{default}\nАктивные штрафы:\n{6}\nАктивные предупреждения:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Штрафы игрока для {lightred}{0}{grey}, Баны: {lightred}{1}{grey}, Гэги: {lightred}{2}{grey}, Муты: {lightred}{3}{grey}, Тишины: {lightred}{4}{grey}, Предупреждения: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}Связанные аккаунты игрока {lightred}{0}{grey}: {1}",
|
||||
"sa_player_ban_message_time": "Вы были забанены по причине {lightred}{0}{default} на {lightred}{1}{default} минут(ы) администратором {lightred}{2}{default}!",
|
||||
"sa_player_ban_message_perm": "Вас забанили навсегда по причине {lightred}{0}{default} администратором {lightred}{1}{default}!",
|
||||
"sa_player_kick_message": "Вы были выгнаны {lightred}{0}{default} администратором {lightred}{1}{default}!",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\nOyuncunun cezaları {lightred}{0}{default} için,\nBan sayısı: {lightred}{1}{default}, Gag sayısı: {lightred}{2}{default}, Mute sayısı: {lightred}{3}{default}, Sessizlik sayısı: {lightred}{4}{default}, Uyarı sayısı: {lightred}{5}{default}\nAktif cezalar:\n{6}\nAktif uyarılar:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}Oyuncunun cezaları {lightred}{0}{grey}, Banlar: {lightred}{1}{grey}, Gaglar: {lightred}{2}{grey}, Mute'lar: {lightred}{3}{grey}, Sessizlikler: {lightred}{4}{grey}, Uyarılar: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}{lightred}{0}{grey} oyuncusunun bağlı hesapları: {1}",
|
||||
"sa_player_ban_message_time": "Senaryo nedeniyle {lightred}{0}{default} dakika boyunca {lightred}{1}{default} tarafından yasaklandınız!",
|
||||
"sa_player_ban_message_perm": "Senaryo nedeniyle kalıcı olarak {lightred}{0}{default} tarafından yasaklandınız!",
|
||||
"sa_player_kick_message": "Senaryo nedeniyle {lightred}{0}{default} tarafından atıldınız!",
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
"sa_player_penalty_info": "===========================\n玩家 {lightred}{0}{default} 的处罚信息,\n禁止次数: {lightred}{1}{default}, 禁言次数: {lightred}{2}{default}, 静音次数: {lightred}{3}{default}, 沉默次数: {lightred}{4}{default}, 警告次数: {lightred}{5}{default}\n活跃的处罚:\n{6}\n活跃的警告:\n{7}\n===========================",
|
||||
"sa_admin_penalty_info": "{grey}玩家 {lightred}{0}{grey} 的处罚信息, 禁止: {lightred}{1}{grey}, 禁言: {lightred}{2}{grey}, 静音: {lightred}{3}{grey}, 沉默: {lightred}{4}{grey}, 警告: {lightred}{5}",
|
||||
"sa_admin_associated_accounts": "{grey}玩家 {lightred}{0}{grey} 的关联账户:{1}",
|
||||
"sa_player_ban_message_time": "您已被 {lightred}{0}{default} 因 {lightred}{2}{default} 禁止 {lightred}{1}{default} 分钟!",
|
||||
"sa_player_ban_message_perm": "您已被 {lightred}{0}{default} 因 {lightred}{1}{default} 永久禁止!",
|
||||
"sa_player_kick_message": "您已被 {lightred}{0}{default} 因 {lightred}{1}{default} 踢出!",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.305" />
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.318" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class PlayerInfo(
|
|||
public int TotalSilences { get; set; } = totalSilences;
|
||||
public int TotalWarns { get; set; } = totalWarns;
|
||||
public bool WaitingForKick { get; set; } = false;
|
||||
public List<(ulong SteamId, string PlayerName)> AccountsAssociated { get; set; } = [];
|
||||
public DiePosition? DiePosition { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue