mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-04-25 10:16:26 +00:00
Compare commits
15 Commits
665962565e
...
build-1.7.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eea700bfb4 | ||
|
|
91615ffc67 | ||
|
|
eb9b438315 | ||
|
|
3d23b8981b | ||
|
|
39cbfdab1e | ||
|
|
4599f08fd7 | ||
|
|
4c43f14c82 | ||
|
|
f16f8cf1a5 | ||
|
|
193685826c | ||
|
|
fe73fa9917 | ||
|
|
bdada2df1e | ||
|
|
310a43fcd9 | ||
|
|
58243e813a | ||
|
|
d53446e0fe | ||
|
|
2404c1bc03 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdmin_ExampleModule.sln.DotSetti
|
|||||||
CS2-SimpleAdmin_BanSoundModule — kopia
|
CS2-SimpleAdmin_BanSoundModule — kopia
|
||||||
*.user
|
*.user
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
|
/Modules/CS2-SimpleAdmin_BanSoundModule
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
||||||
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
||||||
public override string ModuleAuthor => "daffyy";
|
public override string ModuleAuthor => "daffyy";
|
||||||
public override string ModuleVersion => "1.7.8-beta-8";
|
public override string ModuleVersion => "1.7.9a";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
CachedPlayers.Clear();
|
CachedPlayers.Clear();
|
||||||
BotPlayers.Clear();
|
BotPlayers.Clear();
|
||||||
|
|
||||||
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsHLTV).ToArray())
|
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p is { Connected: PlayerConnectedState.Connected, IsHLTV: false }).ToArray())
|
||||||
{
|
{
|
||||||
if (!player.IsBot)
|
if (!player.IsBot)
|
||||||
PlayerManager.LoadPlayerData(player, true);
|
PlayerManager.LoadPlayerData(player, true);
|
||||||
@@ -83,9 +83,9 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
Unload(false);
|
Unload(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddTimer(6.0f, () => ReloadAdmins(null));
|
|
||||||
RegisterEvents();
|
RegisterEvents();
|
||||||
AddTimer(0.5f, RegisterCommands.InitializeCommands);
|
AddTimer(0.5f, RegisterCommands.InitializeCommands);
|
||||||
|
AddTimer(3.0f, () => ReloadAdmins(null));
|
||||||
|
|
||||||
if (!CoreConfig.UnlockConCommands)
|
if (!CoreConfig.UnlockConCommands)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,16 +19,16 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.346">
|
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.367">
|
||||||
<PrivateAssets>none</PrivateAssets>
|
<PrivateAssets>none</PrivateAssets>
|
||||||
<ExcludeAssets>runtime</ExcludeAssets>
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
<PackageReference Include="Dapper" Version="2.1.72" />
|
||||||
<PackageReference Include="MySqlConnector" Version="2.5.0-beta.1" />
|
<PackageReference Include="MySqlConnector" Version="2.5.0" />
|
||||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
||||||
<PackageReference Include="System.Linq.Async" Version="7.0.0-preview.1.g24680b5469" />
|
<PackageReference Include="System.Linq.Async" Version="7.0.1" />
|
||||||
<PackageReference Include="ZLinq" Version="1.5.3" />
|
<PackageReference Include="ZLinq" Version="1.5.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
|
|
||||||
var targets = GetTarget(command);
|
var targets = GetTarget(command);
|
||||||
if (targets == null) return;
|
if (targets == null) return;
|
||||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, IsHLTV: false }).ToList();
|
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, Connected: PlayerConnectedState.Connected, IsHLTV: false }).ToList();
|
||||||
|
|
||||||
if (playersToTarget.Count > 1 && Config.OtherSettings.DisableDangerousCommands || playersToTarget.Count == 0)
|
if (playersToTarget.Count > 1 && Config.OtherSettings.DisableDangerousCommands || playersToTarget.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -373,7 +373,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
|
|
||||||
var targets = GetTarget(command);
|
var targets = GetTarget(command);
|
||||||
if (targets == null) return;
|
if (targets == null) return;
|
||||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList();
|
var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.Connected && !player.IsHLTV).ToList();
|
||||||
|
|
||||||
if (playersToTarget.Count > 1 && Config.OtherSettings.DisableDangerousCommands || playersToTarget.Count == 0)
|
if (playersToTarget.Count > 1 && Config.OtherSettings.DisableDangerousCommands || playersToTarget.Count == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
var adminsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/admins.json");
|
var adminsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/admins.json");
|
||||||
var groupsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/groups.json");
|
var groupsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/groups.json");
|
||||||
|
|
||||||
await Server.NextWorldUpdateAsync(() =>
|
await Server.NextWorldUpdateAsync(() =>
|
||||||
{
|
{
|
||||||
AddTimer(1, () =>
|
AddTimer(1, () =>
|
||||||
{
|
{
|
||||||
@@ -521,7 +521,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
_logger?.LogInformation("Loaded admins!");
|
_logger?.LogInformation("Loaded admins!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//_ = _adminManager.GiveAllGroupsFlags();
|
//_ = _adminManager.GiveAllGroupsFlags();
|
||||||
//_ = _adminManager.GiveAllFlags();
|
//_ = _adminManager.GiveAllFlags();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
/// <param name="command">Optional command info for logging.</param>
|
/// <param name="command">Optional command info for logging.</param>
|
||||||
internal static void Slay(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
internal static void Slay(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||||
{
|
{
|
||||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected) return;
|
if (!player.IsValid || player.Connected != PlayerConnectedState.Connected) return;
|
||||||
if (!caller.CanTarget(player)) return;
|
if (!caller.CanTarget(player)) return;
|
||||||
|
|
||||||
// Set default caller name if not provided
|
// Set default caller name if not provided
|
||||||
@@ -93,7 +93,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
|
|
||||||
playersToTarget.ForEach(player =>
|
playersToTarget.ForEach(player =>
|
||||||
{
|
{
|
||||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
if (player.Connected != PlayerConnectedState.Connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (caller!.CanTarget(player))
|
if (caller!.CanTarget(player))
|
||||||
@@ -207,7 +207,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
internal static void ChangeTeam(CCSPlayerController? caller, CCSPlayerController player, string teamName, CsTeam teamNum, bool kill, CommandInfo? command = null)
|
internal static void ChangeTeam(CCSPlayerController? caller, CCSPlayerController player, string teamName, CsTeam teamNum, bool kill, CommandInfo? command = null)
|
||||||
{
|
{
|
||||||
// Check if the player is valid and connected
|
// Check if the player is valid and connected
|
||||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected)
|
if (!player.IsValid || player.Connected != PlayerConnectedState.Connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Ensure the caller can target the player
|
// Ensure the caller can target the player
|
||||||
@@ -284,7 +284,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
playersToTarget.ForEach(player =>
|
playersToTarget.ForEach(player =>
|
||||||
{
|
{
|
||||||
// Check if the player is connected and can be targeted
|
// Check if the player is connected and can be targeted
|
||||||
if (player.Connected != PlayerConnectedState.PlayerConnected || !caller!.CanTarget(player))
|
if (player.Connected != PlayerConnectedState.Connected || !caller!.CanTarget(player))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Determine message key and arguments for the rename notification
|
// Determine message key and arguments for the rename notification
|
||||||
@@ -330,7 +330,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
playersToTarget.ForEach(player =>
|
playersToTarget.ForEach(player =>
|
||||||
{
|
{
|
||||||
// Check if the player is connected and can be targeted
|
// Check if the player is connected and can be targeted
|
||||||
if (player.Connected != PlayerConnectedState.PlayerConnected || !caller!.CanTarget(player))
|
if (player.Connected != PlayerConnectedState.Connected || !caller!.CanTarget(player))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Determine message key and arguments for the rename notification
|
// Determine message key and arguments for the rename notification
|
||||||
@@ -379,7 +379,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
destinationPlayer = targets.Players.FirstOrDefault(p =>
|
destinationPlayer = targets.Players.FirstOrDefault(p =>
|
||||||
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.Connected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
||||||
|
|
||||||
if (destinationPlayer == null || !caller.CanTarget(destinationPlayer) || caller.PlayerPawn.Value == null)
|
if (destinationPlayer == null || !caller.CanTarget(destinationPlayer) || caller.PlayerPawn.Value == null)
|
||||||
return;
|
return;
|
||||||
@@ -399,7 +399,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
playersToTeleport = targets.Players
|
playersToTeleport = targets.Players
|
||||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.Connected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (!playersToTeleport.Any())
|
if (!playersToTeleport.Any())
|
||||||
@@ -476,7 +476,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
destinationPlayer = caller;
|
destinationPlayer = caller;
|
||||||
|
|
||||||
playersToTeleport = targets.Players
|
playersToTeleport = targets.Players
|
||||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.Connected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -486,7 +486,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
destinationPlayer = destination.Players.FirstOrDefault(p =>
|
destinationPlayer = destination.Players.FirstOrDefault(p =>
|
||||||
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.Connected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
||||||
|
|
||||||
if (destinationPlayer == null)
|
if (destinationPlayer == null)
|
||||||
return;
|
return;
|
||||||
@@ -497,7 +497,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
playersToTeleport = targets.Players
|
playersToTeleport = targets.Players
|
||||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller!.CanTarget(p))
|
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.Connected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller!.CanTarget(p))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public interface IDatabaseProvider
|
|||||||
string GetUpdateBanStatusQuery();
|
string GetUpdateBanStatusQuery();
|
||||||
string GetExpireBansQuery(bool multiServer);
|
string GetExpireBansQuery(bool multiServer);
|
||||||
string GetExpireIpBansQuery(bool multiServer);
|
string GetExpireIpBansQuery(bool multiServer);
|
||||||
|
string GetExpireOldPlayerIpsQuery();
|
||||||
|
|
||||||
// MuteManager
|
// MuteManager
|
||||||
string GetAddMuteQuery(bool includePlayerName);
|
string GetAddMuteQuery(bool includePlayerName);
|
||||||
|
|||||||
@@ -251,6 +251,11 @@ public class MySqlDatabaseProvider(string connectionString) : IDatabaseProvider
|
|||||||
? "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime"
|
? "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime"
|
||||||
: "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime AND server_id = @serverid";
|
: "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime AND server_id = @serverid";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetExpireOldPlayerIpsQuery()
|
||||||
|
{
|
||||||
|
return "DELETE FROM sa_players_ips WHERE used_at <= @ipBansTime";
|
||||||
|
}
|
||||||
|
|
||||||
public string GetAddMuteQuery(bool includePlayerName) =>
|
public string GetAddMuteQuery(bool includePlayerName) =>
|
||||||
includePlayerName
|
includePlayerName
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ public class SqliteDatabaseProvider(string filePath) : IDatabaseProvider
|
|||||||
multiServer
|
multiServer
|
||||||
? "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime"
|
? "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime"
|
||||||
: "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime AND server_id = @serverid";
|
: "UPDATE sa_bans SET player_ip = NULL WHERE status = 'ACTIVE' AND ends <= @ipBansTime AND server_id = @serverid";
|
||||||
|
|
||||||
|
public string GetExpireOldPlayerIpsQuery() =>
|
||||||
|
"DELETE FROM sa_players_ips WHERE used_at <= @ipBansTime";
|
||||||
|
|
||||||
public string GetAdminsQuery() =>
|
public string GetAdminsQuery() =>
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
{
|
{
|
||||||
var player = Utilities.GetPlayerFromSteamId(list.Key);
|
var player = Utilities.GetPlayerFromSteamId(list.Key);
|
||||||
|
|
||||||
if (player == null || !player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected)
|
if (player == null || !player.IsValid || player.Connected != PlayerConnectedState.Connected)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (player.PlayerName.Equals(list.Value))
|
if (player.PlayerName.Equals(list.Value))
|
||||||
@@ -328,7 +328,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
? Utilities.GetPlayerFromUserid(userId)
|
? Utilities.GetPlayerFromUserid(userId)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (target == null || !target.IsValid || target.Connected != PlayerConnectedState.PlayerConnected)
|
if (target == null || !target.IsValid || target.Connected != PlayerConnectedState.Connected)
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
|
|
||||||
return !player.CanTarget(target) ? HookResult.Stop : HookResult.Continue;
|
return !player.CanTarget(target) ? HookResult.Stop : HookResult.Continue;
|
||||||
@@ -448,13 +448,13 @@ public partial class CS2_SimpleAdmin
|
|||||||
|
|
||||||
private void OnMapStart(string mapName)
|
private void OnMapStart(string mapName)
|
||||||
{
|
{
|
||||||
if (!ServerLoaded || ServerId == null)
|
|
||||||
AddTimer(2.0f, OnGameServerSteamAPIActivated);
|
|
||||||
|
|
||||||
if (Config.OtherSettings.ReloadAdminsEveryMapChange && ServerLoaded && ServerId != null)
|
if (Config.OtherSettings.ReloadAdminsEveryMapChange && ServerLoaded && ServerId != null)
|
||||||
AddTimer(5.0f, () => ReloadAdmins(null));
|
ReloadAdmins(null);
|
||||||
|
|
||||||
AddTimer(1.0f, ServerManager.CheckHibernationStatus);
|
AddTimer(1.0f, ServerManager.CheckHibernationStatus);
|
||||||
|
|
||||||
|
if (!ServerLoaded || ServerId == null)
|
||||||
|
AddTimer(1.5f, OnGameServerSteamAPIActivated);
|
||||||
|
|
||||||
// AddTimer(34, () =>
|
// AddTimer(34, () =>
|
||||||
// {
|
// {
|
||||||
@@ -473,7 +473,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
var player = @event.Userid;
|
var player = @event.Userid;
|
||||||
|
|
||||||
if (player?.UserId == null || !player.IsValid || player.IsHLTV ||
|
if (player?.UserId == null || !player.IsValid || player.IsHLTV ||
|
||||||
player.Connected != PlayerConnectedState.PlayerConnected || !PlayersInfo.ContainsKey(player.SteamID) ||
|
player.Connected != PlayerConnectedState.Connected || !PlayersInfo.ContainsKey(player.SteamID) ||
|
||||||
@event.Attacker == null)
|
@event.Attacker == null)
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ using CounterStrikeSharp.API.ValveConstants.Protobuf;
|
|||||||
using CS2_SimpleAdminApi;
|
using CS2_SimpleAdminApi;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using CounterStrikeSharp.API.Core.Plugin.Host;
|
using CounterStrikeSharp.API.Core.Plugin.Host;
|
||||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||||
@@ -64,7 +66,7 @@ internal static class Helper
|
|||||||
|
|
||||||
public static List<CCSPlayerController> GetValidPlayers()
|
public static List<CCSPlayerController> GetValidPlayers()
|
||||||
{
|
{
|
||||||
return CS2_SimpleAdmin.CachedPlayers.AsValueEnumerable().Where(p => p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected).ToList();
|
return CS2_SimpleAdmin.CachedPlayers.AsValueEnumerable().Where(p => p.IsValid && p.Connected == PlayerConnectedState.Connected).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<CCSPlayerController> GetValidPlayersWithBots()
|
public static List<CCSPlayerController> GetValidPlayersWithBots()
|
||||||
@@ -855,26 +857,34 @@ internal static class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateConfig<T>(T config) where T : BasePluginConfig, new()
|
public static void UpdateConfig(BasePluginConfig config)
|
||||||
{
|
{
|
||||||
// get newest config version
|
// get newest config version
|
||||||
var newCfgVersion = new T().Version;
|
var configType = config.GetType();
|
||||||
|
var newCfgVersion = ((BasePluginConfig)Activator.CreateInstance(configType)!).Version;
|
||||||
|
|
||||||
// loaded config is up to date
|
// loaded config is up to date
|
||||||
if (config.Version == newCfgVersion)
|
if (config.Version == newCfgVersion)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// update the version
|
// Load existing JSON file and update version property
|
||||||
config.Version = newCfgVersion;
|
if (!File.Exists(CfgPath))
|
||||||
|
return;
|
||||||
|
|
||||||
// serialize the updated config back to json
|
var json = File.ReadAllText(CfgPath);
|
||||||
var updatedJsonContent = JsonSerializer.Serialize(config,
|
var node = JsonNode.Parse(json);
|
||||||
new JsonSerializerOptions
|
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
node["Version"] = newCfgVersion;
|
||||||
|
var updatedJsonContent = node.ToJsonString(new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
});
|
});
|
||||||
File.WriteAllText(CfgPath, updatedJsonContent);
|
|
||||||
|
File.WriteAllText(CfgPath, updatedJsonContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void TryLogCommandOnDiscord(CCSPlayerController? caller, string commandString)
|
public static void TryLogCommandOnDiscord(CCSPlayerController? caller, string commandString)
|
||||||
|
|||||||
@@ -431,6 +431,9 @@ public async Task UnbanPlayer(string playerPattern, string adminSteamId, string
|
|||||||
var ipBansTime = currentTime.AddDays(-CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans);
|
var ipBansTime = currentTime.AddDays(-CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans);
|
||||||
sql = databaseProvider.GetExpireIpBansQuery(CS2_SimpleAdmin.Instance.Config.MultiServerMode);
|
sql = databaseProvider.GetExpireIpBansQuery(CS2_SimpleAdmin.Instance.Config.MultiServerMode);
|
||||||
await connection.ExecuteAsync(sql, new { ipBansTime, CS2_SimpleAdmin.ServerId });
|
await connection.ExecuteAsync(sql, new { ipBansTime, CS2_SimpleAdmin.ServerId });
|
||||||
|
|
||||||
|
sql = databaseProvider.GetExpireOldPlayerIpsQuery();
|
||||||
|
await connection.ExecuteAsync(sql, new { ipBansTime });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|||||||
@@ -626,34 +626,81 @@ internal class CacheManager: IDisposable
|
|||||||
if (_cachedIgnoredIps.Contains(ipUInt))
|
if (_cachedIgnoredIps.Contains(ipUInt))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_ipIndex.TryGetValue(ipUInt, out var ipBanRecords))
|
// Direct ip ban (ban record has player_ip set)
|
||||||
return false;
|
if (_ipIndex.TryGetValue(ipUInt, out var ipBanRecords))
|
||||||
|
|
||||||
var ipBan = ipBanRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
|
||||||
if (ipBan == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_banCache.TryGetValue(ipBan.Id, out var cachedIpBan) || cachedIpBan.StatusEnum != BanStatus.ACTIVE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var expireOldIpBans = CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans;
|
|
||||||
if (expireOldIpBans > 0)
|
|
||||||
{
|
{
|
||||||
var cutoff = Time.ActualDateTime().AddDays(-expireOldIpBans);
|
var ipBan = ipBanRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (ipBan.Created < cutoff)
|
if (ipBan != null && _banCache.TryGetValue(ipBan.Id, out var cachedIpBan) && cachedIpBan.StatusEnum == BanStatus.ACTIVE)
|
||||||
return false;
|
{
|
||||||
|
var expireOldIpBans = CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans;
|
||||||
|
if (expireOldIpBans <= 0 || ipBan.Created >= Time.ActualDateTime().AddDays(-expireOldIpBans))
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(ipBan.PlayerName))
|
||||||
|
ipBan.PlayerName = playerName;
|
||||||
|
ipBan.PlayerSteamId ??= steamId;
|
||||||
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var unknownName = CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown";
|
// Multiaccount ban - check if other accounts using current ip are banned
|
||||||
|
if (!_playerIpsCache.IsEmpty)
|
||||||
|
{
|
||||||
|
foreach (var (otherSteamId, ipSet) in _playerIpsCache)
|
||||||
|
{
|
||||||
|
// Skip current player
|
||||||
|
if (otherSteamId == steamId)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ipBan.PlayerName))
|
// Check if this ip is in the other accounts ip history
|
||||||
ipBan.PlayerName = playerName;
|
if (ipSet.All(record => record.Ip != ipUInt)) continue;
|
||||||
|
// Found another account using this ip - check if its banned
|
||||||
|
if (!_steamIdIndex.TryGetValue(otherSteamId, out var otherSteamBans)) continue;
|
||||||
|
var activeBan = otherSteamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
||||||
|
if (activeBan == null || !_banCache.TryGetValue(activeBan.Id, out var cachedBan) ||
|
||||||
|
cachedBan.StatusEnum != BanStatus.ACTIVE) continue;
|
||||||
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ipBan.PlayerSteamId ??= steamId;
|
// Multiaccount ban - check if this player used any ip where other banned accounts are connected
|
||||||
|
// Search sa_players_ips for all accounts sharing the same ips as current player
|
||||||
|
if (!CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp)
|
||||||
|
return false;
|
||||||
|
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
if (!_playerIpsCache.TryGetValue(steamId, out var playerIps))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
// For each ip the player used (current or historical)
|
||||||
|
foreach (var playerIpRecord in playerIps)
|
||||||
|
{
|
||||||
|
// Search sa_players_ips for other accounts using this same ip (as uint)
|
||||||
|
foreach (var (otherSteamId, otherIpSet) in _playerIpsCache)
|
||||||
|
{
|
||||||
|
if (otherSteamId == steamId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if this other account used the player ip
|
||||||
|
if (otherIpSet.All(record => record.Ip != playerIpRecord.Ip))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if this other account is banned
|
||||||
|
if (!_steamIdIndex.TryGetValue(otherSteamId, out var otherSteamBans))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var activeBan = otherSteamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
||||||
|
if (activeBan == null || !_banCache.TryGetValue(activeBan.Id, out var cachedBan) ||
|
||||||
|
cachedBan.StatusEnum != BanStatus.ACTIVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace CS2_SimpleAdmin.Managers;
|
|||||||
|
|
||||||
internal class PlayerManager
|
internal class PlayerManager
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _loadPlayerSemaphore = new(10);
|
private readonly SemaphoreSlim _loadPlayerSemaphore = new(6);
|
||||||
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config;
|
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,69 +51,41 @@ internal class PlayerManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _loadPlayerSemaphore.WaitAsync();
|
await _loadPlayerSemaphore.WaitAsync();
|
||||||
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(steamId))
|
|
||||||
|
// Save ip address before ban check
|
||||||
|
await SavePlayerIpAddress(steamId, playerName, ipAddress);
|
||||||
|
|
||||||
|
// Always check bans first, regardless of PlayersInfo state
|
||||||
|
var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
||||||
{
|
{
|
||||||
var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(playerName, steamId, null),
|
||||||
|
_ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp
|
||||||
|
? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(playerName, steamId,
|
||||||
|
ipAddress)
|
||||||
|
: CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(playerName, steamId, ipAddress)
|
||||||
|
};
|
||||||
|
|
||||||
|
CS2_SimpleAdmin._logger?.LogInformation($"[BAN CHECK] Player {playerName} ({steamId}) IP: {ipAddress} - BanType: {CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType} - CheckMultiAccounts: {CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp} - isBanned: {isBanned}");
|
||||||
|
|
||||||
|
if (isBanned)
|
||||||
|
{
|
||||||
|
CS2_SimpleAdmin._logger?.LogInformation($"[BAN CHECK] KICKING {playerName} ({steamId})");
|
||||||
|
await Server.NextWorldUpdateAsync(() =>
|
||||||
{
|
{
|
||||||
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(playerName, steamId, null),
|
CS2_SimpleAdmin._logger?.LogInformation($"[BAN CHECK] Executing kick for {playerName}");
|
||||||
_ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp
|
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
||||||
? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(playerName, steamId,
|
});
|
||||||
ipAddress)
|
|
||||||
: CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(playerName, steamId, ipAddress)
|
|
||||||
};
|
|
||||||
|
|
||||||
// CS2_SimpleAdmin._logger?.LogInformation($"Player {playerName} ({steamId} - {ipAddress}) is banned? {isBanned.ToString()}");
|
return;
|
||||||
|
|
||||||
if (isBanned)
|
|
||||||
{
|
|
||||||
await Server.NextWorldUpdateAsync(() =>
|
|
||||||
{
|
|
||||||
// CS2_SimpleAdmin._logger?.LogInformation($"Kicking {playerName}");
|
|
||||||
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullConnect)
|
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(steamId))
|
||||||
{
|
{
|
||||||
var playerInfo = new PlayerInfo(userId, slot, new SteamID(steamId), playerName, ipAddress);
|
var playerInfo = new PlayerInfo(userId, slot, new SteamID(steamId), playerName, ipAddress);
|
||||||
CS2_SimpleAdmin.PlayersInfo[steamId] = playerInfo;
|
CS2_SimpleAdmin.PlayersInfo[steamId] = playerInfo;
|
||||||
|
|
||||||
if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null &&
|
if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null)
|
||||||
CS2_SimpleAdmin.PlayersInfo[steamId] != null)
|
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
await using var connection = await CS2_SimpleAdmin.DatabaseProvider.CreateConnectionAsync();
|
|
||||||
|
|
||||||
// Eliminates the need for SELECT COUNT and duplicate UPDATE queries
|
|
||||||
var steamId64 = CS2_SimpleAdmin.PlayersInfo[steamId].SteamId.SteamId64;
|
|
||||||
var ipUint = IpHelper.IpToUint(ipAddress);
|
|
||||||
|
|
||||||
// Use database-specific UPSERT query (handles MySQL vs SQLite syntax differences)
|
|
||||||
var upsertQuery = CS2_SimpleAdmin.DatabaseProvider.GetUpsertPlayerIpQuery();
|
|
||||||
|
|
||||||
await connection.ExecuteAsync(upsertQuery, new
|
|
||||||
{
|
|
||||||
SteamID = steamId64,
|
|
||||||
playerName,
|
|
||||||
IPAddress = ipUint
|
|
||||||
});
|
|
||||||
|
|
||||||
// // Cache will be updated on next refresh cycle
|
|
||||||
// if (!CS2_SimpleAdmin.Instance.CacheManager.HasIpForPlayer(steamId, ipAddress))
|
|
||||||
// {
|
|
||||||
// // IP association will be reflected after cache refresh
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
CS2_SimpleAdmin._logger?.LogError(
|
|
||||||
$"Unable to save ip address for {playerInfo.Name} ({ipAddress}): {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
playerInfo.AccountsAssociated =
|
playerInfo.AccountsAssociated =
|
||||||
CS2_SimpleAdmin.Instance.CacheManager?.GetAccountsByIp(ipAddress).AsValueEnumerable()
|
CS2_SimpleAdmin.Instance.CacheManager?.GetAccountsByIp(ipAddress).AsValueEnumerable()
|
||||||
.Select(x => (x.SteamId, x.PlayerName)).ToList() ?? [];
|
.Select(x => (x.SteamId, x.PlayerName)).ToList() ?? [];
|
||||||
@@ -200,7 +172,7 @@ internal class PlayerManager
|
|||||||
AdminManager.PlayerHasPermissions(
|
AdminManager.PlayerHasPermissions(
|
||||||
new SteamID(p.SteamID),
|
new SteamID(p.SteamID),
|
||||||
"@css/ban")) &&
|
"@css/ban")) &&
|
||||||
p.Connected == PlayerConnectedState.PlayerConnected &&
|
p.Connected == PlayerConnectedState.Connected &&
|
||||||
!CS2_SimpleAdmin.AdminDisabledJoinComms
|
!CS2_SimpleAdmin.AdminDisabledJoinComms
|
||||||
.Contains(p.SteamID)))
|
.Contains(p.SteamID)))
|
||||||
{
|
{
|
||||||
@@ -247,13 +219,45 @@ internal class PlayerManager
|
|||||||
_loadPlayerSemaphore.Release();
|
_loadPlayerSemaphore.Release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
||||||
{
|
{
|
||||||
player.Rename(name);
|
player.Rename(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves player's IP address to the database for multi-account detection.
|
||||||
|
/// This is called before ban checks to ensure IP is recorded even if player is banned.
|
||||||
|
/// </summary>
|
||||||
|
private async Task SavePlayerIpAddress(ulong steamId, string playerName, string? ipAddress)
|
||||||
|
{
|
||||||
|
if (!_config.OtherSettings.CheckMultiAccountsByIp || ipAddress == null || CS2_SimpleAdmin.DatabaseProvider == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var connection = await CS2_SimpleAdmin.DatabaseProvider.CreateConnectionAsync();
|
||||||
|
|
||||||
|
var steamId64 = steamId;
|
||||||
|
var ipUint = IpHelper.IpToUint(ipAddress);
|
||||||
|
|
||||||
|
var upsertQuery = CS2_SimpleAdmin.DatabaseProvider.GetUpsertPlayerIpQuery();
|
||||||
|
|
||||||
|
await connection.ExecuteAsync(upsertQuery, new
|
||||||
|
{
|
||||||
|
SteamID = steamId64,
|
||||||
|
playerName,
|
||||||
|
IPAddress = ipUint
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
CS2_SimpleAdmin._logger?.LogError(
|
||||||
|
$"Unable to save ip address for {playerName} ({ipAddress}): {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Periodically checks the status of online players and applies timers for speed, gravity,
|
/// Periodically checks the status of online players and applies timers for speed, gravity,
|
||||||
/// and penalty expiration validation.
|
/// and penalty expiration validation.
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class ServerManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void LoadServerData()
|
public void LoadServerData()
|
||||||
{
|
{
|
||||||
CS2_SimpleAdmin.Instance.AddTimer(2.0f, () =>
|
CS2_SimpleAdmin.Instance.AddTimer(1.0f, () =>
|
||||||
{
|
{
|
||||||
if (CS2_SimpleAdmin.ServerLoaded || CS2_SimpleAdmin.DatabaseProvider == null) return;
|
if (CS2_SimpleAdmin.ServerLoaded || CS2_SimpleAdmin.DatabaseProvider == null) return;
|
||||||
|
|
||||||
@@ -103,14 +103,12 @@ public class ServerManager
|
|||||||
CS2_SimpleAdmin.ServerId = serverId;
|
CS2_SimpleAdmin.ServerId = serverId;
|
||||||
CS2_SimpleAdmin._logger?.LogInformation("Loaded server with ip {ip}", ipAddress);
|
CS2_SimpleAdmin._logger?.LogInformation("Loaded server with ip {ip}", ipAddress);
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.ServerId != null)
|
CS2_SimpleAdmin.ServerLoaded = true;
|
||||||
{
|
|
||||||
await Server.NextWorldUpdateAsync(() => CS2_SimpleAdmin.Instance.ReloadAdmins(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
CS2_SimpleAdmin.ServerLoaded = true;
|
|
||||||
if (CS2_SimpleAdmin.Instance.CacheManager != null)
|
if (CS2_SimpleAdmin.Instance.CacheManager != null)
|
||||||
|
{
|
||||||
await CS2_SimpleAdmin.Instance.CacheManager.InitializeCacheAsync();
|
await CS2_SimpleAdmin.Instance.CacheManager.InitializeCacheAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ internal class WarnManager(IDatabaseProvider? databaseProvider)
|
|||||||
|
|
||||||
return warnId;
|
return warnId;
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.7.8-beta-8
|
1.7.9a
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.346" />
|
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.367" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class CS2_SimpleAdmin_BanSoundModule: BasePlugin
|
|||||||
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot))
|
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot))
|
||||||
{
|
{
|
||||||
var filter = new RecipientFilter(player);
|
var filter = new RecipientFilter(player);
|
||||||
player?.EmitSound("bansound", volume: 0.9f, recipients: filter);
|
player?.EmitSound("bansound", volume: 0.75f, recipients: filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user