mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-02-17 10:31:01 +00:00
.
This commit is contained in:
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
||||
ko_fi: daffyy
|
||||
71
.github/workflows/build.yml
vendored
71
.github/workflows/build.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
paths-ignore:
|
||||
- '**/README.md'
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths-ignore:
|
||||
- '**/README.md'
|
||||
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.run_number }}
|
||||
PROJECT_PATH: "CS2-SimpleAdmin.csproj"
|
||||
PROJECT_NAME: "CS2-SimpleAdmin"
|
||||
OUTPUT_PATH: "./CS2-SimpleAdmin"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Restore
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build ${{ env.PROJECT_PATH }} -c CS2-SimpleAdmin -o ${{ env.OUTPUT_PATH }}
|
||||
|
||||
publish:
|
||||
if: github.event_name == 'push'
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Restore
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build ${{ env.PROJECT_PATH }} -c CS2-SimpleAdmin -o ${{ env.OUTPUT_PATH }}
|
||||
- name: Clean files
|
||||
run: |
|
||||
rm -f \
|
||||
${{ env.OUTPUT_PATH }}/CounterStrikeSharp.API.dll \
|
||||
${{ env.OUTPUT_PATH }}/McMaster.NETCore.Plugins.dll \
|
||||
${{ env.OUTPUT_PATH }}/Microsoft.DotNet.PlatformAbstractions.dll \
|
||||
${{ env.OUTPUT_PATH }}/Microsoft.Extensions.DependencyModel.dll \
|
||||
- name: Zip
|
||||
uses: thedoctor0/zip-release@0.7.6
|
||||
with:
|
||||
type: 'zip'
|
||||
filename: '${{ env.PROJECT_NAME }}.zip'
|
||||
path: ${{ env.OUTPUT_PATH }}
|
||||
- name: CS2-SimpleAdmin
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
artifacts: "${{ env.PROJECT_NAME }}.zip"
|
||||
name: "Build ${{ env.BUILD_NUMBER }}"
|
||||
tag: "build-${{ env.BUILD_NUMBER }}"
|
||||
body: |
|
||||
Place the plugin in game/csgo/addons/counterstrikesharp/plugins/CS2-SimpleAdmin
|
||||
After first launch, u need to configure plugin in addons/counterstrikesharp/configs/plugins/CS2-SimpleAdmin/CS2-SimpleAdmin.json
|
||||
13
.idea/.idea.CS2-SimpleAdmin/.idea/.gitignore
generated
vendored
13
.idea/.idea.CS2-SimpleAdmin/.idea/.gitignore
generated
vendored
@@ -1,13 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/modules.xml
|
||||
/projectSettingsUpdater.xml
|
||||
/.idea.CS2-SimpleAdmin.iml
|
||||
/contentModel.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/Managers/BanManager.cs" dialect="GenericSQL" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/.idea.CS2-SimpleAdmin/.idea/vcs.xml
generated
6
.idea/.idea.CS2-SimpleAdmin/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,166 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Commands.Targeting;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using Discord.Webhook;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
[MinimumApiVersion(253)]
|
||||
public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdminConfig>
|
||||
{
|
||||
public static CS2_SimpleAdmin Instance { get; private set; } = new();
|
||||
|
||||
public static IStringLocalizer? _localizer;
|
||||
public static readonly Dictionary<string, int> VoteAnswers = [];
|
||||
private static bool _serverLoaded;
|
||||
private static readonly HashSet<int> GodPlayers = [];
|
||||
private static readonly HashSet<int> SilentPlayers = [];
|
||||
private static readonly ConcurrentBag<string> BannedPlayers = [];
|
||||
private static readonly Dictionary<ulong, string> RenamedPlayers = [];
|
||||
//private static readonly ConcurrentBag<int> SilentPlayers = [];
|
||||
private static bool _tagsDetected;
|
||||
public static bool VoteInProgress = false;
|
||||
public static int? ServerId = null;
|
||||
private static readonly bool UnlockedCommands = CoreConfig.UnlockConCommands;
|
||||
|
||||
public static DiscordWebhookClient? DiscordWebhookClientLog;
|
||||
// public static DiscordWebhookClient? DiscordWebhookClientPenalty;
|
||||
|
||||
private string _dbConnectionString = string.Empty;
|
||||
private static Database.Database? _database;
|
||||
|
||||
internal static ILogger? _logger;
|
||||
|
||||
private static MemoryFunctionVoid<CBasePlayerController, CCSPlayerPawn, bool, bool>? _cBasePlayerControllerSetPawnFunc;
|
||||
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.5.2c";
|
||||
|
||||
public CS2_SimpleAdminConfig Config { get; set; } = new();
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
RegisterEvents();
|
||||
|
||||
if (hotReload)
|
||||
{
|
||||
_serverLoaded = false;
|
||||
OnGameServerSteamAPIActivated();
|
||||
OnMapStart(string.Empty);
|
||||
}
|
||||
|
||||
_cBasePlayerControllerSetPawnFunc = new MemoryFunctionVoid<CBasePlayerController, CCSPlayerPawn, bool, bool>(GameData.GetSignature("CBasePlayerController_SetPawn"));
|
||||
}
|
||||
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
if (hotReload) return;
|
||||
|
||||
RemoveListener(OnMapStart);
|
||||
RemoveCommandListener("say", OnCommandSay, HookMode.Post);
|
||||
RemoveCommandListener("say_team", OnCommandTeamSay, HookMode.Post);
|
||||
}
|
||||
|
||||
public override void OnAllPluginsLoaded(bool hotReload)
|
||||
{
|
||||
AddTimer(3.0f, () => ReloadAdmins(null));
|
||||
}
|
||||
|
||||
public void OnConfigParsed(CS2_SimpleAdminConfig config)
|
||||
{
|
||||
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
|
||||
{
|
||||
throw new Exception("[CS2-SimpleAdmin] You need to setup Database credentials in config!");
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
_logger = Logger;
|
||||
|
||||
MySqlConnectionStringBuilder builder = new()
|
||||
{
|
||||
Server = config.DatabaseHost,
|
||||
Database = config.DatabaseName,
|
||||
UserID = config.DatabaseUser,
|
||||
Password = config.DatabasePassword,
|
||||
Port = (uint)config.DatabasePort,
|
||||
Pooling = true,
|
||||
MinimumPoolSize = 0,
|
||||
MaximumPoolSize = 640,
|
||||
};
|
||||
|
||||
_dbConnectionString = builder.ConnectionString;
|
||||
_database = new Database.Database(_dbConnectionString);
|
||||
|
||||
if (!_database.CheckDatabaseConnection())
|
||||
{
|
||||
Logger.LogError("Unable connect to database!");
|
||||
Unload(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Run(() => _database.DatabaseMigration());
|
||||
|
||||
Config = config;
|
||||
Helper.UpdateConfig(config);
|
||||
|
||||
if (!Directory.Exists(ModuleDirectory + "/data"))
|
||||
{
|
||||
Directory.CreateDirectory(ModuleDirectory + "/data");
|
||||
}
|
||||
|
||||
_localizer = Localizer;
|
||||
|
||||
if (!string.IsNullOrEmpty(Config.Discord.DiscordLogWebhook))
|
||||
DiscordWebhookClientLog = new DiscordWebhookClient(Config.Discord.DiscordLogWebhook);
|
||||
|
||||
PluginInfo.ShowAd(ModuleVersion);
|
||||
if (Config.EnableUpdateCheck)
|
||||
Task.Run(async () => await PluginInfo.CheckVersion(ModuleVersion, _logger));
|
||||
}
|
||||
|
||||
private static TargetResult? GetTarget(CommandInfo command)
|
||||
{
|
||||
var matches = command.GetArgTargetResult(1);
|
||||
|
||||
if (!matches.Any())
|
||||
{
|
||||
command.ReplyToCommand($"Target {command.GetArg(1)} not found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (command.GetArg(1).StartsWith('@'))
|
||||
return matches;
|
||||
|
||||
if (matches.Count() == 1)
|
||||
return matches;
|
||||
|
||||
command.ReplyToCommand($"Multiple targets found for \"{command.GetArg(1)}\".");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void RemoveFromConcurrentBag(ConcurrentBag<int> bag, int playerSlot)
|
||||
{
|
||||
List<int> tempList = [];
|
||||
while (!bag.IsEmpty)
|
||||
{
|
||||
if (bag.TryTake(out var item) && item != playerSlot)
|
||||
{
|
||||
tempList.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in tempList)
|
||||
{
|
||||
bag.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>CS2_SimpleAdmin</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.255" />
|
||||
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||
<PackageReference Include="Discord.Net.Webhook" Version="3.15.3" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Update="Database\Migrations\010_CreateWarnsTable.sql">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Database\Migrations\*.sql" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="admin_help.txt" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34309.116
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2-SimpleAdmin", "CS2-SimpleAdmin.csproj", "{0DB90496-262F-4BF9-9B55-1490EBF4D49F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0DB90496-262F-4BF9-9B55-1490EBF4D49F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {86114444-059F-4DB8-9A55-E6D1BB76238D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,582 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_ban")]
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnBanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
if (command.ArgCount < 2)
|
||||
return;
|
||||
|
||||
var reason = _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList();
|
||||
|
||||
if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Database.Database database = new(_dbConnectionString);
|
||||
BanManager banManager = new(database, Config);
|
||||
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
|
||||
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
|
||||
reason = command.GetArg(3);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Ban(caller, player, time, reason, callerName, banManager, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void Ban(CCSPlayerController? caller, CCSPlayerController? player, int time, string reason, string? callerName = null, BanManager? banManager = null, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null || player is null || !player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
if (CheckValidBan(caller, time) == false)
|
||||
return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (player.PawnIsAlive)
|
||||
{
|
||||
player.Pawn.Value?.Freeze();
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = new()
|
||||
{
|
||||
SteamId = player.SteamID.ToString(),
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
PlayerInfo adminInfo = new()
|
||||
{
|
||||
SteamId = caller?.SteamID.ToString(),
|
||||
Name = caller?.PlayerName,
|
||||
IpAddress = caller?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
banManager ??= new BanManager(_database, Config);
|
||||
await banManager.BanPlayer(playerInfo, adminInfo, reason, time);
|
||||
});
|
||||
|
||||
if (playerInfo.IpAddress != null && !BannedPlayers.Contains(playerInfo.IpAddress))
|
||||
BannedPlayers.Add(playerInfo.IpAddress);
|
||||
if (!BannedPlayers.Contains(player.SteamID.ToString()))
|
||||
BannedPlayers.Add(player.SteamID.ToString());
|
||||
|
||||
if (time == 0)
|
||||
{
|
||||
if (player is { IsBot: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_perm", reason, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_perm",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!player.IsBot)
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_time",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason,
|
||||
time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (player.UserId.HasValue)
|
||||
AddTimer(Config.KickTime, () =>
|
||||
{
|
||||
if (player is null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
|
||||
Helper.KickPlayer(player.UserId.Value);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
if (UnlockedCommands)
|
||||
Server.ExecuteCommand($"banid 2 {new SteamID(player.SteamID).SteamId3}");
|
||||
|
||||
Helper.LogCommand(caller, $"css_ban {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {time} {reason}");
|
||||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, Helper.PenaltyType.Ban, _localizer);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_addban")]
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnAddBanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (command.ArgCount < 2)
|
||||
return;
|
||||
if (string.IsNullOrEmpty(command.GetArg(1))) return;
|
||||
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
{
|
||||
command.ReplyToCommand($"Invalid SteamID64.");
|
||||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
|
||||
var reason = _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
|
||||
if (CheckValidBan(caller, time) == false)
|
||||
return;
|
||||
|
||||
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
|
||||
reason = command.GetArg(3);
|
||||
|
||||
var adminInfo = new PlayerInfo
|
||||
{
|
||||
SteamId = caller?.SteamID.ToString(),
|
||||
Name = caller?.PlayerName,
|
||||
IpAddress = caller?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
var matches = Helper.GetPlayerFromSteamid64(steamid);
|
||||
if (matches.Count == 1)
|
||||
{
|
||||
var player = matches.FirstOrDefault();
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
if (!caller!.CanTarget(player))
|
||||
{
|
||||
command.ReplyToCommand($"{player.PlayerName} is more powerful than you!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (time == 0)
|
||||
{
|
||||
if (player is { IsBot: false, IsHLTV: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_perm", reason, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_perm",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player is { IsBot: false, IsHLTV: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_time",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason,
|
||||
time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.Pawn.Value?.Freeze();
|
||||
if (player.UserId.HasValue)
|
||||
AddTimer(Config.KickTime, () =>
|
||||
{
|
||||
if (player is null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
|
||||
Helper.KickPlayer(player.UserId.Value);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, Helper.PenaltyType.Ban, _localizer);
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
BanManager banManager = new(_database, Config);
|
||||
await banManager.AddBanBySteamid(steamid, adminInfo, reason, time);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
//Helper.SendDiscordPenaltyMessage(caller, player, reason, time, Helper.PenaltyType.Ban, _discordWebhookClientPenalty, _localizer);
|
||||
if (UnlockedCommands)
|
||||
Server.ExecuteCommand($"banid 2 {steamId.SteamId3}");
|
||||
|
||||
command.ReplyToCommand($"Banned player with steamid {steamid}.");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_banip")]
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<ip> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnBanIp(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (command.ArgCount < 2)
|
||||
return;
|
||||
if (string.IsNullOrEmpty(command.GetArg(1))) return;
|
||||
|
||||
var ipAddress = command.GetArg(1);
|
||||
|
||||
if (!Helper.IsValidIp(ipAddress))
|
||||
{
|
||||
command.ReplyToCommand($"Invalid IP address.");
|
||||
return;
|
||||
}
|
||||
|
||||
var reason = _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
var adminInfo = new PlayerInfo
|
||||
{
|
||||
SteamId = caller?.SteamID.ToString(),
|
||||
Name = caller?.PlayerName,
|
||||
IpAddress = caller?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
if (CheckValidBan(caller, time) == false)
|
||||
return;
|
||||
|
||||
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
|
||||
reason = command.GetArg(3);
|
||||
|
||||
var matches = Helper.GetPlayerFromIp(ipAddress);
|
||||
if (matches.Count == 1)
|
||||
{
|
||||
var player = matches.FirstOrDefault();
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
if (!caller!.CanTarget(player))
|
||||
{
|
||||
command.ReplyToCommand($"{player.PlayerName} is more powerful than you!");
|
||||
return;
|
||||
}
|
||||
|
||||
player.Pawn.Value!.Freeze();
|
||||
|
||||
if (time == 0)
|
||||
{
|
||||
if (player is { IsBot: false, IsHLTV: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_perm", reason, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_perm",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player is { IsBot: false, IsHLTV: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_ban_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_ban_message_time",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason,
|
||||
time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (player.UserId.HasValue)
|
||||
AddTimer(Config.KickTime, () =>
|
||||
{
|
||||
if (player is null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
|
||||
Helper.KickPlayer(player.UserId.Value);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, Helper.PenaltyType.Ban, _localizer);
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
BanManager banManager = new(_database, Config);
|
||||
await banManager.AddBanByIp(ipAddress, adminInfo, reason, time);
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
command.ReplyToCommand($"Banned player with IP address {ipAddress}.");
|
||||
}
|
||||
|
||||
private bool CheckValidBan(CCSPlayerController? caller, int duration)
|
||||
{
|
||||
if (caller == null) return true;
|
||||
|
||||
bool canPermBan = AdminManager.PlayerHasPermissions(caller, "@css/permban");
|
||||
|
||||
if (duration == 0 && canPermBan == false)
|
||||
{
|
||||
caller.PrintToChat($"{_localizer!["sa_prefix"]} {_localizer["sa_ban_perm_restricted"]}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duration <= Config.MaxBanDuration || canPermBan) return true;
|
||||
|
||||
caller.PrintToChat($"{_localizer!["sa_prefix"]} {_localizer["sa_ban_max_duration_exceeded", Config.MaxBanDuration]}");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_unban")]
|
||||
[RequiresPermissions("@css/unban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name or ip> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUnbanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
var callerSteamId = caller?.SteamID.ToString() ?? "Console";
|
||||
|
||||
if (command.GetArg(1).Length <= 1)
|
||||
{
|
||||
command.ReplyToCommand($"Too short pattern to search.");
|
||||
return;
|
||||
}
|
||||
|
||||
var pattern = command.GetArg(1);
|
||||
var reason = command.GetArg(2);
|
||||
|
||||
BanManager banManager = new(_database, Config);
|
||||
Task.Run(async () => await banManager.UnbanPlayer(pattern, callerSteamId, reason));
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
command.ReplyToCommand($"Unbanned player with pattern {pattern}.");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_warn")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnWarnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
if (command.ArgCount < 2)
|
||||
return;
|
||||
|
||||
var reason = _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList();
|
||||
|
||||
if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Database.Database database = new(_dbConnectionString);
|
||||
WarnManager warnManager = new(database);
|
||||
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
|
||||
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
|
||||
reason = command.GetArg(3);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Warn(caller, player, time, reason, callerName, warnManager, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void Warn(CCSPlayerController? caller, CCSPlayerController? player, int time, string reason, string? callerName = null, WarnManager? warnManager = null, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null || player is null || !player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
/*
|
||||
if (CheckValidBan(caller, time) == false)
|
||||
return;
|
||||
*/
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (player.PawnIsAlive)
|
||||
{
|
||||
player.Pawn.Value?.Freeze();
|
||||
|
||||
AddTimer(5.0f, () =>
|
||||
{
|
||||
player.Pawn.Value?.Unfreeze();
|
||||
});
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = new()
|
||||
{
|
||||
SteamId = player.SteamID.ToString(),
|
||||
UserId = player.UserId,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
PlayerInfo adminInfo = new()
|
||||
{
|
||||
SteamId = caller?.SteamID.ToString(),
|
||||
Name = caller?.PlayerName,
|
||||
IpAddress = caller?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
warnManager ??= new WarnManager(_database);
|
||||
await warnManager.WarnPlayer(playerInfo, adminInfo, reason, time);
|
||||
});
|
||||
|
||||
if (time == 0)
|
||||
{
|
||||
if (player is { IsBot: false })
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_warn_message_perm", reason, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_warn_message_perm",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!player.IsBot)
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_warn_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]);
|
||||
}
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_warn_message_time",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
reason,
|
||||
time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (warnManager == null) return;
|
||||
var totalWarns = await warnManager.GetPlayerWarnsCount(player.SteamID.ToString());
|
||||
|
||||
if (Config.WarnThreshold.Count != 0)
|
||||
{
|
||||
var punishCommand = string.Empty;
|
||||
|
||||
var lastKey = Config.WarnThreshold.Keys.MaxBy(key => key);
|
||||
|
||||
if (totalWarns >= lastKey)
|
||||
punishCommand = Config.WarnThreshold[lastKey];
|
||||
else if (Config.WarnThreshold.TryGetValue(totalWarns, out var value))
|
||||
punishCommand = value;
|
||||
|
||||
if (!string.IsNullOrEmpty(punishCommand))
|
||||
{
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
Server.PrintToChatAll(totalWarns.ToString());
|
||||
Server.ExecuteCommand(punishCommand.Replace("USERID", playerInfo.UserId?.ToString()).Replace("STEAMID64", playerInfo.SteamId));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Helper.LogCommand(caller, $"css_warn {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {time} {reason}");
|
||||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, Helper.PenaltyType.Warn, _localizer);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using System.Text;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_asay", "Say to all admins.")]
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminToAdminSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null || !caller.IsValid || command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0) return;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
|
||||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
foreach (var player in Helper.GetValidPlayers()
|
||||
.Where(p => AdminManager.PlayerHasPermissions(p, "@css/chat")))
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_adminchat_template_admin",
|
||||
caller == null ? "Console" : caller.PlayerName,
|
||||
utf8String);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_say", "Say to all players.")]
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0) return;
|
||||
|
||||
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
|
||||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_adminsay_prefix",
|
||||
utf8String);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_psay", "Private message a player.")]
|
||||
[CommandHelper(2, "<#userid or name> <message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminPrivateSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
//Helper.LogCommand(caller, command);
|
||||
|
||||
var range = command.GetArg(0).Length + command.GetArg(1).Length + 2;
|
||||
var message = command.GetCommandString[range..];
|
||||
|
||||
var utf8BytesString = Encoding.UTF8.GetBytes(message);
|
||||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
player.PrintToChat($"({callerName}) {utf8String}".ReplaceColorTags());
|
||||
});
|
||||
|
||||
command.ReplyToCommand($" Private message sent!".ReplaceColorTags());
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_csay", "Say to all players (in center).")]
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminCenterSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
|
||||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
Helper.PrintToCenterAll(utf8String.ReplaceColorTags());
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_hsay", "Say to all players (in hud).")]
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminHudSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
|
||||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
VirtualFunctions.ClientPrintAll(
|
||||
HudDestination.Alert,
|
||||
utf8String.ReplaceColorTags(),
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,793 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CS2_SimpleAdmin.Menus;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_sa_upgrade")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)]
|
||||
public void OnSaUpgradeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller != null || _database == null) return;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
var commandText = "ALTER TABLE `sa_mutes` CHANGE `type` `type` ENUM('GAG','MUTE', 'SILENCE', '') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'GAG';";
|
||||
|
||||
await using var commandSql = connection.CreateCommand();
|
||||
commandSql.CommandText = commandText;
|
||||
await commandSql.ExecuteNonQueryAsync();
|
||||
|
||||
commandText = "ALTER TABLE `sa_servers` MODIFY COLUMN `hostname` varchar(128);";
|
||||
await using var commandSql1 = connection.CreateCommand();
|
||||
commandSql1.CommandText = commandText;
|
||||
await commandSql1.ExecuteNonQueryAsync();
|
||||
|
||||
commandText = "ALTER TABLE `sa_bans` MODIFY `ends` TIMESTAMP NULL DEFAULT NULL;";
|
||||
await using var commandSql2 = connection.CreateCommand();
|
||||
commandSql2.CommandText = commandText;
|
||||
await commandSql2.ExecuteNonQueryAsync();
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
command.ReplyToCommand($"Successfully updated the database - {ModuleVersion}");
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_admin")]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void OnAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null || caller.IsValid == false)
|
||||
return;
|
||||
|
||||
AdminMenu.OpenMenu(caller);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_adminhelp")]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
public void OnAdminHelpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
//if (caller == null ||!caller.IsValid) return;
|
||||
|
||||
/*
|
||||
using (new WithTemporaryCulture(caller.GetLanguage()))
|
||||
{
|
||||
var splitMessage = _localizer!["sa_adminhelp"].ToString().Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||
|
||||
foreach (var line in splitMessage)
|
||||
{
|
||||
caller.PrintToChat(Helper.ReplaceTags($" {line}"));
|
||||
}
|
||||
} */
|
||||
|
||||
var lines = File.ReadAllLines(ModuleDirectory + "/admin_help.txt");
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
command.ReplyToCommand(string.IsNullOrWhiteSpace(line) ? " " : line.ReplaceColorTags());
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_addadmin")]
|
||||
[CommandHelper(minArgs: 4, usage: "<steamid> <name> <flags/groups> <immunity> <duration>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnAddAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
{
|
||||
command.ReplyToCommand($"Invalid SteamID64.");
|
||||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
|
||||
if (command.GetArg(2).Length <= 0)
|
||||
{
|
||||
command.ReplyToCommand($"Invalid player name.");
|
||||
return;
|
||||
}
|
||||
if (!command.GetArg(3).Contains('@') && !command.GetArg(3).Contains('#'))
|
||||
{
|
||||
command.ReplyToCommand($"Invalid flag or group.");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = command.GetArg(2);
|
||||
var flags = command.GetArg(3);
|
||||
var globalAdmin = command.GetArg(4).ToLower().Equals("-g") || command.GetArg(5).ToLower().Equals("-g") ||
|
||||
command.GetArg(6).ToLower().Equals("-g");
|
||||
int.TryParse(command.GetArg(4), out var immunity);
|
||||
int.TryParse(command.GetArg(5), out var time);
|
||||
|
||||
AddAdmin(caller, steamid, name, flags, immunity, time, globalAdmin, command);
|
||||
}
|
||||
|
||||
public static void AddAdmin(CCSPlayerController? caller, string steamid, string name, string flags, int immunity, int time = 0, bool globalAdmin = false, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null) return;
|
||||
PermissionManager adminManager = new(_database);
|
||||
|
||||
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
||||
_ = adminManager.AddAdminBySteamId(steamid, name, flagsList, immunity, time, globalAdmin);
|
||||
|
||||
Helper.LogCommand(caller, $"css_addadmin {steamid} {name} {flags} {immunity} {time}");
|
||||
|
||||
var msg = $"Added '{flags}' flags to '{name}' ({steamid})";
|
||||
if (command != null)
|
||||
command.ReplyToCommand(msg);
|
||||
else if (caller != null && caller.IsValid)
|
||||
caller.PrintToChat(msg);
|
||||
else
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_deladmin")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnDelAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
{
|
||||
command.ReplyToCommand($"Invalid SteamID64.");
|
||||
return;
|
||||
}
|
||||
|
||||
var globalDelete = command.GetArg(2).ToLower().Equals("-g");
|
||||
|
||||
RemoveAdmin(caller, steamId.SteamId64.ToString(), globalDelete, command);
|
||||
}
|
||||
|
||||
public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null) return;
|
||||
PermissionManager adminManager = new(_database);
|
||||
_ = adminManager.DeleteAdminBySteamId(steamid, globalDelete);
|
||||
|
||||
AddTimer(2, () =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(steamid) || !SteamID.TryParse(steamid, out var steamId) ||
|
||||
steamId == null) return;
|
||||
if (PermissionManager.AdminCache.ContainsKey(steamId))
|
||||
{
|
||||
PermissionManager.AdminCache.TryRemove(steamId, out _);
|
||||
}
|
||||
|
||||
AdminManager.ClearPlayerPermissions(steamId);
|
||||
AdminManager.RemovePlayerAdminData(steamId);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
Helper.LogCommand(caller, $"css_deladmin {steamid}");
|
||||
|
||||
var msg = $"Removed flags from '{steamid}'";
|
||||
if (command != null)
|
||||
command.ReplyToCommand(msg);
|
||||
else if (caller != null && caller.IsValid)
|
||||
caller.PrintToChat(msg);
|
||||
else
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_addgroup")]
|
||||
[CommandHelper(minArgs: 3, usage: "<group_name> <flags> <immunity>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnAddGroup(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
if (!command.GetArg(1).StartsWith("#"))
|
||||
{
|
||||
command.ReplyToCommand($"Group name must start with #.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!command.GetArg(2).StartsWith($"@") && !command.GetArg(2).StartsWith($"#"))
|
||||
{
|
||||
command.ReplyToCommand($"Invalid flag or group.");
|
||||
return;
|
||||
}
|
||||
|
||||
var groupName = command.GetArg(1);
|
||||
var flags = command.GetArg(2);
|
||||
int.TryParse(command.GetArg(3), out var immunity);
|
||||
var globalGroup = command.GetArg(4).ToLower().Equals("-g");
|
||||
|
||||
AddGroup(caller, groupName, flags, immunity, globalGroup, command);
|
||||
}
|
||||
|
||||
private static void AddGroup(CCSPlayerController? caller, string name, string flags, int immunity, bool globalGroup, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null) return;
|
||||
PermissionManager adminManager = new(_database);
|
||||
|
||||
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
||||
_ = adminManager.AddGroup(name, flagsList, immunity, globalGroup);
|
||||
|
||||
Helper.LogCommand(caller, $"css_addgroup {name} {flags} {immunity}");
|
||||
|
||||
var msg = $"Created group '{name}' with flags '{flags}'";
|
||||
if (command != null)
|
||||
command.ReplyToCommand(msg);
|
||||
else if (caller != null && caller.IsValid)
|
||||
caller.PrintToChat(msg);
|
||||
else
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_delgroup")]
|
||||
[CommandHelper(minArgs: 1, usage: "<group_name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnDelGroupCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
if (!command.GetArg(1).StartsWith($"#"))
|
||||
{
|
||||
command.ReplyToCommand($"Group name must start with #.");
|
||||
return;
|
||||
}
|
||||
|
||||
var groupName = command.GetArg(1);
|
||||
|
||||
RemoveGroup(caller, groupName, command);
|
||||
}
|
||||
|
||||
private void RemoveGroup(CCSPlayerController? caller, string name, CommandInfo? command = null)
|
||||
{
|
||||
if (_database == null) return;
|
||||
PermissionManager adminManager = new(_database);
|
||||
_ = adminManager.DeleteGroup(name);
|
||||
|
||||
AddTimer(2, () =>
|
||||
{
|
||||
ReloadAdmins(caller);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
Helper.LogCommand(caller, $"css_delgroup {name}");
|
||||
|
||||
var msg = $"Removed group '{name}'";
|
||||
if (command != null)
|
||||
command.ReplyToCommand(msg);
|
||||
else if (caller != null && caller.IsValid)
|
||||
caller.PrintToChat(msg);
|
||||
else
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_reloadadmins")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnRelAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
ReloadAdmins(caller);
|
||||
|
||||
command.ReplyToCommand("Reloaded sql admins and groups");
|
||||
}
|
||||
|
||||
public void ReloadAdmins(CCSPlayerController? caller)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
PermissionManager adminManager = new(_database);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await adminManager.CrateGroupsJsonFile();
|
||||
await adminManager.CreateAdminsJsonFile();
|
||||
|
||||
var adminsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/admins.json") ?? "";
|
||||
var groupsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/groups.json") ?? "";
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(0.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
if (!string.IsNullOrEmpty(groupsFile))
|
||||
AddTimer(1.0f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json"));
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(1.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
});
|
||||
});
|
||||
|
||||
//_ = _adminManager.GiveAllGroupsFlags();
|
||||
//_ = _adminManager.GiveAllFlags();
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_stealth")]
|
||||
[ConsoleCommand("css_hide")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnHideCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null) return;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
if (!SilentPlayers.Add(caller.Slot))
|
||||
{
|
||||
SilentPlayers.Remove(caller.Slot);
|
||||
caller.PrintToChat($"You aren't hidden now!");
|
||||
caller.ChangeTeam(CsTeam.Spectator);
|
||||
}
|
||||
else
|
||||
{
|
||||
Server.ExecuteCommand("sv_disable_teamselect_menu 1");
|
||||
|
||||
if (caller.PlayerPawn.Value != null && caller.PawnIsAlive)
|
||||
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);
|
||||
caller.PrintToChat($"You are hidden now!");
|
||||
AddTimer(2.0f, () => { Server.NextFrame(() => Server.ExecuteCommand("sv_disable_teamselect_menu 0")); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_who")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
public void OnWhoCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
//Helper.SendDiscordLogMessage(caller, command, _discordWebhookClientLog, _localizer);
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
Database.Database database = new(_dbConnectionString);
|
||||
BanManager banManager = new(database, Config);
|
||||
MuteManager muteManager = new(_database);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (!player.UserId.HasValue) return;
|
||||
if (!caller!.CanTarget(player)) return;
|
||||
PlayerInfo playerInfo = new()
|
||||
{
|
||||
UserId = player.UserId.Value,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var totalBans = await banManager.GetPlayerBans(playerInfo);
|
||||
var totalMutes = await muteManager.GetPlayerMutes(playerInfo.SteamId);
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
Action<string> printMethod = caller == null ? Server.PrintToConsole : caller.PrintToConsole;
|
||||
|
||||
printMethod($"--------- INFO ABOUT \"{playerInfo.Name}\" ---------");
|
||||
|
||||
printMethod($"• Clan: \"{player.Clan}\" Name: \"{playerInfo.Name}\"");
|
||||
printMethod($"• UserID: \"{playerInfo.UserId}\"");
|
||||
if (playerInfo.SteamId != null)
|
||||
printMethod($"• SteamID64: \"{playerInfo.SteamId}\"");
|
||||
if (player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
{
|
||||
printMethod($"• SteamID2: \"{player.SteamID}\"");
|
||||
printMethod($"• Community link: \"{new SteamID(player.SteamID).ToCommunityUrl()}\"");
|
||||
}
|
||||
if (playerInfo.IpAddress != null && AdminManager.PlayerHasPermissions(caller, "@css/showip"))
|
||||
printMethod($"• IP Address: \"{playerInfo.IpAddress}\"");
|
||||
printMethod($"• Ping: \"{player.Ping}\"");
|
||||
if (player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
{
|
||||
printMethod($"• Total Bans: \"{totalBans}\"");
|
||||
printMethod($"• Total Mutes: \"{totalMutes}\"");
|
||||
}
|
||||
|
||||
printMethod($"--------- END INFO ABOUT \"{player.PlayerName}\" ---------");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_warns")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnWarnsCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (_database == null) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsBot: false }).ToList();
|
||||
|
||||
if (playersToTarget.Count > 1)
|
||||
return;
|
||||
|
||||
Database.Database database = new(_dbConnectionString);
|
||||
WarnManager warnManager = new(database);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (!player.UserId.HasValue) return;
|
||||
if (!caller!.CanTarget(player)) return;
|
||||
|
||||
var steamid = player.SteamID.ToString();
|
||||
|
||||
BaseMenu warnsMenu = Config.UseChatMenu
|
||||
? new ChatMenu(_localizer!["sa_admin_warns_menu_title", player.PlayerName])
|
||||
: new CenterHtmlMenu(_localizer!["sa_admin_warns_menu_title", player.PlayerName], Instance);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var warnsList = await warnManager.GetPlayerWarns(steamid, false);
|
||||
var sortedWarns = warnsList
|
||||
.OrderBy(warn => (string)warn.status == "ACTIVE" ? 0 : 1)
|
||||
.ThenByDescending(warn => (int)warn.id)
|
||||
.ToList();
|
||||
|
||||
sortedWarns.ForEach(w =>
|
||||
{
|
||||
warnsMenu.AddMenuOption($"[{((string)w.status == "ACTIVE" ? $"{ChatColors.LightRed}X" : $"{ChatColors.Lime}✔️")}{ChatColors.Default}] {(string)w.reason}",
|
||||
(controller, option) =>
|
||||
{
|
||||
_ = warnManager.UnwarnPlayer(steamid, (int)w.id);
|
||||
player.PrintToChat(_localizer["sa_admin_warns_unwarn", player.PlayerName, (string)w.reason]);
|
||||
});
|
||||
});
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
warnsMenu.Open(player);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_players")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
public void OnPlayersCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var isJson = command.GetArg(1).ToLower().Equals("-json");
|
||||
var isDuplicate = command.GetArg(1).ToLower().Equals("-duplicate") || command.GetArg(2).ToLower().Equals("-duplicate");
|
||||
|
||||
var playersToTarget = isDuplicate
|
||||
? Helper.GetValidPlayers().GroupBy(player => player.IpAddress?.Split(":")[0] ?? "Unknown")
|
||||
.Where(group => group.Count() > 1)
|
||||
.SelectMany(group => group)
|
||||
.ToList()
|
||||
: Helper.GetValidPlayers();
|
||||
|
||||
if (!isJson)
|
||||
{
|
||||
if (caller != null)
|
||||
{
|
||||
caller.PrintToConsole($"--------- PLAYER LIST ---------");
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
caller.PrintToConsole(
|
||||
$"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{(AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] : "Unknown")}\" SteamID64: \"{player.SteamID}\")");
|
||||
});
|
||||
caller.PrintToConsole($"--------- END PLAYER LIST ---------");
|
||||
}
|
||||
else
|
||||
{
|
||||
Server.PrintToConsole($"--------- PLAYER LIST ---------");
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")");
|
||||
});
|
||||
Server.PrintToConsole($"--------- END PLAYER LIST ---------");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var playersJson = JsonConvert.SerializeObject(playersToTarget.Select((CCSPlayerController player) =>
|
||||
{
|
||||
var matchStats = player.ActionTrackingServices?.MatchStats;
|
||||
|
||||
return new
|
||||
{
|
||||
player.UserId,
|
||||
Name = player.PlayerName,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
IpAddress = AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] ?? "Unknown" : "Unknown",
|
||||
player.Ping,
|
||||
IsAdmin = AdminManager.PlayerHasPermissions(player, "@css/ban") || AdminManager.PlayerHasPermissions(player, "@css/generic"),
|
||||
Stats = new
|
||||
{
|
||||
player.Score,
|
||||
Kills = matchStats?.Kills ?? 0,
|
||||
Deaths = matchStats?.Deaths ?? 0,
|
||||
player.MVPs
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
if (caller != null)
|
||||
caller.PrintToConsole(playersJson);
|
||||
else
|
||||
Server.PrintToConsole(playersJson);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_kick")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnKickCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var reason = _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players
|
||||
.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.ArgCount >= 2 && command.GetArg(2).Length > 0)
|
||||
reason = command.GetArg(2);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (!player.IsValid)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Kick(caller, player, reason, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Kick(CCSPlayerController? caller, CCSPlayerController? player, string? reason = "Unknown", string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
reason ??= _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
player.Pawn.Value!.Freeze();
|
||||
|
||||
Helper.LogCommand(caller, $"css_kick {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {reason}");
|
||||
|
||||
if (string.IsNullOrEmpty(reason) == false)
|
||||
{
|
||||
if (!player.IsBot)
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
player.PrintToCenter(_localizer!["sa_player_kick_message", reason, callerName]);
|
||||
}
|
||||
if (player.UserId.HasValue)
|
||||
AddTimer(Config.KickTime, () => Helper.KickPlayer(player.UserId.Value, reason),
|
||||
CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player.UserId.HasValue)
|
||||
AddTimer(Config.KickTime, () => Helper.KickPlayer(player.UserId.Value),
|
||||
CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
if (caller != null && (caller.UserId == null || SilentPlayers.Contains(caller.Slot))) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_kick_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty,
|
||||
reason);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_changemap")]
|
||||
[ConsoleCommand("css_map")]
|
||||
[RequiresPermissions("@css/changemap")]
|
||||
[CommandHelper(minArgs: 1, usage: "<mapname>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnMapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var map = command.GetCommandString.Split(" ")[1];
|
||||
ChangeMap(caller, map, command);
|
||||
}
|
||||
|
||||
public void ChangeMap(CCSPlayerController? caller, string map, CommandInfo? command = null)
|
||||
{
|
||||
map = map.ToLower();
|
||||
|
||||
if (map.StartsWith("ws:"))
|
||||
{
|
||||
var issuedCommand = long.TryParse(map.Replace("ws:", ""), out var mapId)
|
||||
? $"host_workshop_map {mapId}"
|
||||
: $"ds_workshop_changelevel {map.Replace("ws:", "")}";
|
||||
|
||||
AddTimer(3.0f, () =>
|
||||
{
|
||||
Server.ExecuteCommand(issuedCommand);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Server.IsMapValid(map))
|
||||
{
|
||||
var msg = $"Map {map} not found.";
|
||||
if (command != null)
|
||||
command.ReplyToCommand(msg);
|
||||
else if (caller != null && caller.IsValid)
|
||||
caller.PrintToChat(msg);
|
||||
else
|
||||
Server.PrintToConsole(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
AddTimer(3.0f, () =>
|
||||
{
|
||||
Server.ExecuteCommand($"changelevel {map}");
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_changemap_message",
|
||||
caller == null ? "Console" : caller.PlayerName,
|
||||
map);
|
||||
}
|
||||
}
|
||||
|
||||
Helper.LogCommand(caller, command?.GetCommandString ?? $"css_map {map}");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_changewsmap", "Change workshop map.")]
|
||||
[ConsoleCommand("css_wsmap", "Change workshop map.")]
|
||||
[ConsoleCommand("css_workshop", "Change workshop map.")]
|
||||
[CommandHelper(1, "<name or id>")]
|
||||
[RequiresPermissions("@css/changemap")]
|
||||
public void OnWorkshopMapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var map = command.GetArg(1);
|
||||
ChangeWorkshopMap(caller, map, command);
|
||||
}
|
||||
|
||||
public void ChangeWorkshopMap(CCSPlayerController? caller, string map, CommandInfo? command = null)
|
||||
{
|
||||
map = map.ToLower();
|
||||
|
||||
var issuedCommand = long.TryParse(map, out var mapId) ? $"host_workshop_map {mapId}" : $"ds_workshop_changelevel {map}";
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_changemap_message",
|
||||
caller == null ? "Console" : caller.PlayerName,
|
||||
map);
|
||||
}
|
||||
}
|
||||
|
||||
AddTimer(3.0f, () =>
|
||||
{
|
||||
Server.ExecuteCommand(issuedCommand);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
Helper.LogCommand(caller, command?.GetCommandString ?? $"css_wsmap {map}");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_cvar", "Change a cvar.")]
|
||||
[CommandHelper(2, "<cvar> <value>")]
|
||||
[RequiresPermissions("@css/cvar")]
|
||||
public void OnCvarCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var cvar = ConVar.Find(command.GetArg(1));
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (cvar == null)
|
||||
{
|
||||
command.ReplyToCommand($"Cvar \"{command.GetArg(1)}\" not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cvar.Name.Equals("sv_cheats") && !AdminManager.PlayerHasPermissions(caller, "@css/cheats"))
|
||||
{
|
||||
command.ReplyToCommand($"You don't have permissions to change \"{command.GetArg(1)}\".");
|
||||
return;
|
||||
}
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
var value = command.GetArg(2);
|
||||
|
||||
Server.ExecuteCommand($"{cvar.Name} {value}");
|
||||
|
||||
command.ReplyToCommand($"{callerName} changed cvar {cvar.Name} to {value}.");
|
||||
Logger.LogInformation($"{callerName} changed cvar {cvar.Name} to {value}.");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_rcon", "Run a server console command.")]
|
||||
[CommandHelper(1, "<command>")]
|
||||
[RequiresPermissions("@css/rcon")]
|
||||
public void OnRconCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
Server.ExecuteCommand(command.ArgString);
|
||||
command.ReplyToCommand($"{callerName} executed command {command.ArgString}.");
|
||||
Logger.LogInformation($"{callerName} executed command ({command.ArgString}).");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_rr")]
|
||||
[ConsoleCommand("css_rg")]
|
||||
[ConsoleCommand("css_restart")]
|
||||
[ConsoleCommand("css_restartgame")]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(minArgs: 0, usage: "", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnRestartCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
RestartGame(caller);
|
||||
}
|
||||
|
||||
public static void RestartGame(CCSPlayerController? admin)
|
||||
{
|
||||
Helper.LogCommand(admin, "css_restartgame");
|
||||
|
||||
// TODO: Localize
|
||||
var name = admin == null ? "Console" : admin.PlayerName;
|
||||
Server.PrintToChatAll($"[SA] {name}: Restarting game...");
|
||||
Server.ExecuteCommand("mp_restartgame 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,95 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_vote")]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(minArgs: 2, usage: "<question> [... options ...]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnVoteCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (command.ArgCount < 2)
|
||||
return;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
VoteAnswers.Clear();
|
||||
|
||||
var question = command.GetArg(1);
|
||||
var answersCount = command.ArgCount;
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
for (var i = 2; i <= answersCount - 1; i++)
|
||||
{
|
||||
VoteAnswers.Add(command.GetArg(i), 0);
|
||||
}
|
||||
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
using (new WithTemporaryCulture(player.GetLanguage()))
|
||||
{
|
||||
BaseMenu voteMenu = Config.UseChatMenu
|
||||
? new ChatMenu(_localizer!["sa_admin_vote_menu_title", question])
|
||||
: new CenterHtmlMenu(_localizer!["sa_admin_vote_menu_title", question], Instance);
|
||||
//ChatMenu voteMenu = new(_localizer!["sa_admin_vote_menu_title", question]);
|
||||
|
||||
for (var i = 2; i <= answersCount - 1; i++)
|
||||
{
|
||||
voteMenu.AddMenuOption(command.GetArg(i), Helper.HandleVotes);
|
||||
}
|
||||
|
||||
voteMenu.PostSelectAction = PostSelectAction.Close;
|
||||
|
||||
Helper.PrintToCenterAll(_localizer["sa_admin_vote_message", caller == null ? "Console" : caller.PlayerName, question]);
|
||||
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_vote_message",
|
||||
caller == null ? "Console" : caller.PlayerName,
|
||||
question);
|
||||
|
||||
voteMenu.Open(player);
|
||||
|
||||
//MenuManager.OpenChatMenu(player, voteMenu);
|
||||
}
|
||||
}
|
||||
|
||||
VoteInProgress = true;
|
||||
}
|
||||
|
||||
if (VoteInProgress)
|
||||
{
|
||||
AddTimer(30, () =>
|
||||
{
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_vote_message_results",
|
||||
question);
|
||||
}
|
||||
|
||||
foreach (var (key, value) in VoteAnswers)
|
||||
{
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
if (_localizer != null)
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_vote_message_results_answer",
|
||||
key,
|
||||
value);
|
||||
}
|
||||
}
|
||||
VoteAnswers.Clear();
|
||||
VoteInProgress = false;
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_noclip", "Noclip a player.")]
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
public void OnNoclipCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player.IsValid &&
|
||||
player is { PawnIsAlive: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
NoClip(caller, player, callerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void NoClip(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
player!.Pawn.Value!.ToggleNoclip();
|
||||
|
||||
Helper.LogCommand(caller, $"css_noclip {player.PlayerName}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_noclip_message",
|
||||
callerName,
|
||||
player.PlayerName);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_freeze", "Freeze a player.")]
|
||||
[CommandHelper(1, "<#userid or name> [duration]")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
public void OnFreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Freeze(caller, player, time, callerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Freeze(CCSPlayerController? caller, CCSPlayerController? player, int time, string? callerName = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player?.Pawn.Value!.Freeze();
|
||||
|
||||
Helper.LogCommand(caller, $"css_freeze {player?.PlayerName}");
|
||||
|
||||
if (time > 0)
|
||||
AddTimer(time, () => player?.Pawn.Value!.Unfreeze(), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_freeze_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_unfreeze", "Unfreeze a player.")]
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
public void OnUnfreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
Unfreeze(caller, player, callerName, command);
|
||||
});
|
||||
}
|
||||
|
||||
public void Unfreeze(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player!.Pawn.Value!.Unfreeze();
|
||||
|
||||
Helper.LogCommand(caller, $"css_unfreeze {player?.PlayerName}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_unfreeze_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,784 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
[ConsoleCommand("css_slay")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSlayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
Slay(caller, player, callerName, command);
|
||||
});
|
||||
}
|
||||
|
||||
public void Slay(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player?.CommitSuicide(false, true);
|
||||
|
||||
Helper.LogCommand(caller, $"css_slay {player?.PlayerName}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_slay_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_give")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 2, usage: "<#userid or name> <weapon>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGiveCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
var weaponName = command.GetArg(2);
|
||||
|
||||
// check if item is typed
|
||||
if (weaponName.Length < 5)
|
||||
{
|
||||
command.ReplyToCommand($"No weapon typed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if item is valid
|
||||
if (!weaponName.Contains("weapon_") && !weaponName.Contains("item_"))
|
||||
{
|
||||
command.ReplyToCommand($"{weaponName} is not a valid item.");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if weapon is knife
|
||||
if (weaponName.Contains("_knife") || weaponName.Contains("bayonet"))
|
||||
{
|
||||
if (CoreConfig.FollowCS2ServerGuidelines)
|
||||
{
|
||||
command.ReplyToCommand($"Cannot Give {weaponName} because it's illegal to be given.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
GiveWeapon(caller, player, weaponName, callerName, command);
|
||||
});
|
||||
}
|
||||
|
||||
public void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, CsItem weapon, string? callerName = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
Helper.LogCommand(caller, $"css_give {player.PlayerName} {weapon.ToString()}");
|
||||
|
||||
player.GiveNamedItem(weapon);
|
||||
SubGiveWeapon(caller, player, weapon.ToString(), callerName);
|
||||
}
|
||||
|
||||
private void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
Helper.LogCommand(caller, $"css_give {player.PlayerName} {weaponName}");
|
||||
|
||||
player.GiveNamedItem(weaponName);
|
||||
SubGiveWeapon(caller, player, weaponName, callerName);
|
||||
}
|
||||
|
||||
private void SubGiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (caller != null && (SilentPlayers.Contains(caller.Slot))) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_give_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty,
|
||||
weaponName);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_strip")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnStripCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
StripWeapons(caller, player, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void StripWeapons(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (player == null || !player.IsValid || !player.PawnIsAlive || player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
player.RemoveWeapons();
|
||||
|
||||
Helper.LogCommand(caller, $"css_strip {player.PlayerName}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_strip_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_hp")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <health>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnHpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
int.TryParse(command.GetArg(2), out var health);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
SetHp(caller, player, health, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SetHp(CCSPlayerController? caller, CCSPlayerController? player, int health, CommandInfo? command = null)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.IsHLTV)
|
||||
return;
|
||||
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player.SetHp(health);
|
||||
|
||||
Helper.LogCommand(caller, $"css_hp {player.PlayerName} {health}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_hp_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_speed")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <speed>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSpeedCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
double.TryParse(command.GetArg(2), out var speed);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
SetSpeed(caller, player, speed, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SetSpeed(CCSPlayerController? caller, CCSPlayerController? player, double speed, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player.SetSpeed((float)speed);
|
||||
|
||||
Helper.LogCommand(caller, $"css_speed {player?.PlayerName} {speed}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_speed_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_gravity")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <gravity>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGravityCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
double.TryParse(command.GetArg(2), out var gravity);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
SetGravity(caller, player, gravity, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SetGravity(CCSPlayerController? caller, CCSPlayerController? player, double gravity, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player.SetGravity((float)gravity);
|
||||
|
||||
Helper.LogCommand(caller, $"css_gravity {player?.PlayerName} {gravity}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_gravity_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_money")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <money>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnMoneyCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
int.TryParse(command.GetArg(2), out var money);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
SetMoney(caller, player, money, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SetMoney(CCSPlayerController? caller, CCSPlayerController? player, int money, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
player.SetMoney(money);
|
||||
|
||||
Helper.LogCommand(caller, $"css_money {player?.PlayerName} {money}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_money_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_god")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGodCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
God(caller, player, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void God(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
Helper.LogCommand(caller, $"css_god {player.PlayerName}");
|
||||
|
||||
if (!GodPlayers.Add(player.Slot))
|
||||
{
|
||||
GodPlayers.Remove(player.Slot);
|
||||
}
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_god_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_slap")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [damage]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSlapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var damage = 0;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { PawnIsAlive: true, IsHLTV: false }).ToList();
|
||||
|
||||
if (command.ArgCount >= 2)
|
||||
{
|
||||
int.TryParse(command.GetArg(2), out damage);
|
||||
}
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Slap(caller, player, damage, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Slap(CCSPlayerController? caller, CCSPlayerController? player, int damage, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
player!.Pawn.Value!.Slap(damage);
|
||||
|
||||
Helper.LogCommand(caller, $"css_slap {player?.PlayerName} {damage}");
|
||||
|
||||
if (_localizer == null)
|
||||
return;
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_slap_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_team")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 2, usage: "<#userid or name> [<ct/tt/spec>] [-k]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnTeamCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var teamName = command.GetArg(2).ToLower();
|
||||
var _teamName = "SPEC";
|
||||
var teamNum = CsTeam.Spectator;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
switch (teamName)
|
||||
{
|
||||
case "ct":
|
||||
case "counterterrorist":
|
||||
teamNum = CsTeam.CounterTerrorist;
|
||||
_teamName = "CT";
|
||||
break;
|
||||
|
||||
case "t":
|
||||
case "tt":
|
||||
case "terrorist":
|
||||
teamNum = CsTeam.Terrorist;
|
||||
_teamName = "TT";
|
||||
break;
|
||||
|
||||
case "swap":
|
||||
_teamName = "SWAP";
|
||||
break;
|
||||
|
||||
default:
|
||||
teamNum = CsTeam.Spectator;
|
||||
_teamName = "SPEC";
|
||||
break;
|
||||
}
|
||||
|
||||
var kill = command.GetArg(3).ToLower().Equals("-k");
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
ChangeTeam(caller, player, _teamName, teamNum, kill, callerName, command);
|
||||
});
|
||||
}
|
||||
|
||||
public void ChangeTeam(CCSPlayerController? caller, CCSPlayerController? player, string teamName, CsTeam teamNum, bool kill, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (!teamName.Equals("swap"))
|
||||
{
|
||||
if (player.PawnIsAlive && teamNum != CsTeam.Spectator && !kill && Config.TeamSwitchType == 1)
|
||||
player.SwitchTeam(teamNum);
|
||||
else
|
||||
player?.ChangeTeam(teamNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player.TeamNum != (byte)CsTeam.Spectator)
|
||||
{
|
||||
var _teamNum = (CsTeam)player.TeamNum == CsTeam.Terrorist ? CsTeam.CounterTerrorist : CsTeam.Terrorist;
|
||||
teamName = _teamNum == CsTeam.Terrorist ? "TT" : "CT";
|
||||
if (player.PawnIsAlive && !kill && Config.TeamSwitchType == 1)
|
||||
{
|
||||
player.SwitchTeam(_teamNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ChangeTeam(_teamNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_team_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty,
|
||||
teamName);
|
||||
}
|
||||
}
|
||||
|
||||
Helper.LogCommand(caller, $"css_team {player?.PlayerName} {teamName}");
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_rename", "Rename a player.")]
|
||||
[CommandHelper(1, "<#userid or name> <new name>")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnRenameCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var newName = command.GetArg(2);
|
||||
|
||||
if (string.IsNullOrEmpty(newName))
|
||||
return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (!caller!.CanTarget(player)) return;
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_rename_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty,
|
||||
newName);
|
||||
}
|
||||
}
|
||||
|
||||
player.Rename(newName);
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_prename", "Permanent rename a player.")]
|
||||
[CommandHelper(1, "<#userid or name> <new name>")]
|
||||
[RequiresPermissions("@css/ban")]
|
||||
public void OnPRenameCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var newName = command.GetArg(2);
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (!caller!.CanTarget(player)) return;
|
||||
if (caller == null || !SilentPlayers.Contains(caller.Slot) && !string.IsNullOrEmpty(newName))
|
||||
{
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_rename_message",
|
||||
callerName,
|
||||
player.PlayerName ?? string.Empty,
|
||||
newName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(newName))
|
||||
{
|
||||
RenamedPlayers[player.SteamID] = newName;
|
||||
}
|
||||
else
|
||||
{
|
||||
RenamedPlayers.Remove(player.SteamID);
|
||||
}
|
||||
|
||||
player.Rename(newName);
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_respawn", "Respawn a dead player.")]
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
public void OnRespawnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected)
|
||||
return;
|
||||
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Respawn(caller, player, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Respawn(CCSPlayerController? caller, CCSPlayerController? player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
callerName ??= caller == null ? "Console" : caller.PlayerName;
|
||||
|
||||
if (_cBasePlayerControllerSetPawnFunc == null || player?.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) return;
|
||||
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
_cBasePlayerControllerSetPawnFunc.Invoke(player, playerPawn, true, false);
|
||||
VirtualFunction.CreateVoid<CCSPlayerController>(player.Handle,
|
||||
GameData.GetOffset("CCSPlayerController_Respawn"))(player);
|
||||
|
||||
Helper.LogCommand(caller, $"css_respawn {player?.PlayerName}");
|
||||
|
||||
if (caller != null && SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_respawn_message",
|
||||
callerName,
|
||||
player?.PlayerName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_tp", "Teleport to a player.")]
|
||||
[ConsoleCommand("css_tpto", "Teleport to a player.")]
|
||||
[ConsoleCommand("css_goto", "Teleport to a player.")]
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnGotoCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null || !caller.PawnIsAlive) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
||||
if (targets == null || targets.Count() > 1)
|
||||
return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected || !player.PawnIsAlive)
|
||||
return;
|
||||
|
||||
if (!caller.CanTarget(player)) return;
|
||||
caller.TeleportPlayer(player);
|
||||
caller.Pawn.Value!.ToggleNoclip();
|
||||
|
||||
AddTimer(3, () =>
|
||||
{
|
||||
caller.Pawn.Value!.ToggleNoclip();
|
||||
});
|
||||
|
||||
if (SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_tp_message",
|
||||
caller.PlayerName,
|
||||
player.PlayerName ?? string.Empty);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_bring", "Teleport a player to you.")]
|
||||
[ConsoleCommand("css_tphere", "Teleport a player to you.")]
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnBringCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null || !caller.PawnIsAlive) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
||||
if (targets == null || targets.Count() > 1)
|
||||
return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (player.Connected != PlayerConnectedState.PlayerConnected || !player.PawnIsAlive)
|
||||
return;
|
||||
|
||||
if (!caller.CanTarget(player)) return;
|
||||
player.TeleportPlayer(caller);
|
||||
caller.Pawn.Value!.ToggleNoclip();
|
||||
|
||||
AddTimer(3, () =>
|
||||
{
|
||||
caller.Pawn.Value!.ToggleNoclip();
|
||||
});
|
||||
|
||||
if (SilentPlayers.Contains(caller.Slot)) return;
|
||||
foreach (var controller in Helper.GetValidPlayers().Where(controller => controller is { IsValid: true, IsBot: false }))
|
||||
{
|
||||
if (_localizer != null)
|
||||
controller.SendLocalizedMessage(_localizer,
|
||||
"sa_admin_bring_message",
|
||||
caller.PlayerName,
|
||||
player.PlayerName ?? string.Empty);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
254
Config.cs
254
Config.cs
@@ -1,254 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public class DurationItem
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("duration")]
|
||||
public int Duration { get; set; }
|
||||
}
|
||||
|
||||
public class AdminFlag
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("flag")]
|
||||
public required string Flag { get; set; }
|
||||
}
|
||||
|
||||
public class DiscordPenaltySetting
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
public string Value { get; set; } = "";
|
||||
}
|
||||
|
||||
public class Discord
|
||||
{
|
||||
[JsonPropertyName("DiscordLogWebhook")]
|
||||
public string DiscordLogWebhook { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("DiscordPenaltyBanSettings")]
|
||||
public DiscordPenaltySetting[] DiscordPenaltyBanSettings { 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 = "" },
|
||||
];
|
||||
|
||||
[JsonPropertyName("DiscordPenaltyMuteSettings")]
|
||||
public DiscordPenaltySetting[] DiscordPenaltyMuteSettings { 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 = "" },
|
||||
];
|
||||
|
||||
[JsonPropertyName("DiscordPenaltyGagSettings")]
|
||||
public DiscordPenaltySetting[] DiscordPenaltyGagSettings { 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 = "" },
|
||||
];
|
||||
|
||||
[JsonPropertyName("DiscordPenaltySilenceSettings")]
|
||||
public DiscordPenaltySetting[] DiscordPenaltySilenceSettings { 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 = "" },
|
||||
];
|
||||
|
||||
[JsonPropertyName("DiscordPenaltyWarnSettings")]
|
||||
public DiscordPenaltySetting[] DiscordPenaltyWarnSettings { 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 = "" },
|
||||
];
|
||||
}
|
||||
|
||||
public class CustomServerCommandData
|
||||
{
|
||||
[JsonPropertyName("Flag")]
|
||||
public string Flag { get; set; } = "@css/generic";
|
||||
|
||||
[JsonPropertyName("DisplayName")]
|
||||
public string DisplayName { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("Command")]
|
||||
public string Command { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("ExecuteOnClient")]
|
||||
public bool ExecuteOnClient { get; set; } = false;
|
||||
}
|
||||
|
||||
public class MenuConfig
|
||||
{
|
||||
[JsonPropertyName("Durations")]
|
||||
public DurationItem[] Durations { get; set; } =
|
||||
[
|
||||
new DurationItem { Name = "1 minute", Duration = 1 },
|
||||
new DurationItem { Name = "5 minutes", Duration = 5 },
|
||||
new DurationItem { Name = "15 minutes", Duration = 15 },
|
||||
new DurationItem { Name = "1 hour", Duration = 60 },
|
||||
new DurationItem { Name = "1 day", Duration = 60 * 24 },
|
||||
new DurationItem { Name = "7 days", Duration = 60 * 24 * 7 },
|
||||
new DurationItem { Name = "14 days", Duration = 60 * 24 * 14 },
|
||||
new DurationItem { Name = "30 days", Duration = 60 * 24 * 30 },
|
||||
new DurationItem { Name = "Permanent", Duration = 0 }
|
||||
];
|
||||
|
||||
[JsonPropertyName("BanReasons")]
|
||||
public List<string> BanReasons { get; set; } =
|
||||
[
|
||||
"Hacking",
|
||||
"Voice Abuse",
|
||||
"Chat Abuse",
|
||||
"Admin disrespect",
|
||||
"Other"
|
||||
];
|
||||
|
||||
[JsonPropertyName("KickReasons")]
|
||||
public List<string> KickReasons { get; set; } =
|
||||
[
|
||||
"Voice Abuse",
|
||||
"Chat Abuse",
|
||||
"Admin disrespect",
|
||||
"Other"
|
||||
];
|
||||
|
||||
[JsonPropertyName("WarnReasons")]
|
||||
public List<string> WarnReasons { get; set; } =
|
||||
[
|
||||
"Voice Abuse",
|
||||
"Chat Abuse",
|
||||
"Admin disrespect",
|
||||
"Other"
|
||||
];
|
||||
|
||||
[JsonPropertyName("MuteReasons")]
|
||||
public List<string> MuteReasons { get; set; } =
|
||||
[
|
||||
"Advertising",
|
||||
"Spamming",
|
||||
"Spectator camera abuse",
|
||||
"Hate",
|
||||
"Admin disrespect",
|
||||
"Other"
|
||||
];
|
||||
|
||||
[JsonPropertyName("AdminFlags")]
|
||||
public AdminFlag[] AdminFlags { get; set; } =
|
||||
[
|
||||
new AdminFlag { Name = "Generic", Flag = "@css/generic" },
|
||||
new AdminFlag { Name = "Chat", Flag = "@css/chat" },
|
||||
new AdminFlag { Name = "Change Map", Flag = "@css/changemap" },
|
||||
new AdminFlag { Name = "Slay", Flag = "@css/slay" },
|
||||
new AdminFlag { Name = "Kick", Flag = "@css/kick" },
|
||||
new AdminFlag { Name = "Ban", Flag = "@css/ban" },
|
||||
new AdminFlag { Name = "Perm Ban", Flag = "@css/permban" },
|
||||
new AdminFlag { Name = "Unban", Flag = "@css/unban" },
|
||||
new AdminFlag { Name = "Show IP", Flag = "@css/showip" },
|
||||
new AdminFlag { Name = "Cvar", Flag = "@css/cvar" },
|
||||
new AdminFlag { Name = "Rcon", Flag = "@css/rcon" },
|
||||
new AdminFlag { Name = "Root (all flags)", Flag = "@css/root" }
|
||||
];
|
||||
}
|
||||
|
||||
public class CS2_SimpleAdminConfig : BasePluginConfig
|
||||
{
|
||||
[JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 18;
|
||||
|
||||
[JsonPropertyName("DatabaseHost")]
|
||||
public string DatabaseHost { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("DatabasePort")]
|
||||
public int DatabasePort { get; set; } = 3306;
|
||||
|
||||
[JsonPropertyName("DatabaseUser")]
|
||||
public string DatabaseUser { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("DatabasePassword")]
|
||||
public string DatabasePassword { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("DatabaseName")]
|
||||
public string DatabaseName { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("EnableMetrics")]
|
||||
public bool EnableMetrics { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("EnableUpdateCheck")]
|
||||
public bool EnableUpdateCheck { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("ReloadAdminsEveryMapChange")]
|
||||
public bool ReloadAdminsEveryMapChange { get; set; } = false;
|
||||
|
||||
[JsonPropertyName("UseChatMenu")]
|
||||
public bool UseChatMenu { get; set; } = false;
|
||||
|
||||
[JsonPropertyName("KickTime")]
|
||||
public int KickTime { get; set; } = 5;
|
||||
|
||||
[JsonPropertyName("WarnThreshold")]
|
||||
public Dictionary<int, string> WarnThreshold { get; set; } = new()
|
||||
{
|
||||
{ 998, "css_addban STEAMID64 60 \"3/4 Warn\"" },
|
||||
{ 999, "css_ban #USERID 120 \"4/4 Warn\"" },
|
||||
};
|
||||
|
||||
[JsonPropertyName("DisableDangerousCommands")]
|
||||
public bool DisableDangerousCommands { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("BanType")]
|
||||
public int BanType { get; set; } = 1;
|
||||
|
||||
[JsonPropertyName("TimeMode")]
|
||||
public int TimeMode { get; set; } = 1;
|
||||
|
||||
[JsonPropertyName("MaxBanDuration")]
|
||||
public int MaxBanDuration { get; set; } = 60 * 24 * 7;
|
||||
|
||||
[JsonPropertyName("MultiServerMode")]
|
||||
public bool MultiServerMode { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("ExpireOldIpBans")]
|
||||
public int ExpireOldIpBans { get; set; } = 0;
|
||||
|
||||
[JsonPropertyName("TeamSwitchType")]
|
||||
public int TeamSwitchType { get; set; } = 1;
|
||||
|
||||
[JsonPropertyName("Discord")]
|
||||
public Discord Discord { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("DefaultMaps")]
|
||||
public List<string> DefaultMaps { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("WorkshopMaps")]
|
||||
public Dictionary<string, long?> WorkshopMaps { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("CustomServerCommands")]
|
||||
public List<CustomServerCommandData> CustomServerCommands { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("MenuConfig")]
|
||||
public MenuConfig MenuConfigs { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace CS2_SimpleAdmin.Database;
|
||||
|
||||
public class Database(string dbConnectionString)
|
||||
{
|
||||
public MySqlConnection GetConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
var connection = new MySqlConnection(dbConnectionString);
|
||||
connection.Open();
|
||||
return connection;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical($"Unable to connect to database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MySqlConnection> GetConnectionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var connection = new MySqlConnection(dbConnectionString);
|
||||
await connection.OpenAsync();
|
||||
return connection;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical($"Unable to connect to database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void DatabaseMigration()
|
||||
{
|
||||
Migration migrator = new(this);
|
||||
migrator.ExecuteMigrations();
|
||||
}
|
||||
|
||||
public bool CheckDatabaseConnection()
|
||||
{
|
||||
using var connection = GetConnection();
|
||||
|
||||
try
|
||||
{
|
||||
return connection.Ping();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace CS2_SimpleAdmin.Database;
|
||||
|
||||
public class Migration(Database database)
|
||||
{
|
||||
public void ExecuteMigrations()
|
||||
{
|
||||
var migrationsDirectory = CS2_SimpleAdmin.Instance.ModuleDirectory + "/Database/Migrations";
|
||||
|
||||
var files = Directory.GetFiles(migrationsDirectory, "*.sql")
|
||||
.OrderBy(f => f);
|
||||
|
||||
using var connection = database.GetConnection();
|
||||
|
||||
// Create sa_migrations table if not exists
|
||||
using var cmd = new MySqlCommand("""
|
||||
CREATE TABLE IF NOT EXISTS `sa_migrations` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`version` VARCHAR(255) NOT NULL
|
||||
);
|
||||
""", connection);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
// Get the last applied migration version
|
||||
var lastAppliedVersion = GetLastAppliedVersion(connection);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var version = Path.GetFileNameWithoutExtension(file);
|
||||
|
||||
// Check if the migration has already been applied
|
||||
if (string.Compare(version, lastAppliedVersion, StringComparison.OrdinalIgnoreCase) <= 0) continue;
|
||||
var sqlScript = File.ReadAllText(file);
|
||||
|
||||
using var cmdMigration = new MySqlCommand(sqlScript, connection);
|
||||
cmdMigration.ExecuteNonQuery();
|
||||
|
||||
// Update the last applied migration version
|
||||
UpdateLastAppliedVersion(connection, version);
|
||||
|
||||
CS2_SimpleAdmin._logger?.LogInformation($"Migration \"{version}\" successfully applied.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLastAppliedVersion(MySqlConnection connection)
|
||||
{
|
||||
using var cmd = new MySqlCommand("SELECT `version` FROM `sa_migrations` ORDER BY `id` DESC LIMIT 1;", connection);
|
||||
var result = cmd.ExecuteScalar();
|
||||
return result?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
private static void UpdateLastAppliedVersion(MySqlConnection connection, string version)
|
||||
{
|
||||
using var cmd = new MySqlCommand("INSERT INTO `sa_migrations` (`version`) VALUES (@Version);", connection);
|
||||
cmd.Parameters.AddWithValue("@Version", version);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_bans` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`player_name` VARCHAR(128),
|
||||
`player_steamid` VARCHAR(64),
|
||||
`player_ip` VARCHAR(128),
|
||||
`admin_steamid` VARCHAR(64) NOT NULL,
|
||||
`admin_name` VARCHAR(128) NOT NULL,
|
||||
`reason` VARCHAR(255) NOT NULL,
|
||||
`duration` INT NOT NULL,
|
||||
`ends` TIMESTAMP NULL,
|
||||
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`server_id` INT NULL,
|
||||
`status` ENUM('ACTIVE', 'UNBANNED', 'EXPIRED', '') NOT NULL DEFAULT 'ACTIVE'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_mutes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`player_name` varchar(128) NULL,
|
||||
`player_steamid` varchar(64) NOT NULL,
|
||||
`admin_steamid` varchar(64) NOT NULL,
|
||||
`admin_name` varchar(128) NOT NULL,
|
||||
`reason` varchar(255) NOT NULL,
|
||||
`duration` int(11) NOT NULL,
|
||||
`ends` timestamp NULL,
|
||||
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`type` enum('GAG','MUTE','SILENCE','') NOT NULL DEFAULT 'GAG',
|
||||
`server_id` INT NULL,
|
||||
`status` enum('ACTIVE','UNMUTED','EXPIRED','') NOT NULL DEFAULT 'ACTIVE',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_admins` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`player_name` varchar(128) NOT NULL,
|
||||
`player_steamid` varchar(64) NOT NULL,
|
||||
`flags` TEXT NULL,
|
||||
`immunity` int(11) NOT NULL DEFAULT 0,
|
||||
`server_id` INT NULL,
|
||||
`ends` timestamp NULL,
|
||||
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_servers` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`hostname` varchar(128) NOT NULL,
|
||||
`address` varchar(64) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `address` (`address`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
@@ -1,9 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_admins_flags` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`admin_id` int(11) NOT NULL,
|
||||
`flag` varchar(64) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
FOREIGN KEY (`admin_id`) REFERENCES `sa_admins` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE `sa_admins` CHANGE `flags` `flags` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;
|
||||
@@ -1,4 +0,0 @@
|
||||
ALTER TABLE `sa_bans` CHANGE `player_name` `player_name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL AFTER `id`;
|
||||
ALTER TABLE `sa_mutes` CHANGE `player_name` `player_name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL AFTER `id`;
|
||||
ALTER TABLE `sa_admins` CHANGE `player_name` `player_name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL AFTER `id`;
|
||||
ALTER TABLE `sa_servers` CHANGE `hostname` `hostname` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL AFTER `id`;
|
||||
@@ -1,36 +0,0 @@
|
||||
INSERT INTO sa_admins_flags (admin_id, flag)
|
||||
SELECT
|
||||
min_admins.admin_id,
|
||||
TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(sa_admins.flags, ',', numbers.n), ',', -1)) AS flag
|
||||
FROM (
|
||||
SELECT MIN(id) AS admin_id, player_steamid, server_id
|
||||
FROM sa_admins
|
||||
WHERE player_steamid != 'Console'
|
||||
GROUP BY player_steamid, server_id
|
||||
) AS min_admins
|
||||
JOIN sa_admins ON min_admins.player_steamid = sa_admins.player_steamid
|
||||
JOIN (
|
||||
SELECT 1 AS n UNION ALL
|
||||
SELECT 2 UNION ALL
|
||||
SELECT 3 UNION ALL
|
||||
SELECT 4 UNION ALL
|
||||
SELECT 5 UNION ALL
|
||||
SELECT 6 UNION ALL
|
||||
SELECT 7 UNION ALL
|
||||
SELECT 8 UNION ALL
|
||||
SELECT 9 UNION ALL
|
||||
SELECT 10 UNION ALL
|
||||
SELECT 11 UNION ALL
|
||||
SELECT 12 UNION ALL
|
||||
SELECT 13 UNION ALL
|
||||
SELECT 14 UNION ALL
|
||||
SELECT 15 UNION ALL
|
||||
SELECT 16 UNION ALL
|
||||
SELECT 17 UNION ALL
|
||||
SELECT 18 UNION ALL
|
||||
SELECT 19 UNION ALL
|
||||
SELECT 20
|
||||
) AS numbers
|
||||
ON CHAR_LENGTH(sa_admins.flags) - CHAR_LENGTH(REPLACE(sa_admins.flags, ',', '')) >= numbers.n - 1
|
||||
AND (min_admins.server_id = sa_admins.server_id OR (min_admins.server_id IS NULL AND sa_admins.server_id IS NULL))
|
||||
WHERE sa_admins.id IS NOT NULL;
|
||||
@@ -1,29 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_unbans` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`ban_id` int(11) NOT NULL,
|
||||
`admin_id` int(11) NOT NULL DEFAULT 0,
|
||||
`reason` varchar(255) NOT NULL DEFAULT 'Unknown',
|
||||
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_unmutes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`mute_id` int(11) NOT NULL,
|
||||
`admin_id` int(11) NOT NULL DEFAULT 0,
|
||||
`reason` varchar(255) NOT NULL DEFAULT 'Unknown',
|
||||
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
INSERT INTO `sa_admins` (`id`, `player_name`, `player_steamid`, `flags`, `immunity`, `server_id`, `ends`, `created`)
|
||||
VALUES (-1, 'Console', 'Console', '', '0', NULL, NULL, NOW());
|
||||
|
||||
UPDATE `sa_admins` SET `id` = 0 WHERE `id` = -1;
|
||||
|
||||
ALTER TABLE `sa_bans` ADD `unban_id` INT NULL AFTER `server_id`;
|
||||
ALTER TABLE `sa_mutes` ADD `unmute_id` INT NULL AFTER `server_id`;
|
||||
ALTER TABLE `sa_bans` ADD FOREIGN KEY (`unban_id`) REFERENCES `sa_unbans`(`id`) ON DELETE CASCADE;
|
||||
ALTER TABLE `sa_mutes` ADD FOREIGN KEY (`unmute_id`) REFERENCES `sa_unmutes`(`id`) ON DELETE CASCADE;
|
||||
ALTER TABLE `sa_unbans` ADD FOREIGN KEY (`admin_id`) REFERENCES `sa_admins`(`id`) ON DELETE CASCADE;
|
||||
ALTER TABLE `sa_unmutes` ADD FOREIGN KEY (`admin_id`) REFERENCES `sa_admins`(`id`) ON DELETE CASCADE;
|
||||
@@ -1,26 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_groups` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`immunity` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_groups_flags` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`flag` varchar(64) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sa_groups_servers` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`server_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE `sa_admins` ADD `group_id` INT NULL AFTER `created`;
|
||||
|
||||
ALTER TABLE `sa_groups_flags` ADD FOREIGN KEY (`group_id`) REFERENCES `sa_groups`(`id`) ON DELETE CASCADE;
|
||||
ALTER TABLE `sa_groups_servers` ADD FOREIGN KEY (`group_id`) REFERENCES `sa_groups`(`id`) ON DELETE CASCADE;
|
||||
ALTER TABLE `sa_admins` ADD FOREIGN KEY (`group_id`) REFERENCES `sa_groups`(`id`) ON DELETE SET NULL;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `sa_groups_servers` CHANGE `server_id` `server_id` INT(11) NULL;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `sa_mutes` ADD `passed` INT NULL AFTER `duration`;
|
||||
@@ -1,8 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_players_ips` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`steamid` bigint(20) NOT NULL,
|
||||
`address` varchar(64) NOT NULL,
|
||||
`used_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `steamid` (`steamid`,`address`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
@@ -1,14 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `sa_warns` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`player_name` varchar(128) DEFAULT NULL,
|
||||
`player_steamid` varchar(64) NOT NULL,
|
||||
`admin_steamid` varchar(64) NOT NULL,
|
||||
`admin_name` varchar(128) NOT NULL,
|
||||
`reason` varchar(255) NOT NULL,
|
||||
`duration` int(11) NOT NULL,
|
||||
`ends` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`server_id` int(11) DEFAULT NULL,
|
||||
`status` enum('ACTIVE','EXPIRED','') NOT NULL DEFAULT 'ACTIVE',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
514
Events.cs
514
Events.cs
@@ -1,514 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
private int _getIpTryCount = 0;
|
||||
|
||||
private void RegisterEvents()
|
||||
{
|
||||
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||
RegisterListener<Listeners.OnGameServerSteamAPIActivated>(OnGameServerSteamAPIActivated);
|
||||
AddCommandListener("say", OnCommandSay);
|
||||
AddCommandListener("say_team", OnCommandTeamSay);
|
||||
}
|
||||
|
||||
private void OnGameServerSteamAPIActivated()
|
||||
{
|
||||
AddTimer(2.0f, () =>
|
||||
{
|
||||
if (_serverLoaded || ServerId != null || _database == null) return;
|
||||
|
||||
var ipAddress = ConVar.Find("ip")?.StringValue;
|
||||
|
||||
if (string.IsNullOrEmpty(ipAddress) || ipAddress.StartsWith("0.0.0"))
|
||||
{
|
||||
ipAddress = Helper.GetServerIp();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ipAddress) || ipAddress.StartsWith("0.0.0"))
|
||||
{
|
||||
if (_getIpTryCount < 12)
|
||||
{
|
||||
_getIpTryCount++;
|
||||
OnGameServerSteamAPIActivated();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var address = $"{ipAddress}:{ConVar.Find("hostport")?.GetPrimitiveValue<int>()}";
|
||||
var hostname = ConVar.Find("hostname")!.StringValue;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
var addressExists = await connection.ExecuteScalarAsync<bool>(
|
||||
"SELECT COUNT(*) FROM sa_servers WHERE address = @address",
|
||||
new { address });
|
||||
|
||||
if (!addressExists)
|
||||
{
|
||||
await connection.ExecuteAsync(
|
||||
"INSERT INTO sa_servers (address, hostname) VALUES (@address, @hostname)",
|
||||
new { address, hostname });
|
||||
}
|
||||
else
|
||||
{
|
||||
await connection.ExecuteAsync(
|
||||
"UPDATE `sa_servers` SET `hostname` = @hostname, `id` = `id` WHERE `address` = @address",
|
||||
new { address, hostname });
|
||||
}
|
||||
|
||||
int? serverId = await connection.ExecuteScalarAsync<int>(
|
||||
"SELECT `id` FROM `sa_servers` WHERE `address` = @address",
|
||||
new { address });
|
||||
|
||||
ServerId = serverId;
|
||||
|
||||
if (ServerId != null)
|
||||
{
|
||||
await Server.NextFrameAsync(() => ReloadAdmins(null));
|
||||
}
|
||||
|
||||
_serverLoaded = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogCritical("Unable to create or get server_id: " + ex.Message);
|
||||
}
|
||||
|
||||
if (Config.EnableMetrics)
|
||||
{
|
||||
var queryString = $"?address={address}&hostname={hostname}";
|
||||
using HttpClient client = new();
|
||||
|
||||
try
|
||||
{
|
||||
await client.GetAsync($"https://api.daffyy.love/index.php{queryString}");
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Logger.LogWarning($"Unable to make metrics call: {ex.Message}");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
_getIpTryCount = 0;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
|
||||
{
|
||||
CCSPlayerController? player = @event.Userid;
|
||||
|
||||
#if DEBUG
|
||||
Logger.LogCritical("[OnClientDisconnect] Before");
|
||||
#endif
|
||||
|
||||
if (player == null || !player.IsValid || player.IsBot)
|
||||
{
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Logger.LogCritical("[OnClientDisconnect] After Check");
|
||||
#endif
|
||||
try
|
||||
{
|
||||
PlayerPenaltyManager.RemoveAllPenalties(player.Slot);
|
||||
|
||||
if (_tagsDetected)
|
||||
Server.ExecuteCommand($"css_tag_unmute {player.SteamID}");
|
||||
|
||||
SilentPlayers.Remove(player.Slot);
|
||||
GodPlayers.Remove(player.Slot);
|
||||
|
||||
var authorizedSteamId = player.AuthorizedSteamID;
|
||||
if (authorizedSteamId == null || !PermissionManager.AdminCache.TryGetValue(authorizedSteamId,
|
||||
out var expirationTime)
|
||||
|| !(expirationTime <= DateTime.UtcNow.ToLocalTime())) return HookResult.Continue;
|
||||
|
||||
AdminManager.ClearPlayerPermissions(authorizedSteamId);
|
||||
AdminManager.RemovePlayerAdminData(authorizedSteamId);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"An error occurred in OnClientDisconnect: {ex.Message}");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerFullConnect(EventPlayerConnectFull @event, GameEventInfo info)
|
||||
{
|
||||
CCSPlayerController? player = @event.Userid;
|
||||
|
||||
if (player == null || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1")
|
||||
|| player.IsBot || !player.UserId.HasValue)
|
||||
return HookResult.Continue;
|
||||
|
||||
var ipAddress = player.IpAddress.Split(":")[0];
|
||||
|
||||
// Check if the player's IP or SteamID is in the bannedPlayers list
|
||||
if (Config.BanType > 0 && BannedPlayers.Contains(ipAddress) || BannedPlayers.Contains(player.SteamID.ToString()))
|
||||
{
|
||||
// Kick the player if banned
|
||||
if (player.UserId.HasValue)
|
||||
Helper.KickPlayer(player.UserId.Value, "Banned");
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
if (_database == null) return HookResult.Continue;
|
||||
|
||||
var playerInfo = new PlayerInfo
|
||||
{
|
||||
UserId = player.UserId.Value,
|
||||
Slot = player.Slot,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
Name = player.PlayerName,
|
||||
IpAddress = ipAddress
|
||||
};
|
||||
|
||||
// Perform asynchronous database operations within a single method
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// Initialize managers
|
||||
BanManager banManager = new(_database, Config);
|
||||
MuteManager muteManager = new(_database);
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
|
||||
const string query = """
|
||||
INSERT INTO `sa_players_ips` (steamid, address)
|
||||
VALUES (@SteamID, @IPAddress) ON DUPLICATE KEY UPDATE `used_at` = CURRENT_TIMESTAMP
|
||||
""";
|
||||
|
||||
await connection.ExecuteAsync(query, new
|
||||
{
|
||||
SteamID = playerInfo.SteamId,
|
||||
IPAddress = playerInfo.IpAddress,
|
||||
});
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
// Check if the player is banned
|
||||
bool isBanned = await banManager.IsPlayerBanned(playerInfo);
|
||||
if (isBanned)
|
||||
{
|
||||
// Add player's IP and SteamID to bannedPlayers list if not already present
|
||||
if (Config.BanType > 0 && playerInfo.IpAddress != null &&
|
||||
!BannedPlayers.Contains(playerInfo.IpAddress))
|
||||
{
|
||||
BannedPlayers.Add(playerInfo.IpAddress);
|
||||
}
|
||||
|
||||
if (playerInfo.SteamId != null && !BannedPlayers.Contains(playerInfo.SteamId))
|
||||
{
|
||||
BannedPlayers.Add(playerInfo.SteamId);
|
||||
}
|
||||
|
||||
// Kick the player if banned
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
var victim = Utilities.GetPlayerFromUserid(playerInfo.UserId.Value);
|
||||
|
||||
if (victim?.UserId != null)
|
||||
{
|
||||
if (UnlockedCommands)
|
||||
Server.ExecuteCommand($"banid 2 {playerInfo.UserId}");
|
||||
|
||||
Helper.KickPlayer(victim.UserId.Value, "Banned");
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the player is muted
|
||||
var activeMutes = await muteManager.IsPlayerMuted(playerInfo.SteamId);
|
||||
if (activeMutes.Count > 0)
|
||||
{
|
||||
foreach (var mute in activeMutes)
|
||||
{
|
||||
string muteType = mute.type;
|
||||
DateTime ends = mute.ends;
|
||||
int duration = mute.duration;
|
||||
switch (muteType)
|
||||
{
|
||||
// Apply mute penalty based on mute type
|
||||
case "GAG":
|
||||
PlayerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Gag, ends, duration);
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
if (_tagsDetected)
|
||||
{
|
||||
Server.ExecuteCommand($"css_tag_mute {playerInfo.SteamId}");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "MUTE":
|
||||
PlayerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Mute, ends, duration);
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
player.VoiceFlags = VoiceFlags.Muted;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
PlayerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Silence, ends, duration);
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
player.VoiceFlags = VoiceFlags.Muted;
|
||||
if (_tagsDetected)
|
||||
{
|
||||
Server.ExecuteCommand($"css_tag_mute {playerInfo.SteamId}");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Error processing player connection: {ex}");
|
||||
}
|
||||
});
|
||||
|
||||
if (RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
||||
{
|
||||
player.Rename(name);
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnRoundEnd(EventRoundStart @event, GameEventInfo info)
|
||||
{
|
||||
#if DEBUG
|
||||
Logger.LogCritical("[OnRoundEnd]");
|
||||
#endif
|
||||
|
||||
GodPlayers.Clear();
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
public HookResult OnCommandSay(CCSPlayerController? player, CommandInfo info)
|
||||
{
|
||||
if (player is null || !player.IsValid || player.IsBot)
|
||||
return HookResult.Continue;
|
||||
|
||||
if (info.GetArg(1).StartsWith($"/")
|
||||
|| info.GetArg(1).StartsWith($"!"))
|
||||
return HookResult.Continue;
|
||||
|
||||
if (info.GetArg(1).Length == 0)
|
||||
return HookResult.Handled;
|
||||
|
||||
if (PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) || PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence))
|
||||
return HookResult.Handled;
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
public HookResult OnCommandTeamSay(CCSPlayerController? player, CommandInfo info)
|
||||
{
|
||||
if (player is null || !player.IsValid || player.IsBot)
|
||||
return HookResult.Continue;
|
||||
|
||||
if (info.GetArg(1).StartsWith($"/")
|
||||
|| info.GetArg(1).StartsWith($"!"))
|
||||
return HookResult.Continue;
|
||||
|
||||
if (info.GetArg(1).Length == 0)
|
||||
return HookResult.Handled;
|
||||
|
||||
if (PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) || PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence))
|
||||
return HookResult.Handled;
|
||||
|
||||
if (!info.GetArg(1).StartsWith($"@")) return HookResult.Continue;
|
||||
|
||||
StringBuilder sb = new();
|
||||
|
||||
if (AdminManager.PlayerHasPermissions(player, "@css/chat"))
|
||||
{
|
||||
sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
|
||||
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat")))
|
||||
{
|
||||
p.PrintToChat(sb.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
|
||||
player.PrintToChat(sb.ToString());
|
||||
foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat")))
|
||||
{
|
||||
p.PrintToChat(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return HookResult.Handled;
|
||||
}
|
||||
|
||||
private void OnMapStart(string mapName)
|
||||
{
|
||||
if (Config.ReloadAdminsEveryMapChange && _serverLoaded && ServerId != null)
|
||||
AddTimer(3.0f, () => ReloadAdmins(null));
|
||||
|
||||
AddTimer(34, () =>
|
||||
{
|
||||
if (!_serverLoaded)
|
||||
OnGameServerSteamAPIActivated();
|
||||
});
|
||||
|
||||
var path = Path.GetDirectoryName(ModuleDirectory);
|
||||
if (Directory.Exists(path + "/CS2-Tags"))
|
||||
{
|
||||
_tagsDetected = true;
|
||||
}
|
||||
|
||||
GodPlayers.Clear();
|
||||
SilentPlayers.Clear();
|
||||
|
||||
PlayerPenaltyManager.RemoveAllPenalties();
|
||||
|
||||
_database = new Database.Database(_dbConnectionString);
|
||||
|
||||
AddTimer(61.0f, () =>
|
||||
{
|
||||
#if DEBUG
|
||||
Logger.LogCritical("[OnMapStart] Expired check");
|
||||
#endif
|
||||
|
||||
var players = Helper.GetValidPlayers();
|
||||
var onlinePlayers = players
|
||||
.Where(player => player.IpAddress != null)
|
||||
.Select(player => (player.IpAddress, player.SteamID, player.UserId, player.Slot))
|
||||
.ToList();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
PermissionManager adminManager = new(_database);
|
||||
BanManager banManager = new(_database, Config);
|
||||
MuteManager muteManager = new(_database);
|
||||
WarnManager warnManager = new(_database);
|
||||
|
||||
await muteManager.ExpireOldMutes();
|
||||
await banManager.ExpireOldBans();
|
||||
await warnManager.ExpireOldWarns();
|
||||
await adminManager.DeleteOldAdmins();
|
||||
|
||||
BannedPlayers.Clear();
|
||||
|
||||
if (onlinePlayers.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
await banManager.CheckOnlinePlayers(onlinePlayers);
|
||||
|
||||
if (Config.TimeMode == 0)
|
||||
{
|
||||
await muteManager.CheckOnlineModeMutes(onlinePlayers);
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
Logger.LogError("Unable to check bans for online players");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
if (onlinePlayers.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var player in players.Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot)))
|
||||
{
|
||||
if (!PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && !PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence))
|
||||
player.VoiceFlags = VoiceFlags.Normal;
|
||||
|
||||
if (!PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) && !PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence))
|
||||
{
|
||||
if (_tagsDetected)
|
||||
Server.ExecuteCommand($"css_tag_unmute {player.SteamID}");
|
||||
}
|
||||
|
||||
if (PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence) ||
|
||||
PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) ||
|
||||
PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag)) continue;
|
||||
player.VoiceFlags = VoiceFlags.Normal;
|
||||
|
||||
if (_tagsDetected)
|
||||
Server.ExecuteCommand($"css_tag_unmute {player.SteamID}");
|
||||
}
|
||||
|
||||
PlayerPenaltyManager.RemoveExpiredPenalties();
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
Logger.LogError("Unable to remove old penalties");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info)
|
||||
{
|
||||
CCSPlayerController? player = @event.Userid;
|
||||
|
||||
if (player is null || @event.Attacker is null || !player.PawnIsAlive || player.PlayerPawn.Value == null)
|
||||
return HookResult.Continue;
|
||||
|
||||
if (!GodPlayers.Contains(player.Slot)) return HookResult.Continue;
|
||||
|
||||
player.PlayerPawn.Value.Health = player.PlayerPawn.Value.MaxHealth;
|
||||
player.PlayerPawn.Value.ArmorValue = 100;
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnChangedName(EventPlayerChangename @event, GameEventInfo _)
|
||||
{
|
||||
CCSPlayerController? player = @event.Userid;
|
||||
|
||||
if (player is null || !player.IsValid || player.IsBot)
|
||||
return HookResult.Continue;
|
||||
|
||||
if (RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
||||
{
|
||||
if (@event.Newname.Equals(name))
|
||||
return HookResult.Continue;
|
||||
|
||||
player.Rename(name);
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Text;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public static class PlayerExtensions
|
||||
{
|
||||
public static void Slap(this CBasePlayerPawn pawn, int damage = 0)
|
||||
{
|
||||
PerformSlap(pawn, damage);
|
||||
}
|
||||
|
||||
public static void Print(this CCSPlayerController controller, string message = "")
|
||||
{
|
||||
StringBuilder _message = new(CS2_SimpleAdmin._localizer!["sa_prefix"]);
|
||||
_message.Append(message);
|
||||
controller.PrintToChat(_message.ToString());
|
||||
}
|
||||
|
||||
public static bool CanTarget(this CCSPlayerController? controller, CCSPlayerController? target)
|
||||
{
|
||||
if (controller is null || target is null) return true;
|
||||
if (target.IsBot) return true;
|
||||
|
||||
return AdminManager.CanPlayerTarget(controller, target) ||
|
||||
AdminManager.CanPlayerTarget(new SteamID(controller.SteamID),
|
||||
new SteamID(target.SteamID));
|
||||
}
|
||||
|
||||
public static void SetSpeed(this CCSPlayerController? controller, float speed)
|
||||
{
|
||||
var playerPawnValue = controller?.PlayerPawn.Value;
|
||||
if (playerPawnValue == null) return;
|
||||
|
||||
playerPawnValue.VelocityModifier = speed;
|
||||
}
|
||||
|
||||
public static void SetGravity(this CCSPlayerController? controller, float gravity)
|
||||
{
|
||||
var playerPawnValue = controller?.PlayerPawn.Value;
|
||||
if (playerPawnValue == null) return;
|
||||
|
||||
playerPawnValue.GravityScale = gravity;
|
||||
}
|
||||
|
||||
public static void SetMoney(this CCSPlayerController? controller, int money)
|
||||
{
|
||||
var moneyServices = controller?.InGameMoneyServices;
|
||||
if (moneyServices == null) return;
|
||||
|
||||
moneyServices.Account = money;
|
||||
|
||||
if (controller != null) Utilities.SetStateChanged(controller, "CCSPlayerController", "m_pInGameMoneyServices");
|
||||
}
|
||||
|
||||
public static void SetHp(this CCSPlayerController? controller, int health = 100)
|
||||
{
|
||||
if (controller == null) return;
|
||||
if ((health <= 0 || !controller.PawnIsAlive || controller.PlayerPawn.Value == null)) return;
|
||||
|
||||
controller.PlayerPawn.Value.Health = health;
|
||||
|
||||
if (health > 100)
|
||||
{
|
||||
controller.PlayerPawn.Value.MaxHealth = health;
|
||||
}
|
||||
|
||||
Utilities.SetStateChanged(controller.PlayerPawn.Value, "CBaseEntity", "m_iHealth");
|
||||
}
|
||||
|
||||
public static void Bury(this CBasePlayerPawn pawn, float depth = 10f)
|
||||
{
|
||||
var newPos = new Vector(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin!.Z - depth);
|
||||
|
||||
pawn.Teleport(newPos, pawn.AbsRotation!, pawn.AbsVelocity);
|
||||
}
|
||||
|
||||
public static void Unbury(this CBasePlayerPawn pawn, float depth = 15f)
|
||||
{
|
||||
var newPos = new Vector(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin!.Z + depth);
|
||||
|
||||
pawn.Teleport(newPos, pawn.AbsRotation!, pawn.AbsVelocity);
|
||||
}
|
||||
|
||||
public static void Freeze(this CBasePlayerPawn pawn)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_OBSOLETE;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 1); // obsolete
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
|
||||
public static void Unfreeze(this CBasePlayerPawn pawn)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
|
||||
public static void ToggleNoclip(this CBasePlayerPawn pawn)
|
||||
{
|
||||
if (pawn.MoveType == MoveType_t.MOVETYPE_NOCLIP)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
else
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_NOCLIP;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Rename(this CCSPlayerController? controller, string newName = "Unknown")
|
||||
{
|
||||
newName ??= CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
if (controller != null)
|
||||
{
|
||||
var playerName = new SchemaString<CBasePlayerController>(controller, "m_iszPlayerName");
|
||||
playerName.Set(newName + " ");
|
||||
|
||||
CS2_SimpleAdmin.Instance.AddTimer(0.25f, () =>
|
||||
{
|
||||
Utilities.SetStateChanged(controller, "CCSPlayerController", "m_szClan");
|
||||
Utilities.SetStateChanged(controller, "CBasePlayerController", "m_iszPlayerName");
|
||||
});
|
||||
|
||||
CS2_SimpleAdmin.Instance.AddTimer(0.3f, () =>
|
||||
{
|
||||
playerName.Set(newName);
|
||||
});
|
||||
}
|
||||
|
||||
CS2_SimpleAdmin.Instance.AddTimer(0.4f, () =>
|
||||
{
|
||||
if (controller != null) Utilities.SetStateChanged(controller, "CBasePlayerController", "m_iszPlayerName");
|
||||
});
|
||||
}
|
||||
|
||||
public static void TeleportPlayer(this CCSPlayerController? controller, CCSPlayerController? target)
|
||||
{
|
||||
if (controller?.PlayerPawn?.Value == null && target!.PlayerPawn?.Value == null)
|
||||
return;
|
||||
|
||||
if (
|
||||
controller?.PlayerPawn?.Value?.AbsOrigin != null &&
|
||||
controller?.PlayerPawn?.Value?.AbsRotation != null &&
|
||||
target?.PlayerPawn?.Value?.AbsOrigin != null &&
|
||||
target?.PlayerPawn?.Value?.AbsRotation != null
|
||||
)
|
||||
{
|
||||
controller.PlayerPawn.Value.Teleport(
|
||||
target.PlayerPawn.Value.AbsOrigin,
|
||||
target.PlayerPawn.Value.AbsRotation,
|
||||
target.PlayerPawn.Value.AbsVelocity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PerformSlap(CBasePlayerPawn pawn, int damage = 0)
|
||||
{
|
||||
if (pawn.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
/* Teleport in a random direction - thank you, Mani!*/
|
||||
/* Thank you AM & al!*/
|
||||
var random = new Random();
|
||||
var vel = new Vector(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z);
|
||||
|
||||
vel.X += ((random.Next(180) + 50) * ((random.Next(2) == 1) ? -1 : 1));
|
||||
vel.Y += ((random.Next(180) + 50) * ((random.Next(2) == 1) ? -1 : 1));
|
||||
vel.Z += random.Next(200) + 100;
|
||||
|
||||
pawn.AbsVelocity.X = vel.X;
|
||||
pawn.AbsVelocity.Y = vel.Y;
|
||||
pawn.AbsVelocity.Z = vel.Z;
|
||||
|
||||
if (damage <= 0)
|
||||
return;
|
||||
|
||||
pawn.Health -= damage;
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iHealth");
|
||||
|
||||
if (pawn.Health <= 0)
|
||||
pawn.CommitSuicide(true, true);
|
||||
}
|
||||
|
||||
public static void SendLocalizedMessage(this CCSPlayerController? controller, IStringLocalizer localizer, string messageKey, params object[] messageArgs)
|
||||
{
|
||||
if (controller == null) return;
|
||||
|
||||
using (new WithTemporaryCulture(controller.GetLanguage()))
|
||||
{
|
||||
StringBuilder sb = new(localizer["sa_prefix"]);
|
||||
sb.Append(localizer[messageKey, messageArgs]);
|
||||
foreach (var part in Helper.SeparateLines(sb.ToString()))
|
||||
{
|
||||
controller.PrintToChat(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
513
Helper.cs
513
Helper.cs
@@ -1,513 +0,0 @@
|
||||
using System.Drawing;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
using Discord;
|
||||
using Discord.Webhook;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using Color = Discord.Color;
|
||||
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
internal class Helper
|
||||
{
|
||||
private static readonly string AssemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? "";
|
||||
private static readonly string CfgPath = $"{Server.GameDirectory}/csgo/addons/counterstrikesharp/configs/plugins/{AssemblyName}/{AssemblyName}.json";
|
||||
|
||||
public delegate nint CNetworkSystem_UpdatePublicIp(nint a1);
|
||||
public static CNetworkSystem_UpdatePublicIp? _networkSystemUpdatePublicIp;
|
||||
|
||||
internal static CS2_SimpleAdminConfig? Config { get; set; }
|
||||
|
||||
public static bool IsDebugBuild
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetPlayerFromName(string name)
|
||||
{
|
||||
return Utilities.GetPlayers().FindAll(x => x.PlayerName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetPlayerFromSteamid64(string steamid)
|
||||
{
|
||||
return GetValidPlayers().FindAll(x =>
|
||||
x.SteamID.ToString().Equals(steamid, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
}
|
||||
|
||||
public static List<CCSPlayerController> GetPlayerFromIp(string ipAddress)
|
||||
{
|
||||
return GetValidPlayers().FindAll(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 });
|
||||
}
|
||||
|
||||
public static IEnumerable<CCSPlayerController?> GetValidPlayersWithBots()
|
||||
{
|
||||
return Utilities.GetPlayers().FindAll(p =>
|
||||
p is { IsValid: true, IsBot: false, IsHLTV: false } or { IsValid: true, IsBot: true, IsHLTV: false }
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsValidSteamId64(string input)
|
||||
{
|
||||
const string pattern = @"^\d{17}$";
|
||||
return Regex.IsMatch(input, pattern);
|
||||
}
|
||||
|
||||
public static bool ValidateSteamId(string input, out SteamID? steamId)
|
||||
{
|
||||
steamId = null;
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SteamID.TryParse(input, out var parsedSteamId)) return false;
|
||||
|
||||
steamId = parsedSteamId;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidIp(string input)
|
||||
{
|
||||
const string pattern = @"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
||||
return Regex.IsMatch(input, pattern);
|
||||
}
|
||||
|
||||
public static void GivePlayerFlags(SteamID? steamid, List<string>? flags = null, uint immunity = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (steamid == null || (flags == null && immunity == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags == null) return;
|
||||
foreach (var flag in flags.Where(flag => !string.IsNullOrEmpty(flag)))
|
||||
{
|
||||
if (flag.StartsWith($"@"))
|
||||
{
|
||||
//Console.WriteLine($"Adding permission {flag} to SteamID {steamid}");
|
||||
AdminManager.AddPlayerPermissions(steamid, flag);
|
||||
}
|
||||
else if (flag.StartsWith($"#"))
|
||||
{
|
||||
//Console.WriteLine($"Adding SteamID {steamid} to group {flag}");
|
||||
AdminManager.AddPlayerToGroup(steamid, flag);
|
||||
}
|
||||
}
|
||||
|
||||
AdminManager.SetPlayerImmunity(steamid, immunity);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static void KickPlayer(int userId, string? reason = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(reason))
|
||||
{
|
||||
var escapeChars = reason.IndexOfAny([';', '|']);
|
||||
|
||||
if (escapeChars != -1)
|
||||
{
|
||||
reason = reason[..escapeChars];
|
||||
}
|
||||
}
|
||||
|
||||
Server.ExecuteCommand($"kickid {userId} {reason}");
|
||||
}
|
||||
|
||||
public static void PrintToCenterAll(string message)
|
||||
{
|
||||
Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false }).ToList().ForEach(controller =>
|
||||
{
|
||||
controller.PrintToCenter(message);
|
||||
});
|
||||
}
|
||||
|
||||
internal static void HandleVotes(CCSPlayerController player, ChatMenuOption option)
|
||||
{
|
||||
if (!CS2_SimpleAdmin.VoteInProgress)
|
||||
return;
|
||||
|
||||
option.Disabled = true;
|
||||
CS2_SimpleAdmin.VoteAnswers[option.Text]++;
|
||||
}
|
||||
|
||||
internal static void LogCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (CS2_SimpleAdmin._localizer == null)
|
||||
return;
|
||||
|
||||
var playerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
var hostname = ConVar.Find("hostname")?.StringValue ?? CS2_SimpleAdmin._localizer["sa_unknown"];
|
||||
|
||||
CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer[
|
||||
"sa_discord_log_command",
|
||||
playerName, command.GetCommandString]}".Replace("HOSTNAME", hostname).Replace("**", ""));
|
||||
|
||||
SendDiscordLogMessage(caller, command, CS2_SimpleAdmin.DiscordWebhookClientLog, CS2_SimpleAdmin._localizer);
|
||||
}
|
||||
|
||||
internal static void LogCommand(CCSPlayerController? caller, string command)
|
||||
{
|
||||
if (CS2_SimpleAdmin._localizer == null)
|
||||
return;
|
||||
|
||||
var playerName = caller?.PlayerName ?? "Console";
|
||||
var hostnameCvar = ConVar.Find("hostname");
|
||||
|
||||
var hostname = hostnameCvar?.StringValue ?? CS2_SimpleAdmin._localizer["sa_unknown"];
|
||||
|
||||
CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer["sa_discord_log_command",
|
||||
playerName, command]}".Replace("HOSTNAME", hostname).Replace("**", ""));
|
||||
|
||||
SendDiscordLogMessage(caller, command, CS2_SimpleAdmin.DiscordWebhookClientLog, CS2_SimpleAdmin._localizer);
|
||||
}
|
||||
|
||||
/*public static IEnumerable<Embed> GenerateEmbedsDiscord(string title, string description, string thumbnailUrl, Color color, string[] fieldNames, string[] fieldValues, bool[] inlineFlags)
|
||||
{
|
||||
var hostname = ConVar.Find("hostname")?.StringValue ?? CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown";
|
||||
var address = $"{ConVar.Find("ip")?.StringValue}:{ConVar.Find("hostport")!.GetPrimitiveValue<int>()}";
|
||||
|
||||
description = description.Replace("{hostname}", hostname);
|
||||
description = description.Replace("{address}", address);
|
||||
|
||||
var embed = new EmbedBuilder
|
||||
{
|
||||
Title = title,
|
||||
Description = description,
|
||||
ThumbnailUrl = thumbnailUrl,
|
||||
Color = color,
|
||||
};
|
||||
|
||||
for (var i = 0; i < fieldNames.Length; i++)
|
||||
{
|
||||
fieldValues[i] = fieldValues[i].Replace("{hostname}", hostname ?? CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown");
|
||||
fieldValues[i] = fieldValues[i].Replace("{address}", address ?? CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown");
|
||||
|
||||
embed.AddField(fieldNames[i], fieldValues[i], inlineFlags[i]);
|
||||
|
||||
if ((i + 1) % 2 == 0 && i < fieldNames.Length - 1)
|
||||
{
|
||||
embed.AddField("\u200b", "\u200b");
|
||||
}
|
||||
}
|
||||
|
||||
return new List<Embed> { embed.Build() };
|
||||
}*/
|
||||
|
||||
private static void SendDiscordLogMessage(CCSPlayerController? caller, CommandInfo command, DiscordWebhookClient? discordWebhookClientLog, IStringLocalizer? localizer)
|
||||
{
|
||||
if (discordWebhookClientLog == null || localizer == null) return;
|
||||
|
||||
var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
|
||||
var callerName = caller != null ? caller.PlayerName : "Console";
|
||||
discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString]));
|
||||
}
|
||||
|
||||
private static void SendDiscordLogMessage(CCSPlayerController? caller, string command, DiscordWebhookClient? discordWebhookClientLog, IStringLocalizer? localizer)
|
||||
{
|
||||
if (discordWebhookClientLog == null || localizer == null) return;
|
||||
|
||||
var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
|
||||
var callerName = caller != null ? caller.PlayerName : "Console";
|
||||
discordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command]));
|
||||
}
|
||||
|
||||
public enum PenaltyType
|
||||
{
|
||||
Ban,
|
||||
Mute,
|
||||
Gag,
|
||||
Silence,
|
||||
Warn
|
||||
}
|
||||
|
||||
private static string ConvertMinutesToTime(int minutes)
|
||||
{
|
||||
var time = TimeSpan.FromMinutes(minutes);
|
||||
|
||||
return time.Days > 0 ? $"{time.Days}d {time.Hours}h {time.Minutes}m" : time.Hours > 0 ? $"{time.Hours}h {time.Minutes}m" : $"{time.Minutes}m";
|
||||
}
|
||||
|
||||
public static void SendDiscordPenaltyMessage(CCSPlayerController? caller, CCSPlayerController? target, string reason, int duration, PenaltyType penalty, IStringLocalizer? localizer)
|
||||
{
|
||||
if (localizer == null) return;
|
||||
|
||||
DiscordPenaltySetting[] penaltySetting = penalty switch
|
||||
{
|
||||
PenaltyType.Ban => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyBanSettings,
|
||||
PenaltyType.Mute => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyMuteSettings,
|
||||
PenaltyType.Gag => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyGagSettings,
|
||||
PenaltyType.Silence => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltySilenceSettings,
|
||||
PenaltyType.Warn => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyWarnSettings,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(penalty), penalty, null)
|
||||
};
|
||||
|
||||
var webhookUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("Webhook"))?.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(webhookUrl)) return;
|
||||
|
||||
var callerCommunityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
|
||||
var targetCommunityUrl = target != null ? "<" + new SteamID(target.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
|
||||
var callerName = caller != null ? caller.PlayerName : "Console";
|
||||
var targetName = target != null ? target.PlayerName : localizer["sa_unknown"];
|
||||
var targetSteamId = target != null ? new SteamID(target.SteamID).SteamId64.ToString() : localizer["sa_unknown"];
|
||||
|
||||
var futureTime = DateTime.Now.AddMinutes(duration);
|
||||
var futureUnixTimestamp = new DateTimeOffset(futureTime).ToUnixTimeSeconds();
|
||||
|
||||
//var time = duration != 0 ? ConvertMinutesToTime(duration) : localizer["sa_permanent"];
|
||||
var time = duration != 0 ? $"<t:{futureUnixTimestamp}:R>": localizer["sa_permanent"];
|
||||
|
||||
string[] fieldNames = [
|
||||
localizer["sa_player"],
|
||||
localizer["sa_steamid"],
|
||||
localizer["sa_duration"],
|
||||
localizer["sa_reason"],
|
||||
localizer["sa_admin"]];
|
||||
string[] fieldValues =
|
||||
[
|
||||
$"[{targetName}]({targetCommunityUrl})", $"||{targetSteamId}||", time, reason,
|
||||
$"[{callerName}]({callerCommunityUrl})"
|
||||
];
|
||||
bool[] inlineFlags = [true, true, true, false, false];
|
||||
|
||||
var hostname = ConVar.Find("hostname")?.StringValue ?? localizer["sa_unknown"];
|
||||
|
||||
var colorHex = penaltySetting.FirstOrDefault(s => s.Name.Equals("Color"))?.Value ?? "#FFFFFF";
|
||||
var color = ColorTranslator.FromHtml(colorHex);
|
||||
|
||||
var embed = new EmbedBuilder
|
||||
{
|
||||
Color = new Color(color.R, color.G, color.B),
|
||||
Title = penalty switch
|
||||
{
|
||||
PenaltyType.Ban => localizer["sa_discord_penalty_ban"],
|
||||
PenaltyType.Mute => localizer["sa_discord_penalty_mute"],
|
||||
PenaltyType.Gag => localizer["sa_discord_penalty_gag"],
|
||||
PenaltyType.Silence => localizer["sa_discord_penalty_silence"],
|
||||
PenaltyType.Warn => localizer["sa_discord_penalty_warn"],
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(penalty), penalty, null)
|
||||
},
|
||||
ThumbnailUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ThumbnailUrl"))?.Value,
|
||||
ImageUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ImageUrl"))?.Value,
|
||||
Footer = new EmbedFooterBuilder
|
||||
{
|
||||
Text = penaltySetting.FirstOrDefault(s => s.Name.Equals("Footer"))?.Value,
|
||||
},
|
||||
Description = $"{hostname}",
|
||||
Timestamp = DateTimeOffset.Now,
|
||||
};
|
||||
|
||||
for (var i = 0; i < fieldNames.Length; i++)
|
||||
{
|
||||
embed.AddField(fieldNames[i], fieldValues[i], inlineFlags[i]);
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await new DiscordWebhookClient(webhookUrl).SendMessageAsync(embeds: [embed.Build()]);
|
||||
});
|
||||
}
|
||||
|
||||
private static string GenerateMessageDiscord(string message)
|
||||
{
|
||||
var hostname = ConVar.Find("hostname")?.StringValue ?? CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown";
|
||||
var address = $"{ConVar.Find("ip")?.StringValue}:{ConVar.Find("hostport")!.GetPrimitiveValue<int>()}";
|
||||
|
||||
message = message.Replace("HOSTNAME", hostname);
|
||||
message = message.Replace("ADDRESS", address);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public static string[] SeparateLines(string message)
|
||||
{
|
||||
return message.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public static string GetServerIp()
|
||||
{
|
||||
var networkSystem = NativeAPI.GetValveInterface(0, "NetworkSystemVersion001");
|
||||
|
||||
unsafe
|
||||
{
|
||||
if (_networkSystemUpdatePublicIp == null)
|
||||
{
|
||||
var funcPtr = *(nint*)(*(nint*)(networkSystem) + 256);
|
||||
_networkSystemUpdatePublicIp = Marshal.GetDelegateForFunctionPointer<CNetworkSystem_UpdatePublicIp>(funcPtr);
|
||||
}
|
||||
/*
|
||||
struct netadr_t
|
||||
{
|
||||
uint32_t type
|
||||
uint8_t ip[4]
|
||||
uint16_t port
|
||||
}
|
||||
*/
|
||||
// + 4 to skip type, because the size of uint32_t is 4 bytes
|
||||
var ipBytes = (byte*)(_networkSystemUpdatePublicIp(networkSystem) + 4);
|
||||
// port is always 0, use the one from convar "hostport"
|
||||
return $"{ipBytes[0]}.{ipBytes[1]}.{ipBytes[2]}.{ipBytes[3]}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void UpdateConfig<T>(T config) where T : BasePluginConfig, new()
|
||||
{
|
||||
// get newest config version
|
||||
var newCfgVersion = new T().Version;
|
||||
|
||||
// loaded config is up to date
|
||||
if (config.Version == newCfgVersion)
|
||||
return;
|
||||
|
||||
// update the version
|
||||
config.Version = newCfgVersion;
|
||||
|
||||
// serialize the updated config back to json
|
||||
var updatedJsonContent = JsonSerializer.Serialize(config,
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
});
|
||||
File.WriteAllText(CfgPath, updatedJsonContent);
|
||||
}
|
||||
|
||||
public static void TryLogCommandOnDiscord(CCSPlayerController? caller, string commandString)
|
||||
{
|
||||
if (CS2_SimpleAdmin.DiscordWebhookClientLog == null || CS2_SimpleAdmin._localizer == null)
|
||||
return;
|
||||
|
||||
if (caller != null && caller.IsValid == false)
|
||||
caller = null;
|
||||
|
||||
var callerName = caller == null ? "Console" : caller.PlayerName;
|
||||
var communityUrl = caller != null
|
||||
? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">"
|
||||
: "<https://steamcommunity.com/profiles/0>";
|
||||
CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(
|
||||
CS2_SimpleAdmin._localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})",
|
||||
commandString]));
|
||||
}
|
||||
}
|
||||
|
||||
public static class PluginInfo
|
||||
{
|
||||
internal static async Task CheckVersion(string version, ILogger logger)
|
||||
{
|
||||
using HttpClient client = new();
|
||||
|
||||
try
|
||||
{
|
||||
var response = await client.GetAsync("https://raw.githubusercontent.com/daffyyyy/CS2-SimpleAdmin/main/VERSION").ConfigureAwait(false);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
remoteVersion = remoteVersion.Trim();
|
||||
|
||||
var comparisonResult = string.CompareOrdinal(version, remoteVersion);
|
||||
|
||||
switch (comparisonResult)
|
||||
{
|
||||
case < 0:
|
||||
logger.LogWarning("Plugin is outdated! Check https://github.com/daffyyyy/CS2-SimpleAdmin");
|
||||
break;
|
||||
case > 0:
|
||||
logger.LogInformation("Probably dev version detected");
|
||||
break;
|
||||
default:
|
||||
logger.LogInformation("Plugin is up to date");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Failed to check version");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Failed to connect to the version server.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "An error occurred while checking version.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ShowAd(string moduleVersion)
|
||||
{
|
||||
Console.WriteLine(" ");
|
||||
Console.WriteLine(" _______ ___ __ __ _______ ___ _______ _______ ______ __ __ ___ __ _ ");
|
||||
Console.WriteLine("| || | | |_| || || | | || _ || | | |_| || | | | | |");
|
||||
Console.WriteLine("| _____|| | | || _ || | | ___|| |_| || _ || || | | |_| |");
|
||||
Console.WriteLine("| |_____ | | | || |_| || | | |___ | || | | || || | | |");
|
||||
Console.WriteLine("|_____ || | | || ___|| |___ | ___|| || |_| || || | | _ |");
|
||||
Console.WriteLine(" _____| || | | ||_|| || | | || |___ | _ || || ||_|| || | | | | |");
|
||||
Console.WriteLine("|_______||___| |_| |_||___| |_______||_______||__| |__||______| |_| |_||___| |_| |__|");
|
||||
Console.WriteLine(" >> Version: " + moduleVersion);
|
||||
Console.WriteLine(" >> GitHub: https://github.com/daffyyyy/CS2-SimpleAdmin");
|
||||
Console.WriteLine(" ");
|
||||
}
|
||||
}
|
||||
|
||||
public class SchemaString<TSchemaClass>(TSchemaClass instance, string member)
|
||||
: NativeObject(Schema.GetSchemaValue<nint>(instance.Handle, typeof(TSchemaClass).Name, member))
|
||||
where TSchemaClass : NativeObject
|
||||
{
|
||||
public unsafe void Set(string str)
|
||||
{
|
||||
var bytes = GetStringBytes(str);
|
||||
|
||||
for (var i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
Unsafe.Write((void*)(Handle.ToInt64() + i), bytes[i]);
|
||||
}
|
||||
|
||||
Unsafe.Write((void*)(Handle.ToInt64() + bytes.Length), 0);
|
||||
}
|
||||
|
||||
private static byte[] GetStringBytes(string str)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
674
LICENSE
674
LICENSE
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -1,464 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
using System.Text;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
internal class BanManager(Database.Database database, CS2_SimpleAdminConfig config)
|
||||
{
|
||||
public async Task BanPlayer(PlayerInfo player, PlayerInfo issuer, string reason, int time = 0)
|
||||
{
|
||||
DateTime now = DateTime.UtcNow.ToLocalTime();
|
||||
DateTime futureTime = now.AddMinutes(time);
|
||||
|
||||
await using MySqlConnection connection = await database.GetConnectionAsync();
|
||||
try
|
||||
{
|
||||
const string sql =
|
||||
"INSERT INTO `sa_bans` (`player_steamid`, `player_name`, `player_ip`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @playerName, @playerIp, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = player.SteamId,
|
||||
playerName = player.Name,
|
||||
playerIp = config.BanType == 1 ? player.IpAddress : null,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.Name ?? "Console",
|
||||
banReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public async Task AddBanBySteamid(string playerSteamId, PlayerInfo issuer, string reason, int time = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerSteamId)) return;
|
||||
|
||||
DateTime now = DateTime.UtcNow.ToLocalTime();
|
||||
DateTime futureTime = now.AddMinutes(time);
|
||||
|
||||
try
|
||||
{
|
||||
await using MySqlConnection connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = "INSERT INTO `sa_bans` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = playerSteamId,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.Name ?? "Console",
|
||||
banReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public async Task AddBanByIp(string playerIp, PlayerInfo issuer, string reason, int time = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerIp)) return;
|
||||
|
||||
DateTime now = DateTime.UtcNow.ToLocalTime();
|
||||
DateTime futureTime = now.AddMinutes(time);
|
||||
|
||||
try
|
||||
{
|
||||
await using MySqlConnection connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = "INSERT INTO `sa_bans` (`player_ip`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerIp, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerIp,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.Name ?? "Console",
|
||||
banReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public async Task<bool> IsPlayerBanned(PlayerInfo player)
|
||||
{
|
||||
if (player.SteamId == null || player.IpAddress == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (CS2_SimpleAdmin._logger!= null)
|
||||
CS2_SimpleAdmin._logger.LogCritical($"IsPlayerBanned for {player.Name}");
|
||||
#endif
|
||||
|
||||
int banCount;
|
||||
|
||||
DateTime currentTime = DateTime.UtcNow.ToLocalTime();
|
||||
|
||||
try
|
||||
{
|
||||
var sql = config.MultiServerMode ? """
|
||||
UPDATE sa_bans
|
||||
SET player_ip = CASE WHEN player_ip IS NULL THEN @PlayerIP ELSE player_ip END,
|
||||
player_name = CASE WHEN player_name IS NULL THEN @PlayerName ELSE player_name END
|
||||
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
|
||||
AND status = 'ACTIVE'
|
||||
AND (duration = 0 OR ends > @CurrentTime);
|
||||
|
||||
SELECT COUNT(*) FROM sa_bans
|
||||
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
|
||||
AND status = 'ACTIVE'
|
||||
AND (duration = 0 OR ends > @CurrentTime);
|
||||
""" : @"
|
||||
UPDATE sa_bans
|
||||
SET player_ip = CASE WHEN player_ip IS NULL THEN @PlayerIP ELSE player_ip END,
|
||||
player_name = CASE WHEN player_name IS NULL THEN @PlayerName ELSE player_name END
|
||||
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
|
||||
AND status = 'ACTIVE'
|
||||
AND (duration = 0 OR ends > @CurrentTime) AND server_id = @serverid;
|
||||
|
||||
SELECT COUNT(*) FROM sa_bans
|
||||
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
|
||||
AND status = 'ACTIVE'
|
||||
AND (duration = 0 OR ends > @CurrentTime) AND server_id = @serverid;";
|
||||
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var parameters = new
|
||||
{
|
||||
PlayerSteamID = player.SteamId,
|
||||
PlayerIP = config.BanType == 0 || string.IsNullOrEmpty(player.IpAddress) ? null : player.IpAddress,
|
||||
PlayerName = !string.IsNullOrEmpty(player.Name) ? player.Name : string.Empty,
|
||||
CurrentTime = currentTime,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
};
|
||||
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql, parameters);
|
||||
|
||||
if (config.BanType == 1 && banCount == 0)
|
||||
{
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
sa_bans
|
||||
JOIN sa_players_ips ON sa_bans.player_steamid = sa_players_ips.steamid
|
||||
WHERE
|
||||
sa_bans.status = 'ACTIVE'
|
||||
AND sa_players_ips.address = @PlayerIP;
|
||||
""";
|
||||
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql, new
|
||||
{
|
||||
PlayerIP = player.IpAddress
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return banCount > 0;
|
||||
}
|
||||
|
||||
public async Task<int> GetPlayerBans(PlayerInfo player)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sql = "";
|
||||
|
||||
sql = config.MultiServerMode
|
||||
? "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)"
|
||||
: "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND server_id = @serverid";
|
||||
|
||||
int banCount;
|
||||
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
if (config.BanType > 0 && !string.IsNullOrEmpty(player.IpAddress))
|
||||
{
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql,
|
||||
new
|
||||
{
|
||||
PlayerSteamID = player.SteamId,
|
||||
PlayerIP = player.IpAddress,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql,
|
||||
new
|
||||
{
|
||||
PlayerSteamID = player.SteamId,
|
||||
PlayerIP = DBNull.Value,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
|
||||
return banCount;
|
||||
}
|
||||
catch { }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task UnbanPlayer(string playerPattern, string adminSteamId, string reason)
|
||||
{
|
||||
if (playerPattern is not { Length: > 1 })
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sqlRetrieveBans = config.MultiServerMode
|
||||
? "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE'"
|
||||
: "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
|
||||
var bans = await connection.QueryAsync(sqlRetrieveBans, new { pattern = playerPattern, serverid = CS2_SimpleAdmin.ServerId });
|
||||
|
||||
var bansList = bans as dynamic[] ?? bans.ToArray();
|
||||
if (bansList.Length == 0)
|
||||
return;
|
||||
|
||||
const string sqlAdmin = "SELECT id FROM sa_admins WHERE player_steamid = @adminSteamId";
|
||||
var sqlInsertUnban = "INSERT INTO sa_unbans (ban_id, admin_id, reason) VALUES (@banId, @adminId, @reason); SELECT LAST_INSERT_ID();";
|
||||
|
||||
var sqlAdminId = await connection.ExecuteScalarAsync<int?>(sqlAdmin, new { adminSteamId });
|
||||
var adminId = sqlAdminId ?? 0;
|
||||
|
||||
foreach (var ban in bansList)
|
||||
{
|
||||
int banId = ban.id;
|
||||
int? unbanId;
|
||||
|
||||
// Insert into sa_unbans
|
||||
if (reason != null)
|
||||
{
|
||||
unbanId = await connection.ExecuteScalarAsync<int>(sqlInsertUnban, new { banId, adminId, reason });
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlInsertUnban = "INSERT INTO sa_unbans (ban_id, admin_id) VALUES (@banId, @adminId); SELECT LAST_INSERT_ID();";
|
||||
unbanId = await connection.ExecuteScalarAsync<int>(sqlInsertUnban, new { banId, adminId });
|
||||
}
|
||||
|
||||
// Update sa_bans to set unban_id
|
||||
const string sqlUpdateBan = "UPDATE sa_bans SET status = 'UNBANNED', unban_id = @unbanId WHERE id = @banId";
|
||||
await connection.ExecuteAsync(sqlUpdateBan, new { unbanId, banId });
|
||||
}
|
||||
|
||||
/*
|
||||
string sqlUnban = "UPDATE sa_bans SET status = 'UNBANNED' WHERE player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern AND status = 'ACTIVE'";
|
||||
await connection.ExecuteAsync(sqlUnban, new { pattern = playerPattern });
|
||||
*/
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/*
|
||||
public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
bool checkIpBans = config.BanType > 0;
|
||||
|
||||
var sql = config.MultiServerMode
|
||||
? "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND status = 'ACTIVE'"
|
||||
: "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
|
||||
foreach (var (IpAddress, SteamID, UserId, Slot) in players)
|
||||
{
|
||||
if (!UserId.HasValue) continue;
|
||||
|
||||
var banCount = 0;
|
||||
if (checkIpBans && !string.IsNullOrEmpty(IpAddress))
|
||||
{
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql,
|
||||
new { PlayerSteamID = SteamID, PlayerIP = IpAddress, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
else
|
||||
{
|
||||
banCount = await connection.ExecuteScalarAsync<int>(sql,
|
||||
new { PlayerSteamID = SteamID, PlayerIP = DBNull.Value, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
|
||||
if (banCount > 0)
|
||||
{
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
Helper.KickPlayer(UserId.Value, "Banned");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
*/
|
||||
|
||||
public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
bool checkIpBans = config.BanType > 0;
|
||||
|
||||
var filteredPlayers = players.Where(p => p.UserId.HasValue).ToList();
|
||||
|
||||
var steamIds = filteredPlayers.Select(p => p.SteamID).Distinct().ToList();
|
||||
var ipAddresses = filteredPlayers
|
||||
.Where(p => !string.IsNullOrEmpty(p.IpAddress))
|
||||
.Select(p => p.IpAddress)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var sql = new StringBuilder();
|
||||
sql.Append("SELECT `player_steamid`, `player_ip` FROM `sa_bans` WHERE `status` = 'ACTIVE' ");
|
||||
|
||||
if (config.MultiServerMode)
|
||||
{
|
||||
sql.Append("AND (player_steamid IN @SteamIDs ");
|
||||
if (checkIpBans && ipAddresses.Count != 0)
|
||||
{
|
||||
sql.Append("OR player_ip IN @IpAddresses");
|
||||
}
|
||||
sql.Append(')');
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.Append("AND server_id = @ServerId AND (player_steamid IN @SteamIDs ");
|
||||
if (checkIpBans && ipAddresses.Count != 0)
|
||||
{
|
||||
sql.Append("OR player_ip IN @IpAddresses");
|
||||
}
|
||||
sql.Append(')');
|
||||
}
|
||||
|
||||
var bannedPlayers = await connection.QueryAsync<(ulong PlayerSteamID, string PlayerIP)>(
|
||||
sql.ToString(),
|
||||
new
|
||||
{
|
||||
SteamIDs = steamIds,
|
||||
IpAddresses = checkIpBans ? ipAddresses : [],
|
||||
ServerId = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
|
||||
var valueTuples = bannedPlayers.ToList();
|
||||
var bannedSteamIds = valueTuples.Select(b => b.PlayerSteamID).ToHashSet();
|
||||
var bannedIps = valueTuples.Select(b => b.PlayerIP).ToHashSet();
|
||||
|
||||
foreach (var player in filteredPlayers.Where(player => bannedSteamIds.Contains(player.SteamID) ||
|
||||
(checkIpBans && bannedIps.Contains(player.IpAddress ?? ""))))
|
||||
{
|
||||
if (!player.UserId.HasValue) continue;
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
Helper.KickPlayer(player.UserId.Value, "Banned");
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError($"Error checking online players: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ExpireOldBans()
|
||||
{
|
||||
var currentTime = DateTime.UtcNow.ToLocalTime();
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
/*
|
||||
string sql = "";
|
||||
await using MySqlConnection connection = await _database.GetConnectionAsync();
|
||||
|
||||
sql = "UPDATE sa_bans SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime";
|
||||
await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow.ToLocalTime() });
|
||||
*/
|
||||
|
||||
var sql = "";
|
||||
|
||||
sql = config.MultiServerMode ? """
|
||||
|
||||
UPDATE sa_bans
|
||||
SET
|
||||
status = 'EXPIRED'
|
||||
WHERE
|
||||
status = 'ACTIVE'
|
||||
AND
|
||||
`duration` > 0
|
||||
AND
|
||||
ends <= @currentTime
|
||||
""" : """
|
||||
|
||||
UPDATE sa_bans
|
||||
SET
|
||||
status = 'EXPIRED'
|
||||
WHERE
|
||||
status = 'ACTIVE'
|
||||
AND
|
||||
`duration` > 0
|
||||
AND
|
||||
ends <= @currentTime
|
||||
AND server_id = @serverid
|
||||
""";
|
||||
|
||||
await connection.ExecuteAsync(sql, new { currentTime, serverid = CS2_SimpleAdmin.ServerId });
|
||||
|
||||
if (config.ExpireOldIpBans > 0)
|
||||
{
|
||||
var ipBansTime = currentTime.AddDays(-config.ExpireOldIpBans);
|
||||
sql = config.MultiServerMode ? """
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
await connection.ExecuteAsync(sql, new { ipBansTime, CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical("Unable to remove expired bans");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
internal class MuteManager(Database.Database database)
|
||||
{
|
||||
public async Task MutePlayer(PlayerInfo player, PlayerInfo issuer, string reason, int time = 0, int type = 0)
|
||||
{
|
||||
if (player.SteamId == null) return;
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
var futureTime = now.AddMinutes(time);
|
||||
|
||||
var muteType = type switch
|
||||
{
|
||||
1 => "MUTE",
|
||||
2 => "SILENCE",
|
||||
_ => "GAG"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
const string sql =
|
||||
"INSERT INTO `sa_mutes` (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @playerName, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @type, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = player.SteamId,
|
||||
playerName = player.Name,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.SteamId == null ? "Console" : issuer.Name,
|
||||
muteReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
type = muteType,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
public async Task AddMuteBySteamid(string playerSteamId, PlayerInfo issuer, string reason, int time = 0, int type = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerSteamId)) return;
|
||||
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
var futureTime = now.AddMinutes(time);
|
||||
|
||||
var muteType = type switch
|
||||
{
|
||||
1 => "MUTE",
|
||||
2 => "SILENCE",
|
||||
_ => "GAG"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
const string sql = "INSERT INTO `sa_mutes` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @type, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = playerSteamId,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.Name ?? "Console",
|
||||
muteReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
type = muteType,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
public async Task<List<dynamic>> IsPlayerMuted(string steamId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(steamId))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (CS2_SimpleAdmin._logger!= null)
|
||||
CS2_SimpleAdmin._logger.LogCritical($"IsPlayerMuted for {steamId}");
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
var currentTime = DateTime.UtcNow.ToLocalTime();
|
||||
var sql = "";
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
sql = CS2_SimpleAdmin.Instance.Config.TimeMode == 1
|
||||
? "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)"
|
||||
: "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR duration > COALESCE(passed, 0))";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = CS2_SimpleAdmin.Instance.Config.TimeMode == 1
|
||||
? "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime) AND server_id = @serverid"
|
||||
: "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR duration > COALESCE(passed, 0)) AND server_id = @serverid";
|
||||
|
||||
}
|
||||
|
||||
var parameters = new { PlayerSteamID = steamId, CurrentTime = currentTime, serverid = CS2_SimpleAdmin.ServerId };
|
||||
var activeMutes = (await connection.QueryAsync(sql, parameters)).ToList();
|
||||
return activeMutes;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetPlayerMutes(string steamId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? "SELECT COUNT(*) FROM sa_mutes WHERE player_steamid = @PlayerSteamID"
|
||||
: "SELECT COUNT(*) FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND server_id = @serverid";
|
||||
|
||||
var muteCount = await connection.ExecuteScalarAsync<int>(sql, new { PlayerSteamID = steamId, serverid = CS2_SimpleAdmin.ServerId });
|
||||
return muteCount;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CheckOnlineModeMutes(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
|
||||
{
|
||||
try
|
||||
{
|
||||
int batchSize = 10;
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? "UPDATE `sa_mutes` SET passed = COALESCE(passed, 0) + 1 WHERE (player_steamid = @PlayerSteamID) AND duration > 0 AND status = 'ACTIVE'"
|
||||
: "UPDATE `sa_mutes` SET passed = COALESCE(passed, 0) + 1 WHERE (player_steamid = @PlayerSteamID) AND duration > 0 AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
/*
|
||||
foreach (var (IpAddress, SteamID, UserId, Slot) in players)
|
||||
{
|
||||
await connection.ExecuteAsync(sql,
|
||||
new { PlayerSteamID = SteamID, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}*/
|
||||
|
||||
for (var i = 0; i < players.Count; i += batchSize)
|
||||
{
|
||||
var batch = players.Skip(i).Take(batchSize);
|
||||
var parametersList = new List<object>();
|
||||
|
||||
foreach (var (IpAddress, SteamID, UserId, Slot) in batch)
|
||||
{
|
||||
parametersList.Add(new { PlayerSteamID = SteamID, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
|
||||
await connection.ExecuteAsync(sql, parametersList);
|
||||
}
|
||||
|
||||
sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? "SELECT * FROM `sa_mutes` WHERE player_steamid = @PlayerSteamID AND passed >= duration AND duration > 0 AND status = 'ACTIVE'"
|
||||
: "SELECT * FROM `sa_mutes` WHERE player_steamid = @PlayerSteamID AND passed >= duration AND duration > 0 AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
|
||||
|
||||
foreach (var (IpAddress, SteamID, UserId, Slot) in players)
|
||||
{
|
||||
var muteRecords = await connection.QueryAsync(sql, new { PlayerSteamID = SteamID, serverid = CS2_SimpleAdmin.ServerId });
|
||||
|
||||
foreach (var muteRecord in muteRecords)
|
||||
{
|
||||
DateTime endDateTime = muteRecord.ends;
|
||||
PlayerPenaltyManager.RemovePenaltiesByDateTime(Slot, endDateTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public async Task UnmutePlayer(string playerPattern, string adminSteamId, string reason, int type = 0)
|
||||
{
|
||||
if (playerPattern.Length <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var muteType = type switch
|
||||
{
|
||||
1 => "MUTE",
|
||||
2 => "SILENCE",
|
||||
_ => "GAG"
|
||||
};
|
||||
|
||||
string sqlRetrieveMutes;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
sqlRetrieveMutes = "SELECT id FROM sa_mutes WHERE (player_steamid = @pattern OR player_name = @pattern) AND " +
|
||||
"type = @muteType AND status = 'ACTIVE'";
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlRetrieveMutes = "SELECT id FROM sa_mutes WHERE (player_steamid = @pattern OR player_name = @pattern) AND " +
|
||||
"type = @muteType AND status = 'ACTIVE' AND server_id = @serverid";
|
||||
}
|
||||
|
||||
var mutes = await connection.QueryAsync(sqlRetrieveMutes, new { pattern = playerPattern, muteType, serverid = CS2_SimpleAdmin.ServerId });
|
||||
|
||||
var mutesList = mutes as dynamic[] ?? mutes.ToArray();
|
||||
if (mutesList.Length == 0)
|
||||
return;
|
||||
|
||||
const string sqlAdmin = "SELECT id FROM sa_admins WHERE player_steamid = @adminSteamId";
|
||||
var sqlInsertUnmute = "INSERT INTO sa_unmutes (mute_id, admin_id, reason) VALUES (@muteId, @adminId, @reason); SELECT LAST_INSERT_ID();";
|
||||
|
||||
var sqlAdminId = await connection.ExecuteScalarAsync<int?>(sqlAdmin, new { adminSteamId });
|
||||
var adminId = sqlAdminId ?? 0;
|
||||
|
||||
foreach (var mute in mutesList)
|
||||
{
|
||||
int muteId = mute.id;
|
||||
int? unmuteId;
|
||||
|
||||
// Insert into sa_unmutes
|
||||
if (reason != null)
|
||||
{
|
||||
unmuteId = await connection.ExecuteScalarAsync<int>(sqlInsertUnmute, new { muteId, adminId, reason });
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlInsertUnmute = "INSERT INTO sa_unmutes (muteId, admin_id) VALUES (@muteId, @adminId); SELECT LAST_INSERT_ID();";
|
||||
unmuteId = await connection.ExecuteScalarAsync<int>(sqlInsertUnmute, new { muteId, adminId });
|
||||
}
|
||||
|
||||
// Update sa_mutes to set unmute_id
|
||||
const string sqlUpdateMute = "UPDATE sa_mutes SET status = 'UNMUTED', unmute_id = @unmuteId WHERE id = @muteId";
|
||||
await connection.ExecuteAsync(sqlUpdateMute, new { unmuteId, muteId });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ExpireOldMutes()
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
var sql = "";
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
sql = CS2_SimpleAdmin.Instance.Config.TimeMode == 1
|
||||
? "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"
|
||||
: "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND `passed` >= `duration`";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = CS2_SimpleAdmin.Instance.Config.TimeMode == 1
|
||||
? "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime AND server_id = @serverid"
|
||||
: "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND `passed` >= `duration` AND server_id = @serverid";
|
||||
}
|
||||
|
||||
await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow.ToLocalTime(), serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical("Unable to remove expired mutes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,535 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
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 async Task<List<(List<string>, int)>> GetAdminFlags(string steamId)
|
||||
{
|
||||
DateTime now = DateTime.UtcNow.ToLocalTime();
|
||||
|
||||
await using MySqlConnection connection = await _database.GetConnectionAsync();
|
||||
|
||||
string sql = "SELECT flags, immunity, ends FROM sa_admins WHERE player_steamid = @PlayerSteamID AND (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR server_id = @serverid)";
|
||||
List<dynamic>? activeFlags = (await connection.QueryAsync(sql, new { PlayerSteamID = steamId, CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList();
|
||||
|
||||
if (activeFlags == null)
|
||||
{
|
||||
return new List<(List<string>, int)>();
|
||||
}
|
||||
|
||||
List<(List<string>, int)> filteredFlagsWithImmunity = [];
|
||||
|
||||
foreach (dynamic flags in activeFlags)
|
||||
{
|
||||
if (flags is not IDictionary<string, object> flagsDict)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!flagsDict.TryGetValue("flags", out var flagsValueObj) || !flagsDict.TryGetValue("immunity", out var immunityValueObj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(flagsValueObj is string flagsValue) || !int.TryParse(immunityValueObj.ToString(), out var immunityValue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Console.WriteLine($"Flags: {flagsValue}, Immunity: {immunityValue}");
|
||||
|
||||
filteredFlagsWithImmunity.Add((flagsValue.Split(',').ToList(), immunityValue));
|
||||
}
|
||||
|
||||
return filteredFlagsWithImmunity;
|
||||
}
|
||||
*/
|
||||
|
||||
private async Task<List<(string, string, List<string>, int, DateTime?)>> GetAllPlayersFlags()
|
||||
{
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
const string sql = """
|
||||
SELECT sa_admins.player_steamid, sa_admins.player_name, sa_admins_flags.flag, sa_admins.immunity, sa_admins.ends
|
||||
FROM sa_admins_flags
|
||||
JOIN sa_admins ON sa_admins_flags.admin_id = sa_admins.id
|
||||
WHERE (sa_admins.ends IS NULL OR sa_admins.ends > @CurrentTime)
|
||||
AND (sa_admins.server_id IS NULL OR sa_admins.server_id = @serverid)
|
||||
ORDER BY sa_admins.player_steamid
|
||||
""";
|
||||
|
||||
var admins = (await connection.QueryAsync(sql, new { CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId })).ToList();
|
||||
|
||||
// Group by player_steamid and aggregate the flags
|
||||
var groupedPlayers = admins
|
||||
.GroupBy(r => new { r.player_steamid, r.player_name, r.immunity, r.ends })
|
||||
.Select(g => (
|
||||
PlayerSteamId: (string)g.Key.player_steamid,
|
||||
PlayerName: (string)g.Key.player_name,
|
||||
Flags: g.Select(r => (string)r.flag).Distinct().ToList(),
|
||||
Immunity: g.Key.immunity is int i ? i : int.TryParse((string)g.Key.immunity, out var immunity) ? immunity : 0,
|
||||
Ends: g.Key.ends is DateTime dateTime ? dateTime : (DateTime?)null
|
||||
))
|
||||
.ToList();
|
||||
|
||||
/*
|
||||
foreach (var player in groupedPlayers)
|
||||
{
|
||||
Console.WriteLine($"Player SteamID: {player.PlayerSteamId}, Name: {player.PlayerName}, Flags: {string.Join(", ", player.Flags)}, Immunity: {player.Immunity}, Ends: {player.Ends}");
|
||||
}
|
||||
*/
|
||||
|
||||
List<(string, string, List<string>, int, DateTime?)> filteredFlagsWithImmunity = [];
|
||||
|
||||
// Add the grouped players to the list
|
||||
filteredFlagsWithImmunity.AddRange(groupedPlayers);
|
||||
|
||||
return filteredFlagsWithImmunity;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public async Task<Dictionary<int, Tuple<List<string>, List<Tuple<string, DateTime?>>, int>>> GetAllGroupsFlags()
|
||||
{
|
||||
try
|
||||
{
|
||||
await using MySqlConnection connection = await _database.GetConnectionAsync();
|
||||
|
||||
string sql = "SELECT group_id FROM sa_groups_servers WHERE server_id = @serverid";
|
||||
var groupIds = connection.Query<int>(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList();
|
||||
|
||||
sql = @"
|
||||
SELECT g.group_id, f.flag
|
||||
FROM sa_groups_flags f
|
||||
JOIN sa_groups_servers g ON f.group_id = g.group_id
|
||||
WHERE g.server_id = @serverid";
|
||||
|
||||
var groupFlagData = connection.Query(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList();
|
||||
|
||||
if (groupIds.Count == 0 || groupFlagData.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var groupInfoDictionary = new Dictionary<int, Tuple<List<string>, List<Tuple<string, DateTime?>>, int>>();
|
||||
|
||||
foreach (var groupId in groupIds)
|
||||
{
|
||||
groupInfoDictionary[groupId] = new Tuple<List<string>, List<Tuple<string, DateTime?>>, int>([], [], 0);
|
||||
}
|
||||
|
||||
foreach (var row in groupFlagData)
|
||||
{
|
||||
var groupId = (int)row.group_id;
|
||||
var flag = (string)row.flag;
|
||||
|
||||
groupInfoDictionary[groupId].Item1.Add(flag);
|
||||
}
|
||||
|
||||
sql = @"
|
||||
SELECT a.group_id, a.player_steamid, a.ends, g.immunity, g.name
|
||||
FROM sa_admins a
|
||||
JOIN sa_groups g ON a.group_id = g.id
|
||||
WHERE a.group_id IN @groupIds";
|
||||
|
||||
var playerData = (await connection.QueryAsync(sql, new { groupIds })).ToList();
|
||||
|
||||
foreach (var row in playerData)
|
||||
{
|
||||
var groupId = (int)row.group_id;
|
||||
var playerSteamid = (string)row.player_steamid;
|
||||
var ends = row.ends as DateTime?;
|
||||
var immunity = (int)row.immunity;
|
||||
|
||||
groupInfoDictionary[groupId].Item2.Add(new Tuple<string, DateTime?>(playerSteamid, ends));
|
||||
groupInfoDictionary[groupId] = new Tuple<List<string>, List<Tuple<string, DateTime?>>, int>(groupInfoDictionary[groupId].Item1, groupInfoDictionary[groupId].Item2, immunity);
|
||||
}
|
||||
|
||||
return groupInfoDictionary;
|
||||
}
|
||||
catch { }
|
||||
|
||||
return [];
|
||||
}
|
||||
*/
|
||||
|
||||
private async Task<Dictionary<string, (List<string>, int)>> GetAllGroupsData()
|
||||
{
|
||||
await using MySqlConnection connection = await database.GetConnectionAsync();
|
||||
try
|
||||
{
|
||||
var sql = "SELECT group_id FROM sa_groups_servers WHERE (server_id = @serverid OR server_id IS NULL)";
|
||||
var groupDataSql = connection.Query<int>(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList();
|
||||
|
||||
sql = """
|
||||
SELECT g.group_id, sg.name AS group_name, sg.immunity, f.flag
|
||||
FROM sa_groups_flags f
|
||||
JOIN sa_groups_servers g ON f.group_id = g.group_id
|
||||
JOIN sa_groups sg ON sg.id = g.group_id
|
||||
WHERE (g.server_id = @serverid OR server_id IS NULL)
|
||||
""";
|
||||
|
||||
var groupData = connection.Query(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList();
|
||||
|
||||
if (groupDataSql.Count == 0 || groupData.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var groupInfoDictionary = new Dictionary<string, (List<string>, int)>();
|
||||
|
||||
foreach (var row in groupData)
|
||||
{
|
||||
var groupName = (string)row.group_name;
|
||||
var flag = (string)row.flag;
|
||||
var immunity = (int)row.immunity;
|
||||
|
||||
// Check if the group name already exists in the dictionary
|
||||
if (!groupInfoDictionary.TryGetValue(groupName, out (List<string>, int) value))
|
||||
{
|
||||
value = ([], immunity);
|
||||
// If it doesn't exist, add a new entry with an empty list of flags and immunity
|
||||
groupInfoDictionary[groupName] = value;
|
||||
}
|
||||
|
||||
value.Item1.Add(flag);
|
||||
}
|
||||
|
||||
return groupInfoDictionary;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public async Task CrateGroupsJsonFile()
|
||||
{
|
||||
var groupsData = await GetAllGroupsData();
|
||||
|
||||
var jsonData = new Dictionary<string, object>();
|
||||
|
||||
foreach (var kvp in groupsData)
|
||||
{
|
||||
var groupData = new Dictionary<string, object>
|
||||
{
|
||||
["flags"] = kvp.Value.Item1,
|
||||
["immunity"] = kvp.Value.Item2
|
||||
};
|
||||
|
||||
jsonData[kvp.Key] = groupData;
|
||||
}
|
||||
|
||||
var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented);
|
||||
var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "groups.json");
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
}
|
||||
|
||||
/*
|
||||
public async Task GiveAllGroupsFlags()
|
||||
{
|
||||
Dictionary<int, Tuple<List<string>, List<Tuple<string, DateTime?>>, int>> groupFlags = await GetAllGroupsFlags();
|
||||
|
||||
foreach (var kvp in groupFlags)
|
||||
{
|
||||
var flags = kvp.Value.Item1;
|
||||
var players = kvp.Value.Item2;
|
||||
int immunity = kvp.Value.Item3;
|
||||
|
||||
foreach (var playerTuple in players)
|
||||
{
|
||||
var steamIdStr = playerTuple.Item1;
|
||||
var ends = playerTuple.Item2;
|
||||
|
||||
if (!string.IsNullOrEmpty(steamIdStr) && SteamID.TryParse(steamIdStr, out var steamId) && steamId != null)
|
||||
{
|
||||
if (!_adminCache.ContainsKey(steamId))
|
||||
{
|
||||
_adminCache.TryAdd(steamId, ends);
|
||||
}
|
||||
|
||||
Helper.GivePlayerFlags(steamId, flags, (uint)immunity);
|
||||
// Often need to call 2 times
|
||||
Helper.GivePlayerFlags(steamId, flags, (uint)immunity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
public async Task GiveAllFlags()
|
||||
{
|
||||
List<(string, string, List<string>, int, DateTime?)> allPlayers = await GetAllPlayersFlags();
|
||||
|
||||
foreach (var record in allPlayers)
|
||||
{
|
||||
string steamIdStr = record.Item1;
|
||||
List<string> flags = record.Item2;
|
||||
int immunity = record.Item3;
|
||||
|
||||
DateTime? ends = record.Item4;
|
||||
|
||||
if (!string.IsNullOrEmpty(steamIdStr) && SteamID.TryParse(steamIdStr, out var steamId) && steamId != null)
|
||||
{
|
||||
if (!_adminCache.ContainsKey(steamId))
|
||||
{
|
||||
_adminCache.TryAdd(steamId, ends);
|
||||
//_adminCacheTimestamps.Add(steamId, ends);
|
||||
}
|
||||
|
||||
Helper.GivePlayerFlags(steamId, flags, (uint)immunity);
|
||||
// Often need to call 2 times
|
||||
Helper.GivePlayerFlags(steamId, flags, (uint)immunity);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public async Task CreateAdminsJsonFile()
|
||||
{
|
||||
List<(string identity, string name, List<string> flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlags();
|
||||
var validPlayers = allPlayers
|
||||
.Where(player => SteamID.TryParse(player.identity, out _)) // Filter invalid SteamID
|
||||
.ToList();
|
||||
|
||||
/*
|
||||
foreach (var player in allPlayers)
|
||||
{
|
||||
var (steamId, name, flags, immunity, ends) = player;
|
||||
|
||||
// Print or process each item
|
||||
Console.WriteLine($"Player SteamID: {steamId}");
|
||||
Console.WriteLine($"Player Name: {name}");
|
||||
Console.WriteLine($"Flags: {string.Join(", ", flags)}");
|
||||
Console.WriteLine($"Immunity: {immunity}");
|
||||
Console.WriteLine($"Ends: {(ends.HasValue ? ends.Value.ToString("yyyy-MM-dd HH:mm:ss") : "Never")}");
|
||||
Console.WriteLine(); // New line for better readability
|
||||
}
|
||||
*/
|
||||
|
||||
var jsonData = validPlayers
|
||||
.Select(player =>
|
||||
{
|
||||
SteamID.TryParse(player.identity, out var steamId);
|
||||
|
||||
// Update cache if SteamID is valid and not already cached
|
||||
if (steamId != null && !AdminCache.ContainsKey(steamId))
|
||||
{
|
||||
AdminCache.TryAdd(steamId, player.ends);
|
||||
}
|
||||
|
||||
// Create an anonymous object with player data
|
||||
return new
|
||||
{
|
||||
playerName = player.name,
|
||||
playerData = new
|
||||
{
|
||||
player.identity,
|
||||
player.immunity,
|
||||
flags = player.flags.Where(flag => flag.StartsWith("@")).ToList(),
|
||||
groups = player.flags.Where(flag => flag.StartsWith("#")).ToList()
|
||||
}
|
||||
};
|
||||
})
|
||||
.ToDictionary(item => item.playerName, item => (object)item.playerData);
|
||||
|
||||
var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented);
|
||||
|
||||
var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "admins.json");
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
|
||||
//await File.WriteAllTextAsync(CS2_SimpleAdmin.Instance.ModuleDirectory + "/data/admins.json", json);
|
||||
}
|
||||
|
||||
public async Task DeleteAdminBySteamId(string playerSteamId, bool globalDelete = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerSteamId)) return;
|
||||
|
||||
//_adminCache.TryRemove(playerSteamId, out _);
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = globalDelete
|
||||
? "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID"
|
||||
: "DELETE FROM sa_admins WHERE player_steamid = @PlayerSteamID AND server_id = @ServerId";
|
||||
|
||||
await connection.ExecuteAsync(sql, new { PlayerSteamID = playerSteamId, CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddAdminBySteamId(string playerSteamId, string playerName, List<string> flagsList, int immunity = 0, int time = 0, bool globalAdmin = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerSteamId) || flagsList.Count == 0) return;
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
DateTime? futureTime;
|
||||
|
||||
if (time != 0)
|
||||
futureTime = now.AddMinutes(time);
|
||||
else
|
||||
futureTime = null;
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
// Insert admin into sa_admins table
|
||||
const string insertAdminSql = "INSERT INTO `sa_admins` (`player_steamid`, `player_name`, `immunity`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @playerName, @immunity, @ends, @created, @serverid); SELECT LAST_INSERT_ID();";
|
||||
|
||||
var adminId = await connection.ExecuteScalarAsync<int>(insertAdminSql, new
|
||||
{
|
||||
playerSteamId,
|
||||
playerName,
|
||||
immunity,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = globalAdmin ? null : CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
|
||||
// Insert flags into sa_admins_flags table
|
||||
foreach (var flag in flagsList)
|
||||
{
|
||||
if (flag.StartsWith($"#"))
|
||||
{
|
||||
const string sql = "SELECT id FROM `sa_groups` WHERE name = @groupName";
|
||||
var groupId = await connection.QuerySingleOrDefaultAsync<int?>(sql, new { groupName = flag });
|
||||
|
||||
if (groupId != null)
|
||||
{
|
||||
const string updateAdminGroup = "UPDATE `sa_admins` SET group_id = @groupId WHERE id = @adminId";
|
||||
await connection.ExecuteAsync(updateAdminGroup, new
|
||||
{
|
||||
groupId,
|
||||
adminId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const string insertFlagsSql = "INSERT INTO `sa_admins_flags` (`admin_id`, `flag`) " +
|
||||
"VALUES (@adminId, @flag)";
|
||||
|
||||
await connection.ExecuteAsync(insertFlagsSql, new
|
||||
{
|
||||
adminId,
|
||||
flag
|
||||
});
|
||||
}
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.ReloadAdmins(null);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddGroup(string groupName, List<string> flagsList, int immunity = 0, bool globalGroup = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupName) || flagsList.Count == 0) return;
|
||||
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
try
|
||||
{
|
||||
// Insert group into sa_groups table
|
||||
const string insertGroup = "INSERT INTO `sa_groups` (`name`, `immunity`) " +
|
||||
"VALUES (@groupName, @immunity); SELECT LAST_INSERT_ID();";
|
||||
var groupId = await connection.ExecuteScalarAsync<int>(insertGroup, new
|
||||
{
|
||||
groupName,
|
||||
immunity
|
||||
});
|
||||
|
||||
// Insert flags into sa_groups_flags table
|
||||
foreach (var flag in flagsList)
|
||||
{
|
||||
const string insertFlagsSql = "INSERT INTO `sa_groups_flags` (`group_id`, `flag`) " +
|
||||
"VALUES (@groupId, @flag)";
|
||||
|
||||
await connection.ExecuteAsync(insertFlagsSql, new
|
||||
{
|
||||
groupId,
|
||||
flag
|
||||
});
|
||||
}
|
||||
|
||||
const string insertGroupServer = "INSERT INTO `sa_groups_servers` (`group_id`, `server_id`) " +
|
||||
"VALUES (@groupId, @server_id)";
|
||||
|
||||
await connection.ExecuteAsync(insertGroupServer, new { groupId, server_id = globalGroup ? null : CS2_SimpleAdmin.ServerId });
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.ReloadAdmins(null);
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteGroup(string groupName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupName)) return;
|
||||
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
try
|
||||
{
|
||||
const string sql = "DELETE FROM `sa_groups` WHERE name = @groupName";
|
||||
await connection.ExecuteAsync(sql, new { groupName });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteOldAdmins()
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
const string sql = "DELETE FROM sa_admins WHERE ends IS NOT NULL AND ends <= @CurrentTime";
|
||||
await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow.ToLocalTime() });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical("Unable to remove expired admins");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public enum PenaltyType
|
||||
{
|
||||
Mute,
|
||||
Gag,
|
||||
Silence
|
||||
}
|
||||
|
||||
public class PlayerPenaltyManager
|
||||
{
|
||||
private static readonly ConcurrentDictionary<int, Dictionary<PenaltyType, List<(DateTime EndDateTime, int Duration, bool Passed)>>> Penalties =
|
||||
new();
|
||||
|
||||
// Add a penalty for a player
|
||||
public static void AddPenalty(int slot, PenaltyType penaltyType, DateTime endDateTime, int durationInMinutes)
|
||||
{
|
||||
Penalties.AddOrUpdate(slot,
|
||||
(_) =>
|
||||
{
|
||||
var dict = new Dictionary<PenaltyType, List<(DateTime, int, bool)>>
|
||||
{
|
||||
[penaltyType] = [(endDateTime, durationInMinutes, false)]
|
||||
};
|
||||
return dict;
|
||||
},
|
||||
(_, existingDict) =>
|
||||
{
|
||||
if (!existingDict.TryGetValue(penaltyType, out var value))
|
||||
{
|
||||
value = new List<(DateTime, int, bool)>();
|
||||
existingDict[penaltyType] = value;
|
||||
}
|
||||
|
||||
value.Add((endDateTime, durationInMinutes, false));
|
||||
return existingDict;
|
||||
});
|
||||
}
|
||||
|
||||
public static bool IsPenalized(int slot, PenaltyType penaltyType)
|
||||
{
|
||||
//Console.WriteLine($"Checking penalties for player with slot {slot} and penalty type {penaltyType}");
|
||||
|
||||
if (!Penalties.TryGetValue(slot, out var penaltyDict) ||
|
||||
!penaltyDict.TryGetValue(penaltyType, out var penaltiesList)) return false;
|
||||
//Console.WriteLine($"Found penalties for player with slot {slot} and penalty type {penaltyType}");
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.TimeMode == 0)
|
||||
return penaltiesList.Count != 0;
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
|
||||
// Check if any active penalties exist
|
||||
foreach (var penalty in penaltiesList.ToList())
|
||||
{
|
||||
// Check if the penalty is still active
|
||||
if (penalty.Duration > 0 && now >= penalty.EndDateTime)
|
||||
{
|
||||
//Console.WriteLine($"Removing expired penalty for player with slot {slot} and penalty type {penaltyType}");
|
||||
penaltiesList.Remove(penalty); // Remove expired penalty
|
||||
if (penaltiesList.Count == 0)
|
||||
{
|
||||
//Console.WriteLine($"No more penalties of type {penaltyType} for player with slot {slot}. Removing penalty type.");
|
||||
penaltyDict.Remove(penaltyType); // Remove penalty type if no more penalties exist
|
||||
}
|
||||
}
|
||||
else if (penalty.Duration == 0 || now < penalty.EndDateTime)
|
||||
{
|
||||
//Console.WriteLine($"Player with slot {slot} is penalized for type {penaltyType}");
|
||||
// Return true if there's an active penalty
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return false if no active penalties are found
|
||||
//Console.WriteLine($"Player with slot {slot} is not penalized for type {penaltyType}");
|
||||
return false;
|
||||
|
||||
// Return false if no penalties of the specified type were found for the player
|
||||
//Console.WriteLine($"No penalties found for player with slot {slot} and penalty type {penaltyType}");
|
||||
}
|
||||
|
||||
// Get the end datetime and duration of penalties for a player and penalty type
|
||||
public static List<(DateTime EndDateTime, int Duration, bool Passed)> GetPlayerPenalties(int slot, PenaltyType penaltyType)
|
||||
{
|
||||
if (Penalties.TryGetValue(slot, out var penaltyDict) &&
|
||||
penaltyDict.TryGetValue(penaltyType, out var penaltiesList))
|
||||
{
|
||||
return penaltiesList;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public static bool IsSlotInPenalties(int slot)
|
||||
{
|
||||
return Penalties.ContainsKey(slot);
|
||||
}
|
||||
|
||||
// Remove all penalties for a player slot
|
||||
public static void RemoveAllPenalties(int slot)
|
||||
{
|
||||
if (Penalties.ContainsKey(slot))
|
||||
{
|
||||
Penalties.TryRemove(slot, out _);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all penalties
|
||||
public static void RemoveAllPenalties()
|
||||
{
|
||||
Penalties.Clear();
|
||||
}
|
||||
|
||||
// Remove all penalties of a selected type from a specific player
|
||||
public static void RemovePenaltiesByType(int slot, PenaltyType penaltyType)
|
||||
{
|
||||
if (Penalties.TryGetValue(slot, out var penaltyDict) &&
|
||||
penaltyDict.ContainsKey(penaltyType))
|
||||
{
|
||||
penaltyDict.Remove(penaltyType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemovePenaltiesByDateTime(int slot, DateTime dateTime)
|
||||
{
|
||||
if (!Penalties.TryGetValue(slot, out var penaltyDict)) return;
|
||||
|
||||
foreach (var penaltiesList in penaltyDict.Values)
|
||||
{
|
||||
for (var i = 0; i < penaltiesList.Count; i++)
|
||||
{
|
||||
if (penaltiesList[i].EndDateTime != dateTime) continue;
|
||||
// Create a copy of the penalty
|
||||
var penalty = penaltiesList[i];
|
||||
|
||||
// Update the end datetime of the copied penalty to the current datetime
|
||||
penalty.Passed = true;
|
||||
|
||||
// Replace the original penalty with the modified one
|
||||
penaltiesList[i] = penalty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all expired penalties for all players and penalty types
|
||||
public static void RemoveExpiredPenalties()
|
||||
{
|
||||
if (CS2_SimpleAdmin.Instance.Config.TimeMode == 0)
|
||||
{
|
||||
foreach (var (playerSlot, penaltyDict) in Penalties.ToList()) // Use ToList to avoid modification while iterating
|
||||
{
|
||||
// Remove expired penalties for the player
|
||||
foreach (var penaltiesList in penaltyDict.Values)
|
||||
{
|
||||
penaltiesList.RemoveAll(p => p is { Duration: > 0, Passed: true });
|
||||
}
|
||||
|
||||
// Remove player slot if no penalties left
|
||||
if (penaltyDict.Count == 0)
|
||||
{
|
||||
Penalties.TryRemove(playerSlot, out _);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
foreach (var (playerSlot, penaltyDict) in Penalties.ToList()) // Use ToList to avoid modification while iterating
|
||||
{
|
||||
// Remove expired penalties for the player
|
||||
foreach (var penaltiesList in penaltyDict.Values)
|
||||
{
|
||||
penaltiesList.RemoveAll(p => p.Duration > 0 && now >= p.EndDateTime);
|
||||
}
|
||||
|
||||
// Remove player slot if no penalties left
|
||||
if (penaltyDict.Count == 0)
|
||||
{
|
||||
Penalties.TryRemove(playerSlot, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
internal class WarnManager(Database.Database database)
|
||||
{
|
||||
public async Task WarnPlayer(PlayerInfo player, PlayerInfo issuer, string reason, int time = 0)
|
||||
{
|
||||
if (player.SteamId == null) return;
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
var futureTime = now.AddMinutes(time);
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
const string sql =
|
||||
"INSERT INTO `sa_warns` (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @playerName, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = player.SteamId,
|
||||
playerName = player.Name,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.SteamId == null ? "Console" : issuer.Name,
|
||||
muteReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
public async Task AddWarnBySteamid(string playerSteamId, PlayerInfo issuer, string reason, int time = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerSteamId)) return;
|
||||
|
||||
|
||||
var now = DateTime.UtcNow.ToLocalTime();
|
||||
var futureTime = now.AddMinutes(time);
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
const string sql = "INSERT INTO `sa_warns` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " +
|
||||
"VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid)";
|
||||
|
||||
await connection.ExecuteAsync(sql, new
|
||||
{
|
||||
playerSteamid = playerSteamId,
|
||||
adminSteamid = issuer.SteamId ?? "Console",
|
||||
adminName = issuer.Name ?? "Console",
|
||||
muteReason = reason,
|
||||
duration = time,
|
||||
ends = futureTime,
|
||||
created = now,
|
||||
serverid = CS2_SimpleAdmin.ServerId
|
||||
});
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<dynamic>> GetPlayerWarns(string steamId, bool active = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
string sql;
|
||||
|
||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||
{
|
||||
sql = active
|
||||
? "SELECT * FROM sa_warns WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' ORDER BY id DESC"
|
||||
: "SELECT * FROM sa_warns WHERE player_steamid = @PlayerSteamID ORDER BY id DESC";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = active
|
||||
? "SELECT * FROM sa_warns WHERE player_steamid = @PlayerSteamID AND server_id = @serverid AND status = 'ACTIVE' ORDER BY id DESC"
|
||||
: "SELECT * FROM sa_warns WHERE player_steamid = @PlayerSteamID AND server_id = @serverid ORDER BY id DESC";
|
||||
}
|
||||
|
||||
var parameters = new { PlayerSteamID = steamId, serverid = CS2_SimpleAdmin.ServerId };
|
||||
var warns = await connection.QueryAsync<dynamic>(sql, parameters);
|
||||
|
||||
return warns;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GetPlayerWarnsCount(string steamId, bool active = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? active
|
||||
? "SELECT COUNT(*) FROM sa_warns WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE'"
|
||||
: "SELECT COUNT(*) FROM sa_warns WHERE player_steamid = @PlayerSteamID"
|
||||
: active
|
||||
? "SELECT COUNT(*) FROM sa_warns WHERE player_steamid = @PlayerSteamID AND server_id = @serverid AND status = 'ACTIVE'"
|
||||
: "SELECT COUNT(*) FROM sa_warns WHERE player_steamid = @PlayerSteamID'";
|
||||
|
||||
var muteCount = await connection.ExecuteScalarAsync<int>(sql, new { PlayerSteamID = steamId, serverid = CS2_SimpleAdmin.ServerId });
|
||||
return muteCount;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UnwarnPlayer(string steamid, int warnId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = @warnId"
|
||||
: "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = @warnId AND server_id = @serverid";
|
||||
|
||||
await connection.ExecuteAsync(sql, new { steamid, warnId, serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical($"Unable to remove warn + {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ExpireOldWarns()
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await database.GetConnectionAsync();
|
||||
|
||||
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
|
||||
? "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"
|
||||
: "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime AND server_id = @serverid";
|
||||
|
||||
await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow.ToLocalTime(), serverid = CS2_SimpleAdmin.ServerId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogCritical($"Unable to remove expired warns + {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Menu;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class AdminMenu
|
||||
{
|
||||
public static BaseMenu CreateMenu(string title)
|
||||
{
|
||||
return CS2_SimpleAdmin.Instance.Config.UseChatMenu ? new ChatMenu(title) : new CenterHtmlMenu(title, CS2_SimpleAdmin.Instance);
|
||||
}
|
||||
|
||||
public static void OpenMenu(CCSPlayerController player, BaseMenu menu)
|
||||
{
|
||||
switch (menu)
|
||||
{
|
||||
case CenterHtmlMenu centerHtmlMenu:
|
||||
MenuManager.OpenCenterHtmlMenu(CS2_SimpleAdmin.Instance, player, centerHtmlMenu);
|
||||
break;
|
||||
case ChatMenu chatMenu:
|
||||
MenuManager.OpenChatMenu(player, chatMenu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/generic") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = CreateMenu(localizer?["sa_title"] ?? "SimpleAdmin");
|
||||
List<ChatMenuOptionData> options =
|
||||
[
|
||||
new ChatMenuOptionData(localizer?["sa_menu_players_manage"] ?? "Players Manage", () => ManagePlayersMenu.OpenMenu(admin)),
|
||||
new ChatMenuOptionData(localizer?["sa_menu_server_manage"] ?? "Server Manage", () => ManageServerMenu.OpenMenu(admin)),
|
||||
new ChatMenuOptionData(localizer?["sa_menu_fun_commands"] ?? "Fun Commands", () => FunActionsMenu.OpenMenu(admin)),
|
||||
];
|
||||
|
||||
var customCommands = CS2_SimpleAdmin.Instance.Config.CustomServerCommands;
|
||||
if (customCommands.Count > 0)
|
||||
{
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_menu_custom_commands"] ?? "Custom Commands", () => CustomCommandsMenu.OpenMenu(admin)));
|
||||
}
|
||||
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/root"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_menu_admins_manage"] ?? "Admins Manage", () => ManageAdminsMenu.OpenMenu(admin)));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
OpenMenu(admin, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public class ChatMenuOptionData(string name, Action action, bool disabled = false)
|
||||
{
|
||||
public readonly string Name = name;
|
||||
public readonly Action Action = action;
|
||||
public readonly bool Disabled = disabled;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class CustomCommandsMenu
|
||||
{
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/generic") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_custom_commands"] ?? "Custom Commands");
|
||||
List<ChatMenuOptionData> options = [];
|
||||
|
||||
var customCommands = CS2_SimpleAdmin.Instance.Config.CustomServerCommands;
|
||||
options.AddRange(from customCommand in customCommands
|
||||
where !string.IsNullOrEmpty(customCommand.DisplayName) && !string.IsNullOrEmpty(customCommand.Command)
|
||||
let hasRights = AdminManager.PlayerHasPermissions(admin, customCommand.Flag)
|
||||
where hasRights
|
||||
select new ChatMenuOptionData(customCommand.DisplayName, () =>
|
||||
{
|
||||
Helper.TryLogCommandOnDiscord(admin, customCommand.Command);
|
||||
|
||||
if (customCommand.ExecuteOnClient)
|
||||
admin.ExecuteClientCommandFromServer(customCommand.Command);
|
||||
else
|
||||
Server.ExecuteCommand(customCommand.Command);
|
||||
}));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class DurationMenu
|
||||
{
|
||||
public static void OpenMenu(CCSPlayerController admin, string menuName, CCSPlayerController? player, Action<CCSPlayerController, CCSPlayerController?, int> onSelectAction)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu(menuName);
|
||||
|
||||
foreach (var durationItem in CS2_SimpleAdmin.Instance.Config.MenuConfigs.Durations)
|
||||
{
|
||||
menu.AddMenuOption(durationItem.Name, (_, _) => { onSelectAction(admin, player, durationItem.Duration); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class FunActionsMenu
|
||||
{
|
||||
private static Dictionary<int, CsItem>? _weaponsCache;
|
||||
|
||||
private static Dictionary<int, CsItem> GetWeaponsCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_weaponsCache != null) return _weaponsCache;
|
||||
|
||||
var weaponsArray = Enum.GetValues(typeof(CsItem));
|
||||
|
||||
// avoid duplicates in the menu
|
||||
_weaponsCache = new Dictionary<int, CsItem>();
|
||||
foreach (CsItem item in weaponsArray)
|
||||
{
|
||||
if (item == CsItem.Tablet)
|
||||
continue;
|
||||
|
||||
_weaponsCache[(int)item] = item;
|
||||
}
|
||||
|
||||
return _weaponsCache;
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/generic") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_fun_commands"] ?? "Fun Commands");
|
||||
List<ChatMenuOptionData> options = [];
|
||||
|
||||
//var hasCheats = AdminManager.PlayerHasPermissions(admin, "@css/cheats");
|
||||
//var hasSlay = AdminManager.PlayerHasPermissions(admin, "@css/slay");
|
||||
|
||||
// options added in order
|
||||
|
||||
if (AdminManager.CommandIsOverriden("css_god")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_god"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/cheats"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_godmode"] ?? "God Mode", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_godmode"] ?? "God Mode", GodMode)));
|
||||
if (AdminManager.CommandIsOverriden("css_noclip")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_noclip"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/cheats"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_noclip"] ?? "No Clip", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_noclip"] ?? "No Clip", NoClip)));
|
||||
if (AdminManager.CommandIsOverriden("css_respawn")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_respawn"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/cheats"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_respawn"] ?? "Respawn", () => PlayersMenu.OpenDeadMenu(admin, localizer?["sa_respawn"] ?? "Respawn", Respawn)));
|
||||
if (AdminManager.CommandIsOverriden("css_give")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_give"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/cheats"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_give_weapon"] ?? "Give Weapon", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_give_weapon"] ?? "Give Weapon", GiveWeaponMenu)));
|
||||
|
||||
if (AdminManager.CommandIsOverriden("css_strip")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_strip"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_strip_weapons"] ?? "Strip Weapons", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_strip_weapons"] ?? "Strip Weapons", StripWeapons)));
|
||||
if (AdminManager.CommandIsOverriden("css_freeze")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_freeze"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_freeze"] ?? "Freeze", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_freeze"] ?? "Freeze", Freeze)));
|
||||
if (AdminManager.CommandIsOverriden("css_hp")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_hp"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_set_hp"] ?? "Set Hp", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_set_hp"] ?? "Set Hp", SetHpMenu)));
|
||||
if (AdminManager.CommandIsOverriden("css_speed")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_speed"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_set_speed"] ?? "Set Speed", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_set_speed"] ?? "Set Speed", SetSpeedMenu)));
|
||||
if (AdminManager.CommandIsOverriden("css_gravity")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_gravity"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_set_gravity"] ?? "Set Gravity", () => PlayersMenu.OpenAliveMenu(admin, localizer?["sa_set_gravity"] ?? "Set Gravity", SetGravityMenu)));
|
||||
if (AdminManager.CommandIsOverriden("css_money")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_money"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/slay"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_set_money"] ?? "Set Money", () => PlayersMenu.OpenMenu(admin, localizer?["sa_set_money"] ?? "Set Money", SetMoneyMenu)));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void GodMode(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.God(admin, player);
|
||||
}
|
||||
|
||||
private static void NoClip(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.NoClip(admin, player);
|
||||
}
|
||||
|
||||
private static void Respawn(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.Respawn(admin, player);
|
||||
}
|
||||
|
||||
private static void GiveWeaponMenu(CCSPlayerController admin, CCSPlayerController player)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_give_weapon"] ?? "Give Weapon"}: {player.PlayerName}");
|
||||
|
||||
foreach (var weapon in GetWeaponsCache)
|
||||
{
|
||||
menu.AddMenuOption(weapon.Value.ToString(), (_, _) => { GiveWeapon(admin, player, weapon.Value); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void GiveWeapon(CCSPlayerController admin, CCSPlayerController player, CsItem weaponValue)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.GiveWeapon(admin, player, weaponValue);
|
||||
}
|
||||
|
||||
private static void StripWeapons(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.StripWeapons(admin, player);
|
||||
}
|
||||
|
||||
private static void Freeze(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
if (!(player?.PlayerPawn.Value?.IsValid ?? false))
|
||||
return;
|
||||
|
||||
if (player.PlayerPawn.Value.MoveType != MoveType_t.MOVETYPE_OBSOLETE)
|
||||
CS2_SimpleAdmin.Instance.Freeze(admin, player, -1);
|
||||
else
|
||||
CS2_SimpleAdmin.Instance.Unfreeze(admin, player);
|
||||
}
|
||||
|
||||
private static void SetHpMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var hpArray = new[]
|
||||
{
|
||||
new Tuple<string, int>("1", 1),
|
||||
new Tuple<string, int>("10", 10),
|
||||
new Tuple<string, int>("25", 25),
|
||||
new Tuple<string, int>("50", 50),
|
||||
new Tuple<string, int>("100", 100),
|
||||
new Tuple<string, int>("200", 200),
|
||||
new Tuple<string, int>("500", 500),
|
||||
new Tuple<string, int>("999", 999)
|
||||
};
|
||||
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_set_hp"] ?? "Set Hp"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var (optionName, value) in hpArray)
|
||||
{
|
||||
menu.AddMenuOption(optionName, (_, _) => { SetHp(admin, player, value); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void SetHp(CCSPlayerController admin, CCSPlayerController? player, int hp)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.SetHp(admin, player, hp);
|
||||
}
|
||||
|
||||
private static void SetSpeedMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var speedArray = new[]
|
||||
{
|
||||
new Tuple<string, float>("0.1", .1f),
|
||||
new Tuple<string, float>("0.25", .25f),
|
||||
new Tuple<string, float>("0.5", .5f),
|
||||
new Tuple<string, float>("0.75", .75f),
|
||||
new Tuple<string, float>("1", 1),
|
||||
new Tuple<string, float>("2", 2),
|
||||
new Tuple<string, float>("3", 3),
|
||||
new Tuple<string, float>("4", 4)
|
||||
};
|
||||
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_set_speed"] ?? "Set Speed"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var (optionName, value) in speedArray)
|
||||
{
|
||||
menu.AddMenuOption(optionName, (_, _) => { SetSpeed(admin, player, value); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void SetSpeed(CCSPlayerController admin, CCSPlayerController? player, float speed)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.SetSpeed(admin, player, speed);
|
||||
}
|
||||
|
||||
private static void SetGravityMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var gravityArray = new[]
|
||||
{
|
||||
new Tuple<string, float>("0.1", .1f),
|
||||
new Tuple<string, float>("0.25", .25f),
|
||||
new Tuple<string, float>("0.5", .5f),
|
||||
new Tuple<string, float>("0.75", .75f),
|
||||
new Tuple<string, float>("1", 1),
|
||||
new Tuple<string, float>("2", 2)
|
||||
};
|
||||
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_set_gravity"] ?? "Set Gravity"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var (optionName, value) in gravityArray)
|
||||
{
|
||||
menu.AddMenuOption(optionName, (_, _) => { SetGravity(admin, player, value); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void SetGravity(CCSPlayerController admin, CCSPlayerController? player, float gravity)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.SetGravity(admin, player, gravity);
|
||||
}
|
||||
|
||||
private static void SetMoneyMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var moneyArray = new[]
|
||||
{
|
||||
new Tuple<string, int>("$0", 0),
|
||||
new Tuple<string, int>("$1000", 1000),
|
||||
new Tuple<string, int>("$2500", 2500),
|
||||
new Tuple<string, int>("$5000", 5000),
|
||||
new Tuple<string, int>("$10000", 10000),
|
||||
new Tuple<string, int>("$16000", 16000)
|
||||
};
|
||||
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_set_money"] ?? "Set Money"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var (optionName, value) in moneyArray)
|
||||
{
|
||||
menu.AddMenuOption(optionName, (_, _) => { SetMoney(admin, player, value); });
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void SetMoney(CCSPlayerController admin, CCSPlayerController? player, int money)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.SetMoney(admin, player, money);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class ManageAdminsMenu
|
||||
{
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/root") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_admins_manage"] ?? "Admins Manage");
|
||||
List<ChatMenuOptionData> options =
|
||||
[
|
||||
new ChatMenuOptionData(localizer?["sa_admin_add"] ?? "Add Admin",
|
||||
() => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_admin_add"] ?? "Add Admin", AddAdminMenu)),
|
||||
new ChatMenuOptionData(localizer?["sa_admin_remove"] ?? "Remove Admin",
|
||||
() => PlayersMenu.OpenAdminPlayersMenu(admin, localizer?["sa_admin_remove"] ?? "Remove Admin", RemoveAdmin,
|
||||
player => player != admin && admin.CanTarget(player))),
|
||||
new ChatMenuOptionData(localizer?["sa_admin_reload"] ?? "Reload Admins", () => ReloadAdmins(admin))
|
||||
];
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void AddAdminMenu(CCSPlayerController admin, CCSPlayerController player)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_admin_add"] ?? "Add Admin"}: {player.PlayerName}");
|
||||
|
||||
foreach (var adminFlag in CS2_SimpleAdmin.Instance.Config.MenuConfigs.AdminFlags)
|
||||
{
|
||||
var disabled = AdminManager.PlayerHasPermissions(player, adminFlag.Flag);
|
||||
menu.AddMenuOption(adminFlag.Name, (_, _) => { AddAdmin(admin, player, adminFlag.Flag); }, disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void AddAdmin(CCSPlayerController admin, CCSPlayerController player, string flag)
|
||||
{
|
||||
// TODO: Change default immunity?
|
||||
CS2_SimpleAdmin.AddAdmin(admin, player.SteamID.ToString(), player.PlayerName, flag, 10);
|
||||
}
|
||||
|
||||
private static void RemoveAdmin(CCSPlayerController admin, CCSPlayerController player)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.RemoveAdmin(admin, player.SteamID.ToString());
|
||||
}
|
||||
|
||||
private static void ReloadAdmins(CCSPlayerController admin)
|
||||
{
|
||||
CS2_SimpleAdmin.Instance.ReloadAdmins(admin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class ManagePlayersMenu
|
||||
{
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/generic") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_players_manage"] ?? "Manage Players");
|
||||
List<ChatMenuOptionData> options = [];
|
||||
|
||||
// permissions
|
||||
var hasSlay = AdminManager.CommandIsOverriden("css_slay") ? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_slay")) : AdminManager.PlayerHasPermissions(admin, "@css/slay");
|
||||
var hasKick = AdminManager.CommandIsOverriden("css_kick") ? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_kick")) : AdminManager.PlayerHasPermissions(admin, "@css/kick");
|
||||
var hasBan = AdminManager.CommandIsOverriden("css_ban") ? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_ban")) : AdminManager.PlayerHasPermissions(admin, "@css/ban");
|
||||
var hasChat = AdminManager.CommandIsOverriden("css_gag") ? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_gag")) : AdminManager.PlayerHasPermissions(admin, "@css/chat");
|
||||
|
||||
// TODO: Localize options
|
||||
// options added in order
|
||||
|
||||
if (hasSlay)
|
||||
{
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_slap"] ?? "Slap", () => PlayersMenu.OpenMenu(admin, localizer?["sa_slap"] ?? "Slap", SlapMenu)));
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_slay"] ?? "Slay", () => PlayersMenu.OpenMenu(admin, localizer?["sa_slay"] ?? "Slay", Slay)));
|
||||
}
|
||||
|
||||
if (hasKick)
|
||||
{
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_kick"] ?? "Kick", () => PlayersMenu.OpenMenu(admin, localizer?["sa_kick"] ?? "Kick", KickMenu)));
|
||||
}
|
||||
|
||||
if (AdminManager.CommandIsOverriden("css_warn")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_warn"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/kick"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_warn"] ?? "Warn", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_warn"] ?? "Warn", (admin, player) => DurationMenu.OpenMenu(admin, $"{localizer?["sa_warn"] ?? "Warn"}: {player.PlayerName}", player, WarnMenu))));
|
||||
|
||||
if (hasBan)
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_ban"] ?? "Ban", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_ban"] ?? "Ban", (admin, player) => DurationMenu.OpenMenu(admin, $"{localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player, BanMenu))));
|
||||
|
||||
if (hasChat)
|
||||
{
|
||||
if (AdminManager.CommandIsOverriden("css_gag")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_gag"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/chat"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_gag"] ?? "Gag", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_gag"] ?? "Gag", (admin, player) => DurationMenu.OpenMenu(admin, $"{localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player, GagMenu))));
|
||||
if (AdminManager.CommandIsOverriden("css_mute")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_mute"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/chat"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_mute"] ?? "Mute", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_mute"] ?? "Mute", (admin, player) => DurationMenu.OpenMenu(admin, $"{localizer?["sa_mute"] ?? "Mute"}: {player.PlayerName}", player, MuteMenu))));
|
||||
if (AdminManager.CommandIsOverriden("css_silence")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_silence"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/chat"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_silence"] ?? "Silence", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_silence"] ?? "Silence", (admin, player) => DurationMenu.OpenMenu(admin, $"{localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player, SilenceMenu))));
|
||||
}
|
||||
|
||||
if (AdminManager.CommandIsOverriden("css_team")
|
||||
? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_team"))
|
||||
: AdminManager.PlayerHasPermissions(admin, "@css/kick"))
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_team_force"] ?? "Force Team", () => PlayersMenu.OpenMenu(admin, localizer?["sa_team_force"] ?? "Force Team", ForceTeamMenu)));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void SlapMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_slap"] ?? "Slap"}: {player?.PlayerName}");
|
||||
List<ChatMenuOptionData> options =
|
||||
[
|
||||
// options added in order
|
||||
new ChatMenuOptionData("0 hp", () => ApplySlapAndKeepMenu(admin, player, 0)),
|
||||
new ChatMenuOptionData("1 hp", () => ApplySlapAndKeepMenu(admin, player, 1)),
|
||||
new ChatMenuOptionData("5 hp", () => ApplySlapAndKeepMenu(admin, player, 5)),
|
||||
new ChatMenuOptionData("10 hp", () => ApplySlapAndKeepMenu(admin, player, 10)),
|
||||
new ChatMenuOptionData("50 hp", () => ApplySlapAndKeepMenu(admin, player, 50)),
|
||||
new ChatMenuOptionData("100 hp", () => ApplySlapAndKeepMenu(admin, player, 100)),
|
||||
];
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void ApplySlapAndKeepMenu(CCSPlayerController admin, CCSPlayerController? player, int damage)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Slap(admin, player, damage);
|
||||
SlapMenu(admin, player);
|
||||
}
|
||||
|
||||
private static void Slay(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Slay(admin, player);
|
||||
}
|
||||
|
||||
private static void KickMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_kick"] ?? "Kick"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Kick(admin, player, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Kick(CCSPlayerController admin, CCSPlayerController? player, string? reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Kick(admin, player, reason);
|
||||
}
|
||||
|
||||
private static void BanMenu(CCSPlayerController admin, CCSPlayerController? player, int duration)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_ban"] ?? "Ban"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Ban(admin, player, duration, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Ban(CCSPlayerController admin, CCSPlayerController? player, int duration, string reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Ban(admin, player, duration, reason);
|
||||
}
|
||||
|
||||
private static void WarnMenu(CCSPlayerController admin, CCSPlayerController? player, int duration)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_warn"] ?? "Warn"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Warn(admin, player, duration, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Warn(CCSPlayerController admin, CCSPlayerController? player, int duration, string reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Warn(admin, player, duration, reason);
|
||||
}
|
||||
|
||||
private static void GagMenu(CCSPlayerController admin, CCSPlayerController? player, int duration)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_gag"] ?? "Gag"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Gag(admin, player, duration, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Gag(CCSPlayerController admin, CCSPlayerController? player, int duration, string reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Gag(admin, player, duration, reason);
|
||||
}
|
||||
|
||||
private static void MuteMenu(CCSPlayerController admin, CCSPlayerController? player, int duration)
|
||||
{
|
||||
// TODO: Localize and make options in config?
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_mute"] ?? "Mute"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Mute(admin, player, duration, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Mute(CCSPlayerController admin, CCSPlayerController? player, int duration, string reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Mute(admin, player, duration, reason);
|
||||
}
|
||||
|
||||
private static void SilenceMenu(CCSPlayerController admin, CCSPlayerController? player, int duration)
|
||||
{
|
||||
// TODO: Localize and make options in config?
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_silence"] ?? "Silence"}: {player?.PlayerName}");
|
||||
|
||||
foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
|
||||
{
|
||||
menu.AddMenuOption(option, (_, _) =>
|
||||
{
|
||||
if (player is { IsValid: true })
|
||||
Silence(admin, player, duration, option);
|
||||
});
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void Silence(CCSPlayerController admin, CCSPlayerController? player, int duration, string reason)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.Silence(admin, player, duration, reason);
|
||||
}
|
||||
|
||||
private static void ForceTeamMenu(CCSPlayerController admin, CCSPlayerController? player)
|
||||
{
|
||||
// TODO: Localize
|
||||
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_team_force"] ?? "Force Team"} {player?.PlayerName}");
|
||||
List<ChatMenuOptionData> options =
|
||||
[
|
||||
new ChatMenuOptionData(CS2_SimpleAdmin._localizer?["sa_team_ct"] ?? "CT", () => ForceTeam(admin, player, "ct", CsTeam.CounterTerrorist)),
|
||||
new ChatMenuOptionData(CS2_SimpleAdmin._localizer?["sa_team_t"] ?? "T", () => ForceTeam(admin, player, "t", CsTeam.Terrorist)),
|
||||
new ChatMenuOptionData(CS2_SimpleAdmin._localizer?["sa_team_swap"] ?? "Swap", () => ForceTeam(admin, player, "swap", CsTeam.Spectator)),
|
||||
new ChatMenuOptionData(CS2_SimpleAdmin._localizer?["sa_team_spec"] ?? "Spec", () => ForceTeam(admin, player, "spec", CsTeam.Spectator)),
|
||||
];
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void ForceTeam(CCSPlayerController admin, CCSPlayerController? player, string teamName, CsTeam teamNum)
|
||||
{
|
||||
if (player is not { IsValid: true }) return;
|
||||
|
||||
CS2_SimpleAdmin.Instance.ChangeTeam(admin, player, teamName, teamNum, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class ManageServerMenu
|
||||
{
|
||||
public static void OpenMenu(CCSPlayerController admin)
|
||||
{
|
||||
if (admin.IsValid == false)
|
||||
return;
|
||||
|
||||
var localizer = CS2_SimpleAdmin._localizer;
|
||||
if (AdminManager.PlayerHasPermissions(admin, "@css/generic") == false)
|
||||
{
|
||||
admin.PrintToChat(localizer?["sa_prefix"] ??
|
||||
"[SimpleAdmin] " +
|
||||
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_server_manage"] ?? "Server Manage");
|
||||
List<ChatMenuOptionData> options = [];
|
||||
|
||||
|
||||
// permissions
|
||||
var hasMap = AdminManager.CommandIsOverriden("css_map") ? AdminManager.PlayerHasPermissions(admin, AdminManager.GetPermissionOverrides("css_map")) : AdminManager.PlayerHasPermissions(admin, "@css/changemap");
|
||||
|
||||
//bool hasMap = AdminManager.PlayerHasPermissions(admin, "@css/changemap");
|
||||
|
||||
// options added in order
|
||||
|
||||
if (hasMap)
|
||||
{
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_changemap"] ?? "Change Map", () => ChangeMapMenu(admin)));
|
||||
}
|
||||
|
||||
options.Add(new ChatMenuOptionData(localizer?["sa_restart_game"] ?? "Restart Game", () => CS2_SimpleAdmin.RestartGame(admin)));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void ChangeMapMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu(CS2_SimpleAdmin._localizer?["sa_changemap"] ?? "Change Map");
|
||||
List<ChatMenuOptionData> options = [];
|
||||
|
||||
var maps = CS2_SimpleAdmin.Instance.Config.DefaultMaps;
|
||||
options.AddRange(maps.Select(map => new ChatMenuOptionData(map, () => ExecuteChangeMap(admin, map, false))));
|
||||
|
||||
var wsMaps = CS2_SimpleAdmin.Instance.Config.WorkshopMaps;
|
||||
options.AddRange(wsMaps.Select(map => new ChatMenuOptionData($"{map.Key} (WS)", () => ExecuteChangeMap(admin, map.Value?.ToString() ?? map.Key, true))));
|
||||
|
||||
foreach (var menuOptionData in options)
|
||||
{
|
||||
var menuName = menuOptionData.Name;
|
||||
menu.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
|
||||
private static void ExecuteChangeMap(CCSPlayerController admin, string mapName, bool workshop)
|
||||
{
|
||||
if (workshop)
|
||||
CS2_SimpleAdmin.Instance.ChangeWorkshopMap(admin, mapName);
|
||||
else
|
||||
CS2_SimpleAdmin.Instance.ChangeMap(admin, mapName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using System.Web;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus
|
||||
{
|
||||
public static class PlayersMenu
|
||||
{
|
||||
public static void OpenRealPlayersMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
{
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.IsBot == false);
|
||||
}
|
||||
|
||||
public static void OpenAdminPlayersMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController?, bool>? enableFilter = null)
|
||||
{
|
||||
OpenMenu(admin, menuName, onSelectAction, p => AdminManager.GetPlayerAdminData(p)?.Flags.Count > 0);
|
||||
}
|
||||
|
||||
public static void OpenAliveMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
{
|
||||
OpenMenu(admin, menuName, onSelectAction, p => p.PawnIsAlive);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static void OpenMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
|
||||
{
|
||||
var menu = AdminMenu.CreateMenu(menuName);
|
||||
|
||||
var players = Helper.GetValidPlayersWithBots();
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player != null && player.PlayerName.Length > 26 ? player.PlayerName[..26] : player?.PlayerName;
|
||||
|
||||
var optionName = HttpUtility.HtmlEncode(playerName);
|
||||
if (player != null && enableFilter != null && enableFilter(player) == false)
|
||||
continue;
|
||||
|
||||
var enabled = admin.CanTarget(player);
|
||||
|
||||
if (optionName != null)
|
||||
menu.AddMenuOption(optionName, (_, _) =>
|
||||
{
|
||||
if (player != null) onSelectAction.Invoke(admin, player);
|
||||
},
|
||||
enabled == false);
|
||||
}
|
||||
|
||||
AdminMenu.OpenMenu(admin, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace CS2_SimpleAdmin
|
||||
{
|
||||
public class PlayerInfo
|
||||
{
|
||||
public int? UserId { get; init; }
|
||||
public int Slot { get; init; }
|
||||
public string? SteamId { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? IpAddress { get; init; }
|
||||
}
|
||||
}
|
||||
101
README.md
101
README.md
@@ -1,101 +0,0 @@
|
||||
# CS2-SimpleAdmin
|
||||
|
||||
### Do you appreciate what I do? Buy me a cup of tea ❤️
|
||||
[](https://ko-fi.com/Y8Y4THKXG)
|
||||
|
||||
### Description
|
||||
Manage your Counter-Strike 2 server by simple commands :)
|
||||
|
||||
### Info
|
||||
~~It's only plugin base~~, I don't have much time for more extensive development, so if you want to help, do it :)
|
||||
**The plugin will be developed as much as possible**, so it is no longer just a base for other plugins
|
||||
|
||||
### Commands
|
||||
```js
|
||||
- css_addadmin <steamid> <name> <flags/groups> <immunity> [time in minutes] - Add admin by steamid // @css/root
|
||||
- css_deladmin <steamid> - Delete admin by steamid // @css/root
|
||||
- css_reloadadmins - Reload sql admins // @css/root
|
||||
- css_hide - Hide admin on scoreboard and commands action // @css/kick
|
||||
- css_admin - Display all admin commands // @css/generic
|
||||
- css_who <#userid or name> - Display informations about player // @css/generic
|
||||
- css_players - Display player list // @css/generic
|
||||
- css_ban <#userid or name> [time in minutes/0 perm] [reason] - Ban player // @css/ban
|
||||
- css_addban <steamid> [time in minutes/0 perm] [reason] - Ban player via steamid64 // @css/ban
|
||||
- css_banip <ip> [time in minutes/0 perm] [reason] - Ban player via IP address // @css/ban
|
||||
- css_unban <steamid or name or ip> - Unban player // @css/unban
|
||||
- css_kick <#userid or name> [reason] - Kick player / @css/kick
|
||||
- css_gag <#userid or name> [time in minutes/0 perm] [reason] - Gag player // @css/chat
|
||||
- css_addgag <steamid> [time in minutes/0 perm] [reason] - Gag player via steamid64 // @css/chat
|
||||
- css_ungag <steamid or name> - Ungag player // @css/chat
|
||||
- css_mute <#userid or name> [time in minutes/0 perm] [reason] - Mute player // @css/chat
|
||||
- css_addmute <steamid> [time in minutes/0 perm] [reason] - Mute player via steamid64 // @css/chat
|
||||
- css_unmute <steamid or name> - Unmute player // @css/chat
|
||||
- css_silence <#userid or name> [time in minutes/0 perm] [reason] - Silence player // @css/chat
|
||||
- css_addsilence <steamid> [time in minutes/0 perm] [reason] - Silence player via steamid64 // @css/chat
|
||||
- css_unsilence <steamid or name> - Unsilence player // @css/chat
|
||||
- css_give <#userid or name> <weapon> - Give weapon to player // @css/cheats
|
||||
- css_strip <#userid or name> - Takes all of the player weapons // @css/slay
|
||||
- css_hp <#userid or name> [health] - Set player health // @css/slay
|
||||
- css_speed <#userid or name> [speed] - Set player speed // @css/slay
|
||||
- css_god <#userid or name> - Toggle godmode for player // @css/cheats
|
||||
- css_slay <#userid or name> - Kill player // @css/slay
|
||||
- css_slap <#userid or name> [damage] - Slap player // @css/slay
|
||||
- css_team <#userid or name> [<ct/tt/spec/swap>] [-k] - Change player team (swap - swap player team, -k - kill player) // @css/kick
|
||||
- css_vote <"Question?"> ["Answer1"] ["Answer2"] ... - Create vote // @css/generic
|
||||
- css_map <mapname> - Change map // @css/changemap
|
||||
- css_wsmap <name or id> - Change workshop map // @css/changemap
|
||||
- css_asay <message> - Say message to all admins // @css/chat
|
||||
- css_say <message> - Say message as admin in chat // @css/chat
|
||||
- css_psay <#userid or name> <message> - Sends private message to player // @css/chat
|
||||
- css_csay <message> - Say message as admin in center // @css/chat
|
||||
- css_hsay <message> - Say message as admin in hud // @css/chat
|
||||
- css_noclip <#userid or name> - Toggle noclip for player // @css/cheats
|
||||
- css_freeze <#userid or name> [duration] - Freeze player // @css/slay
|
||||
- css_unfreeze <#userid or name> - Unfreeze player // @css/slay
|
||||
- css_rename <#userid or name> <new name> - Rename player // @css/kick
|
||||
- css_prename <#userid or name> <new name> - Permanently rename player (until the server restarts - don't set new name to remove perm rename) // @css/ban
|
||||
- css_respawn <#userid or name> - Respawn player // @css/cheats
|
||||
- css_cvar <cvar> <value> - Change cvar value // @css/cvar
|
||||
- css_rcon <command> - Run command as server // @css/rcon
|
||||
- css_give <#userid or name> <WeaponName> - Gives a weapon to a Player // @css/give
|
||||
|
||||
- team_chat @Message - Say message to all admins // @css/chat
|
||||
```
|
||||
|
||||
### Requirements
|
||||
- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on 228**
|
||||
- MySQL **tested on MySQL (MariaDB) Server version: 10.11.4-MariaDB-1~deb12u1 Debian 12**
|
||||
|
||||
|
||||
### Configuration
|
||||
After first launch, u need to configure plugin in addons/counterstrikesharp/configs/plugins/CS2-SimpleAdmin/CS2-SimpleAdmin.json
|
||||
|
||||
### Metrics
|
||||
From version 1.3.7a, CS2-SimpleAdmin now initiates metrics data collection. This includes gathering essential information such as the `server name`, `server address` and `country`.
|
||||
You can disable metrics by set `EnableMetrics` to false in plugin configuration.
|
||||
|
||||
### Colors
|
||||
```
|
||||
public static char Default = '\x01';
|
||||
public static char White = '\x01';
|
||||
public static char Darkred = '\x02';
|
||||
public static char Green = '\x04';
|
||||
public static char LightYellow = '\x03';
|
||||
public static char LightBlue = '\x03';
|
||||
public static char Olive = '\x05';
|
||||
public static char Lime = '\x06';
|
||||
public static char Red = '\x07';
|
||||
public static char Purple = '\x03';
|
||||
public static char Grey = '\x08';
|
||||
public static char Yellow = '\x09';
|
||||
public static char Gold = '\x10';
|
||||
public static char Silver = '\x0A';
|
||||
public static char Blue = '\x0B';
|
||||
public static char DarkBlue = '\x0C';
|
||||
public static char BlueGrey = '\x0D';
|
||||
public static char Magenta = '\x0E';
|
||||
public static char LightRed = '\x0F';
|
||||
```
|
||||
Use color name for e.g. {LightRed}
|
||||
|
||||
Credits for https://github.com/Hackmastr/css-basic-admin/
|
||||
@@ -1,39 +0,0 @@
|
||||
{GREEN}[ CS2-SimpleAdmin HELP ]{DEFAULT}
|
||||
- css_who <#userid or name> - Display informations about player
|
||||
- css_players - Display player list
|
||||
- css_ban <#userid or name> [time in minutes/0 perm] [reason] - Ban player
|
||||
- css_addban <steamid> [time in minutes/0 perm] [reason] - Ban player via steamid64
|
||||
- css_banip <ip> [time in minutes/0 perm] [reason] - Ban player via IP address
|
||||
- css_unban <steamid or name or ip> - Unban player
|
||||
- css_kick <#userid or name> [reason] - Kick player
|
||||
- css_gag <#userid or name> [time in minutes/0 perm] [reason] - Gag player
|
||||
- css_addgag <steamid> [time in minutes/0 perm] [reason] - Gag player via steamid64
|
||||
- css_unmute <steamid or name> - Ungag player
|
||||
- css_mute <#userid or name> [time in minutes/0 perm] [reason] - Mute player
|
||||
- css_addmute <steamid> [time in minutes/0 perm] [reason] - Mute player via steamid64
|
||||
- css_give <#userid or name> <weapon> - Give player a weapon
|
||||
- css_strip <#userid or name> <weapon> - Takes all of the player weapons
|
||||
- css_hp <#userid or name> [health] - Set player health
|
||||
- css_speed <#userid or name> [speed] - Set player speed
|
||||
- css_gravity <#userid or name> [gravity] - Set player gravity
|
||||
- css_money <#userid or name> [money] - Set player money
|
||||
- css_god <#userid or name> - Toggle player godmode
|
||||
- css_slay <#userid or name> - Kill player
|
||||
- css_slap <#userid or name> [damage] - Slap player
|
||||
- css_vote <'Question?'> ['Answer1'] ['Answer2'] ... - Create vote
|
||||
- css_map <mapname> - Change map
|
||||
- css_wsmap <name or id> - Change workshop map
|
||||
- css_asay <message> - Say message to all admins
|
||||
- css_say <message> - Say message as admin in chat
|
||||
- css_psay <#userid or name> <message> - Sends private message to player
|
||||
- css_csay <message> - Say message as admin in center
|
||||
- css_hsay <message> - Say message as admin in hud
|
||||
- css_noclip <#userid or name> - Toggle noclip for player
|
||||
- css_freeze <#userid or name> [duration] - Freeze player
|
||||
- css_unfreeze <#userid or name> - Unfreeze player
|
||||
- css_respawn <#userid or name> - Respawn player
|
||||
- css_cvar <cvar> <value> - Change cvar value
|
||||
- css_rcon <command> - Run command as server
|
||||
|
||||
{Green}This is a sample admin_help.txt file
|
||||
{LightRed}Write all useful information for admins here
|
||||
114
lang/ar.json
114
lang/ar.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "مجهول",
|
||||
"sa_no_permission": "ليس لديك الصلاحيات لاستخدام هذا الأمر.",
|
||||
"sa_ban_max_duration_exceeded": "مدة الحظر لا يمكن أن تتجاوز {lightred}{0}{default} دقيقة.",
|
||||
"sa_ban_perm_restricted": "ليس لديك الحق في الحظر الدائم.",
|
||||
|
||||
"sa_admin_add": "إضافة مسؤول",
|
||||
"sa_admin_remove": "إزالة المسؤول",
|
||||
"sa_admin_reload": "إعادة تحميل المسؤولين",
|
||||
|
||||
"sa_godmode": "وضع الإله",
|
||||
"sa_noclip": "بدون قصاصات",
|
||||
"sa_respawn": "إعادة الظهور",
|
||||
"sa_give_weapon": "إعطاء سلاح",
|
||||
"sa_strip_weapons": "تجريد الأسلحة",
|
||||
"sa_freeze": "تجميد",
|
||||
"sa_set_hp": "تعيين الصحة",
|
||||
"sa_set_speed": "تعيين السرعة",
|
||||
"sa_set_gravity": "تعيين الجاذبية",
|
||||
"sa_set_money": "تعيين المال",
|
||||
|
||||
"sa_changemap": "تغيير الخريطة",
|
||||
"sa_restart_game": "إعادة تشغيل اللعبة",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "تبديل",
|
||||
"sa_team_spec": "المشاهدة",
|
||||
|
||||
"sa_slap": "صفعة",
|
||||
"sa_slay": "قتل",
|
||||
"sa_kick": "طرد",
|
||||
"sa_ban": "حظر",
|
||||
"sa_gag": "كتم",
|
||||
"sa_mute": "كتم",
|
||||
"sa_silence": "صمت",
|
||||
"sa_warn": "تحذير",
|
||||
"sa_team_force": "فرض الفريق",
|
||||
|
||||
"sa_menu_custom_commands": "الأوامر المخصصة",
|
||||
"sa_menu_server_manage": "إدارة الخادم",
|
||||
"sa_menu_fun_commands": "أوامر ممتعة",
|
||||
"sa_menu_admins_manage": "إدارة المسؤولين",
|
||||
"sa_menu_players_manage": "إدارة اللاعبين",
|
||||
|
||||
"sa_player": "اللاعب",
|
||||
"sa_steamid": "معرف البخار",
|
||||
"sa_duration": "المدة",
|
||||
"sa_reason": "السبب",
|
||||
"sa_admin": "المشرف",
|
||||
"sa_permanent": "دائم",
|
||||
|
||||
"sa_discord_penalty_ban": "الحظر مسجل",
|
||||
"sa_discord_penalty_mute": "الكتم مسجل",
|
||||
"sa_discord_penalty_gag": "الصمت مسجل",
|
||||
"sa_discord_penalty_silence": "الصمت مسجل",
|
||||
"sa_discord_penalty_warn": "التحذير مسجل",
|
||||
"sa_discord_penalty_unknown": "غير معروف مسجل",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "تم تكميم فمك لمدة {lightred}{0}{default} لمدة {lightred}{1}{default} دقيقة من قبل {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "تم تكميم فمك بشكل دائم لمدة {lightred}{0}{default} من قبل {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "تم كتم صوتك لمدة {lightred}{0}{default} لمدة {lightred}{1}{default} دقيقة من قبل {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "تم كتم صوتك بشكل دائم لمدة {lightred}{0}{default} من قبل {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "تم إسكاتك لمدة {lightred}{0}{default} لمدة {lightred}{1}{default} دقيقة من قبل {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "تم إسكاتك بشكل دائم لمدة {lightred}{0}{default} من قبل {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "لقد تم تحذيرك بسبب {lightred}{0}{default} لمدة {lightred}{1}{default} دقيقة بواسطة {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "لقد تم تحذيرك بشكل دائم بسبب {lightred}{0}{default} بواسطة {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "المسؤول {lightred}{0}{default} حظر {lightred}{1}{default} لمدة {lightred}{2}{default} لمدة {lightred}{3}{default} دقيقة!",
|
||||
"sa_admin_ban_message_perm": "المسؤول {lightred}{0}{default} حظر {lightred}{1}{default} بشكل دائم لمدة {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "المسؤول {lightred}{0}{default} طرد {lightred}{1}{default} لمدة {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "المسؤول {lightred}{0}{default} قام بتكميم فم {lightred}{1}{default} لمدة {lightred}{2}{default} لمدة {lightred}{3}{default} دقيقة!",
|
||||
"sa_admin_gag_message_perm": "المسؤول {lightred}{0}{default} قام بتكميم فم {lightred}{1}{default} بشكل دائم لمدة {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "المسؤول {lightred}{0}{default} قام بكتم صوت {lightred}{1}{default} لمدة {lightred}{2}{default} لمدة {lightred}{3}{default} دقيقة!",
|
||||
"sa_admin_mute_message_perm": "المسؤول {lightred}{0}{default} قام بكتم صوت {lightred}{1}{default} بشكل دائم لمدة {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "المسؤول {lightred}{0}{default} قام بإسكات {lightred}{1}{default} لمدة {lightred}{2}{default} لمدة {lightred}{3}{default} دقيقة!",
|
||||
"sa_admin_silence_message_perm": "المسؤول {lightred}{0}{default} قام بإسكات {lightred}{1}{default} بشكل دائم لمدة {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "الإداري {lightred}{0}{default} حذر {lightred}{1}{default} بسبب {lightred}{2}{default} لمدة {lightred}{3}{default} دقيقة!",
|
||||
"sa_admin_warn_message_perm": "الإداري {lightred}{0}{default} حذر {lightred}{1}{default} بشكل دائم بسبب {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "المسؤول {lightred}{0}{default} قام بإعطاء {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "المسؤول {lightred}{0}{default} قام بسحب كل أسلحة {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "المسؤول {lightred}{0}{default} قام بتغيير كمية نقاط الصحة لـ {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "المسؤول {lightred}{0}{default} قام بتغيير السرعة لـ {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "المسؤول {lightred}{0}{default} قام بتغيير الجاذبية لـ {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "المسؤول {lightred}{0}{default} قام بتغيير المال لـ {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "المسؤول {lightred}{0}{default} قام بتغيير وضع الإله لـ {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "المسؤول {lightred}{0}{default} قام بقتل {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "المسؤول {lightred}{0}{default} قام بصفع {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "المسؤول {lightred}{0}{default} قام بتغيير الخريطة إلى {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "المسؤول {lightred}{0}{default} قام بتبديل الطيران لـ {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "المسؤول {lightred}{0}{default} قام بتجميد {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "المسؤول {lightred}{0}{default} قام بفك تجميد {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "المسؤول {lightred}{0}{default} قام بتغيير اسم {lightred}{1}{default} إلى {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "المسؤول {lightred}{0}{default} قام بإعادة تولد {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "المسؤول {lightred}{0}{default} قام بالانتقال إلى {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "المسؤول {lightred}{0}{default} قام بنقل نفسه إلى {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "المسؤول {lightred}{0}{default} قام بنقل {lightred}{1}{default} إلى {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}التحذيرات",
|
||||
"sa_admin_warns_unwarn": "{lime}تم بنجاح{default} إزالة التحذير عن {gold}{0} {default}من {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}التصويت على {gold}{0}",
|
||||
"sa_admin_vote_message": "المسؤول {lightred}{0}{default} بدأ التصويت على {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}نتائج التصويت على {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}مسؤول: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(مسؤول) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(لاعب) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** أصدر الأمر `{1}` على الخادم `HOSTNAME`"
|
||||
}
|
||||
114
lang/de.json
114
lang/de.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Unbekannt",
|
||||
"sa_no_permission": "Du hast keine Berechtigung zur Verwendung dieses Befehls.",
|
||||
"sa_ban_max_duration_exceeded": "Die Dauer des Banns darf {lightred}{0}{default} Minuten nicht überschreiten.",
|
||||
"sa_ban_perm_restricted": "Du hast nicht die Berechtigung, einen permanenten Bann auszusprechen.",
|
||||
|
||||
"sa_admin_add": "Admin hinzufügen",
|
||||
"sa_admin_remove": "Admin entfernen",
|
||||
"sa_admin_reload": "Admins neuladen",
|
||||
|
||||
"sa_godmode": "Gottmodus",
|
||||
"sa_noclip": "No Clip",
|
||||
"sa_respawn": "Wiederbeleben",
|
||||
"sa_give_weapon": "Waffe gegeben",
|
||||
"sa_strip_weapons": "Waffen abnehmen",
|
||||
"sa_freeze": "Einfrieren",
|
||||
"sa_set_hp": "Lp setzen",
|
||||
"sa_set_speed": "Geschwindigkeit setzen",
|
||||
"sa_set_gravity": "Gravitation setzen",
|
||||
"sa_set_money": "Geld setzen",
|
||||
|
||||
"sa_changemap": "Map wechseln",
|
||||
"sa_restart_game": "Spiel neustarten",
|
||||
|
||||
"sa_team_ct": "AT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Wechseln",
|
||||
"sa_team_spec": "Zuschauer",
|
||||
|
||||
"sa_slap": "Klaps",
|
||||
"sa_slay": "töten",
|
||||
"sa_kick": "Kicken",
|
||||
"sa_ban": "Bann",
|
||||
"sa_gag": "Chat stummschalten",
|
||||
"sa_mute": "Sprachchat stummschalten",
|
||||
"sa_silence": "Komplett stummschalten",
|
||||
"sa_warn": "Warnen",
|
||||
"sa_team_force": "Team zuweisen",
|
||||
|
||||
"sa_menu_custom_commands": "Eigene Befehle",
|
||||
"sa_menu_server_manage": "Server Verwalten",
|
||||
"sa_menu_fun_commands": "Spaß Befehle",
|
||||
"sa_menu_admins_manage": "Admins verwalten",
|
||||
"sa_menu_players_manage": "Spieler verwalten",
|
||||
|
||||
"sa_player": "Spieler",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Dauer",
|
||||
"sa_reason": "Grund",
|
||||
"sa_admin": "Admin",
|
||||
"sa_permanent": "Permanent",
|
||||
|
||||
"sa_discord_penalty_ban": "Bann registriert",
|
||||
"sa_discord_penalty_mute": "Chat-Stummschaltung registriert",
|
||||
"sa_discord_penalty_gag": "Sprachchat-Stummschaltung registriert",
|
||||
"sa_discord_penalty_silence": "Komplett-Stummschaltung registriert",
|
||||
"sa_discord_penalty_warn": "Warnung registriert",
|
||||
"sa_discord_penalty_unknown": "Unbekanntes registriert",
|
||||
|
||||
"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!",
|
||||
"sa_player_gag_message_time": "Du wurdest wegen {lightred}{0}{default} für {lightred}{1}{default} Minuten von {lightred}{2}{default} im Chat stummgeschaltet!",
|
||||
"sa_player_gag_message_perm": "Du wurdest wegen {lightred}{0}{default} von {lightred}{1}{default} permanent im Chat stummgeschaltet!",
|
||||
"sa_player_mute_message_time": "Du wurdest wegen {lightred}{0}{default} für {lightred}{1}{default} Minuten von {lightred}{2}{default} im Sprachchat stummgeschaltet!",
|
||||
"sa_player_mute_message_perm": "Du wurdest wegen {lightred}{0}{default} von {lightred}{1}{default} permanent im Sprachchat stummgeschaltet!",
|
||||
"sa_player_silence_message_time": "Du wurdest wegen {lightred}{0}{default} für {lightred}{1}{default} Minuten von {lightred}{2}{default} vollständig stummgeschaltet!",
|
||||
"sa_player_silence_message_perm": "Du wurdest wegen {lightred}{0}{default} von {lightred}{1}{default} permanent vollständig stummgeschaltet!",
|
||||
"sa_player_warn_message_time": "Du wurdest wegen {lightred}{0}{default} für {lightred}{1}{default} Minuten von {lightred}{2}{default} gewarnt!",
|
||||
"sa_player_warn_message_perm": "Du wurdest dauerhaft wegen {lightred}{0}{default} von {lightred}{1}{default} gewarnt!",
|
||||
"sa_admin_ban_message_time": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} für {lightred}{3}{default} Minuten gebannt!",
|
||||
"sa_admin_ban_message_perm": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} permanent gebannt!",
|
||||
"sa_admin_kick_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} gekickt!",
|
||||
"sa_admin_gag_message_time": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} für {lightred}{3}{default} Minuten im Chat stummgeschaltet!",
|
||||
"sa_admin_gag_message_perm": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} permanent im Chat stummgeschaltet!",
|
||||
"sa_admin_mute_message_time": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} für {lightred}{3}{default} Minuten im Sprachchat stummgeschaltet!",
|
||||
"sa_admin_mute_message_perm": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} permanent im Sprachchat stummgeschaltet!",
|
||||
"sa_admin_silence_message_time": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} für {lightred}{3}{default} Minuten vollständig stummgeschaltet!",
|
||||
"sa_admin_silence_message_perm": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} permanent vollständig stummgeschaltet!",
|
||||
"sa_admin_warn_message_time": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wegen {lightred}{2}{default} für {lightred}{3}{default} Minuten gewarnt!",
|
||||
"sa_admin_warn_message_perm": "Admin {lightred}{0}{default} hat {lightred}{1}{default} dauerhaft wegen {lightred}{2}{default} gewarnt!",
|
||||
"sa_admin_give_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} eine {lightred}{2}{default} gegeben!",
|
||||
"sa_admin_strip_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} alle Waffen abgenommen!",
|
||||
"sa_admin_hp_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Lp geändert{default}!",
|
||||
"sa_admin_speed_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Geschwindigkeit geändert!",
|
||||
"sa_admin_gravity_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Gravitation geändert!",
|
||||
"sa_admin_money_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Geld geändert!",
|
||||
"sa_admin_god_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Gottmodus umgeschaltet!",
|
||||
"sa_admin_slay_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} getötet!",
|
||||
"sa_admin_slap_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} einen Klaps gegeben!",
|
||||
"sa_admin_changemap_message": "Admin {lightred}{0}{default} hat die Map zu {lightred}{1}{default} geändert!",
|
||||
"sa_admin_noclip_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Noclip umgeschaltet!",
|
||||
"sa_admin_freeze_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} eingefroren!",
|
||||
"sa_admin_unfreeze_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} aufgetaut!",
|
||||
"sa_admin_rename_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} Namen zu {lightred}{2}{default} geändert!",
|
||||
"sa_admin_respawn_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} wiederbelebt!",
|
||||
"sa_admin_tp_message": "Admin {lightred}{0}{default} hat sich zu {lightred}{1}{default} teleportiert!",
|
||||
"sa_admin_bring_message": "Admin {lightred}{0}{default} hat zu sich {lightred}{1}{default} teleportiert!",
|
||||
"sa_admin_team_message": "Admin {lightred}{0}{default} hat {lightred}{1}{default} zu {lightred}{2}{default} gewechselt!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}WARNUNGEN",
|
||||
"sa_admin_warns_unwarn": "{lime}Erfolgreich{default} Warnung von {gold}{0} {default}von {gold}{1}{default} entfernt!",
|
||||
"sa_admin_vote_menu_title": "{lime}ABSTIMMUNG FÜR {gold}{0}",
|
||||
"sa_admin_vote_message": "Admin {lightred}{0}{default} hat eine Abstimmung für {lightred}{1}{default} gestartet",
|
||||
"sa_admin_vote_message_results": "{lime}ABSTIMMUNGS ERGEBNISSE FÜR {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(PLAYER) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** hat den Befehl `{1}` auf dem Server `HOSTNAME` ausgeführt"
|
||||
}
|
||||
113
lang/en.json
113
lang/en.json
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Unknown",
|
||||
"sa_no_permission": "You do not have permissions to use this command.",
|
||||
"sa_ban_max_duration_exceeded": "Ban duration cannot exceed {lightred}{0}{default} minutes.",
|
||||
"sa_ban_perm_restricted": "You do not have the right to permanently ban.",
|
||||
|
||||
"sa_admin_add": "Add Admin",
|
||||
"sa_admin_remove": "Remove Admin",
|
||||
"sa_admin_reload": "Reload Admins",
|
||||
|
||||
"sa_godmode": "God Mode",
|
||||
"sa_noclip": "No Clip",
|
||||
"sa_respawn": "Respawn",
|
||||
"sa_give_weapon": "Give Weapon",
|
||||
"sa_strip_weapons": "Strip Weapons",
|
||||
"sa_freeze": "Freeze",
|
||||
"sa_set_hp": "Set Hp",
|
||||
"sa_set_speed": "Set Speed",
|
||||
"sa_set_gravity": "Set Gravity",
|
||||
"sa_set_money": "Set Money",
|
||||
|
||||
"sa_changemap": "Change Map",
|
||||
"sa_restart_game": "Restart Game",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Swap",
|
||||
"sa_team_spec": "Spec",
|
||||
|
||||
"sa_slap": "Slap",
|
||||
"sa_slay": "slay",
|
||||
"sa_kick": "Kick",
|
||||
"sa_ban": "Ban",
|
||||
"sa_gag": "Gag",
|
||||
"sa_mute": "Mute",
|
||||
"sa_silence": "Silence",
|
||||
"sa_warn": "Warn",
|
||||
"sa_team_force": "Force Team",
|
||||
|
||||
"sa_menu_custom_commands": "Custom Commands",
|
||||
"sa_menu_server_manage": "Server Manage",
|
||||
"sa_menu_fun_commands": "Fun Commands",
|
||||
"sa_menu_admins_manage": "Admins Manage",
|
||||
"sa_menu_players_manage": "Players Manage",
|
||||
|
||||
"sa_player": "Player",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Duration",
|
||||
"sa_reason": "Reason",
|
||||
"sa_admin": "Admin",
|
||||
"sa_permanent": "Permanent",
|
||||
|
||||
"sa_discord_penalty_ban": "Ban registered",
|
||||
"sa_discord_penalty_mute": "Mute registered",
|
||||
"sa_discord_penalty_gag": "Gag registered",
|
||||
"sa_discord_penalty_silence": "Silence registered",
|
||||
"sa_discord_penalty_warn": "Warn registered",
|
||||
"sa_discord_penalty_unknown": "Unknown registered",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "You have been gagged for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "You have been gagged permanently for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "You have been muted for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "You have been muted permanently for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "You have been silenced for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "You have been silenced permanently for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "You have been warned for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "You have been warned permanently for {lightred}{0}{default} by {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Admin {lightred}{0}{default} banned {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!",
|
||||
"sa_admin_ban_message_perm": "Admin {lightred}{0}{default} banned {lightred}{1}{default} permanently for {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Admin {lightred}{0}{default} kicked {lightred}{1}{default} for {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Admin {lightred}{0}{default} gagged {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!",
|
||||
"sa_admin_gag_message_perm": "Admin {lightred}{0}{default} gagged {lightred}{1}{default} permanently for {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Admin {lightred}{0}{default} muted {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!",
|
||||
"sa_admin_mute_message_perm": "Admin {lightred}{0}{default} muted {lightred}{1}{default} permanently for {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Admin {lightred}{0}{default} silenced {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!",
|
||||
"sa_admin_silence_message_perm": "Admin {lightred}{0}{default} silenced {lightred}{1}{default} permanently for {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Admin {lightred}{0}{default} warned {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!",
|
||||
"sa_admin_warn_message_perm": "Admin {lightred}{0}{default} warned {lightred}{1}{default} permanently for {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Admin {lightred}{0}{default} gave {lightred}{1}{default} a {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Admin {lightred}{0}{default} took all of player {lightred}{1}{default} weapons!",
|
||||
"sa_admin_hp_message": "Admin {lightred}{0}{default} changed {lightred}{1}{default} hp amount{default}!",
|
||||
"sa_admin_speed_message": "Admin {lightred}{0}{default} changed speed for {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Admin {lightred}{0}{default} changed gravity for {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Admin {lightred}{0}{default} changed money for {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Admin {lightred}{0}{default} changed god mode for {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Admin {lightred}{0}{default} slayed {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Admin {lightred}{0}{default} slapped {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Admin {lightred}{0}{default} changed map to {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Admin {lightred}{0}{default} toggled noclip for {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Admin {lightred}{0}{default} froze {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Admin {lightred}{0}{default} unfroze {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "Admin {lightred}{0}{default} changed {lightred}{1}{default} nickname to {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "Admin {lightred}{0}{default} respawned {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Admin {lightred}{0}{default} teleported to {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Admin {lightred}{0}{default} teleported to himself {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "Admin {lightred}{0}{default} transfered {lightred}{1}{default} to {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}WARNS",
|
||||
"sa_admin_warns_unwarn": "{lime}Successfully{default} unwarned {gold}{0} {default}for {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}VOTING FOR {gold}{0}",
|
||||
"sa_admin_vote_message": "Admin {lightred}{0}{default} started voting for {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}VOTING RESULTS FOR {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(PLAYER) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_discord_log_command": "**{0}** issued command `{1}` on server `HOSTNAME`"
|
||||
}
|
||||
114
lang/es.json
114
lang/es.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Desconocido",
|
||||
"sa_no_permission": "No tienes permisos para usar este comando.",
|
||||
"sa_ban_max_duration_exceeded": "La duración de la prohibición no puede exceder {lightred}{0}{default} minutos.",
|
||||
"sa_ban_perm_restricted": "No tienes derecho a prohibir permanentemente.",
|
||||
|
||||
"sa_admin_add": "Agregar Administrador",
|
||||
"sa_admin_remove": "Eliminar Administrador",
|
||||
"sa_admin_reload": "Recargar Administradores",
|
||||
|
||||
"sa_godmode": "Modo Dios",
|
||||
"sa_noclip": "Sin Colisión",
|
||||
"sa_respawn": "Reaparecer",
|
||||
"sa_give_weapon": "Dar Arma",
|
||||
"sa_strip_weapons": "Eliminar Armas",
|
||||
"sa_freeze": "Congelar",
|
||||
"sa_set_hp": "Establecer Vida",
|
||||
"sa_set_speed": "Establecer Velocidad",
|
||||
"sa_set_gravity": "Establecer Gravedad",
|
||||
"sa_set_money": "Establecer Dinero",
|
||||
|
||||
"sa_changemap": "Cambiar Mapa",
|
||||
"sa_restart_game": "Reiniciar Juego",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Intercambiar",
|
||||
"sa_team_spec": "Espectador",
|
||||
|
||||
"sa_slap": "Golpear",
|
||||
"sa_slay": "Matar",
|
||||
"sa_kick": "Expulsar",
|
||||
"sa_ban": "Banear",
|
||||
"sa_gag": "Callar",
|
||||
"sa_mute": "Silenciar",
|
||||
"sa_silence": "Silencio",
|
||||
"sa_warn": "Advertencia",
|
||||
"sa_team_force": "Forzar Equipo",
|
||||
|
||||
"sa_menu_custom_commands": "Comandos Personalizados",
|
||||
"sa_menu_server_manage": "Administrar Servidor",
|
||||
"sa_menu_fun_commands": "Comandos Divertidos",
|
||||
"sa_menu_admins_manage": "Administrar Administradores",
|
||||
"sa_menu_players_manage": "Administrar Jugadores",
|
||||
|
||||
"sa_player": "Jugador",
|
||||
"sa_steamid": "ID de Steam",
|
||||
"sa_duration": "Duración",
|
||||
"sa_reason": "Motivo",
|
||||
"sa_admin": "Admin",
|
||||
"sa_permanent": "Permanente",
|
||||
|
||||
"sa_discord_penalty_ban": "Ban registrado",
|
||||
"sa_discord_penalty_mute": "Silencio registrado",
|
||||
"sa_discord_penalty_gag": "Mordaza registrada",
|
||||
"sa_discord_penalty_silence": "Silencio registrado",
|
||||
"sa_discord_penalty_warn": "Advertencia registrada",
|
||||
"sa_discord_penalty_unknown": "Registro desconocido",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Has sido silenciado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "Has sido silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Has sido muteado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "Has sido muteado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Has sido silenciado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "Has sido silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "¡Has sido advertido por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "¡Has sido advertido permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "El administrador {lightred}{0}{default} ha baneado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_ban_message_perm": "El administrador {lightred}{0}{default} ha baneado permanentemente a {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "El administrador {lightred}{0}{default} ha expulsado a {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_gag_message_perm": "El administrador {lightred}{0}{default} ha silenciado permanentemente a {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "El administrador {lightred}{0}{default} ha muteado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_mute_message_perm": "El administrador {lightred}{0}{default} ha muteado permanentemente a {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_silence_message_perm": "El administrador {lightred}{0}{default} ha silenciado permanentemente a {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "¡El administrador {lightred}{0}{default} advirtió a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_warn_message_perm": "¡El administrador {lightred}{0}{default} advirtió a {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "El administrador {lightred}{0}{default} ha dado a {lightred}{1}{default} un {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "El administrador {lightred}{0}{default} ha quitado todas las armas de {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "El administrador {lightred}{0}{default} ha cambiado la cantidad de puntos de vida de {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "El administrador {lightred}{0}{default} ha cambiado la velocidad de {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "El administrador {lightred}{0}{default} ha cambiado la gravedad de {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "El administrador {lightred}{0}{default} ha cambiado el dinero de {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "El administrador {lightred}{0}{default} ha cambiado el modo dios de {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "El administrador {lightred}{0}{default} ha matado a {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "El administrador {lightred}{0}{default} ha abofeteado a {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "El administrador {lightred}{0}{default} ha cambiado el mapa a {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "El administrador {lightred}{0}{default} ha activado el modo de vuelo para {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "El administrador {lightred}{0}{default} ha congelado a {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "El administrador {lightred}{0}{default} ha descongelado a {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "El administrador {lightred}{0}{default} ha cambiado el apodo de {lightred}{1}{default} a {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "El administrador {lightred}{0}{default} ha resucitado a {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "El administrador {lightred}{0}{default} se ha teletransportado a {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "El administrador {lightred}{0}{default} se ha teletransportado a sí mismo a {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "El administrador {lightred}{0}{default} ha transferido a {lightred}{1}{default} a {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}ADVERTENCIAS",
|
||||
"sa_admin_warns_unwarn": "{lime}Exitosamente{default} advertencia eliminada de {gold}{0} {default}de {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}VOTACIÓN PARA {gold}{0}",
|
||||
"sa_admin_vote_message": "El administrador {lightred}{0}{default} ha iniciado una votación para {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}RESULTADOS DE LA VOTACIÓN PARA {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(JUGADOR) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** emitió el comando `{1}` en el servidor `HOSTNAME`"
|
||||
}
|
||||
114
lang/fa.json
114
lang/fa.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "ناشناخته",
|
||||
"sa_no_permission": "شما دسترسی برای استفاده از این دستور را ندارید.",
|
||||
"sa_ban_max_duration_exceeded": "مدت ممنوعیت نمیتواند بیشتر از {lightred}{0}{default} دقیقه باشد.",
|
||||
"sa_ban_perm_restricted": "شما اجازه ممنوعیت دائم را ندارید.",
|
||||
|
||||
"sa_admin_add": "افزودن مدیر",
|
||||
"sa_admin_remove": "حذف مدیر",
|
||||
"sa_admin_reload": "بارگذاری مجدد مدیران",
|
||||
|
||||
"sa_godmode": "حالت خدا",
|
||||
"sa_noclip": "بدون بریدن",
|
||||
"sa_respawn": "باززایی",
|
||||
"sa_give_weapon": "دادن اسلحه",
|
||||
"sa_strip_weapons": "برداشتن اسلحه",
|
||||
"sa_freeze": "یخزدن",
|
||||
"sa_set_hp": "تنظیم پلیر",
|
||||
"sa_set_speed": "تنظیم سرعت",
|
||||
"sa_set_gravity": "تنظیم گرانش",
|
||||
"sa_set_money": "تنظیم پول",
|
||||
|
||||
"sa_changemap": "تغییر نقشه",
|
||||
"sa_restart_game": "شروع مجدد بازی",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "جابهجایی",
|
||||
"sa_team_spec": "ناظر",
|
||||
|
||||
"sa_slap": "چپاد زدن",
|
||||
"sa_slay": "کشتن",
|
||||
"sa_kick": "اخراج",
|
||||
"sa_ban": "مسدود کردن",
|
||||
"sa_gag": "بیصدا کردن",
|
||||
"sa_mute": "بیصدا کردن",
|
||||
"sa_silence": "سکوت",
|
||||
"sa_warn": "هشدار",
|
||||
"sa_team_force": "اجبار تیم",
|
||||
|
||||
"sa_menu_custom_commands": "دستورات سفارشی",
|
||||
"sa_menu_server_manage": "مدیریت سرور",
|
||||
"sa_menu_fun_commands": "دستورات جالب",
|
||||
"sa_menu_admins_manage": "مدیریت مدیران",
|
||||
"sa_menu_players_manage": "مدیریت بازیکنان",
|
||||
|
||||
"sa_player": "بازیکن",
|
||||
"sa_steamid": "شناسه استیم",
|
||||
"sa_duration": "مدت زمان",
|
||||
"sa_reason": "دلیل",
|
||||
"sa_admin": "مدیر",
|
||||
"sa_permanent": "دائمی",
|
||||
|
||||
"sa_discord_penalty_ban": "بن انجام شده",
|
||||
"sa_discord_penalty_mute": "سکوت انجام شده",
|
||||
"sa_discord_penalty_gag": "بند زدن انجام شده",
|
||||
"sa_discord_penalty_silence": "سکوت انجام شده",
|
||||
"sa_discord_penalty_warn": "هشدار ثبت شد",
|
||||
"sa_discord_penalty_unknown": "ناشناخته انجام شده",
|
||||
|
||||
"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} اخراج شدهاید!",
|
||||
"sa_player_gag_message_time": "شما توسط {lightred}{2}{default} برای {lightred}{1}{default} دقیقه به دلیل {lightred}{0}{default} خفه شدهاید!",
|
||||
"sa_player_gag_message_perm": "شما توسط {lightred}{1}{default} به دلیل {lightred}{0}{default} برای همیشه خفه شدهاید!",
|
||||
"sa_player_mute_message_time": "شما توسط {lightred}{2}{default} برای {lightred}{1}{default} دقیقه به دلیل {lightred}{0}{default} بیصدا شدهاید!",
|
||||
"sa_player_mute_message_perm": "شما توسط {lightred}{1}{default} به دلیل {lightred}{0}{default} برای همیشه بیصدا شدهاید!",
|
||||
"sa_player_silence_message_time": "شما توسط {lightred}{2}{default} برای {lightred}{1}{default} دقیقه به دلیل {lightred}{0}{default} ساکت شدهاید!",
|
||||
"sa_player_silence_message_perm": "شما توسط {lightred}{1}{default} به دلیل {lightred}{0}{default} برای همیشه ساکت شدهاید!",
|
||||
"sa_player_warn_message_time": "شما به خاطر {lightred}{0}{default} به مدت {lightred}{1}{default} دقیقه توسط {lightred}{2}{default} هشدار داده شده\u200Cاید!",
|
||||
"sa_player_warn_message_perm": "شما به طور دائم به خاطر {lightred}{0}{default} توسط {lightred}{1}{default} هشدار داده شده\u200Cاید!",
|
||||
"sa_admin_ban_message_time": "مدیر {lightred}{0}{default} {lightred}{3}{default} توسط {lightred}{2}{default} برای {lightred}{1}{default} دقیقه برای {lightred}{3}{default} مسدود کرد!",
|
||||
"sa_admin_ban_message_perm": "مدیر {lightred}{0}{default} {lightred}{2}{default} را به دلیل {lightred}{1}{default} برای همیشه مسدود کرد!",
|
||||
"sa_admin_kick_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را به دلیل {lightred}{2}{default} اخراج کرد!",
|
||||
"sa_admin_gag_message_time": "مدیر {lightred}{0}{default} {lightred}{1}{default} را برای {lightred}{3}{default} دقیقه به دلیل {lightred}{2}{default} خفه کرد!",
|
||||
"sa_admin_gag_message_perm": "مدیر {lightred}{0}{default} {lightred}{1}{default} را به دلیل {lightred}{2}{default} برای همیشه خفه کرد!",
|
||||
"sa_admin_mute_message_time": "مدیر {lightred}{0}{default} {lightred}{1}{default} را برای {lightred}{3}{default} دقیقه به دلیل {lightred}{2}{default} بیصدا کرد!",
|
||||
"sa_admin_mute_message_perm": "مدیر {lightred}{0}{default} {lightred}{1}{default} را به دلیل {lightred}{2}{default} برای همیشه بیصدا کرد!",
|
||||
"sa_admin_silence_message_time": "مدیر {lightred}{0}{default} {lightred}{1}{default} را برای {lightred}{3}{default} دقیقه به دلیل {lightred}{2}{default} ساکت کرد!",
|
||||
"sa_admin_silence_message_perm": "مدیر {lightred}{0}{default} {lightred}{1}{default} را به دلیل {lightred}{2}{default} برای همیشه ساکت کرد!",
|
||||
"sa_admin_warn_message_time": "مدیر {lightred}{0}{default} به دلیل {lightred}{2}{default} به مدت {lightred}{3}{default} دقیقه به {lightred}{1}{default} هشدار داد!",
|
||||
"sa_admin_warn_message_perm": "مدیر {lightred}{0}{default} به طور دائم به {lightred}{1}{default} به خاطر {lightred}{2}{default} هشدار داد!",
|
||||
"sa_admin_give_message": "مدیر {lightred}{0}{default} {lightred}{2}{default} به {lightred}{1}{default} داد!",
|
||||
"sa_admin_strip_message": "مدیر {lightred}{0}{default} تمام اسلحههای {lightred}{1}{default} را گرفت!",
|
||||
"sa_admin_hp_message": "مدیر {lightred}{0}{default} مقدار اچپی {lightred}{1}{default} را تغییر داد!",
|
||||
"sa_admin_speed_message": "مدیر {lightred}{0}{default} سرعت برای {lightred}{1}{default} تغییر داد!",
|
||||
"sa_admin_gravity_message": "مدیر {lightred}{0}{default} گرانش را برای {lightred}{1}{default} تغییر داد!",
|
||||
"sa_admin_money_message": "مدیر {lightred}{0}{default} پول را برای {lightred}{1}{default} تغییر داد!",
|
||||
"sa_admin_god_message": "مدیر {lightred}{0}{default} حالت خدا را برای {lightred}{1}{default} تغییر داد!",
|
||||
"sa_admin_slay_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را کشت!",
|
||||
"sa_admin_slap_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را چلوپید!",
|
||||
"sa_admin_changemap_message": "مدیر {lightred}{0}{default} نقشه را به {lightred}{1}{default} تغییر داد!",
|
||||
"sa_admin_noclip_message": "مدیر {lightred}{0}{default} برای {lightred}{1}{default} نقشه فعال کرد!",
|
||||
"sa_admin_freeze_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را منجمد کرد!",
|
||||
"sa_admin_unfreeze_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را از منجمدی خارج کرد!",
|
||||
"sa_admin_rename_message": "مدیر {lightred}{0}{default} نام {lightred}{1}{default} را به {lightred}{2}{default} تغییر داد!",
|
||||
"sa_admin_respawn_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را دوباره زنده کرد!",
|
||||
"sa_admin_tp_message": "مدیر {lightred}{0}{default} به {lightred}{1}{default} جابجا شد!",
|
||||
"sa_admin_bring_message": "مدیر {lightred}{0}{default} خودش به {lightred}{1}{default} جابجا شد!",
|
||||
"sa_admin_team_message": "مدیر {lightred}{0}{default} {lightred}{1}{default} را به {lightred}{2}{default} منتقل کرد!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}اخطارها",
|
||||
"sa_admin_warns_unwarn": "{lime}با موفقیت{default} اخطار {gold}{0} {default}از {gold}{1}{default} حذف شد!",
|
||||
"sa_admin_vote_menu_title": "{lime}رأی گیری برای {gold}{0}",
|
||||
"sa_admin_vote_message": "مدیر {lightred}{0}{default} رأی گیری برای {lightred}{1}{default} را شروع کرد",
|
||||
"sa_admin_vote_message_results": "{lime}نتایج رأی گیری برای {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}مدیر: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(مدیر) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(بازیکن) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** دستور `{1}` را در سرور `HOSTNAME` اجرا کرد"
|
||||
}
|
||||
114
lang/fr.json
114
lang/fr.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Inconnu",
|
||||
"sa_no_permission": "Vous n'avez pas les permissions pour utiliser cette commande.",
|
||||
"sa_ban_max_duration_exceeded": "La durée d'interdiction ne peut pas dépasser {lightred}{0}{default} minutes.",
|
||||
"sa_ban_perm_restricted": "Vous n'avez pas le droit de bannir définitivement.",
|
||||
|
||||
"sa_admin_add": "Ajouter un administrateur",
|
||||
"sa_admin_remove": "Supprimer un administrateur",
|
||||
"sa_admin_reload": "Recharger les administrateurs",
|
||||
|
||||
"sa_godmode": "Mode Dieu",
|
||||
"sa_noclip": "Mode Spectateur",
|
||||
"sa_respawn": "Réapparaître",
|
||||
"sa_give_weapon": "Donner une arme",
|
||||
"sa_strip_weapons": "Retirer les armes",
|
||||
"sa_freeze": "Geler",
|
||||
"sa_set_hp": "Définir les PV",
|
||||
"sa_set_speed": "Définir la vitesse",
|
||||
"sa_set_gravity": "Définir la gravité",
|
||||
"sa_set_money": "Définir l'argent",
|
||||
|
||||
"sa_changemap": "Changer de carte",
|
||||
"sa_restart_game": "Redémarrer le jeu",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Échanger",
|
||||
"sa_team_spec": "Spectateur",
|
||||
|
||||
"sa_slap": "Gifler",
|
||||
"sa_slay": "Tuer",
|
||||
"sa_kick": "Expulser",
|
||||
"sa_ban": "Bannir",
|
||||
"sa_gag": "Réduire au silence",
|
||||
"sa_mute": "Muter",
|
||||
"sa_silence": "Silence",
|
||||
"sa_warn": "Avertir",
|
||||
"sa_team_force": "Forcer l'équipe",
|
||||
|
||||
"sa_menu_custom_commands": "Commandes personnalisées",
|
||||
"sa_menu_server_manage": "Gérer le serveur",
|
||||
"sa_menu_fun_commands": "Commandes amusantes",
|
||||
"sa_menu_admins_manage": "Gérer les administrateurs",
|
||||
"sa_menu_players_manage": "Gérer les joueurs",
|
||||
|
||||
"sa_player": "Joueur",
|
||||
"sa_steamid": "ID Steam",
|
||||
"sa_duration": "Durée",
|
||||
"sa_reason": "Raison",
|
||||
"sa_admin": "Admin",
|
||||
"sa_permanent": "Permanent",
|
||||
|
||||
"sa_discord_penalty_ban": "Bannissement enregistré",
|
||||
"sa_discord_penalty_mute": "Mute enregistré",
|
||||
"sa_discord_penalty_gag": "Gag enregistré",
|
||||
"sa_discord_penalty_silence": "Silence enregistré",
|
||||
"sa_discord_penalty_warn": "Avertissement enregistré",
|
||||
"sa_discord_penalty_unknown": "Inconnu enregistré",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Vous avez été réduit au silence pour {lightred}{0}{default} pendant {lightred}{1}{default} minutes par {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "Vous avez été réduit au silence définitivement pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Vous avez été réduit au silence pour {lightred}{0}{default} pendant {lightred}{1}{default} minutes par {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "Vous avez été réduit au silence définitivement pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Vous avez été mis en sourdine pour {lightred}{0}{default} pendant {lightred}{1}{default} minutes par {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "Vous avez été mis en sourdine définitivement pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "Vous avez été averti pour {lightred}{0}{default} pendant {lightred}{1}{default} minutes par {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "Vous avez été averti définitivement pour {lightred}{0}{default} par {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Admin {lightred}{0}{default} a banni {lightred}{1}{default} pour {lightred}{2}{default} pendant {lightred}{3}{default} minutes!",
|
||||
"sa_admin_ban_message_perm": "Admin {lightred}{0}{default} a banni {lightred}{1}{default} définitivement pour {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Admin {lightred}{0}{default} a expulsé {lightred}{1}{default} pour {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Admin {lightred}{0}{default} a réduit au silence {lightred}{1}{default} pour {lightred}{2}{default} pendant {lightred}{3}{default} minutes!",
|
||||
"sa_admin_gag_message_perm": "Admin {lightred}{0}{default} a réduit au silence {lightred}{1}{default} définitivement pour {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Admin {lightred}{0}{default} a réduit au silence {lightred}{1}{default} pour {lightred}{2}{default} pendant {lightred}{3}{default} minutes!",
|
||||
"sa_admin_mute_message_perm": "Admin {lightred}{0}{default} a réduit au silence {lightred}{1}{default} définitivement pour {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Admin {lightred}{0}{default} a mis en sourdine {lightred}{1}{default} pour {lightred}{2}{default} pendant {lightred}{3}{default} minutes!",
|
||||
"sa_admin_silence_message_perm": "Admin {lightred}{0}{default} a mis en sourdine {lightred}{1}{default} définitivement pour {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Admin {lightred}{0}{default} a averti {lightred}{1}{default} pour {lightred}{2}{default} pendant {lightred}{3}{default} minutes!",
|
||||
"sa_admin_warn_message_perm": "Admin {lightred}{0}{default} a averti {lightred}{1}{default} définitivement pour {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Admin {lightred}{0}{default} a donné à {lightred}{1}{default} un {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Admin {lightred}{0}{default} a retiré toutes les armes de {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "Admin {lightred}{0}{default} a changé la quantité de points de vie de {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "Admin {lightred}{0}{default} a changé la vitesse de {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Admin {lightred}{0}{default} a changé la gravité de {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Admin {lightred}{0}{default} a changé l'argent de {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Admin {lightred}{0}{default} a changé le mode dieu de {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Admin {lightred}{0}{default} a tué {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Admin {lightred}{0}{default} a giflé {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Admin {lightred}{0}{default} a changé la carte pour {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Admin {lightred}{0}{default} a activé le noclip pour {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Admin {lightred}{0}{default} a gelé {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Admin {lightred}{0}{default} a dégelé {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "Admin {lightred}{0}{default} a changé le surnom de {lightred}{1}{default} en {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "Admin {lightred}{0}{default} a fait réapparaître {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Admin {lightred}{0}{default} s'est téléporté à {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Admin {lightred}{0}{default} s'est téléporté à lui-même à {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "Admin {lightred}{0}{default} a transféré {lightred}{1}{default} à {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}AVERTISSEMENTS",
|
||||
"sa_admin_warns_unwarn": "{lime}Réussi{default} à enlever l'avertissement de {gold}{0} {default}de {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}VOTE POUR {gold}{0}",
|
||||
"sa_admin_vote_message": "Admin {lightred}{0}{default} a lancé un vote pour {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}RÉSULTATS DU VOTE POUR {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN : {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default} : {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(JOUEUR) {lightred}{0}{default} : {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** a exécuté la commande `{1}` sur le serveur `HOSTNAME`"
|
||||
}
|
||||
114
lang/lv.json
114
lang/lv.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Nezināms",
|
||||
"sa_no_permission": "Jums nav atļauju izmantot šo komandu.",
|
||||
"sa_ban_max_duration_exceeded": "Aizlieguma ilgums nevar pārsniegt {lightred}{0}{default} minūtes.",
|
||||
"sa_ban_perm_restricted": "Jums nav tiesību uz pastāvīgu aizliegumu.",
|
||||
|
||||
"sa_admin_add": "Pievienot administratoru",
|
||||
"sa_admin_remove": "Noņemt administratoru",
|
||||
"sa_admin_reload": "Pārlādēt administratorus",
|
||||
|
||||
"sa_godmode": "Dieva režīms",
|
||||
"sa_noclip": "Bez šķēršļiem",
|
||||
"sa_respawn": "Atdzimt",
|
||||
"sa_give_weapon": "Dot ieroci",
|
||||
"sa_strip_weapons": "Noņemt ieročus",
|
||||
"sa_freeze": "Salauzt",
|
||||
"sa_set_hp": "Iestatīt veselību",
|
||||
"sa_set_speed": "Iestatīt ātrumu",
|
||||
"sa_set_gravity": "Iestatīt gravitāciju",
|
||||
"sa_set_money": "Iestatīt naudu",
|
||||
|
||||
"sa_changemap": "Mainīt karti",
|
||||
"sa_restart_game": "Restartēt spēli",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Mainīt",
|
||||
"sa_team_spec": "Skatītājs",
|
||||
|
||||
"sa_slap": "Plašs",
|
||||
"sa_slay": "Nogalināt",
|
||||
"sa_kick": "Izraidīt",
|
||||
"sa_ban": "Bloķēt",
|
||||
"sa_gag": "Izslēgt runu",
|
||||
"sa_mute": "Noklusināt",
|
||||
"sa_silence": "Klusums",
|
||||
"sa_warn": "Brīdināt",
|
||||
"sa_team_force": "Spēka komanda",
|
||||
|
||||
"sa_menu_custom_commands": "Pielāgotās komandas",
|
||||
"sa_menu_server_manage": "Servera pārvaldība",
|
||||
"sa_menu_fun_commands": "Jautras komandas",
|
||||
"sa_menu_admins_manage": "Administratoru pārvaldība",
|
||||
"sa_menu_players_manage": "Spēlētāju pārvaldība",
|
||||
|
||||
"sa_player": "Spēlētājs",
|
||||
"sa_steamid": "Steam ID",
|
||||
"sa_duration": "Ilgums",
|
||||
"sa_reason": "Iemesls",
|
||||
"sa_admin": "Admins",
|
||||
"sa_permanent": "Pastāvīgs",
|
||||
|
||||
"sa_discord_penalty_ban": "Bans reģistrēts",
|
||||
"sa_discord_penalty_mute": "Mute reģistrēts",
|
||||
"sa_discord_penalty_gag": "Gag reģistrēts",
|
||||
"sa_discord_penalty_silence": "Klusums reģistrēts",
|
||||
"sa_discord_penalty_warn": "Brīdinājums reģistrēts",
|
||||
"sa_discord_penalty_unknown": "Nezināms reģistrēts",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Tev ir izliegta čata rakstīšana uz {lightred}{0}{default} uz {lightred}{1}{default} minūtēm, iemesls: {lightred}{2}{default}, Admins: {lightred}{3}{default}!",
|
||||
"sa_player_gag_message_perm": "Tev ir izliegta čata rakstīšana uz mūžu, iemesls: {lightred}{0}{default}, Admins: {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Tev ir izliegta balsu rakstīšana uz {lightred}{0}{default} uz {lightred}{1}{default} minūtēm, iemesls: {lightred}{2}{default}, Admins: {lightred}{3}{default}!",
|
||||
"sa_player_mute_message_perm": "Tev ir izliegta balsu rakstīšana uz mūžu, iemesls: {lightred}{0}{default}, Admins: {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Tevis balss ir izslēgta uz {lightred}{0}{default} uz {lightred}{1}{default} minūtēm, iemesls: {lightred}{2}{default}, Admins: {lightred}{3}{default}!",
|
||||
"sa_player_silence_message_perm": "Tevis balss ir izslēgta uz mūžu, iemesls: {lightred}{0}{default}, Admins: {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "Jums ir izteikts brīdinājums par {lightred}{0}{default} uz {lightred}{1}{default} minūtēm no {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "Jums ir izteikts pastāvīgs brīdinājums par {lightred}{0}{default} no {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Admins {lightred}{0}{default} nobanoja {lightred}{1}{default} uz {lightred}{2}{default} uz {lightred}{3}{default} minūtēm, iemesls: {lightred}{4}{default}!",
|
||||
"sa_admin_ban_message_perm": "Admins {lightred}{0}{default} nobanoja {lightred}{1}{default} uz mūžu, iemesls: {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Admins {lightred}{0}{default} izmeta {lightred}{1}{default}, iemesls: {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Admins {lightred}{0}{default} izliega čata rakstīšanu {lightred}{1}{default} uz {lightred}{2}{default} uz {lightred}{3}{default} minūtēm, iemesls: {lightred}{4}{default}!",
|
||||
"sa_admin_gag_message_perm": "Admins {lightred}{0}{default} izliega čata rakstīšanu {lightred}{1}{default} uz mūžu, iemesls: {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Admins {lightred}{0}{default} izliega balsu rakstīšanu {lightred}{1}{default} uz {lightred}{2}{default} uz {lightred}{3}{default} minūtēm, iemesls: {lightred}{4}{default}!",
|
||||
"sa_admin_mute_message_perm": "Admins {lightred}{0}{default} izliega balsu rakstīšanu {lightred}{1}{default} uz mūžu, iemesls: {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Admins {lightred}{0}{default} izslēdza balss iespēju {lightred}{1}{default} uz {lightred}{2}{default} uz {lightred}{3}{default} minūtēm, iemesls: {lightred}{4}{default}!",
|
||||
"sa_admin_silence_message_perm": "Admins {lightred}{0}{default} izslēdza balss iespēju {lightred}{1}{default} uz mūžu, iemesls: {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Admins {lightred}{0}{default} brīdināja {lightred}{1}{default} par {lightred}{2}{default} uz {lightred}{3}{default} minūtēm!",
|
||||
"sa_admin_warn_message_perm": "Admins {lightred}{0}{default} brīdināja {lightred}{1}{default} pastāvīgi par {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Admins {lightred}{0}{default} deva {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Admins {lightred}{0}{default} paņēma visus spēlētāja {lightred}{1}{default} ieročus!",
|
||||
"sa_admin_hp_message": "Admins {lightred}{0}{default} mainīja {lightred}{1}{default} HP daudzumu!",
|
||||
"sa_admin_speed_message": "Admins {lightred}{0}{default} mainīja ātrumu uz {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Admins {lightred}{0}{default} mainīja gravitāciju uz {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Admins {lightred}{0}{default} mainīja naudu uz {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Admins {lightred}{0}{default} mainīja dieva režīmu priekš {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Admins {lightred}{0}{default} nogalināja {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Admins {lightred}{0}{default} sita {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Admins {lightred}{0}{default} nomainīja karti uz {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Admins {lightred}{0}{default} pārslēdza noclip {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Admins {lightred}{0}{default} sasaldēja {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Admins {lightred}{0}{default} atkausēja {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "Admins {lightred}{0}{default} mainīja {lightred}{1}{default} uz {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "Admins {lightred}{0}{default} atdzīvināja {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Admins {lightred}{0}{default} teleported uz {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Admins {lightred}{0}{default} teleportēja sevi uz {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "Admins {lightred}{0}{default} pārveidoja {lightred}{1}{default} uz {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}BRĪDINĀJUMI",
|
||||
"sa_admin_warns_unwarn": "{lime}Veiksmīgi{default} noņemts brīdinājums no {gold}{0} {default}no {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}BALSOŠANA PAR {gold}{0}",
|
||||
"sa_admin_vote_message": "Admins {lightred}{0}{default} sāka balsošanu par {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}BALSOŠANAS REZULTĀTI PAR {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}Admins: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(Admins) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(SPĒLĒTĀJS) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** izmantoja komandu `{1}` uz servera `HOSTNAME`"
|
||||
}
|
||||
114
lang/pl.json
114
lang/pl.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Brak",
|
||||
"sa_no_permission": "Nie masz uprawnień do korzystania z tej komendy.",
|
||||
"sa_ban_max_duration_exceeded": "Czas bana nie może przekraczać {lightred}{0}{default} minut.",
|
||||
"sa_ban_perm_restricted": "Nie masz prawa do trwałego zbanowania.",
|
||||
|
||||
"sa_admin_add": "Dodaj administratora",
|
||||
"sa_admin_remove": "Usuń administratora",
|
||||
"sa_admin_reload": "Przeładuj administratorów",
|
||||
|
||||
"sa_godmode": "Tryb Boga",
|
||||
"sa_noclip": "Tryb Latania",
|
||||
"sa_respawn": "Odrodzenie",
|
||||
"sa_give_weapon": "Daj broń",
|
||||
"sa_strip_weapons": "Usuń bronie",
|
||||
"sa_freeze": "Zamroź",
|
||||
"sa_set_hp": "Ustaw HP",
|
||||
"sa_set_speed": "Ustaw prędkość",
|
||||
"sa_set_gravity": "Ustaw grawitację",
|
||||
"sa_set_money": "Ustaw pieniądze",
|
||||
|
||||
"sa_changemap": "Zmień mapę",
|
||||
"sa_restart_game": "Zrestartuj mapę",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Zamień",
|
||||
"sa_team_spec": "Spec",
|
||||
|
||||
"sa_slap": "Uderz",
|
||||
"sa_slay": "Zabij",
|
||||
"sa_kick": "Wyrzuć",
|
||||
"sa_ban": "Zbanuj",
|
||||
"sa_gag": "Zaknebluj",
|
||||
"sa_mute": "Wycisz",
|
||||
"sa_silence": "Ucisz",
|
||||
"sa_warn": "Ostrzeżenie",
|
||||
"sa_team_force": "Wymuś drużynę",
|
||||
|
||||
"sa_menu_custom_commands": "Komendy niestandardowe",
|
||||
"sa_menu_server_manage": "Zarządzaj serwerem",
|
||||
"sa_menu_fun_commands": "Komendy rozrywkowe",
|
||||
"sa_menu_admins_manage": "Zarządzaj administratorami",
|
||||
"sa_menu_players_manage": "Zarządzaj graczami",
|
||||
|
||||
"sa_player": "Gracz",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Czas trwania",
|
||||
"sa_reason": "Powód",
|
||||
"sa_admin": "Administrator",
|
||||
"sa_permanent": "Na zawsze",
|
||||
|
||||
"sa_discord_penalty_ban": "Nowy ban",
|
||||
"sa_discord_penalty_mute": "Nowe wyciszenie",
|
||||
"sa_discord_penalty_gag": "Nowe zakneblowanie",
|
||||
"sa_discord_penalty_silence": "Nowe uciszenie",
|
||||
"sa_discord_penalty_warn": "Nowe ostrzeżenie",
|
||||
"sa_discord_penalty_unknown": "Nowa nieznana blokada",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Zostałeś zakneblowany za {lightred}{0}{default} na {lightred}{1}{default} minut przez {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "Zostałeś zakneblowany na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Zostałeś uciszony za {lightred}{0}{default} na {lightred}{1}{default} minute przez {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "Zostałeś uciszony na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Zostałeś wyciszony za {lightred}{0}{default} na {lightred}{1}{default} minut przez {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "Zostałeś wyciszony na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "Otrzymałeś ostrzeżenie za {lightred}{0}{default} na {lightred}{1}{default} minut od {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "Otrzymałeś ostrzeżenie za {lightred}{0}{default} od {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Admin {lightred}{0}{default} zbanował {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!",
|
||||
"sa_admin_ban_message_perm": "Admin {lightred}{0}{default} zbanował {lightred}{1}{default} na zawsze za {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Admin {lightred}{0}{default} wyrzucił {lightred}{1}{default} za {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Admin {lightred}{0}{default} zakneblował {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!",
|
||||
"sa_admin_gag_message_perm": "Admin {lightred}{0}{default} zakneblował {lightred}{1}{default} na zawsze za {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Admin {lightred}{0}{default} uciszył {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!",
|
||||
"sa_admin_mute_message_perm": "Admin {lightred}{0}{default} uciszył {lightred}{1}{default} na zawsze za {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Admin {lightred}{0}{default} wyciszył {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!",
|
||||
"sa_admin_silence_message_perm": "Admin {lightred}{0}{default} wyciszył {lightred}{1}{default} na zawsze za {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Admin {lightred}{0}{default} ostrzegł {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!",
|
||||
"sa_admin_warn_message_perm": "Admin {lightred}{0}{default} ostrzegł {lightred}{1}{default} na zawsze za {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Admin {lightred}{0}{default} dał {lightred}{1}{default} przedmiot {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Admin {lightred}{0}{default} zabrał wszystkie bronie {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "Admin {lightred}{0}{default} zmienił ilość hp dla {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "Admin {lightred}{0}{default} zmienił prędkość dla {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Admin {lightred}{0}{default} zmienił grawitacje dla {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Admin {lightred}{0}{default} zmienił pieniądze dla {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Admin {lightred}{0}{default} zmienił tryb Boga dla {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Admin {lightred}{0}{default} zgładził {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Admin {lightred}{0}{default} uderzył {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Admin {lightred}{0}{default} zmienił mapę na {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Admin {lightred}{0}{default} ustawił latanie dla {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Admin {lightred}{0}{default} zamroził {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Admin {lightred}{0}{default} odmroził {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "Admin {lightred}{0}{default} zmienił nick gracza {lightred}{1}{default} na {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "Admin {lightred}{0}{default} odrodził {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Admin {lightred}{0}{default} teleportował się do {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Admin {lightred}{0}{default} teleportował do siebie {lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "Admin {lightred}{0}{default} przerzucił {lightred}{1}{default} do {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{lime}OSTRZEŻENIA {gold}{0}",
|
||||
"sa_admin_warns_unwarn": "{lime}Pomyślnie{default} usunięto ostrzeżenie dla {gold}{0} {default}za {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}GŁOSOWANIE NA {gold}{0}",
|
||||
"sa_admin_vote_message": "Admin {lightred}{0}{default} rozpoczął głosowanie na {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}WYNIKI GŁOSOWANIA {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}[{1}]",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(GRACZ) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** użył komendy `{1}` na serwerze `HOSTNAME`"
|
||||
}
|
||||
114
lang/pt-BR.json
114
lang/pt-BR.json
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Desconhecido",
|
||||
"sa_no_permission": "Você não tem permissão para usar este comando.",
|
||||
"sa_ban_max_duration_exceeded": "A duração da proibição não pode exceder {lightred}{0}{default} minutos.",
|
||||
"sa_ban_perm_restricted": "Você não tem permissão para banir permanentemente.",
|
||||
|
||||
"sa_admin_add": "Adicionar Admin",
|
||||
"sa_admin_remove": "Remover Admin",
|
||||
"sa_admin_reload": "Recarregar Admins",
|
||||
|
||||
"sa_godmode": "Modo Deus",
|
||||
"sa_noclip": "Modo Espectador",
|
||||
"sa_respawn": "Ressurgir",
|
||||
"sa_give_weapon": "Dar Arma",
|
||||
"sa_strip_weapons": "Remover Armas",
|
||||
"sa_freeze": "Congelar",
|
||||
"sa_set_hp": "Definir HP",
|
||||
"sa_set_speed": "Definir Velocidade",
|
||||
"sa_set_gravity": "Definir Gravidade",
|
||||
"sa_set_money": "Definir Dinheiro",
|
||||
|
||||
"sa_changemap": "Mudar Mapa",
|
||||
"sa_restart_game": "Reiniciar Jogo",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Trocar",
|
||||
"sa_team_spec": "Espec",
|
||||
|
||||
"sa_slap": "Tapa",
|
||||
"sa_slay": "Matar",
|
||||
"sa_kick": "Expulsar",
|
||||
"sa_ban": "Banir",
|
||||
"sa_gag": "Silenciar",
|
||||
"sa_mute": "Mutar",
|
||||
"sa_silence": "Silêncio",
|
||||
"sa_warn": "Aviso",
|
||||
"sa_team_force": "Forçar Time",
|
||||
|
||||
"sa_menu_custom_commands": "Comandos Personalizados",
|
||||
"sa_menu_server_manage": "Gerenciar Servidor",
|
||||
"sa_menu_fun_commands": "Comandos Divertidos",
|
||||
"sa_menu_admins_manage": "Gerenciar Admins",
|
||||
"sa_menu_players_manage": "Gerenciar Jogadores",
|
||||
|
||||
"sa_player": "Jogador",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Duração",
|
||||
"sa_reason": "Motivo",
|
||||
"sa_admin": "Admin",
|
||||
"sa_permanent": "Permanente",
|
||||
|
||||
"sa_discord_penalty_ban": "Banimento registrado",
|
||||
"sa_discord_penalty_mute": "Mute registrado",
|
||||
"sa_discord_penalty_gag": "Gag registrado",
|
||||
"sa_discord_penalty_silence": "Silêncio registrado",
|
||||
"sa_discord_penalty_warn": "Aviso registrado",
|
||||
"sa_discord_penalty_unknown": "Desconhecido registrado",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Você foi silenciado por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "Você foi silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Você foi mutado por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "Você foi mutado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Você foi silenciado por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "Você foi silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "Você foi advertido por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "Você foi advertido permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Admin {lightred}{0}{default} baniu {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!",
|
||||
"sa_admin_ban_message_perm": "Admin {lightred}{0}{default} baniu {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Admin {lightred}{0}{default} expulsou {lightred}{1}{default} por {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!",
|
||||
"sa_admin_gag_message_perm": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Admin {lightred}{0}{default} mutou {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!",
|
||||
"sa_admin_mute_message_perm": "Admin {lightred}{0}{default} mutou {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!",
|
||||
"sa_admin_silence_message_perm": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Admin {lightred}{0}{default} advertiu {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos!",
|
||||
"sa_admin_warn_message_perm": "Admin {lightred}{0}{default} advertiu {lightred}{1}{default} permanentemente por {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Admin {lightred}{0}{default} deu {lightred}{1}{default} um {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Admin {lightred}{0}{default} removeu todas as armas do jogador {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "Admin {lightred}{0}{default} alterou a quantidade de HP para {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "Admin {lightred}{0}{default} alterou a velocidade para {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Admin {lightred}{0}{default} alterou a gravidade para {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Admin {lightred}{0}{default} alterou o dinheiro para {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Admin {lightred}{0}{default} alterou o modo de Deus para {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Admin {lightred}{0}{default} matou {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Admin {lightred}{0}{default} deu um tapa em {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Admin {lightred}{0}{default} alterou o mapa para {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Admin {lightred}{0}{default} ativou o noclip para {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Admin {lightred}{0}{default} congelou {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Admin {lightred}{0}{default} descongelou {lightred}{1}{default}!",
|
||||
"sa_admin_rename_message": "Admin {lightred}{0}{default} alterou o apelido de {lightred}{1}{default} para {lightred}{2}{default}!",
|
||||
"sa_admin_respawn_message": "Admin {lightred}{0}{default} reviveu {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Admin {lightred}{0}{default} teleportou para {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Admin {lightred}{0}{default} teleportou {lightred}{1}{default} para si mesmo!",
|
||||
"sa_admin_team_message": "Admin {lightred}{0}{default} transferiu {lightred}{1}{default} para o time {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}ADVERTÊNCIAS",
|
||||
"sa_admin_warns_unwarn": "{lime}Removido com sucesso{default} o aviso de {gold}{0} {default}de {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}VOTAÇÃO PARA {gold}{0}",
|
||||
"sa_admin_vote_message": "Admin {lightred}{0}{default} iniciou uma votação para {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}RESULTADOS DA VOTAÇÃO PARA {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(JOGADOR) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** emitiu o comando `{1}` no servidor `HOSTNAME`"
|
||||
}
|
||||
113
lang/ru.json
113
lang/ru.json
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Неизвестный",
|
||||
"sa_no_permission": "У вас нет прав для использования этой команды.",
|
||||
"sa_ban_max_duration_exceeded": "Продолжительность бана не может превышать {lightred}{0}{default} минут.",
|
||||
"sa_ban_perm_restricted": "У вас нет прав на постоянный бан.",
|
||||
|
||||
"sa_admin_add": "Добавить администратора",
|
||||
"sa_admin_remove": "Удалить администратора",
|
||||
"sa_admin_reload": "Перезагрузить администраторов",
|
||||
|
||||
"sa_godmode": "Режим бога",
|
||||
"sa_noclip": "Режим бесконечного прохождения",
|
||||
"sa_respawn": "Возрождение",
|
||||
"sa_give_weapon": "Выдать оружие",
|
||||
"sa_strip_weapons": "Удалить оружие",
|
||||
"sa_freeze": "Заморозить",
|
||||
"sa_set_hp": "Установить здоровье",
|
||||
"sa_set_speed": "Установить скорость",
|
||||
"sa_set_gravity": "Установить гравитацию",
|
||||
"sa_set_money": "Установить деньги",
|
||||
|
||||
"sa_changemap": "Сменить карту",
|
||||
"sa_restart_game": "Перезапустить игру",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Поменять",
|
||||
"sa_team_spec": "Спец",
|
||||
|
||||
"sa_slap": "Шлепнуть",
|
||||
"sa_slay": "Убить",
|
||||
"sa_kick": "Выгнать",
|
||||
"sa_ban": "Забанить",
|
||||
"sa_gag": "Заглушить",
|
||||
"sa_mute": "Отключить звук",
|
||||
"sa_silence": "Тишина",
|
||||
"sa_warn": "Предупреждение",
|
||||
"sa_team_force": "Принудить к команде",
|
||||
|
||||
"sa_menu_custom_commands": "Пользовательские команды",
|
||||
"sa_menu_server_manage": "Управление сервером",
|
||||
"sa_menu_fun_commands": "Развлекательные команды",
|
||||
"sa_menu_admins_manage": "Управление администраторами",
|
||||
"sa_menu_players_manage": "Управление игроками",
|
||||
|
||||
"sa_player": "Игрок",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Продолжительность",
|
||||
"sa_reason": "Причина",
|
||||
"sa_admin": "Администратор",
|
||||
"sa_permanent": "Постоянный",
|
||||
|
||||
"sa_discord_penalty_ban": "Бан зарегистрирован",
|
||||
"sa_discord_penalty_mute": "Мут зарегистрирован",
|
||||
"sa_discord_penalty_gag": "Запрет зарегистрирован",
|
||||
"sa_discord_penalty_silence": "Молчание зарегистрировано",
|
||||
"sa_discord_penalty_warn": "Предупреждение зарегистрировано",
|
||||
"sa_discord_penalty_unknown": "Неизвестно зарегистрировано",
|
||||
|
||||
"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}!",
|
||||
"sa_player_gag_message_time": "Вам запрещено общаться в чате по причине {lightred}{0}{default} на {lightred}{1}{default} минут(ы) администратором {lightred}{2}{default}!",
|
||||
"sa_player_gag_message_perm": "Вам навсегда запрещено общаться в чате по причине {lightred}{0}{default} администратором {lightred}{1}{default}!",
|
||||
"sa_player_mute_message_time": "Вам запрещено использовать голосовой чат по причине {lightred}{0}{default} на {lightred}{1}{default} минут(ы) администратором {lightred}{2}{default}!",
|
||||
"sa_player_mute_message_perm": "Вам навсегда запрещено использовать голосовой чат по причине {lightred}{0}{default} администратором {lightred}{1}{default}!",
|
||||
"sa_player_silence_message_time": "Вам запрещено общаться по причине {lightred}{0}{default} на {lightred}{1}{default} минут(ы) администратором {lightred}{2}{default}!",
|
||||
"sa_player_silence_message_perm": "Вам навсегда запрещено общаться по причине {lightred}{0}{default} администратором {lightred}{1}{default}!",
|
||||
"sa_player_warn_message_time": "Вы получили предупреждение за {lightred}{0}{default} на {lightred}{1}{default} минут от {lightred}{2}{default}!",
|
||||
"sa_player_warn_message_perm": "Вы получили постоянное предупреждение за {lightred}{0}{default} от {lightred}{1}{default}!",
|
||||
"sa_admin_ban_message_time": "Администратор {lightred}{0}{default} забанил {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут(ы)!",
|
||||
"sa_admin_ban_message_perm": "Администратор {lightred}{0}{default} забанил {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!",
|
||||
"sa_admin_kick_message": "Администратор {lightred}{0}{default} выгнал {lightred}{1}{default} по причине {lightred}{2}{default}!",
|
||||
"sa_admin_gag_message_time": "Администратор {lightred}{0}{default} запретил общаться в чате {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут(ы)!",
|
||||
"sa_admin_gag_message_perm": "Администратор {lightred}{0}{default} запретил общаться в чате {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!",
|
||||
"sa_admin_mute_message_time": "Администратор {lightred}{0}{default} запретил использовать голосовой чат {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут(ы)!",
|
||||
"sa_admin_mute_message_perm": "Администратор {lightred}{0}{default} запретил использовать голосовой чат {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!",
|
||||
"sa_admin_silence_message_time": "Администратор {lightred}{0}{default} запретил общаться {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут(ы)!",
|
||||
"sa_admin_silence_message_perm": "Администратор {lightred}{0}{default} запретил общаться {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!",
|
||||
"sa_admin_warn_message_time": "Администратор {lightred}{0}{default} предупредил {lightred}{1}{default} за {lightred}{2}{default} на {lightred}{3}{default} минут!",
|
||||
"sa_admin_warn_message_perm": "Администратор {lightred}{0}{default} предупредил {lightred}{1}{default} навсегда за {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "Администратор {lightred}{0}{default} выдал {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "Администратор {lightred}{0}{default} забрал все оружия у игрока {lightred}{1}{default}!",
|
||||
"sa_admin_hp_message": "Администратор {lightred}{0}{default} изменил количество HP на {lightred}{1}{default}!",
|
||||
"sa_admin_speed_message": "Администратор {lightred}{0}{default} изменил скорость на {lightred}{1}{default}!",
|
||||
"sa_admin_gravity_message": "Администратор {lightred}{0}{default} изменил гравитацию на {lightred}{1}{default}!",
|
||||
"sa_admin_money_message": "Администратор {lightred}{0}{default} изменил количество денег на {lightred}{1}{default}!",
|
||||
"sa_admin_god_message": "Администратор {lightred}{0}{default} изменил режим бога для {lightred}{1}{default}!",
|
||||
"sa_admin_slay_message": "Администратор {lightred}{0}{default} убил {lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "Администратор {lightred}{0}{default} ударил {lightred}{1}{default}!",
|
||||
"sa_admin_changemap_message": "Администратор {lightred}{0}{default} сменил карту на {lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "Администратор {lightred}{0}{default} включил noclip для {lightred}{1}{default}!",
|
||||
"sa_admin_freeze_message": "Администратор {lightred}{0}{default} заморозил {lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "Администратор {lightred}{0}{default} разморозил {lightred}{1}{default}!",
|
||||
"sa_admin_respawn_message": "Администратор {lightred}{0}{default} воскресил {lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "Администратор {lightred}{0}{default} телепортировался к {lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "Администратор {lightred}{0}{default} телепортировал {lightred}{1}{default} к себе!",
|
||||
"sa_admin_team_message": "Администратор {lightred}{0}{default} переместил {lightred}{1}{default} в команду {lightred}{2}{default}!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}ПРЕДУПРЕЖДЕНИЯ",
|
||||
"sa_admin_warns_unwarn": "{lime}Успешно{default} удалено предупреждение у {gold}{0} {default}от {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}ГОЛОСОВАНИЕ ЗА {gold}{0}",
|
||||
"sa_admin_vote_message": "Администратор {lightred}{0}{default} начал голосование за {lightred}{1}{default}",
|
||||
"sa_admin_vote_message_results": "{lime}РЕЗУЛЬТАТЫ ГОЛОСОВАНИЯ ЗА {gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} {default}- {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}АДМИНИСТРАТОР: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(АДМИНИСТРАТОР) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(ИГРОК) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** выполнил команду `{1}` на сервере `HOSTNAME`"
|
||||
}
|
||||
113
lang/tr.json
113
lang/tr.json
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "Bilinmeyen",
|
||||
"sa_no_permission": "Bu komutu kullanma izniniz yok.",
|
||||
"sa_ban_max_duration_exceeded": "Yasaklama süresi {lightred}{0}{default} dakikadan fazla olamaz.",
|
||||
"sa_ban_perm_restricted": "Kalıcı yasaklama hakkınız yok.",
|
||||
|
||||
"sa_admin_add": "Yönetici Ekle",
|
||||
"sa_admin_remove": "Yönetici Kaldır",
|
||||
"sa_admin_reload": "Yöneticileri Yeniden Yükle",
|
||||
|
||||
"sa_godmode": "Tanrı Modu",
|
||||
"sa_noclip": "Duvar Arkası Modu",
|
||||
"sa_respawn": "Tekrar Doğma",
|
||||
"sa_give_weapon": "Silah Ver",
|
||||
"sa_strip_weapons": "Silahları Çıkart",
|
||||
"sa_freeze": "Dondur",
|
||||
"sa_set_hp": "HP Ayarla",
|
||||
"sa_set_speed": "Hız Ayarla",
|
||||
"sa_set_gravity": "Yerçekimi Ayarla",
|
||||
"sa_set_money": "Para Ayarla",
|
||||
|
||||
"sa_changemap": "Haritayı Değiştir",
|
||||
"sa_restart_game": "Oyunu Yeniden Başlat",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "Değiştir",
|
||||
"sa_team_spec": "İzleyici",
|
||||
|
||||
"sa_slap": "Tokatla",
|
||||
"sa_slay": "Öldür",
|
||||
"sa_kick": "At",
|
||||
"sa_ban": "Yasakla",
|
||||
"sa_gag": "Ağzını Kapat",
|
||||
"sa_mute": "Sustur",
|
||||
"sa_silence": "Sessizlik",
|
||||
"sa_warn": "Uyarı",
|
||||
"sa_team_force": "Takımı Zorla",
|
||||
|
||||
"sa_menu_custom_commands": "Özel Komutlar",
|
||||
"sa_menu_server_manage": "Sunucu Yönetimi",
|
||||
"sa_menu_fun_commands": "Eğlenceli Komutlar",
|
||||
"sa_menu_admins_manage": "Yönetici Yönetimi",
|
||||
"sa_menu_players_manage": "Oyuncu Yönetimi",
|
||||
|
||||
"sa_player": "Oyuncu",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "Süre",
|
||||
"sa_reason": "Neden",
|
||||
"sa_admin": "Yönetici",
|
||||
"sa_permanent": "Kalıcı",
|
||||
|
||||
"sa_discord_penalty_ban": "Yasak kaydedildi",
|
||||
"sa_discord_penalty_mute": "Susturma kaydedildi",
|
||||
"sa_discord_penalty_gag": "Susturma kaydedildi",
|
||||
"sa_discord_penalty_silence": "Sessizlik kaydedildi",
|
||||
"sa_discord_penalty_warn": "Uyarı kaydedildi",
|
||||
"sa_discord_penalty_unknown": "Bilinmeyen kaydedildi",
|
||||
|
||||
"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!",
|
||||
"sa_player_gag_message_time": "Senaryo nedeniyle {lightred}{0}{default} dakika boyunca {lightred}{1}{default} tarafından susturuldunuz!",
|
||||
"sa_player_gag_message_perm": "Senaryo nedeniyle kalıcı olarak {lightred}{0}{default} tarafından susturuldunuz!",
|
||||
"sa_player_mute_message_time": "Senaryo nedeniyle {lightred}{0}{default} dakika boyunca {lightred}{1}{default} tarafından sessize alındınız!",
|
||||
"sa_player_mute_message_perm": "Senaryo nedeniyle kalıcı olarak {lightred}{0}{default} tarafından sessize alındınız!",
|
||||
"sa_player_silence_message_time": "Senaryo nedeniyle {lightred}{0}{default} dakika boyunca {lightred}{1}{default} tarafından susturuldunuz!",
|
||||
"sa_player_silence_message_perm": "Senaryo nedeniyle kalıcı olarak {lightred}{0}{default} tarafından susturuldunuz!",
|
||||
"sa_player_warn_message_time": "{lightred}{0}{default} nedeniyle {lightred}{1}{default} dakika boyunca {lightred}{2}{default} tarafından uyarıldınız!",
|
||||
"sa_player_warn_message_perm": "{lightred}{0}{default} nedeniyle {lightred}{1}{default} tarafından kalıcı olarak uyarıldınız!",
|
||||
"sa_admin_ban_message_time": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} {lightred}{2}{default} için {lightred}{3}{default} dakika boyunca yasakladı!",
|
||||
"sa_admin_ban_message_perm": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} {lightred}{2}{default} kalıcı olarak yasakladı!",
|
||||
"sa_admin_kick_message": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} tarafından atıldınız!",
|
||||
"sa_admin_gag_message_time": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} {lightred}{2}{default} için {lightred}{3}{default} dakika boyunca susturdu!",
|
||||
"sa_admin_gag_message_perm": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} kalıcı olarak {lightred}{2}{default} susturdu!",
|
||||
"sa_admin_mute_message_time": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} {lightred}{2}{default} için {lightred}{3}{default} dakika boyunca sessize aldı!",
|
||||
"sa_admin_mute_message_perm": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} kalıcı olarak {lightred}{2}{default} sessize aldı!",
|
||||
"sa_admin_silence_message_time": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} {lightred}{2}{default} için {lightred}{3}{default} dakika boyunca susturdu!",
|
||||
"sa_admin_silence_message_perm": "Yönetici {lightred}{0}{default}, senaryo nedeniyle {lightred}{1}{default} kalıcı olarak {lightred}{2}{default} susturdu!",
|
||||
"sa_admin_warn_message_time": "Yönetici {lightred}{0}{default} {lightred}{1}{default} kişiyi {lightred}{2}{default} nedeniyle {lightred}{3}{default} dakika boyunca uyardı!",
|
||||
"sa_admin_warn_message_perm": "Yönetici {lightred}{0}{default} {lightred}{1}{default} kişiyi kalıcı olarak {lightred}{2}{default} nedeniyle uyardı!",
|
||||
"sa_admin_give_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} adlı oyuncuya {lightred}{2}{default} verdi!",
|
||||
"sa_admin_strip_message": "Yönetici {lightred}{0}{default}, tüm {lightred}{1}{default} silahlarını aldı!",
|
||||
"sa_admin_hp_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} HP miktarını değiştirdi!",
|
||||
"sa_admin_speed_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} hızını değiştirdi!",
|
||||
"sa_admin_gravity_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} yerçekimini değiştirdi!",
|
||||
"sa_admin_money_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} para miktarını değiştirdi!",
|
||||
"sa_admin_god_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} için tanrı modunu değiştirdi!",
|
||||
"sa_admin_slay_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} öldürdü!",
|
||||
"sa_admin_slap_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} tokatladı!",
|
||||
"sa_admin_changemap_message": "Yönetici {lightred}{0}{default}, haritayı {lightred}{1}{default} olarak değiştirdi!",
|
||||
"sa_admin_noclip_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} için noclip'i değiştirdi!",
|
||||
"sa_admin_freeze_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} dondurdu!",
|
||||
"sa_admin_unfreeze_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} çözdü!",
|
||||
"sa_admin_respawn_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} yeniden doğdu!",
|
||||
"sa_admin_tp_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default}'e teleport edildi!",
|
||||
"sa_admin_bring_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default}'yi kendine teleport etti!",
|
||||
"sa_admin_team_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} {lightred}{2}{default} takımına transfer edildi!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}UYARILAR",
|
||||
"sa_admin_warns_unwarn": "{lime}Başarıyla{default} uyarı {gold}{0} {default}şu adresten {gold}{1}{default} kaldırıldı!",
|
||||
"sa_admin_vote_menu_title": "{lime}{0} için OYLAMA",
|
||||
"sa_admin_vote_message": "Yönetici {lightred}{0}{default}, {lightred}{1}{default} için oy vermeye başladı",
|
||||
"sa_admin_vote_message_results": "{lime}{0} için OYLAMA SONUÇLARI",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} - {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}YÖNETİCİ: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(YÖNETİCİ) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(OYUNCU) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}**, sunucuda `HOSTNAME` üzerinde `{1}` komutunu gerçekleştirdi!"
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"sa_title": "SimpleAdmin",
|
||||
"sa_prefix": "{lightred}[SA] {default}",
|
||||
|
||||
"sa_unknown": "未知",
|
||||
"sa_no_permission": "您没有权限使用此命令。",
|
||||
"sa_ban_max_duration_exceeded": "禁令持续时间不能超过{lightred}{0}{default}分钟。",
|
||||
"sa_ban_perm_restricted": "您没有永久封禁的权限。",
|
||||
|
||||
"sa_admin_add": "添加管理员",
|
||||
"sa_admin_remove": "移除管理员",
|
||||
"sa_admin_reload": "重新加载管理员",
|
||||
|
||||
"sa_godmode": "上帝模式",
|
||||
"sa_noclip": "穿墙模式",
|
||||
"sa_respawn": "重生",
|
||||
"sa_give_weapon": "给予武器",
|
||||
"sa_strip_weapons": "剥夺武器",
|
||||
"sa_freeze": "冻结",
|
||||
"sa_set_hp": "设置生命值",
|
||||
"sa_set_speed": "设置速度",
|
||||
"sa_set_gravity": "设置重力",
|
||||
"sa_set_money": "设置金钱",
|
||||
|
||||
"sa_changemap": "更换地图",
|
||||
"sa_restart_game": "重启游戏",
|
||||
|
||||
"sa_team_ct": "CT",
|
||||
"sa_team_t": "T",
|
||||
"sa_team_swap": "交换",
|
||||
"sa_team_spec": "观战",
|
||||
|
||||
"sa_slap": "掌掴",
|
||||
"sa_slay": "杀死",
|
||||
"sa_kick": "踢出",
|
||||
"sa_ban": "封禁",
|
||||
"sa_gag": "禁言",
|
||||
"sa_mute": "静音",
|
||||
"sa_silence": "沉默",
|
||||
"sa_warn": "警告",
|
||||
"sa_team_force": "强制队伍",
|
||||
|
||||
"sa_menu_custom_commands": "自定义命令",
|
||||
"sa_menu_server_manage": "服务器管理",
|
||||
"sa_menu_fun_commands": "娱乐命令",
|
||||
"sa_menu_admins_manage": "管理员管理",
|
||||
"sa_menu_players_manage": "玩家管理",
|
||||
|
||||
"sa_player": "玩家",
|
||||
"sa_steamid": "SteamID",
|
||||
"sa_duration": "持续时间",
|
||||
"sa_reason": "原因",
|
||||
"sa_admin": "管理员",
|
||||
"sa_permanent": "永久",
|
||||
|
||||
"sa_discord_penalty_ban": "封禁已记录",
|
||||
"sa_discord_penalty_mute": "禁言已记录",
|
||||
"sa_discord_penalty_gag": "禁言已记录",
|
||||
"sa_discord_penalty_silence": "禁声已记录",
|
||||
"sa_discord_penalty_warn": "警告已注册",
|
||||
"sa_discord_penalty_unknown": "未知已记录",
|
||||
|
||||
"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}踢出!",
|
||||
"sa_player_gag_message_time": "你因为{lightred}{0}{default}的原因被{lightred}{2}{default}禁言{lightred}{1}{default}分钟!",
|
||||
"sa_player_gag_message_perm": "你因为{lightred}{0}{default}的原因被{lightred}{1}{default}永久禁言!",
|
||||
"sa_player_mute_message_time": "你因为{lightred}{0}{default}的原因被{lightred}{2}{default}禁声{lightred}{1}{default}分钟!",
|
||||
"sa_player_mute_message_perm": "你因为{lightred}{0}{default}的原因被{lightred}{1}{default}永久禁声!",
|
||||
"sa_player_silence_message_time": "你因为{lightred}{0}{default}的原因被{lightred}{2}{default}禁止发言{lightred}{1}{default}分钟!",
|
||||
"sa_player_silence_message_perm": "你因为{lightred}{0}{default}的原因被{lightred}{1}{default}永久禁止发言!",
|
||||
"sa_player_warn_message_time": "您因 {lightred}{0}{default} 被 {lightred}{1}{default} 分钟内由 {lightred}{2}{default} 警告!",
|
||||
"sa_player_warn_message_perm": "您因 {lightred}{0}{default} 被 {lightred}{1}{default} 永久警告!",
|
||||
"sa_admin_ban_message_time": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因禁止了{lightred}{1}{default} {lightred}{3}{default}分钟!",
|
||||
"sa_admin_ban_message_perm": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因永久禁止了{lightred}{1}{default}!",
|
||||
"sa_admin_kick_message": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因踢出了{lightred}{1}{default}!",
|
||||
"sa_admin_gag_message_time": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因禁言了{lightred}{1}{default} {lightred}{3}{default}分钟!",
|
||||
"sa_admin_gag_message_perm": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因永久禁言了{lightred}{1}{default}!",
|
||||
"sa_admin_mute_message_time": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因禁声了{lightred}{1}{default} {lightred}{3}{default}分钟!",
|
||||
"sa_admin_mute_message_perm": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因永久禁声了{lightred}{1}{default}!",
|
||||
"sa_admin_silence_message_time": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因禁止了{lightred}{1}{default} {lightred}{3}{default}分钟的发言!",
|
||||
"sa_admin_silence_message_perm": "管理员{lightred}{0}{default}因为{lightred}{2}{default}的原因永久禁止了{lightred}{1}{default}的发言!",
|
||||
"sa_admin_warn_message_time": "管理员 {lightred}{0}{default} 警告了 {lightred}{1}{default} {lightred}{2}{default} 因为 {lightred}{3}{default} 分钟!",
|
||||
"sa_admin_warn_message_perm": "管理员 {lightred}{0}{default} 永久警告了 {lightred}{1}{default} 因为 {lightred}{2}{default}!",
|
||||
"sa_admin_give_message": "管理员{lightred}{0}{default}给了{lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"sa_admin_strip_message": "管理员{lightred}{0}{default}拿走了玩家{lightred}{1}{default}的所有武器!",
|
||||
"sa_admin_hp_message": "管理员{lightred}{0}{default}改变了{lightred}{1}{default}的HP数值!",
|
||||
"sa_admin_speed_message": "管理员{lightred}{0}{default}改变了{lightred}{1}{default}的速度!",
|
||||
"sa_admin_gravity_message": "管理员{lightred}{0}{default}改变了{lightred}{1}{default}的重力!",
|
||||
"sa_admin_money_message": "管理员{lightred}{0}{default}改变了{lightred}{1}{default}的金钱数值!",
|
||||
"sa_admin_god_message": "管理员{lightred}{0}{default}改变了{lightred}{1}{default}的上帝模式!",
|
||||
"sa_admin_slay_message": "管理员{lightred}{0}{default}击杀了{lightred}{1}{default}!",
|
||||
"sa_admin_slap_message": "管理员{lightred}{0}{default}扇了{lightred}{1}{default}一巴掌!",
|
||||
"sa_admin_changemap_message": "管理员{lightred}{0}{default}将地图更改为{lightred}{1}{default}!",
|
||||
"sa_admin_noclip_message": "管理员{lightred}{0}{default}为{lightred}{1}{default}切换了穿墙模式!",
|
||||
"sa_admin_freeze_message": "管理员{lightred}{0}{default}冻结了{lightred}{1}{default}!",
|
||||
"sa_admin_unfreeze_message": "管理员{lightred}{0}{default}解冻了{lightred}{1}{default}!",
|
||||
"sa_admin_respawn_message": "管理员{lightred}{0}{default}重生了{lightred}{1}{default}!",
|
||||
"sa_admin_tp_message": "管理员{lightred}{0}{default}传送到了{lightred}{1}{default}!",
|
||||
"sa_admin_bring_message": "管理员{lightred}{0}{default}将自己传送到了{lightred}{1}{default}!",
|
||||
"sa_admin_team_message": "管理员{lightred}{0}{default}将{lightred}{1}{default}转移到了{lightred}{2}{default}队伍!",
|
||||
"sa_admin_warns_menu_title": "{gold}{0} {lime}警告",
|
||||
"sa_admin_warns_unwarn": "{lime}成功{default} 取消了 {gold}{0} {default}的警告,来自 {gold}{1}{default}!",
|
||||
"sa_admin_vote_menu_title": "{lime}投票选举{gold}{0}",
|
||||
"sa_admin_vote_message": "管理员{lightred}{0}{default}开始对{lightred}{1}{default}进行投票",
|
||||
"sa_admin_vote_message_results": "{lime}投票结果{gold}{0}",
|
||||
"sa_admin_vote_message_results_answer": "{lime}{0} - {gold}{1}",
|
||||
"sa_adminsay_prefix": "{RED}管理员: {lightred}{0}{default}",
|
||||
"sa_adminchat_template_admin": "{LIME}(管理员) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
"sa_adminchat_template_player": "{SILVER}(玩家) {lightred}{0}{default}: {lightred}{1}{default}",
|
||||
|
||||
"sa_discord_log_command": "**{0}** 在服务器 `HOSTNAME` 上执行了命令 `{1}`!"
|
||||
}
|
||||
Reference in New Issue
Block a user