From 92cbfe95a280e8ee85696365aa9df274030b8208 Mon Sep 17 00:00:00 2001
From: K4ryuu <104531589+K4ryuu@users.noreply.github.com>
Date: Thu, 11 Apr 2024 19:35:40 +0200
Subject: [PATCH] Release v4.1.0
---
CHANGELOG | 14 +
K4-SharedApi/src/K4-SharedApi.cs | 16 +-
K4-SharedApi/src/K4-SharedApi.csproj | 9 +-
K4-SharedApi/src/K4-SharedApi.dll | Bin 4096 -> 4096 bytes
K4-System/src/K4-System.csproj | 7 +-
K4-System/src/Models/PlayerModel.cs | 61 ++
.../src/Module/Interfaces/IModuleTime.cs | 3 +-
K4-System/src/Module/ModuleRank.cs | 30 +-
K4-System/src/Module/ModuleStat.cs | 13 +-
K4-System/src/Module/ModuleTime.cs | 13 +-
K4-System/src/Module/ModuleUtils.cs | 11 +-
K4-System/src/Module/Rank/RankCommands.cs | 324 ++++------
K4-System/src/Module/Rank/RankConfig.cs | 4 +-
K4-System/src/Module/Rank/RankEvents.cs | 208 +++----
K4-System/src/Module/Rank/RankFunctions.cs | 210 ++++---
K4-System/src/Module/Rank/RankGlobals.cs | 6 +-
K4-System/src/Module/Rank/RankMenus.cs | 128 ++--
K4-System/src/Module/Stat/StatCommands.cs | 11 +-
K4-System/src/Module/Stat/StatEvents.cs | 219 +++++--
K4-System/src/Module/Stat/StatFunctions.cs | 29 +-
K4-System/src/Module/Stat/StatGlobals.cs | 5 +-
K4-System/src/Module/Time/TimeCommands.cs | 11 +-
K4-System/src/Module/Time/TimeEvents.cs | 41 +-
K4-System/src/Module/Time/TimeFunctions.cs | 52 +-
K4-System/src/Module/Time/TimeGlobals.cs | 4 +-
K4-System/src/Module/Utils/UtilsCommands.cs | 56 +-
K4-System/src/Module/Utils/UtilsGlobals.cs | 4 +-
K4-System/src/Plugin/Plugin.cs | 108 ++--
K4-System/src/Plugin/PluginAPI.cs | 77 ++-
K4-System/src/Plugin/PluginBasics.cs | 206 ++++++-
K4-System/src/Plugin/PluginCache.cs | 108 ----
K4-System/src/Plugin/PluginConfig.cs | 2 +-
K4-System/src/Plugin/PluginDatabase.cs | 541 ++++++++++++++---
K4-System/src/Plugin/PluginManifest.cs | 2 +-
K4-System/src/Plugin/PluginStock.cs | 552 +-----------------
K4-System/src/lang/en.json | 4 +-
.../src/lang/{fr.json => fr.json.outdated} | 0
.../src/lang/{ro.json => ro.json.outdated} | 0
README.md | 12 +-
39 files changed, 1522 insertions(+), 1579 deletions(-)
create mode 100644 K4-System/src/Models/PlayerModel.cs
delete mode 100644 K4-System/src/Plugin/PluginCache.cs
rename K4-System/src/lang/{fr.json => fr.json.outdated} (100%)
rename K4-System/src/lang/{ro.json => ro.json.outdated} (100%)
diff --git a/CHANGELOG b/CHANGELOG
index 8887d3c..60a2662 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,17 @@
+-- 2023.04.11 - V4.1.0
+
+- feat: Add Reset option for all module
+- feat: Add 25 new statistics
+- feat: Add new API endpoints
+- fix: Rank name not updating in MySQL
+- fix: Admin shows a user multiple times
+- fix: Toplist and Rank command lag spikes
+- fix: Rank resets sets 0 instead of starting points
+- fix: AutoPurge delete freshly moved database
+- fix: Add loading message to commands where needed
+- optimise: The full plugins code
+- upgrade: Changed support from NET7 to NET8
+
-- 2023.03.28 - V4.0.4
- fix: Table generation problems because of lastseen default value
diff --git a/K4-SharedApi/src/K4-SharedApi.cs b/K4-SharedApi/src/K4-SharedApi.cs
index e01dac9..2f73936 100644
--- a/K4-SharedApi/src/K4-SharedApi.cs
+++ b/K4-SharedApi/src/K4-SharedApi.cs
@@ -1,8 +1,16 @@
-namespace K4SharedApi
+using CounterStrikeSharp.API.Core;
+
+namespace K4SharedApi
{
- public interface IK4SharedApi
+ public interface IPlayerAPI
{
- int PlayerPoints { get; }
- int PlayerRankID { get; }
+ bool IsLoaded { get; }
+ bool IsValid { get; }
+ bool IsPlayer { get; }
+ CCSPlayerController Controller { get; }
+ int Points { get; set; }
+ int RankID { get; }
+ string RankName { get; }
+ string RankClanTag { get; }
}
}
diff --git a/K4-SharedApi/src/K4-SharedApi.csproj b/K4-SharedApi/src/K4-SharedApi.csproj
index c9fe644..a786503 100644
--- a/K4-SharedApi/src/K4-SharedApi.csproj
+++ b/K4-SharedApi/src/K4-SharedApi.csproj
@@ -6,9 +6,16 @@
./
- net7.0
+ net8.0
K4_SharedApi
enable
enable
+
+
+ none
+ runtime
+ compile; build; native; contentfiles; analyzers; buildtransitive
+
+
\ No newline at end of file
diff --git a/K4-SharedApi/src/K4-SharedApi.dll b/K4-SharedApi/src/K4-SharedApi.dll
index ee904ecdfb022a84f13215595286920fd82036ec..60de566535a351939f9e781efa17aa9033909c29 100644
GIT binary patch
delta 1465
zcmZvcOKcle7=_Or+Y`r0oVX=XUmyn;IaQ*;k2H4315y`KQwSzb3*lA9@i?_IvB7q#
zc7p?|M1)u*noW?Z0ul>gQMF1WkU$8r=mG_Sgo=dNuwhXNLAPZAoO{QCAaSkv?m7Q|
zpX1+N4X=jR*Sya@aNymIw~uJoq8lHd4ZaWso&wt=z@}%Te}Cu8K&SLf9C7-!A!lAh
z#kTW0x#@f)o;kSAjBKa)Xz(Ey2JYy9a6;`V=e%~bxvBw?*MMKy??|0*)XJ5`x}5c?
z5Ad>&oXO*J>K>`5&ty-s-=RM$=ug$Z~5|;I59-(I7kL?jO;;Naa3_iF{}8r;=H0s3Y5uSMDaWh
z2?HH?6bANVhCGaAGJ*@_AhyY75;xh6;d?TJpUKlIktZ`)z&%1!w;01Pk9tb6ph=zA
z(&Sg#1Q~?n9Hz)0#T4%*;2~wrX;f{bmtV8=9n9&Z#%NcQogdv~JMZjWbqj>6wAx>M
zgR(+)+abKDq;}=htHz(K7FTR*5{p*j+^ktyVy$MXE0u;-lXbmh<NXcb%LtZA2BEti=wmo4Nk)f?8bG0Wx3wEw@Zk*U_4dEedO
z%!+NB1>4G0x%)+DT0hZy!L(Pbe~y;1&B~m)=&b1j&J8^>X3Sb8+gfOps}(gyPOMdJ
z+o~ax$*a@W_Qc#XyJ6=yJ=>IlT(w+j)KULew%*L`z?)xxa`>Io>)UtwCSu=RgEuUM
z-xG%LQG`O$1|@v{>kpr6hHeEOVp8*lv2T<@jtqJR7#NU&0R{#T^o!Paa~~_+`Lb<7
zq@6$8`pK~0m`n;7aU*8L221I5F+H+yycA0m62;W0nJN`xrZt)z9$pwpnu$a_IUG;K
zSyVptli|7@&RhQb_g!xNeaTB)l{&o9->0odoge&bPB1VT9QU;D$8Ox?JQuhst~hrC
z5pi+r-j2_N=M6mQ{M0#^A4Caheu{iXSk=erV@RODr-&3rVUi{K7?nkzWTg*tVWD2iWdT%Zso3
z$iBBBJ?PeGNDm&^Ou|7U!HY)1q1r?a!~~3T@IW+?izbF}!i$E)nBc+qo7vLv+stQv
ze`bEanK!eu=B~My)?@49*w?L(y7_v`ZfNL~lVjaIfRc@{{LeTf3yGRt3*
zr&te*$@hul@=La`_dZ3GOj6^BT~n6NRr;E^ojZ6IQ89RC*@bXtGV#ZRc4b1|FT2a
zO*Ki~K~2q6y6UOCo~>*uqMOoH1Ab=h-o!!H%}q2l1K4~AhH1EokMSupvBVw`|AFGB
z=1+LkBx6bkKG3dVs1%YtApas)T)+dJzg>i>qO22rDDhWFZ(F;lq_Q|ZqXm7>ejqo8
zfjs_T2QclbWnSE4P-cd=wkPzFA_U3sCig(
zRI{jgLi3bnnP_5_xC@@vd$1FX70`i~Q9u`7CGKm|{tC$9EU_O~h=;I2Jc@6LWB8F+
z(*9ZE7~aM`qC>1`y|SfO@GBja+Q0?gPfSxb^#u%KjILB{?a6UbP|FP(oOrT-<=IES
zEg7B)stsR^U|B?Grv37&sLzyZ@6gqmT@53#QkZGfB5y_Djg>`Ft%~YsME7p75ebY1
zE9X65)F(tu)XUM+q3uEQVR>1!E#8Rack#!vWIFP9^PtQodRS3TCUVc=q^O5pP}?pk
zmV8l($Rj^b6q{3Cr5=RAQdAfVs$#TO_E$qM#CDCja-9|*KDC4Cz^jo%$>q!Q*Y^MY
z$>cYKw?;}Odj>I=G0Skl;-q9U%1mqZu(fgQOfz%OIl@gfz%qJaSq!pjO|T((-O3X0
zT7{zyLwv9>P#B=Uj5>zAx{c}<&hgZ!?*|vA8h+%R_XRoZV(px$d-QQYsXFM5kZ;./bin/K4-System/plugins/K4-System
- net7.0
+ net8.0
enable
enable
-
+
none
runtime
compile; build; native; contentfiles; analyzers; buildtransitive
-
+
+
../../K4-SharedApi/src/K4-SharedApi.dll
diff --git a/K4-System/src/Models/PlayerModel.cs b/K4-System/src/Models/PlayerModel.cs
new file mode 100644
index 0000000..a558731
--- /dev/null
+++ b/K4-System/src/Models/PlayerModel.cs
@@ -0,0 +1,61 @@
+
+using CounterStrikeSharp.API;
+using CounterStrikeSharp.API.Core;
+using CounterStrikeSharp.API.Modules.Commands;
+using static K4System.ModuleRank;
+using static K4System.ModuleStat;
+using static K4System.ModuleTime;
+
+namespace K4System.Models;
+
+public class K4Player
+{
+ //** ? Main */
+ private readonly Plugin Plugin;
+
+ //** ? Player */
+ public readonly CCSPlayerController Controller;
+ public readonly ulong SteamID;
+ public readonly string PlayerName;
+
+ //** ? Data */
+ public RankData? rankData { get; set; }
+ public StatData? statData { get; set; }
+ public TimeData? timeData { get; set; }
+ public (int killStreak, DateTime lastKillTime) KillStreak = (0, DateTime.MinValue);
+
+ public K4Player(Plugin plugin, CCSPlayerController playerController)
+ {
+ Plugin = plugin;
+
+ Controller = playerController;
+ SteamID = playerController.SteamID;
+ PlayerName = playerController.PlayerName;
+ }
+
+ public bool IsValid
+ {
+ get
+ {
+ return Controller?.IsValid == true && Controller.PlayerPawn?.IsValid == true && Controller.Connected == PlayerConnectedState.PlayerConnected;
+ }
+ }
+
+ public bool IsPlayer
+ {
+ get
+ {
+ return !Controller.IsBot && !Controller.IsHLTV;
+ }
+ }
+
+ public string ClanTag
+ {
+ get { return Controller.Clan; }
+ set
+ {
+ Controller.Clan = value;
+ Utilities.SetStateChanged(Controller, "CCSPlayerController", "m_szClan");
+ }
+ }
+}
\ No newline at end of file
diff --git a/K4-System/src/Module/Interfaces/IModuleTime.cs b/K4-System/src/Module/Interfaces/IModuleTime.cs
index 400a35c..ac1dadc 100644
--- a/K4-System/src/Module/Interfaces/IModuleTime.cs
+++ b/K4-System/src/Module/Interfaces/IModuleTime.cs
@@ -1,4 +1,5 @@
using CounterStrikeSharp.API.Core;
+using K4System.Models;
namespace K4System;
@@ -8,5 +9,5 @@ public interface IModuleTime
public void Release(bool hotReload);
- public void BeforeDisconnect(CCSPlayerController player);
+ public void BeforeDisconnect(K4Player k4player);
}
diff --git a/K4-System/src/Module/ModuleRank.cs b/K4-System/src/Module/ModuleRank.cs
index d902658..d7c47e1 100644
--- a/K4-System/src/Module/ModuleRank.cs
+++ b/K4-System/src/Module/ModuleRank.cs
@@ -6,40 +6,40 @@ namespace K4System
using CounterStrikeSharp.API.Core.Plugin;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleRank : IModuleRank
{
public ModuleRank(ILogger logger, IPluginContext pluginContext)
{
this.Logger = logger;
- this.PluginContext = (pluginContext as PluginContext)!;
+ this.plugin = (pluginContext.Plugin as Plugin)!;
+ this.Config = plugin.Config;
}
public void Initialize(bool hotReload)
{
this.Logger.LogInformation("Initializing '{0}'", this.GetType().Name);
- //** ? Forwarded Variables */
-
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- this.Config = plugin.Config;
- this.ModuleDirectory = plugin._ModuleDirectory;
-
//** ? Register Module Parts */
- Initialize_Config(plugin);
- Initialize_Menus(plugin);
- Initialize_Events(plugin);
- Initialize_Commands(plugin);
+ Initialize_Config();
+ Initialize_Menus();
+ Initialize_Events();
+ Initialize_Commands();
//** ? Register Timers */
plugin.AddTimer(Config.PointSettings.PlaytimeMinutes * 60, () =>
{
- Utilities.GetPlayers().Where(p => p.TeamNum == (int)CsTeam.Terrorist)
- .ToList()
- .ForEach(p => ModifyPlayerPoints(p, Config.PointSettings.PlaytimePoints, "k4.phrases.playtime"));
+ foreach (K4Player k4player in plugin.K4Players)
+ {
+ if (!k4player.IsValid || !k4player.IsPlayer)
+ continue;
+
+ if (k4player.Controller.Team == CsTeam.Terrorist)
+ ModifyPlayerPoints(k4player, Config.PointSettings.PlaytimePoints, "k4.phrases.playtime");
+ }
}, TimerFlags.REPEAT);
}
diff --git a/K4-System/src/Module/ModuleStat.cs b/K4-System/src/Module/ModuleStat.cs
index 8aeda19..27a0bde 100644
--- a/K4-System/src/Module/ModuleStat.cs
+++ b/K4-System/src/Module/ModuleStat.cs
@@ -9,23 +9,18 @@ public partial class ModuleStat : IModuleStat
public ModuleStat(ILogger logger, IPluginContext pluginContext)
{
this.Logger = logger;
- this.PluginContext = (pluginContext as PluginContext)!;
+ this.plugin = (pluginContext.Plugin as Plugin)!;
+ this.Config = plugin.Config;
}
public void Initialize(bool hotReload)
{
this.Logger.LogInformation("Initializing '{0}'", this.GetType().Name);
- //** ? Forwarded Variables */
-
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- this.Config = plugin.Config;
-
//** ? Register Module Parts */
- Initialize_Events(plugin);
- Initialize_Commands(plugin);
+ Initialize_Events();
+ Initialize_Commands();
}
public void Release(bool hotReload)
diff --git a/K4-System/src/Module/ModuleTime.cs b/K4-System/src/Module/ModuleTime.cs
index 33e4bda..876c3ec 100644
--- a/K4-System/src/Module/ModuleTime.cs
+++ b/K4-System/src/Module/ModuleTime.cs
@@ -9,23 +9,18 @@ public partial class ModuleTime : IModuleTime
public ModuleTime(ILogger logger, IPluginContext pluginContext)
{
this.Logger = logger;
- this.PluginContext = (pluginContext as PluginContext)!;
+ this.plugin = (pluginContext.Plugin as Plugin)!;
+ this.Config = plugin.Config;
}
public void Initialize(bool hotReload)
{
this.Logger.LogInformation("Initializing '{0}'", this.GetType().Name);
- //** ? Forwarded Variables */
-
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- this.Config = plugin.Config;
-
//** ? Register Module Parts */
- Initialize_Events(plugin);
- Initialize_Commands(plugin);
+ Initialize_Events();
+ Initialize_Commands();
}
public void Release(bool hotReload)
diff --git a/K4-System/src/Module/ModuleUtils.cs b/K4-System/src/Module/ModuleUtils.cs
index 01d6dcf..997fe45 100644
--- a/K4-System/src/Module/ModuleUtils.cs
+++ b/K4-System/src/Module/ModuleUtils.cs
@@ -9,22 +9,17 @@ public partial class ModuleUtils : IModuleUtils
public ModuleUtils(ILogger logger, IPluginContext pluginContext)
{
this.Logger = logger;
- this.PluginContext = (pluginContext as PluginContext)!;
+ this.plugin = (pluginContext.Plugin as Plugin)!;
+ this.Config = plugin.Config;
}
public void Initialize(bool hotReload)
{
this.Logger.LogInformation("Initializing '{0}'", this.GetType().Name);
- //** ? Forwarded Variables */
-
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- this.Config = plugin.Config;
-
//** ? Register Module Parts */
- Initialize_Commands(plugin);
+ Initialize_Commands();
}
public void Release(bool hotReload)
diff --git a/K4-System/src/Module/Rank/RankCommands.cs b/K4-System/src/Module/Rank/RankCommands.cs
index 4838d57..9122727 100644
--- a/K4-System/src/Module/Rank/RankCommands.cs
+++ b/K4-System/src/Module/Rank/RankCommands.cs
@@ -10,10 +10,12 @@ namespace K4System
using CounterStrikeSharp.API.Modules.Menu;
using Microsoft.Extensions.Logging;
using System.Data;
+ using K4System.Models;
+ using Dapper;
public partial class ModuleRank : IModuleRank
{
- public void Initialize_Commands(Plugin plugin)
+ public void Initialize_Commands()
{
CommandSettings commands = Config.CommandSettings;
@@ -27,17 +29,12 @@ public void Initialize_Commands(Plugin plugin)
plugin.AddCommand($"css_{commandString}", "Check the available ranks and their data", plugin.CallbackAnonymizer(OnCommandRanks));
});
- commands.ResetMyCommands.ForEach(commandString =>
- {
- plugin.AddCommand($"css_{commandString}", "Resets the player's own points to zero", plugin.CallbackAnonymizer(OnCommandResetMyRank));
- });
-
commands.TopCommands.ForEach(commandString =>
{
plugin.AddCommand($"css_{commandString}", "Check the top players by points", plugin.CallbackAnonymizer(OnCommandTop));
});
- plugin.AddCommand("css_resetrank", "Resets the targeted player's points to zero", plugin.CallbackAnonymizer(OnCommandResetRank));
+
plugin.AddCommand("css_setpoints", "SEt the targeted player's points", plugin.CallbackAnonymizer(OnCommandSetPoints));
plugin.AddCommand("css_givepoints", "Give points the targeted player", plugin.CallbackAnonymizer(OnCommandGivePoints));
plugin.AddCommand("css_removepoints", "Remove points from the targeted player", plugin.CallbackAnonymizer(OnCommandRemovePoints));
@@ -47,12 +44,18 @@ public void Initialize_Commands(Plugin plugin)
public void OnCommandTogglePointMessages(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player!).rankData;
+ K4Player? k4player = plugin.GetK4Player(player!);
+
+ if (k4player is null)
+ {
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
+ return;
+ }
+
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
@@ -63,37 +66,37 @@ public void OnCommandTogglePointMessages(CCSPlayerController? player, CommandInf
public void OnCommandToggleTag(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player!).rankData;
+ K4Player? k4player = plugin.GetK4Player(player!);
+
+ if (k4player is null)
+ {
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
+ return;
+ }
+
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
playerData.HideAdminTag = !playerData.HideAdminTag;
- string tag = string.Empty;
- if (Config.RankSettings.ScoreboardClantags)
- {
- tag = playerData.Rank.Tag ?? $"[{playerData.Rank.Name}]";
- }
-
- SetPlayerClanTag(player!, playerData, tag);
+ SetPlayerClanTag(k4player);
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.toggletag", playerData.HideAdminTag ? plugin.Localizer["k4.general.state.disabled"] : plugin.Localizer["k4.general.state.enabled"]]}");
}
public void OnCommandRank(CCSPlayerController? player, CommandInfo info)
{
- if (player == null || !player.IsValid || player.PlayerPawn.Value == null)
+ if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
+ K4Player? k4player = plugin.GetK4Player(player!);
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ if (k4player is null)
{
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
return;
@@ -106,99 +109,61 @@ public void OnCommandRank(CCSPlayerController? player, CommandInfo info)
printCount = Math.Clamp(parsedInt, 1, 25);
}
- string steamID = player!.SteamID.ToString();
-
- Task<(int playerPlace, int totalPlayers)> task = Task.Run(() => FetchRankDataAsync(steamID));
- task.Wait();
- var result = task.Result;
-
- int playerPlace = result.playerPlace;
- int totalPlayers = result.totalPlayers;
+ Task.Run(async () =>
+ {
+ (int playerPlace, int totalPlayers) taskValues = await GetPlayerPlaceAndCountAsync(k4player);
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
+ int playerPlace = taskValues.playerPlace;
+ int totalPlayers = taskValues.totalPlayers;
- if (playerData is null)
- return;
+ RankData? playerData = k4player.rankData;
- int higherRanksCount = rankDictionary.Count(kv => kv.Value.Point > playerData.Points);
+ if (playerData is null)
+ return;
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.rank.title", player.PlayerName]}");
- info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line1", playerData.Points, playerData.Rank.Color, playerData.Rank.Name, rankDictionary.Count - higherRanksCount, rankDictionary.Count]);
+ int higherRanksCount = rankDictionary.Count(kv => kv.Value.Point > playerData.Points);
- KeyValuePair nextRankEntry = rankDictionary
- .Where(kv => kv.Value.Point > playerData.Rank.Point)
- .OrderBy(kv => kv.Value.Point)
- .FirstOrDefault();
+ Server.NextFrame(() =>
+ {
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.rank.title", k4player.PlayerName]}");
+ info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line1", playerData.Points, playerData.Rank.Color, playerData.Rank.Name, rankDictionary.Count - higherRanksCount, rankDictionary.Count]);
- if (nextRankEntry.Value != null)
- {
- Rank nextRank = nextRankEntry.Value;
+ KeyValuePair nextRankEntry = rankDictionary
+ .Where(kv => kv.Value.Point > playerData.Rank.Point)
+ .OrderBy(kv => kv.Value.Point)
+ .FirstOrDefault();
- info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line2", nextRank.Color, nextRank.Name]);
- info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line3", nextRank.Point - playerData.Points]);
- }
+ if (nextRankEntry.Value != null)
+ {
+ Rank nextRank = nextRankEntry.Value;
- info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line4", playerPlace, totalPlayers]);
- }
+ info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line2", nextRank.Color, nextRank.Name]);
+ info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line3", nextRank.Point - playerData.Points]);
+ }
- public async Task<(int, int)> FetchRankDataAsync(string steamID)
- {
- try
- {
- var (playerPlace, totalPlayers) = await GetPlayerPlaceAndCountAsync(steamID);
- return (playerPlace, totalPlayers);
- }
- catch (Exception ex)
- {
- Logger.LogError($"Error fetching rank data: {ex.Message}");
- return (0, 0);
- }
+ info.ReplyToCommand(plugin.Localizer["k4.ranks.rank.line4", playerPlace, totalPlayers]);
+ });
+ });
}
public void OnCommandRanks(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
MenuManager.OpenChatMenu(player!, ranksMenu);
}
- public void OnCommandResetMyRank(CCSPlayerController? player, CommandInfo info)
- {
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
- return;
-
- if (!PlayerCache.Instance.ContainsPlayer(player!))
- {
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
- return;
- }
-
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player!).rankData;
-
- if (playerData is null)
- return;
-
- playerData.RoundPoints -= playerData.Points;
- playerData.Points = 0;
- plugin.SavePlayerCache(player!, false);
-
- Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.resetmyrank", player!.PlayerName]}");
- }
public void OnCommandTop(CCSPlayerController? player, CommandInfo info)
{
- if (player == null || !player.IsValid || player.PlayerPawn.Value == null)
+ if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
+ K4Player? k4player = plugin.GetK4Player(player!);
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ if (k4player is null)
{
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
return;
@@ -211,56 +176,47 @@ public void OnCommandTop(CCSPlayerController? player, CommandInfo info)
printCount = Math.Clamp(parsedInt, 1, 25);
}
- CCSPlayerController savedPlayer = player;
- List playersData = plugin.PreparePlayersData();
-
- Task?> task = Task.Run(() => FetchTopDataAsync(printCount));
- task.Wait();
- List<(int points, string name)>? rankData = task.Result;
-
- if (rankData?.Count > 0)
+ Task.Run(async () =>
{
- for (int i = 0; i < rankData.Count; i++)
+ List<(int points, string name)>? rankData = await FetchTopDataAsync(printCount);
+
+ if (rankData?.Count > 0)
{
- int points = rankData[i].points;
- string name = rankData[i].name;
+ for (int i = 0; i < rankData.Count; i++)
+ {
+ int points = rankData[i].points;
+ string name = rankData[i].name;
- Rank rank = GetPlayerRank(points);
+ Rank rank = GetPlayerRank(points);
+
+ Server.NextFrame(() =>
+ {
+ player!.PrintToChat($" {plugin.Localizer["k4.ranks.top.line", i + 1, rank.Color, rank.Name, name, points]}");
+ });
+ }
- player.PrintToChat($" {plugin.Localizer["k4.ranks.top.line", i + 1, rank.Color, rank.Name, name, points]}");
}
- }
- else
- {
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.top.notfound", printCount]}");
- }
+ else
+ {
+ player!.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.top.notfound", printCount]}");
+ }
+ });
}
public async Task?> FetchTopDataAsync(int printCount)
{
- string query = $"SELECT `points`, `name` FROM `{Config.DatabaseSettings.TablePrefix}k4ranks` ORDER BY `points` DESC LIMIT {printCount};";
-
- List<(int points, string name)> rankData = new List<(int points, string name)>();
+ string query = $@"SELECT `points`, `name` FROM `{Config.DatabaseSettings.TablePrefix}k4ranks` ORDER BY `points` DESC LIMIT @PrintCount;";
try
{
-
- using (MySqlCommand command = new MySqlCommand(query))
+ using (var connection = plugin.CreateConnection(Config))
{
- DataTable dataTable = await Database.Instance.ExecuteReaderAsync(command.CommandText);
+ await connection.OpenAsync();
- if (dataTable.Rows.Count > 0)
- {
- foreach (DataRow row in dataTable.Rows)
- {
- int points = Convert.ToInt32(row[0]);
- string name = Convert.ToString(row[1]) ?? "Unknown";
- rankData.Add((points, name));
- }
- }
- }
+ var rankData = (await connection.QueryAsync<(int, string)>(query, new { PrintCount = printCount })).ToList();
- return rankData;
+ return rankData;
+ }
}
catch (Exception ex)
{
@@ -269,62 +225,8 @@ public void OnCommandTop(CCSPlayerController? player, CommandInfo info)
}
}
- public void OnCommandResetRank(CCSPlayerController? player, CommandInfo info)
- {
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
- if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_AND_SERVER, 1, "", "@k4system/admin"))
- return;
-
- string playerName = player != null && player.IsValid && player.PlayerPawn.Value != null ? player.PlayerName : "SERVER";
-
- TargetResult targetResult = info.GetArgTargetResult(1);
-
- if (!targetResult.Any())
- {
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnotfound"]}");
- return;
- }
-
- foreach (CCSPlayerController target in targetResult.Players)
- {
- if (target.IsBot || target.IsHLTV)
- {
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
- continue;
- }
-
- if (!AdminManager.CanPlayerTarget(player, target))
- {
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
- continue;
- }
-
- if (!PlayerCache.Instance.ContainsPlayer(target))
- {
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
- continue;
- }
-
- RankData? playerData = PlayerCache.Instance.GetPlayerData(target).rankData;
-
- if (playerData is null)
- return;
-
- playerData.RoundPoints -= playerData.Points;
- playerData.Points = 0;
-
- plugin.SavePlayerCache(target, false);
-
- if (playerName != "SERVER")
- Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.resetrank", target.PlayerName, playerName]}");
- }
- }
-
public void OnCommandSetPoints(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_AND_SERVER, 2, " ", "@k4system/admin"))
return;
@@ -346,25 +248,27 @@ public void OnCommandSetPoints(CCSPlayerController? player, CommandInfo info)
foreach (CCSPlayerController target in targetResult.Players)
{
- if (target.IsBot || target.IsHLTV)
+ K4Player? k4player = plugin.GetK4Player(target);
+
+ if (k4player is null || !k4player.IsValid)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
continue;
}
- if (!AdminManager.CanPlayerTarget(player, target))
+ if (!k4player.IsPlayer)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
continue;
}
- if (!PlayerCache.Instance.ContainsPlayer(target))
+ if (!AdminManager.CanPlayerTarget(player, target))
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
continue;
}
- RankData? playerData = PlayerCache.Instance.GetPlayerData(target).rankData;
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
@@ -372,17 +276,15 @@ public void OnCommandSetPoints(CCSPlayerController? player, CommandInfo info)
playerData.RoundPoints = parsedInt;
playerData.Points = 0;
- plugin.SavePlayerCache(target, false);
-
if (playerName != "SERVER")
Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.setpoints", target.PlayerName, parsedInt, playerName]}");
+
+ Task.Run(() => plugin.SavePlayerDataAsync(k4player, false));
}
}
public void OnCommandGivePoints(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_AND_SERVER, 2, " ", "@k4system/admin"))
return;
@@ -404,25 +306,27 @@ public void OnCommandGivePoints(CCSPlayerController? player, CommandInfo info)
foreach (CCSPlayerController target in targetResult.Players)
{
- if (target.IsBot || target.IsHLTV)
+ K4Player? k4player = plugin.GetK4Player(target);
+
+ if (k4player is null || !k4player.IsValid)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
continue;
}
- if (!AdminManager.CanPlayerTarget(player, target))
+ if (!k4player.IsPlayer)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
continue;
}
- if (!PlayerCache.Instance.ContainsPlayer(target))
+ if (!AdminManager.CanPlayerTarget(player, target))
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
continue;
}
- RankData? playerData = PlayerCache.Instance.GetPlayerData(target).rankData;
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
@@ -430,17 +334,15 @@ public void OnCommandGivePoints(CCSPlayerController? player, CommandInfo info)
playerData.RoundPoints += parsedInt;
playerData.Points += parsedInt;
- plugin.SavePlayerCache(target, false);
-
if (playerName != "SERVER")
Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.givepoints", playerName, parsedInt, target.PlayerName]}");
+
+ Task.Run(() => plugin.SavePlayerDataAsync(k4player, false));
}
}
public void OnCommandRemovePoints(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_AND_SERVER, 2, " ", "@k4system/admin"))
return;
@@ -462,25 +364,27 @@ public void OnCommandRemovePoints(CCSPlayerController? player, CommandInfo info)
foreach (CCSPlayerController target in targetResult.Players)
{
- if (target.IsBot || target.IsHLTV)
+ K4Player? k4player = plugin.GetK4Player(target);
+
+ if (k4player is null || !k4player.IsValid)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
continue;
}
- if (!AdminManager.CanPlayerTarget(player, target))
+ if (!k4player.IsPlayer)
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetnobot", target.PlayerName]}");
continue;
}
- if (!PlayerCache.Instance.ContainsPlayer(target))
+ if (!AdminManager.CanPlayerTarget(player, target))
{
- info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetloading", target.PlayerName]}");
+ info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.targetimmunity", target.PlayerName]}");
continue;
}
- RankData? playerData = PlayerCache.Instance.GetPlayerData(target).rankData;
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
@@ -488,10 +392,10 @@ public void OnCommandRemovePoints(CCSPlayerController? player, CommandInfo info)
playerData.RoundPoints -= parsedInt;
playerData.Points -= parsedInt;
- plugin.SavePlayerCache(target, false);
-
if (playerName != "SERVER")
Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.removepoints", playerName, parsedInt, target.PlayerName]}");
+
+ Task.Run(() => plugin.SavePlayerDataAsync(k4player, false));
}
}
}
diff --git a/K4-System/src/Module/Rank/RankConfig.cs b/K4-System/src/Module/Rank/RankConfig.cs
index ed52709..e4718a9 100644
--- a/K4-System/src/Module/Rank/RankConfig.cs
+++ b/K4-System/src/Module/Rank/RankConfig.cs
@@ -7,9 +7,9 @@ namespace K4System
public partial class ModuleRank : IModuleRank
{
- public void Initialize_Config(Plugin plugin)
+ public void Initialize_Config()
{
- string ranksFilePath = Path.Join(ModuleDirectory, "ranks.jsonc");
+ string ranksFilePath = Path.Join(plugin.ModuleDirectory, "ranks.jsonc");
string defaultRanksContent = @"{
""None"": { // Whatever you set here, be unique. Not read by plugin
diff --git a/K4-System/src/Module/Rank/RankEvents.cs b/K4-System/src/Module/Rank/RankEvents.cs
index 2024b46..1b0b596 100644
--- a/K4-System/src/Module/Rank/RankEvents.cs
+++ b/K4-System/src/Module/Rank/RankEvents.cs
@@ -6,19 +6,19 @@ namespace K4System
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleRank : IModuleRank
{
- public void Initialize_Events(Plugin plugin)
+ public void Initialize_Events()
{
plugin.RegisterEventHandler((EventPlayerTeam @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid || player.IsBot || player.IsHLTV || !PlayerCache.Instance.ContainsPlayer(player))
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- RankData? rankData = PlayerCache.Instance.GetPlayerData(player).rankData;
+ RankData? rankData = k4player.rankData;
if (rankData is null)
return HookResult.Continue;
@@ -27,7 +27,7 @@ public void Initialize_Events(Plugin plugin)
{
foreach (Permission permission in rankData.Rank.Permissions)
{
- AdminManager.AddPlayerPermissions(Utilities.GetPlayerFromSlot(player.Slot), permission.PermissionName);
+ AdminManager.AddPlayerPermissions(k4player.Controller, permission.PermissionName);
}
}
@@ -36,136 +36,123 @@ public void Initialize_Events(Plugin plugin)
rankData.PlayedRound = false;
}
- if (Config.RankSettings.ScoreboardClantags)
- {
- string tag = rankData.Rank.Tag ?? $"[{rankData.Rank.Name}]";
- SetPlayerClanTag(player, rankData, tag);
- }
+ SetPlayerClanTag(k4player);
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventPlayerSpawn @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid || player.IsBot || player.IsHLTV)
- return HookResult.Continue;
-
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- if (Config.RankSettings.ScoreboardClantags)
- {
- RankData? rankData = PlayerCache.Instance.GetPlayerData(player).rankData;
-
- if (rankData is null)
- return HookResult.Continue;
-
- string tag = rankData.Rank.Tag ?? $"[{rankData.Rank.Name}]";
- SetPlayerClanTag(player, rankData, tag);
- }
-
+ SetPlayerClanTag(k4player);
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventHostageRescued @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.HostageRescue, "k4.phrases.hostagerescued");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.HostageRescue, "k4.phrases.hostagerescued");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventHostageKilled @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.HostageKill, "k4.phrases.hostagekilled");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.HostageKill, "k4.phrases.hostagekilled");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventHostageHurt @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.HostageHurt, "k4.phrases.hostagehurt");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.HostageHurt, "k4.phrases.hostagehurt");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventBombPickup @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.BombPickup, "k4.phrases.bombpickup");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.BombPickup, "k4.phrases.bombpickup");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventBombDefused @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.BombDefused, "k4.phrases.bombdefused");
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
+ return HookResult.Continue;
+
+ ModifyPlayerPoints(k4player, Config.PointSettings.BombDefused, "k4.phrases.bombdefused");
- Utilities.GetPlayers().Where(p => p.TeamNum == (int)CsTeam.CounterTerrorist && p.Slot != player.Slot)
- .ToList()
- .ForEach(p => ModifyPlayerPoints(p, Config.PointSettings.BombDefusedOthers, "k4.phrases.bombdefused"));
+ var players = plugin.K4Players.Where(p => p.IsValid && p.IsPlayer && p.Controller.Team == CsTeam.CounterTerrorist && p != k4player);
+ foreach (K4Player player in players)
+ {
+ ModifyPlayerPoints(player, Config.PointSettings.BombDefusedOthers, "k4.phrases.bombdefused");
+ }
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventBombDropped @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.BombDrop, "k4.phrases.bombdropped");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.BombDrop, "k4.phrases.bombdropped");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventBombExploded @event, GameEventInfo info) =>
{
- Utilities.GetPlayers().Where(p => p.TeamNum == (int)CsTeam.Terrorist)
- .ToList()
- .ForEach(p => ModifyPlayerPoints(p, Config.PointSettings.BombExploded, "k4.phrases.bombexploded"));
-
+ foreach (K4Player k4player in plugin.K4Players)
+ {
+ if (k4player.IsValid && k4player.IsPlayer && k4player.Controller.Team == CsTeam.Terrorist)
+ {
+ ModifyPlayerPoints(k4player, Config.PointSettings.BombExploded, "k4.phrases.bombexploded");
+ }
+ }
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventHostageRescuedAll @event, GameEventInfo info) =>
{
- Utilities.GetPlayers().Where(p => p.TeamNum == (int)CsTeam.CounterTerrorist)
- .ToList()
- .ForEach(p => ModifyPlayerPoints(p, Config.PointSettings.HostageRescueAll, "k4.phrases.hostagerescuedall"));
-
+ foreach (K4Player k4player in plugin.K4Players)
+ {
+ if (k4player.IsValid && k4player.IsPlayer && k4player.Controller.Team == CsTeam.CounterTerrorist)
+ {
+ ModifyPlayerPoints(k4player, Config.PointSettings.HostageRescueAll, "k4.phrases.hostagerescuedall");
+ }
+ }
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventRoundMvp @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.MVP, "k4.phrases.mvp");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.MVP, "k4.phrases.mvp");
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventRoundStart @event, GameEventInfo info) =>
{
- List players = Utilities.GetPlayers().Where(p => p?.IsValid == true && p.PlayerPawn?.IsValid == true && !p.IsBot && !p.IsHLTV && p.SteamID.ToString().Length == 17).ToList();
-
- players.Where(p => p.PawnIsAlive && PlayerCache.Instance.ContainsPlayer(p))
- .ToList()
- .ForEach(p =>
+ foreach (K4Player k4player in plugin.K4Players)
+ {
+ if (k4player.IsValid && k4player.IsPlayer)
{
- RankData? rankData = PlayerCache.Instance.GetPlayerData(p).rankData;
+ RankData? rankData = k4player.rankData;
if (rankData is not null)
{
rankData.PlayedRound = true;
}
- });
+ }
+ }
- if (players.Count < Config.RankSettings.MinPlayers)
+ if (plugin.K4Players.Count(p => p.IsPlayer) < Config.RankSettings.MinPlayers)
+ {
Server.PrintToChatAll($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.notenoughplayers", Config.RankSettings.MinPlayers]}");
+ }
return HookResult.Continue;
}, HookMode.Post);
plugin.RegisterEventHandler((EventBombPlanted @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
- ModifyPlayerPoints(player, Config.PointSettings.BombPlant, "k4.phrases.bombplanted");
+ ModifyPlayerPointsConnector(@event.Userid, Config.PointSettings.BombPlant, "k4.phrases.bombplanted");
return HookResult.Continue;
});
@@ -176,69 +163,71 @@ public void Initialize_Events(Plugin plugin)
return HookResult.Continue;
}
- CCSPlayerController victim = @event.Userid;
-
- if (victim is null || !victim.IsValid || !victim.PlayerPawn.IsValid || victim.Connected == PlayerConnectedState.PlayerDisconnecting)
+ K4Player? k4victim = plugin.GetK4Player(@event.Userid);
+ if (k4victim is null || !k4victim.IsValid)
return HookResult.Continue;
- CCSPlayerController killer = @event.Attacker;
+ K4Player? k4attacker = plugin.GetK4Player(@event.Attacker);
- if (!victim.IsBot)
+ if (!k4victim.IsPlayer)
{
- playerKillStreaks[victim.Slot] = (0, DateTime.Now);
+ k4victim.KillStreak = (0, DateTime.Now);
- if (killer is null || !killer.IsValid || victim.UserId == killer.UserId)
+ if (k4attacker is null || !k4attacker.IsValid)
{
- ModifyPlayerPoints(victim, Config.PointSettings.Suicide, "k4.phrases.suicide");
+ ModifyPlayerPoints(k4victim, Config.PointSettings.Suicide, "k4.phrases.suicide");
}
- else if (killer != null && killer.IsValid && (Config.RankSettings.PointsForBots || !killer.IsBot))
+ else
{
- string? extraInfo = Config.RankSettings.PlayerNameKillMessages ? plugin.Localizer["k4.phrases.dying.extra", killer.PlayerName] : null!;
- ModifyPlayerPoints(victim, CalculateDynamicPoints(killer, victim, Config.PointSettings.Death), "k4.phrases.dying", extraInfo);
+ if (Config.RankSettings.PointsForBots || k4attacker.IsPlayer)
+ {
+ string? extraInfo = Config.RankSettings.PlayerNameKillMessages ? plugin.Localizer["k4.phrases.dying.extra", k4attacker.PlayerName] : null!;
+ ModifyPlayerPoints(k4victim, CalculateDynamicPoints(k4attacker, k4victim, Config.PointSettings.Death), "k4.phrases.dying", extraInfo);
+ }
}
}
- if (killer?.IsValid == true && killer.PlayerPawn?.IsValid == true && !killer.IsBot && victim.UserId != killer.UserId && (Config.RankSettings.PointsForBots || !victim.IsBot))
+ if (k4attacker?.IsValid == true && k4attacker.IsPlayer && (Config.RankSettings.PointsForBots || k4victim.IsPlayer))
{
- if (!Config.GeneralSettings.FFAMode && killer.TeamNum == victim.TeamNum)
+ if (!Config.GeneralSettings.FFAMode && k4attacker.Controller.Team == k4victim.Controller.Team)
{
- ModifyPlayerPoints(killer, Config.PointSettings.TeamKill, "k4.phrases.teamkill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.TeamKill, "k4.phrases.teamkill");
}
else
{
- string? extraInfo = Config.RankSettings.PlayerNameKillMessages ? plugin.Localizer["k4.phrases.kill.extra", victim.PlayerName] : null!;
- ModifyPlayerPoints(killer, CalculateDynamicPoints(killer, victim, Config.PointSettings.Kill), "k4.phrases.kill", extraInfo);
+ string? extraInfo = Config.RankSettings.PlayerNameKillMessages ? plugin.Localizer["k4.phrases.kill.extra", k4victim.PlayerName] : null!;
+ ModifyPlayerPoints(k4attacker, CalculateDynamicPoints(k4attacker, k4victim, Config.PointSettings.Kill), "k4.phrases.kill", extraInfo);
if (@event.Headshot)
{
- ModifyPlayerPoints(killer, Config.PointSettings.Headshot, "k4.phrases.headshot");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.Headshot, "k4.phrases.headshot");
}
int penetrateCount = @event.Penetrated;
if (penetrateCount > 0 && Config.PointSettings.Penetrated > 0)
{
int calculatedPoints = penetrateCount * Config.PointSettings.Penetrated;
- ModifyPlayerPoints(killer, calculatedPoints, "k4.phrases.penetrated");
+ ModifyPlayerPoints(k4attacker, calculatedPoints, "k4.phrases.penetrated");
}
if (@event.Noscope)
{
- ModifyPlayerPoints(killer, Config.PointSettings.NoScope, "k4.phrases.noscope");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.NoScope, "k4.phrases.noscope");
}
if (@event.Thrusmoke)
{
- ModifyPlayerPoints(killer, Config.PointSettings.Thrusmoke, "k4.phrases.thrusmoke");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.Thrusmoke, "k4.phrases.thrusmoke");
}
if (@event.Attackerblind)
{
- ModifyPlayerPoints(killer, Config.PointSettings.BlindKill, "k4.phrases.blindkill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.BlindKill, "k4.phrases.blindkill");
}
if (@event.Distance >= Config.PointSettings.LongDistance)
{
- ModifyPlayerPoints(killer, Config.PointSettings.LongDistanceKill, "k4.phrases.longdistance");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.LongDistanceKill, "k4.phrases.longdistance");
}
string lowerCaseWeaponName = @event.Weapon.ToLower();
@@ -248,45 +237,43 @@ public void Initialize_Events(Plugin plugin)
//Killed by grenade explosion
case var _ when lowerCaseWeaponName.Contains("hegrenade"):
{
- ModifyPlayerPoints(killer, Config.PointSettings.GrenadeKill, "k4.phrases.grenadekill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.GrenadeKill, "k4.phrases.grenadekill");
break;
}
//Molotov or Incendiary fire kill
case var _ when lowerCaseWeaponName.Contains("inferno"):
{
- ModifyPlayerPoints(killer, Config.PointSettings.InfernoKill, "k4.phrases.infernokill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.InfernoKill, "k4.phrases.infernokill");
break;
}
// Grenade impact kill (hitting a player and killing them with a grenade when they are 1hp for example)
case var _ when lowerCaseWeaponName.Contains("grenade") || lowerCaseWeaponName.Contains("molotov") || lowerCaseWeaponName.Contains("flashbang") || lowerCaseWeaponName.Contains("bumpmine"):
{
- ModifyPlayerPoints(killer, Config.PointSettings.ImpactKill, "k4.phrases.impactkill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.ImpactKill, "k4.phrases.impactkill");
break;
}
// knife_ would not handle default knives (therefore changed to just "knife"), this will also not handle other Danger Zone items such as axes and wrenches (if they are even implemented yet in CS2)
case var _ when lowerCaseWeaponName.Contains("knife") || lowerCaseWeaponName.Contains("bayonet"):
{
- ModifyPlayerPoints(killer, Config.PointSettings.KnifeKill, "k4.phrases.knifekill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.KnifeKill, "k4.phrases.knifekill");
break;
}
case "taser":
{
- ModifyPlayerPoints(killer, Config.PointSettings.TaserKill, "k4.phrases.taserkill");
+ ModifyPlayerPoints(k4attacker, Config.PointSettings.TaserKill, "k4.phrases.taserkill");
break;
}
}
- if (playerKillStreaks.ContainsKey(killer.Slot))
- {
- int time = Config.PointSettings.SecondsBetweenKills;
- bool isTimeBetweenKills = time <= 0 || DateTime.Now - playerKillStreaks[killer.Slot].lastKillTime <= TimeSpan.FromSeconds(time);
+ int time = Config.PointSettings.SecondsBetweenKills;
+ bool isTimeBetweenKills = time <= 0 || DateTime.Now - k4attacker.KillStreak.lastKillTime <= TimeSpan.FromSeconds(time);
- if (playerKillStreaks[killer.Slot].killStreak > 0 && isTimeBetweenKills)
- {
- playerKillStreaks[killer.Slot] = (playerKillStreaks[killer.Slot].killStreak + 1, DateTime.Now);
- int killStreak = playerKillStreaks[killer.Slot].killStreak;
+ if (k4attacker.KillStreak.killStreak > 0 && isTimeBetweenKills)
+ {
+ k4attacker.KillStreak = (k4attacker.KillStreak.killStreak + 1, DateTime.Now);
+ int killStreak = k4attacker.KillStreak.killStreak;
- Dictionary killStreakMap = new Dictionary
+ Dictionary killStreakMap = new Dictionary
{
{ 2, (Config.PointSettings.DoubleKill, "k4.phrases.doublekill") },
{ 3, (Config.PointSettings.TripleKill, "k4.phrases.triplekill") },
@@ -301,30 +288,27 @@ public void Initialize_Events(Plugin plugin)
{ 12, (Config.PointSettings.GodLike, "k4.phrases.godlike") }
};
- if (killStreakMap.TryGetValue(killStreak, out var killStreakInfo))
- {
- ModifyPlayerPoints(killer, killStreakInfo.points, killStreakInfo.message);
- }
- else
- playerKillStreaks[killer.Slot] = (1, DateTime.Now);
+ if (killStreakMap.TryGetValue(killStreak, out var killStreakInfo))
+ {
+ ModifyPlayerPoints(k4attacker, killStreakInfo.points, killStreakInfo.message);
}
else
- playerKillStreaks[killer.Slot] = (1, DateTime.Now);
+ k4attacker.KillStreak = (1, DateTime.Now);
}
else
- playerKillStreaks[killer.Slot] = (1, DateTime.Now);
+ k4attacker.KillStreak = (1, DateTime.Now);
+
}
}
- CCSPlayerController assiter = @event.Assister;
-
- if (assiter != null && assiter.IsValid && assiter.PlayerPawn.IsValid && !assiter.IsBot && (Config.RankSettings.PointsForBots || !victim.IsBot))
+ K4Player? k4assister = plugin.GetK4Player(@event.Assister);
+ if (k4assister?.IsValid == true && k4assister.IsPlayer && (Config.RankSettings.PointsForBots || k4victim.IsPlayer))
{
- ModifyPlayerPoints(assiter, Config.PointSettings.Assist, "k4.phrases.assist");
+ ModifyPlayerPoints(k4assister, Config.PointSettings.Assist, "k4.phrases.assist");
if (@event.Assistedflash)
{
- ModifyPlayerPoints(assiter, Config.PointSettings.AssistFlash, "k4.phrases.assistflash");
+ ModifyPlayerPoints(k4assister, Config.PointSettings.AssistFlash, "k4.phrases.assistflash");
}
}
diff --git a/K4-System/src/Module/Rank/RankFunctions.cs b/K4-System/src/Module/Rank/RankFunctions.cs
index ec2095a..0a7ab02 100644
--- a/K4-System/src/Module/Rank/RankFunctions.cs
+++ b/K4-System/src/Module/Rank/RankFunctions.cs
@@ -9,13 +9,15 @@ namespace K4System
using Microsoft.Extensions.Logging;
using System.Data;
using K4SharedApi;
+ using K4System.Models;
+ using Dapper;
+ using MaxMind.GeoIP2;
+ using MaxMind.GeoIP2.Exceptions;
public partial class ModuleRank : IModuleRank
{
public bool IsPointsAllowed()
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (plugin.GameRules == null)
return false;
@@ -31,14 +33,15 @@ public Rank GetNoneRank()
public void BeforeRoundEnd(int winnerTeam)
{
- List players = Utilities.GetPlayers().Where(p => p?.IsValid == true && p.PlayerPawn?.IsValid == true && !p.IsBot && !p.IsHLTV && p.SteamID.ToString().Length == 17 && PlayerCache.Instance.ContainsPlayer(p)).ToList();
-
- foreach (CCSPlayerController player in players)
+ foreach (K4Player k4player in plugin.K4Players)
{
- if (!player.PawnIsAlive)
- playerKillStreaks[player.Slot] = (0, DateTime.Now);
+ if (!k4player.IsValid || !k4player.IsPlayer)
+ continue;
+
+ if (!k4player.Controller.PawnIsAlive)
+ k4player.KillStreak = (0, DateTime.Now);
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
+ RankData? playerData = k4player.rankData;
if (playerData is null)
continue;
@@ -46,32 +49,30 @@ public void BeforeRoundEnd(int winnerTeam)
if (!playerData.PlayedRound)
continue;
- if (player.TeamNum <= (int)CsTeam.Spectator)
+ if (k4player.Controller.TeamNum <= (int)CsTeam.Spectator)
continue;
- if (winnerTeam == player.TeamNum)
+ if (winnerTeam == k4player.Controller.TeamNum)
{
- ModifyPlayerPoints(player, Config.PointSettings.RoundWin, "k4.phrases.roundwin");
+ ModifyPlayerPoints(k4player, Config.PointSettings.RoundWin, "k4.phrases.roundwin");
}
else
{
- ModifyPlayerPoints(player, Config.PointSettings.RoundLose, "k4.phrases.roundlose");
+ ModifyPlayerPoints(k4player, Config.PointSettings.RoundLose, "k4.phrases.roundlose");
}
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!playerData.MuteMessages && Config.RankSettings.RoundEndPoints)
{
if (playerData.RoundPoints > 0)
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.gain", playerData.RoundPoints]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.gain", playerData.RoundPoints]}");
}
else if (playerData.RoundPoints < 0)
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.loss", Math.Abs(playerData.RoundPoints)]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.loss", Math.Abs(playerData.RoundPoints)]}");
}
else
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.nochange"]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.summarypoints.nochange"]}");
}
playerData.RoundPoints = 0;
@@ -83,78 +84,44 @@ public Rank GetPlayerRank(int points)
return rankDictionary.LastOrDefault(kv => points >= kv.Value.Point).Value ?? noneRank!;
}
- public static int GetPlayerRankID(CCSPlayerController player)
+ public void ModifyPlayerPointsConnector(CCSPlayerController player, int amount, string reason, string? extraInfo = null)
{
- if (!PlayerCache.Instance.ContainsPlayer(player))
- return 0;
-
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
-
- if (playerData is null)
- return 0;
-
- return playerData.Rank.Id++;
- }
-
- public static int GetPlayerPoints(CCSPlayerController player)
- {
- if (!PlayerCache.Instance.ContainsPlayer(player))
- return 0;
-
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
-
- if (playerData is null)
- return 0;
+ K4Player? k4player = plugin.GetK4Player(player);
+ if (k4player is null)
+ return;
- return playerData.Points;
+ ModifyPlayerPoints(k4player, amount, reason, extraInfo);
}
- public void ModifyPlayerPoints(CCSPlayerController player, int amount, string reason, string? extraInfo = null)
+ public void ModifyPlayerPoints(K4Player k4player, int amount, string reason, string? extraInfo = null)
{
if (!IsPointsAllowed())
return;
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return;
-
- if (player.IsBot || player.IsHLTV)
- return;
-
- if (player.SteamID.ToString().Length != 17)
- return;
-
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ if (!k4player.IsValid || !k4player.IsPlayer)
return;
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
+ RankData? playerData = k4player.rankData;
if (playerData is null)
return;
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (Config.RankSettings.RoundEndPoints && plugin.GameRules != null && !plugin.GameRules.WarmupPeriod)
playerData.RoundPoints += amount;
if (amount == 0)
return;
- if (amount > 0 && AdminManager.PlayerHasPermissions(player, "@k4system/vip/points-multiplier"))
+ if (amount > 0 && AdminManager.PlayerHasPermissions(k4player.Controller, "@k4system/vip/points-multiplier"))
{
amount = (int)Math.Round(amount * Config.RankSettings.VipMultiplier);
}
playerData.Points += amount;
- Server.NextWorldUpdate(() =>
+ Server.NextFrame(() =>
{
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return;
-
- if (player.IsBot || player.IsHLTV)
- return;
-
- if (player.SteamID.ToString().Length != 17)
+ if (!k4player.IsValid || !k4player.IsPlayer)
return;
if (!playerData.MuteMessages && (!Config.RankSettings.RoundEndPoints || plugin.GameRules == null || plugin.GameRules.WarmupPeriod))
@@ -163,22 +130,22 @@ public void ModifyPlayerPoints(CCSPlayerController player, int amount, string re
{
if (extraInfo != null)
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.gain", playerData.Points, amount, plugin.Localizer[reason]]}{extraInfo}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.gain", playerData.Points, amount, plugin.Localizer[reason]]}{extraInfo}");
}
else
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.gain", playerData.Points, amount, plugin.Localizer[reason]]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.gain", playerData.Points, amount, plugin.Localizer[reason]]}");
}
}
else if (amount < 0)
{
if (extraInfo != null)
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.loss", playerData.Points, Math.Abs(amount), plugin.Localizer[reason]]}{extraInfo}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.loss", playerData.Points, Math.Abs(amount), plugin.Localizer[reason]]}{extraInfo}");
}
else
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.loss", playerData.Points, Math.Abs(amount), plugin.Localizer[reason]]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.points.loss", playerData.Points, Math.Abs(amount), plugin.Localizer[reason]]}");
}
}
}
@@ -188,19 +155,19 @@ public void ModifyPlayerPoints(CCSPlayerController player, int amount, string re
playerData.Points = 0;
if (Config.RankSettings.ScoreboardScoreSync)
- player.Score = playerData.Points;
+ k4player.Controller.Score = playerData.Points;
Rank newRank = GetPlayerRank(playerData.Points);
if (playerData.Rank.Name != newRank.Name)
{
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer[playerData.Rank.Point > newRank.Point ? "k4.ranks.demote" : "k4.ranks.promote", newRank.Color, newRank.Name]}");
+ k4player.Controller.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer[playerData.Rank.Point > newRank.Point ? "k4.ranks.demote" : "k4.ranks.promote", newRank.Color, newRank.Name]}");
if (playerData.Rank.Permissions != null && playerData.Rank.Permissions.Count > 0)
{
foreach (Permission permission in playerData.Rank.Permissions)
{
- AdminManager.RemovePlayerPermissions(Utilities.GetPlayerFromSlot(player.Slot), permission.PermissionName);
+ AdminManager.RemovePlayerPermissions(k4player.Controller, permission.PermissionName);
}
}
@@ -208,47 +175,37 @@ public void ModifyPlayerPoints(CCSPlayerController player, int amount, string re
{
foreach (Permission permission in newRank.Permissions)
{
- AdminManager.AddPlayerPermissions(Utilities.GetPlayerFromSlot(player.Slot), permission.PermissionName);
+ AdminManager.AddPlayerPermissions(k4player.Controller, permission.PermissionName);
}
}
playerData.Rank = newRank;
}
- if (Config.RankSettings.ScoreboardClantags)
- {
- string tag = playerData.Rank.Tag ?? $"[{playerData.Rank.Name}]";
- SetPlayerClanTag(player, playerData, tag);
- }
+ SetPlayerClanTag(k4player);
}
- public async Task<(int playerPlace, int totalPlayers)> GetPlayerPlaceAndCountAsync(string steamID)
+ public async Task<(int playerPlace, int totalPlayers)> GetPlayerPlaceAndCountAsync(K4Player k4player)
{
string query = $@"SELECT
(SELECT COUNT(*) FROM `{Config.DatabaseSettings.TablePrefix}k4ranks`
WHERE `points` >
- (SELECT `points` FROM `{Config.DatabaseSettings.TablePrefix}k4ranks` WHERE `steam_id` = @steamId)) AS playerPlace,
+ (SELECT `points` FROM `{Config.DatabaseSettings.TablePrefix}k4ranks` WHERE `steam_id` = @SteamId)) AS playerPlace,
(SELECT COUNT(*) FROM `{Config.DatabaseSettings.TablePrefix}k4ranks`) AS totalPlayers";
- MySqlParameter[] parameters = new MySqlParameter[]
- {
- new MySqlParameter("@steamid", steamID),
- };
-
try
{
- using (MySqlCommand command = new MySqlCommand(query))
+ using (var connection = plugin.CreateConnection(Config))
{
- DataTable dataTable = await Database.Instance.ExecuteReaderAsync(command.CommandText, parameters);
+ await connection.OpenAsync();
- if (dataTable.Rows.Count > 0)
+ var result = await connection.QueryFirstOrDefaultAsync(query, new { SteamId = k4player.SteamID });
+
+ if (result != null)
{
- foreach (DataRow row in dataTable.Rows)
- {
- int playerPlace = Convert.ToInt32(row[0]) + 1;
- int totalPlayers = Convert.ToInt32(row[1]);
- return (playerPlace, totalPlayers);
- }
+ int playerPlace = result.playerPlace + 1;
+ int totalPlayers = result.totalPlayers;
+ return (playerPlace, totalPlayers);
}
}
}
@@ -260,19 +217,16 @@ public void ModifyPlayerPoints(CCSPlayerController player, int amount, string re
return (0, 0);
}
- public int CalculateDynamicPoints(CCSPlayerController from, CCSPlayerController to, int amount)
+ public int CalculateDynamicPoints(K4Player from, K4Player to, int amount)
{
if (!Config.RankSettings.DynamicDeathPoints)
return amount;
- if (to.IsBot || from.IsBot)
- return amount;
-
- if (!PlayerCache.Instance.ContainsPlayer(from) || !PlayerCache.Instance.ContainsPlayer(to))
+ if (!to.IsPlayer || !from.IsPlayer)
return amount;
- RankData? fromCache = PlayerCache.Instance.GetPlayerData(from).rankData;
- RankData? toCache = PlayerCache.Instance.GetPlayerData(to).rankData;
+ RankData? fromCache = from.rankData;
+ RankData? toCache = to.rankData;
if (fromCache is null || toCache is null)
return amount;
@@ -285,9 +239,16 @@ public int CalculateDynamicPoints(CCSPlayerController from, CCSPlayerController
return (int)Math.Round(result);
}
- public void SetPlayerClanTag(CCSPlayerController player, RankData playerData, string tag)
+ public void SetPlayerClanTag(K4Player k4player)
{
- if (!playerData.HideAdminTag)
+ string tag = string.Empty;
+
+ if (Config.RankSettings.ScoreboardClantags && k4player.rankData != null)
+ {
+ tag = k4player.rankData.Rank.Tag ?? $"[{k4player.rankData.Rank.Name}]";
+ }
+
+ if (k4player.rankData?.HideAdminTag == false)
{
foreach (AdminSettingsEntry adminSettings in Config.GeneralSettings.AdminSettingsList)
{
@@ -297,15 +258,15 @@ public void SetPlayerClanTag(CCSPlayerController player, RankData playerData, st
switch (adminSettings.Permission[0])
{
case '@':
- if (AdminManager.PlayerHasPermissions(player, adminSettings.Permission))
+ if (AdminManager.PlayerHasPermissions(k4player.Controller, adminSettings.Permission))
tag = adminSettings.ClanTag;
break;
case '#':
- if (AdminManager.PlayerInGroup(player, adminSettings.Permission))
+ if (AdminManager.PlayerInGroup(k4player.Controller, adminSettings.Permission))
tag = adminSettings.ClanTag;
break;
default:
- if (AdminManager.PlayerHasCommandOverride(player, adminSettings.Permission))
+ if (AdminManager.PlayerHasCommandOverride(k4player.Controller, adminSettings.Permission))
tag = adminSettings.ClanTag;
break;
}
@@ -314,11 +275,48 @@ public void SetPlayerClanTag(CCSPlayerController player, RankData playerData, st
if (Config.RankSettings.CountryTagEnabled)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
- tag = $"{plugin.GetPlayerCountryCode(player)} | {tag}";
+ string countryTag = GetPlayerCountryCode(k4player.Controller);
+ tag = tag.Length > 0 ? $"{countryTag} | {tag}" : countryTag;
+ }
+
+ k4player.ClanTag = tag;
+ }
+
+ public string GetPlayerCountryCode(CCSPlayerController player)
+ {
+ string? playerIp = player.IpAddress;
+
+ if (playerIp == null)
+ return "??";
+
+ string[] parts = playerIp.Split(':');
+ string realIP = parts.Length == 2 ? parts[0] : playerIp;
+
+ string filePath = Path.Combine(plugin.ModuleDirectory, "GeoLite2-Country.mmdb");
+ if (!File.Exists(filePath))
+ {
+ Logger.LogError($"GeoLite2-Country.mmdb not found in {filePath}. Download it from https://github.com/P3TERX/GeoLite.mmdb/releases and place it in the same directory as the plugin.");
+ return "??";
}
- player.Clan = tag;
+ using (DatabaseReader reader = new DatabaseReader(filePath))
+ {
+ try
+ {
+ MaxMind.GeoIP2.Responses.CountryResponse response = reader.Country(realIP);
+ return response.Country.IsoCode ?? "??";
+ }
+ catch (AddressNotFoundException)
+ {
+ Logger.LogError($"The address {realIP} is not in the database.");
+ return "??";
+ }
+ catch (GeoIP2Exception ex)
+ {
+ Logger.LogError($"Error: {ex.Message}");
+ return "??";
+ }
+ }
}
}
}
diff --git a/K4-System/src/Module/Rank/RankGlobals.cs b/K4-System/src/Module/Rank/RankGlobals.cs
index 8b2c699..3f5bd73 100644
--- a/K4-System/src/Module/Rank/RankGlobals.cs
+++ b/K4-System/src/Module/Rank/RankGlobals.cs
@@ -32,14 +32,12 @@ public class RankData
public required bool MuteMessages { get; set; }
}
- public readonly PluginContext PluginContext;
+ public readonly Plugin plugin;
public readonly ILogger Logger;
- public required PluginConfig Config { get; set; }
- public required string ModuleDirectory { get; set; }
+ public readonly PluginConfig Config;
public Dictionary rankDictionary = new Dictionary();
- public Dictionary playerKillStreaks = new Dictionary();
public Rank? noneRank;
}
}
\ No newline at end of file
diff --git a/K4-System/src/Module/Rank/RankMenus.cs b/K4-System/src/Module/Rank/RankMenus.cs
index 7f7a862..b20f532 100644
--- a/K4-System/src/Module/Rank/RankMenus.cs
+++ b/K4-System/src/Module/Rank/RankMenus.cs
@@ -1,72 +1,79 @@
namespace K4System
{
- using MySqlConnector;
-
using CounterStrikeSharp.API.Modules.Menu;
using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging;
- using System.Data;
+ using Dapper;
+ using K4System.Models;
+ using CounterStrikeSharp.API;
public partial class ModuleRank : IModuleRank
{
ChatMenu ranksMenu = new ChatMenu("Available Rank List");
- public void Initialize_Menus(Plugin plugin)
+ public void Initialize_Menus()
{
foreach (Rank rank in rankDictionary.Values)
{
ranksMenu.AddMenuOption(rank.Point == -1 ? plugin.Localizer["k4.ranks.listdefault", rank.Color, rank.Name] : plugin.Localizer["k4.ranks.listitem", rank.Color, rank.Name, rank.Point],
(player, option) =>
{
- Task<(int playerCount, float percentage)> task = Task.Run(() => FetchRanksMenuDataAsync(rank.Name));
- task.Wait();
- var result = task.Result;
-
- int playerCount = result.playerCount;
- float percentage = result.percentage;
+ ulong steamID = player.SteamID;
- if (!PlayerCache.Instance.ContainsPlayer(player))
- return;
-
- RankData? playerData = PlayerCache.Instance.GetPlayerData(player).rankData;
+ Task.Run(async () =>
+ {
+ (int playerCount, float percentage) taskValues = await FetchRanksMenuDataAsync(rank.Name);
- if (playerData is null)
- return;
+ int playerCount = taskValues.playerCount;
+ float percentage = taskValues.percentage;
- int pointsDifference = Math.Abs(rank.Point - playerData.Points);
+ Server.NextFrame(() =>
+ {
+ K4Player? k4player = plugin.GetK4Player(steamID);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
+ return;
- player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.selected.title", rank.Color, rank.Name]}");
- player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.line1", playerCount, percentage]}");
+ RankData? playerData = k4player.rankData;
- if (rank.Name == playerData.Rank.Name)
- player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.line2.current", rank.Point]}");
- else
- player.PrintToChat($" {plugin.Localizer[rank.Point > playerData.Rank.Point ? "k4.ranks.selected.line2" : "k4.ranks.selected.line2.passed", rank.Point == -1 ? "None" : rank.Point, pointsDifference]}");
+ if (playerData is null)
+ return;
- if (rank.Permissions != null && rank.Permissions.Count > 0)
- {
- player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.benefitline"]}");
+ int pointsDifference = Math.Abs(rank.Point - playerData.Points);
- int permissionCount = 0;
- string permissionLine = "";
+ player.PrintToChat($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.ranks.selected.title", rank.Color, rank.Name]}");
+ player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.line1", playerCount, percentage]}");
- foreach (Permission permission in rank.Permissions)
- {
- permissionLine += $"{ChatColors.Lime}{permission.DisplayName}{ChatColors.Silver}, ";
- permissionCount++;
+ if (rank.Name == playerData.Rank.Name)
+ player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.line2.current", rank.Point]}");
+ else
+ player.PrintToChat($" {plugin.Localizer[rank.Point > playerData.Rank.Point ? "k4.ranks.selected.line2" : "k4.ranks.selected.line2.passed", rank.Point == -1 ? "None" : rank.Point, pointsDifference]}");
- if (permissionCount % 3 == 0)
+ if (rank.Permissions != null && rank.Permissions.Count > 0)
{
- player.PrintToChat($" {permissionLine.TrimEnd(',', ' ')}");
- permissionLine = "";
+ player.PrintToChat($" {plugin.Localizer["k4.ranks.selected.benefitline"]}");
+
+ int permissionCount = 0;
+ string permissionLine = "";
+
+ foreach (Permission permission in rank.Permissions)
+ {
+ permissionLine += $"{ChatColors.Lime}{permission.DisplayName}{ChatColors.Silver}, ";
+ permissionCount++;
+
+ if (permissionCount % 3 == 0)
+ {
+ player.PrintToChat($" {permissionLine.TrimEnd(',', ' ')}");
+ permissionLine = "";
+ }
+ }
+
+ if (!string.IsNullOrEmpty(permissionLine))
+ {
+ player.PrintToChat($" {permissionLine.TrimEnd(',', ' ')}");
+ }
}
- }
-
- if (!string.IsNullOrEmpty(permissionLine))
- {
- player.PrintToChat($" {permissionLine.TrimEnd(',', ' ')}");
- }
- }
+ });
+ });
});
}
}
@@ -77,30 +84,30 @@ public void Initialize_Menus(Plugin plugin)
float percentage = 0.0f;
string query = $@"
- SELECT
- COUNT(*) AS PlayerCount,
- ROUND((COUNT(*) / TotalPlayers) * 100, 2) AS Percentage
- FROM
- `{Config.DatabaseSettings.TablePrefix}k4ranks`,
- (SELECT COUNT(*) AS TotalPlayers FROM `{Config.DatabaseSettings.TablePrefix}k4ranks`) AS Total
- WHERE
- `rank` = '{rankName}'
- GROUP BY
- `rank`;";
+ SELECT
+ COUNT(*) AS PlayerCount,
+ ROUND((COUNT(*) / TotalPlayers.Total) * 100, 2) AS Percentage
+ FROM
+ `{Config.DatabaseSettings.TablePrefix}k4ranks`
+ CROSS JOIN
+ (SELECT COUNT(*) AS Total FROM `{Config.DatabaseSettings.TablePrefix}k4ranks`) TotalPlayers
+ WHERE
+ `rank` = @RankName
+ GROUP BY
+ `rank`;";
try
{
- using (MySqlCommand command = new MySqlCommand(query))
+ using (var connection = plugin.CreateConnection(Config))
{
- DataTable dataTable = await Database.Instance.ExecuteReaderAsync(command.CommandText);
+ await connection.OpenAsync();
- if (dataTable.Rows.Count > 0)
+ var result = await connection.QueryFirstOrDefaultAsync<(int, float)>(query, new { RankName = rankName });
+
+ if (result != default)
{
- foreach (DataRow row in dataTable.Rows)
- {
- playerCount = Convert.ToInt32(row[0]);
- percentage = Convert.ToSingle(row[1]);
- }
+ playerCount = result.Item1;
+ percentage = result.Item2;
}
}
@@ -112,5 +119,6 @@ GROUP BY
return (0, 0);
}
}
+
}
}
\ No newline at end of file
diff --git a/K4-System/src/Module/Stat/StatCommands.cs b/K4-System/src/Module/Stat/StatCommands.cs
index 99466d9..6c7b90c 100644
--- a/K4-System/src/Module/Stat/StatCommands.cs
+++ b/K4-System/src/Module/Stat/StatCommands.cs
@@ -2,10 +2,11 @@ namespace K4System
{
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands;
+ using K4System.Models;
public partial class ModuleStat : IModuleStat
{
- public void Initialize_Commands(Plugin plugin)
+ public void Initialize_Commands()
{
CommandSettings commands = Config.CommandSettings;
@@ -17,18 +18,18 @@ public void Initialize_Commands(Plugin plugin)
public void OnCommandStats(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- if (!PlayerCache.Instance.ContainsPlayer(player!))
+ K4Player? k4player = plugin.GetK4Player(player!);
+
+ if (k4player is null)
{
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
return;
}
- StatData? playerData = PlayerCache.Instance.GetPlayerData(player!).statData;
+ StatData? playerData = k4player.statData;
if (playerData is null)
return;
diff --git a/K4-System/src/Module/Stat/StatEvents.cs b/K4-System/src/Module/Stat/StatEvents.cs
index de74e6c..170dd3d 100644
--- a/K4-System/src/Module/Stat/StatEvents.cs
+++ b/K4-System/src/Module/Stat/StatEvents.cs
@@ -4,46 +4,104 @@ namespace K4System
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleStat : IModuleStat
{
- public void Initialize_Events(Plugin plugin)
+ public void Initialize_Events()
{
plugin.RegisterEventHandler((EventPlayerDeath @event, GameEventInfo info) =>
{
if (!IsStatsAllowed())
- {
return HookResult.Continue;
- }
- CCSPlayerController victim = @event.Userid;
+ K4Player? k4victim = plugin.GetK4Player(@event.Userid);
- if (victim.IsBot && !Config.StatisticSettings.StatsForBots)
+ if (k4victim is null || !k4victim.IsValid)
return HookResult.Continue;
- if (victim != null && victim.IsValid && victim.PlayerPawn.IsValid && victim.UserId.HasValue && victim.UserId != -1 && !victim.IsBot)
+ if (!k4victim.IsPlayer && !Config.StatisticSettings.StatsForBots)
+ return HookResult.Continue;
+
+ if (!k4victim.IsPlayer)
{
- ModifyPlayerStats(victim, "deaths", 1);
+ ModifyPlayerStats(k4victim, "deaths", 1);
}
- CCSPlayerController attacker = @event.Attacker;
-
- if (attacker != null && attacker.IsValid && attacker.PlayerPawn.IsValid && !attacker.IsBot && !attacker.IsHLTV)
+ K4Player? k4attacker = plugin.GetK4Player(@event.Attacker);
+ if (k4attacker != null && k4attacker.IsValid && k4attacker.IsPlayer)
{
- ModifyPlayerStats(attacker, "kills", 1);
+ ModifyPlayerStats(k4attacker, "kills", 1);
if (!FirstBlood)
{
FirstBlood = true;
- ModifyPlayerStats(attacker, "firstblood", 1);
+ ModifyPlayerStats(k4attacker, "firstblood", 1);
}
- }
- CCSPlayerController assister = @event.Assister;
+ if (@event.Noscope)
+ ModifyPlayerStats(k4attacker, "noscope_kill", 1);
+
+ if (@event.Penetrated > 0)
+ ModifyPlayerStats(k4attacker, "penetrated_kill", 1);
+
+ if (@event.Thrusmoke)
+ ModifyPlayerStats(k4attacker, "thrusmoke_kill", 1);
+
+ if (@event.Attackerblind)
+ ModifyPlayerStats(k4attacker, "flashed_kill", 1);
- if (assister != null && assister.IsValid && assister.PlayerPawn.IsValid && !assister.IsBot && !assister.IsHLTV)
+ if (@event.Dominated > 0)
+ ModifyPlayerStats(k4attacker, "dominated_kill", 1);
+
+ if (@event.Revenge > 0)
+ ModifyPlayerStats(k4attacker, "revenge_kill", 1);
+
+ if (@event.Assistedflash)
+ ModifyPlayerStats(k4attacker, "assist_flash", 1);
+
+ switch (@event.Hitgroup)
+ {
+ case (int)HitGroup_t.HITGROUP_HEAD:
+ ModifyPlayerStats(k4attacker, "headshots", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_CHEST:
+ ModifyPlayerStats(k4attacker, "chest_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_STOMACH:
+ ModifyPlayerStats(k4attacker, "stomach_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_LEFTARM:
+ ModifyPlayerStats(k4attacker, "left_arm_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_RIGHTARM:
+ ModifyPlayerStats(k4attacker, "right_arm_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_LEFTLEG:
+ ModifyPlayerStats(k4attacker, "left_leg_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_RIGHTLEG:
+ ModifyPlayerStats(k4attacker, "right_leg_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_NECK:
+ ModifyPlayerStats(k4attacker, "neck_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_UNUSED:
+ ModifyPlayerStats(k4attacker, "unused_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_GEAR:
+ ModifyPlayerStats(k4attacker, "gear_hits", 1);
+ break;
+ case (int)HitGroup_t.HITGROUP_SPECIAL:
+ ModifyPlayerStats(k4attacker, "special_hits", 1);
+ break;
+ }
+ }
+
+ K4Player? k4assister = plugin.GetK4Player(@event.Assister);
+ if (k4assister != null && k4assister.IsValid && k4assister.IsPlayer)
{
- ModifyPlayerStats(assister, "assists", 1);
+ ModifyPlayerStats(k4assister, "assists", 1);
}
return HookResult.Continue;
@@ -52,43 +110,38 @@ public void Initialize_Events(Plugin plugin)
plugin.RegisterEventHandler((EventGrenadeThrown @event, GameEventInfo info) =>
{
if (!IsStatsAllowed())
- {
return HookResult.Continue;
- }
- CCSPlayerController player = @event.Userid;
-
- if (player != null && player.IsValid && player.PlayerPawn.IsValid && !player.IsBot && !player.IsHLTV)
- {
- ModifyPlayerStats(player, "grenades", 1);
- }
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
+ return HookResult.Continue;
+ ModifyPlayerStats(k4player, "grenades", 1);
return HookResult.Continue;
});
plugin.RegisterEventHandler((EventPlayerHurt @event, GameEventInfo info) =>
{
if (!IsStatsAllowed())
- {
return HookResult.Continue;
- }
- CCSPlayerController victim = @event.Userid;
+ K4Player? k4victim = plugin.GetK4Player(@event.Userid);
+ if (k4victim is null || !k4victim.IsValid)
+ return HookResult.Continue;
- if (victim != null && victim.IsValid && victim.PlayerPawn.IsValid && victim.UserId.HasValue && victim.UserId != -1 && !victim.IsBot && !victim.IsHLTV)
+ if (k4victim.IsPlayer)
{
- ModifyPlayerStats(victim, "hits_taken", 1);
+ ModifyPlayerStats(k4victim, "hits_taken", 1);
}
- CCSPlayerController attacker = @event.Attacker;
-
- if (attacker != null && attacker.IsValid && attacker.PlayerPawn.IsValid && !attacker.IsBot && !attacker.IsHLTV)
+ K4Player? k4attacker = plugin.GetK4Player(@event.Attacker);
+ if (k4attacker != null && k4attacker.IsValid && k4attacker.IsPlayer)
{
- ModifyPlayerStats(attacker, "hits_given", 1);
+ ModifyPlayerStats(k4attacker, "hits_given", 1);
if (@event.Hitgroup == 1)
{
- ModifyPlayerStats(attacker, "headshots", 1);
+ ModifyPlayerStats(k4attacker, "headshots", 1);
}
}
@@ -101,68 +154,110 @@ public void Initialize_Events(Plugin plugin)
return HookResult.Continue;
});
- plugin.RegisterEventHandler((EventWeaponFire @event, GameEventInfo info) =>
+ plugin.RegisterEventHandler((EventBombPlanted @event, GameEventInfo info) =>
{
- if (!IsStatsAllowed())
- {
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- }
- CCSPlayerController player = @event.Userid;
+ ModifyPlayerStats(k4player, "bomb_planted", 1);
+ return HookResult.Continue;
+ });
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
+ plugin.RegisterEventHandler((EventHostageRescued @event, GameEventInfo info) =>
+ {
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- if (player.IsBot || player.IsHLTV)
+ ModifyPlayerStats(k4player, "hostage_rescued", 1);
+ return HookResult.Continue;
+ });
+
+ plugin.RegisterEventHandler((EventHostageKilled @event, GameEventInfo info) =>
+ {
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- if (@event.Weapon.Contains("knife") || @event.Weapon.Contains("bayonet"))
- {
+ ModifyPlayerStats(k4player, "hostage_killed", 1);
+ return HookResult.Continue;
+ });
+
+ plugin.RegisterEventHandler((EventBombDefused @event, GameEventInfo info) =>
+ {
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- }
- ModifyPlayerStats(player, "shoots", 1);
+ ModifyPlayerStats(k4player, "bomb_defused", 1);
return HookResult.Continue;
});
- plugin.RegisterEventHandler((EventRoundMvp @event, GameEventInfo info) =>
+ plugin.RegisterEventHandler((EventRoundEnd @event, GameEventInfo info) =>
{
- if (!IsStatsAllowed())
+ foreach (K4Player k4player in plugin.K4Players)
{
- return HookResult.Continue;
+ if (!k4player.IsValid || !k4player.IsPlayer)
+ continue;
+
+ CsTeam team = k4player.Controller.Team;
+
+ if (team <= CsTeam.Spectator)
+ continue;
+
+ ModifyPlayerStats(k4player, "rounds_overall", 1);
+ ModifyPlayerStats(k4player, team == CsTeam.Terrorist ? "rounds_t" : "rounds_ct", 1);
}
+ return HookResult.Continue;
+ });
- CCSPlayerController player = @event.Userid;
+ plugin.RegisterEventHandler((EventWeaponFire @event, GameEventInfo info) =>
+ {
+ if (!IsStatsAllowed())
+ return HookResult.Continue;
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- if (player.IsBot || player.IsHLTV)
+ if (@event.Weapon.Contains("knife") || @event.Weapon.Contains("bayonet"))
return HookResult.Continue;
- ModifyPlayerStats(player, "mvp", 1);
+ ModifyPlayerStats(k4player, "shoots", 1);
+ return HookResult.Continue;
+ });
+
+ plugin.RegisterEventHandler((EventRoundMvp @event, GameEventInfo info) =>
+ {
+ if (!IsStatsAllowed())
+ return HookResult.Continue;
+
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
+ return HookResult.Continue;
+
+ ModifyPlayerStats(k4player, "mvp", 1);
return HookResult.Continue;
});
plugin.RegisterEventHandler((@event, info) =>
{
if (!IsStatsAllowed())
- {
return HookResult.Continue;
- }
- List players = Utilities.GetPlayers().Where(p => p?.IsValid == true && p.PlayerPawn?.IsValid == true && !p.IsBot && !p.IsHLTV && p.SteamID.ToString().Length == 17).ToList();
+ List k4players = plugin.K4Players.Where(p => p.IsValid && p.IsPlayer).ToList();
if (Config.GeneralSettings.FFAMode)
{
- CCSPlayerController? player = players.OrderByDescending(p => p?.Score).FirstOrDefault();
+ K4Player? k4player = k4players.OrderByDescending(p => p.Controller.Score).FirstOrDefault();
- if (player != null)
+ if (k4player != null)
{
- ModifyPlayerStats(player, "game_win", 1);
+ ModifyPlayerStats(k4player, "game_win", 1);
}
- players.Where(p => p != player).ToList().ForEach(p => ModifyPlayerStats(p, "game_lose", 1));
+ k4players.Where(p => p != k4player).ToList().ForEach(p => ModifyPlayerStats(p, "game_lose", 1));
}
else
{
@@ -178,11 +273,11 @@ public void Initialize_Events(Plugin plugin)
CsTeam winnerTeam = ctScore > tScore ? CsTeam.CounterTerrorist : tScore > ctScore ? CsTeam.Terrorist : CsTeam.None;
- if ((int)winnerTeam > (int)CsTeam.Spectator)
+ if (winnerTeam > CsTeam.Spectator)
{
- players.Where(p => p.TeamNum > (int)CsTeam.Spectator)
+ k4players.Where(p => p.Controller.Team > CsTeam.Spectator)
.ToList()
- .ForEach(p => ModifyPlayerStats(p, (CsTeam)p.TeamNum == winnerTeam ? "game_win" : "game_lose", 1));
+ .ForEach(p => ModifyPlayerStats(p, p.Controller.Team == winnerTeam ? "game_win" : "game_lose", 1));
}
}
diff --git a/K4-System/src/Module/Stat/StatFunctions.cs b/K4-System/src/Module/Stat/StatFunctions.cs
index 16e622d..6667dbf 100644
--- a/K4-System/src/Module/Stat/StatFunctions.cs
+++ b/K4-System/src/Module/Stat/StatFunctions.cs
@@ -3,14 +3,13 @@ namespace K4System
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleStat : IModuleStat
{
public bool IsStatsAllowed()
{
int notBots = Utilities.GetPlayers().Count(player => !player.IsBot);
-
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
return plugin.GameRules != null && (!plugin.GameRules.WarmupPeriod || Config.StatisticSettings.WarmupStats) && (Config.StatisticSettings.MinPlayers <= notBots);
}
@@ -21,36 +20,22 @@ public void BeforeRoundEnd(int winnerTeam)
if (winnerTeam > (int)CsTeam.Spectator)
{
- List players = Utilities.GetPlayers();
-
- foreach (CCSPlayerController player in players)
+ foreach (K4Player k4player in plugin.K4Players)
{
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
continue;
- if (player.IsBot || player.IsHLTV)
+ if (k4player.Controller.Team <= CsTeam.Spectator)
continue;
- if (player.TeamNum <= (int)CsTeam.Spectator)
- continue;
-
- ModifyPlayerStats(player, player.TeamNum == winnerTeam ? "round_win" : "round_lose", 1);
+ ModifyPlayerStats(k4player, k4player.Controller.TeamNum == winnerTeam ? "round_win" : "round_lose", 1);
}
}
}
- public void ModifyPlayerStats(CCSPlayerController player, string field, int amount)
+ public void ModifyPlayerStats(K4Player k4player, string field, int amount)
{
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return;
-
- if (player.IsBot || player.IsHLTV)
- return;
-
- if (!PlayerCache.Instance.ContainsPlayer(player))
- return;
-
- StatData? playerData = PlayerCache.Instance.GetPlayerData(player).statData;
+ StatData? playerData = k4player.statData;
if (playerData != null)
{
diff --git a/K4-System/src/Module/Stat/StatGlobals.cs b/K4-System/src/Module/Stat/StatGlobals.cs
index a4e9c5f..d95c798 100644
--- a/K4-System/src/Module/Stat/StatGlobals.cs
+++ b/K4-System/src/Module/Stat/StatGlobals.cs
@@ -11,9 +11,10 @@ public class StatData
public Dictionary StatFields { get; set; } = new Dictionary();
}
- public readonly PluginContext PluginContext;
+ public readonly Plugin plugin;
public readonly ILogger Logger;
- public required PluginConfig Config { get; set; }
+ public readonly PluginConfig Config;
+
public bool FirstBlood = false;
}
}
\ No newline at end of file
diff --git a/K4-System/src/Module/Time/TimeCommands.cs b/K4-System/src/Module/Time/TimeCommands.cs
index cf180b7..84cdfd9 100644
--- a/K4-System/src/Module/Time/TimeCommands.cs
+++ b/K4-System/src/Module/Time/TimeCommands.cs
@@ -3,10 +3,11 @@ namespace K4System
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleTime : IModuleTime
{
- public void Initialize_Commands(Plugin plugin)
+ public void Initialize_Commands()
{
CommandSettings commands = Config.CommandSettings;
@@ -18,18 +19,18 @@ public void Initialize_Commands(Plugin plugin)
public void OnCommandTime(CCSPlayerController? player, CommandInfo info)
{
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
if (!plugin.CommandHelper(player, info, CommandUsage.CLIENT_ONLY))
return;
- if (!PlayerCache.Instance.ContainsPlayer(player!))
+ K4Player? k4player = plugin.GetK4Player(player!);
+
+ if (k4player is null)
{
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.general.loading"]}");
return;
}
- TimeData? playerData = PlayerCache.Instance.GetPlayerData(player!).timeData;
+ TimeData? playerData = k4player.timeData;
if (playerData is null)
return;
diff --git a/K4-System/src/Module/Time/TimeEvents.cs b/K4-System/src/Module/Time/TimeEvents.cs
index a417079..d51bce6 100644
--- a/K4-System/src/Module/Time/TimeEvents.cs
+++ b/K4-System/src/Module/Time/TimeEvents.cs
@@ -3,25 +3,19 @@ namespace K4System
{
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleTime : IModuleTime
{
- public void Initialize_Events(Plugin plugin)
+ public void Initialize_Events()
{
plugin.RegisterEventHandler((EventPlayerTeam @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return HookResult.Continue;
-
- if (player.IsBot || player.IsHLTV)
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- if (!PlayerCache.Instance.ContainsPlayer(player))
- return HookResult.Continue;
-
- TimeData? playerData = PlayerCache.Instance.GetPlayerData(player).timeData;
+ TimeData? playerData = k4player.timeData;
if (playerData is null)
return HookResult.Continue;
@@ -43,18 +37,11 @@ public void Initialize_Events(Plugin plugin)
plugin.RegisterEventHandler((EventPlayerSpawn @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return HookResult.Continue;
-
- if (player.IsBot || player.IsHLTV)
- return HookResult.Continue;
-
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- TimeData? playerData = PlayerCache.Instance.GetPlayerData(player).timeData;
+ TimeData? playerData = k4player.timeData;
if (playerData is null)
return HookResult.Continue;
@@ -71,18 +58,12 @@ public void Initialize_Events(Plugin plugin)
plugin.RegisterEventHandler((EventPlayerDeath @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return HookResult.Continue;
-
- if (player.IsBot || player.IsHLTV)
- return HookResult.Continue;
+ K4Player? k4player = plugin.GetK4Player(@event.Userid);
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
- TimeData? playerData = PlayerCache.Instance.GetPlayerData(player).timeData;
+ TimeData? playerData = k4player.timeData;
if (playerData is null)
return HookResult.Continue;
diff --git a/K4-System/src/Module/Time/TimeFunctions.cs b/K4-System/src/Module/Time/TimeFunctions.cs
index 518d152..e7a50b4 100644
--- a/K4-System/src/Module/Time/TimeFunctions.cs
+++ b/K4-System/src/Module/Time/TimeFunctions.cs
@@ -1,26 +1,27 @@
namespace K4System
{
+ using System.Runtime.CompilerServices;
using System.Text;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleTime : IModuleTime
{
- public void BeforeDisconnect(CCSPlayerController player)
+ public void BeforeDisconnect(K4Player k4player)
{
DateTime now = DateTime.UtcNow;
-
- TimeData? playerData = PlayerCache.Instance.GetPlayerData(player).timeData;
+ TimeData? playerData = k4player.timeData;
if (playerData is null)
return;
playerData.TimeFields["all"] += (int)(now - playerData.Times["Connect"]).TotalSeconds;
- playerData.TimeFields[GetFieldForTeam((CsTeam)player.TeamNum)] += (int)(now - playerData.Times["Team"]).TotalSeconds;
+ playerData.TimeFields[GetFieldForTeam(k4player.Controller.Team)] += (int)(now - playerData.Times["Team"]).TotalSeconds;
- if ((CsTeam)player.TeamNum > CsTeam.Spectator)
- playerData.TimeFields[player.PawnIsAlive ? "alive" : "dead"] += (int)(now - playerData.Times["Death"]).TotalSeconds;
+ if (k4player.Controller.Team > CsTeam.Spectator)
+ playerData.TimeFields[k4player.Controller.PawnIsAlive ? "alive" : "dead"] += (int)(now - playerData.Times["Death"]).TotalSeconds;
// This is for the mapchange cases
playerData.Times = new Dictionary
@@ -33,43 +34,48 @@ public void BeforeDisconnect(CCSPlayerController player)
public string GetFieldForTeam(CsTeam team)
{
- switch (team)
+ return team switch
{
- case CsTeam.Terrorist:
- return "t";
- case CsTeam.CounterTerrorist:
- return "ct";
- default:
- return "spec";
- }
+ CsTeam.Terrorist => "t",
+ CsTeam.CounterTerrorist => "ct",
+ _ => "spec"
+ };
}
public string FormatPlaytime(int totalSeconds)
{
- string[] units = { "k4.phrases.shortyear", "k4.phrases.shortmonth", "k4.phrases.shortday", "k4.phrases.shorthour", "k4.phrases.shortminute", "k4.phrases.shortsecond" };
- int[] values = { totalSeconds / 31536000, totalSeconds % 31536000 / 2592000, totalSeconds % 2592000 / 86400, totalSeconds % 86400 / 3600, totalSeconds % 3600 / 60, totalSeconds % 60 };
+ string[] units = { "year", "month", "day", "hour", "minute", "second" };
+ int[] timeDivisors = { 31536000, 2592000, 86400, 3600, 60, 1 };
StringBuilder formattedTime = new StringBuilder();
-
bool addedValue = false;
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
-
for (int i = 0; i < units.Length; i++)
{
- if (values[i] > 0)
+ int timeValue = totalSeconds / timeDivisors[i];
+ totalSeconds %= timeDivisors[i];
+ if (timeValue > 0)
{
- formattedTime.Append($"{values[i]}{plugin.Localizer[units[i]]}, ");
+ if (formattedTime.Length > 0)
+ {
+ formattedTime.Append(", ");
+ }
+ formattedTime.Append($"{timeValue}{GetShortUnit(units[i])}");
addedValue = true;
}
}
if (!addedValue)
{
- formattedTime.Append("0s");
+ return "0" + GetShortUnit("second");
}
- return formattedTime.ToString().TrimEnd(' ', ',');
+ return formattedTime.ToString();
+
+ string GetShortUnit(string unit)
+ {
+ return plugin.Localizer[$"k4.phrases.short{unit}"];
+ }
}
}
}
diff --git a/K4-System/src/Module/Time/TimeGlobals.cs b/K4-System/src/Module/Time/TimeGlobals.cs
index a654973..4337f41 100644
--- a/K4-System/src/Module/Time/TimeGlobals.cs
+++ b/K4-System/src/Module/Time/TimeGlobals.cs
@@ -12,9 +12,9 @@ public class TimeData
public Dictionary TimeFields { get; set; } = new Dictionary();
}
- public readonly PluginContext PluginContext;
+ public readonly Plugin plugin;
public readonly ILogger Logger;
- public required PluginConfig Config { get; set; }
+ public readonly PluginConfig Config;
}
}
\ No newline at end of file
diff --git a/K4-System/src/Module/Utils/UtilsCommands.cs b/K4-System/src/Module/Utils/UtilsCommands.cs
index 3ffa93e..3195971 100644
--- a/K4-System/src/Module/Utils/UtilsCommands.cs
+++ b/K4-System/src/Module/Utils/UtilsCommands.cs
@@ -5,10 +5,11 @@ namespace K4System
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public partial class ModuleUtils : IModuleUtils
{
- public void Initialize_Commands(Plugin plugin)
+ public void Initialize_Commands()
{
CommandSettings commands = Config.CommandSettings;
@@ -23,36 +24,45 @@ public void OnCommandAdmins(CCSPlayerController? player, CommandInfo info)
if (player == null || !player.IsValid || player.PlayerPawn.Value == null)
return;
- Plugin plugin = (this.PluginContext.Plugin as Plugin)!;
+ List adminList = new List();
- List onlineAdmins = Utilities.GetPlayers()
- .SelectMany(adminPlayer => Config.GeneralSettings.AdminSettingsList.Where(adminSettings =>
+ foreach (K4Player k4player in plugin.K4Players)
+ {
+ if (!k4player.IsValid || !k4player.IsPlayer)
+ continue;
+
+ foreach (AdminSettingsEntry entry in Config.GeneralSettings.AdminSettingsList)
{
- if (adminSettings.ListColor == null)
- return false;
-
- switch (adminSettings.Permission[0])
- {
- case '@':
- return AdminManager.PlayerHasPermissions(adminPlayer, adminSettings.Permission);
- case '#':
- return AdminManager.PlayerInGroup(adminPlayer, adminSettings.Permission);
- default:
- return AdminManager.PlayerHasCommandOverride(adminPlayer, adminSettings.Permission);
- }
- }).Select(adminSettings => new { adminPlayer, adminSettings }))
- .Select(x => $"{plugin.ApplyPrefixColors(x.adminSettings.ListColor ?? "default")}{x.adminPlayer.PlayerName}")
- .ToList();
-
- if (onlineAdmins.Count > 0)
+ if (entry.ListColor == null)
+ continue;
+
+ if (PlayerHasPermission(k4player, entry.Permission))
+ adminList.Add($"{plugin.ApplyPrefixColors(entry.ListColor ?? "default")}{k4player.PlayerName}");
+ }
+ }
+
+ if (adminList.Count > 0)
{
- string adminList = string.Join($"{ChatColors.Silver},", onlineAdmins);
+ string onlineAdmins = string.Join($"{ChatColors.Silver},", adminList);
info.ReplyToCommand($" {plugin.Localizer["k4.general.prefix"]} {plugin.Localizer["k4.adminlist.title"]}");
- info.ReplyToCommand($" {adminList}");
+ info.ReplyToCommand($" {onlineAdmins}");
}
else
info.ReplyToCommand($" {plugin.Localizer["k4.adminlist.no-admins"]}");
+
+ bool PlayerHasPermission(K4Player k4player, string permission)
+ {
+ switch (permission[0])
+ {
+ case '@':
+ return AdminManager.PlayerHasPermissions(k4player.Controller, permission);
+ case '#':
+ return AdminManager.PlayerInGroup(k4player.Controller, permission);
+ default:
+ return AdminManager.PlayerHasCommandOverride(k4player.Controller, permission);
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/K4-System/src/Module/Utils/UtilsGlobals.cs b/K4-System/src/Module/Utils/UtilsGlobals.cs
index 4958260..619452c 100644
--- a/K4-System/src/Module/Utils/UtilsGlobals.cs
+++ b/K4-System/src/Module/Utils/UtilsGlobals.cs
@@ -6,9 +6,9 @@ namespace K4System
public partial class ModuleUtils : IModuleUtils
{
- public readonly PluginContext PluginContext;
+ public readonly Plugin plugin;
public readonly ILogger Logger;
- public required PluginConfig Config { get; set; }
+ public readonly PluginConfig Config;
}
}
\ No newline at end of file
diff --git a/K4-System/src/Plugin/Plugin.cs b/K4-System/src/Plugin/Plugin.cs
index b90c80f..8a48b03 100644
--- a/K4-System/src/Plugin/Plugin.cs
+++ b/K4-System/src/Plugin/Plugin.cs
@@ -6,6 +6,8 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API;
+ using K4System.Models;
+ using Dapper;
[MinimumApiVersion(191)]
public sealed partial class Plugin : BasePlugin, IPluginConfig
@@ -21,6 +23,8 @@ public sealed partial class Plugin : BasePlugin, IPluginConfig
private readonly IModuleTime ModuleTime;
private readonly IModuleUtils ModuleUtils;
+ public List K4Players = new List();
+
public Plugin(ModuleRank moduleRank, ModuleStat moduleStat, ModuleTime moduleTime, ModuleUtils moduleUtils)
{
this.ModuleRank = moduleRank;
@@ -36,19 +40,6 @@ public void OnConfigParsed(PluginConfig config)
base.Logger.LogWarning("Configuration version mismatch (Expected: {0} | Current: {1})", this.Config.Version, config.Version);
}
- //** ? Database Connection Init */
-
- DatabaseSettings databaseSettings = config.DatabaseSettings;
-
- Database.Instance.Initialize(
- server: databaseSettings.Host,
- database: databaseSettings.Database,
- userId: databaseSettings.Username,
- password: databaseSettings.Password,
- port: databaseSettings.Port,
- sslMode: databaseSettings.Sslmode,
- logger: base.Logger);
-
//** ? Save Config */
this.Config = config;
@@ -97,7 +88,7 @@ public override void Unload(bool hotReload)
{
//** ? Save Player Caches */
- SaveAllPlayersCache();
+ Task.Run(SaveAllPlayersDataAsync);
//** ? Release Modules */
@@ -132,25 +123,49 @@ public async Task CreateMultipleTablesAsync()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
string statsModuleTable = $@"CREATE TABLE IF NOT EXISTS `{this.Config.DatabaseSettings.TablePrefix}k4stats` (
- `steam_id` VARCHAR(32) COLLATE 'utf8mb4_unicode_ci' UNIQUE NOT NULL,
- `name` VARCHAR(255) COLLATE 'utf8mb4_unicode_ci' NOT NULL,
- `lastseen` DATETIME NOT NULL,
- `kills` INT NOT NULL DEFAULT 0,
- `firstblood` INT NOT NULL DEFAULT 0,
- `deaths` INT NOT NULL DEFAULT 0,
- `assists` INT NOT NULL DEFAULT 0,
- `shoots` INT NOT NULL DEFAULT 0,
- `hits_taken` INT NOT NULL DEFAULT 0,
- `hits_given` INT NOT NULL DEFAULT 0,
- `headshots` INT NOT NULL DEFAULT 0,
- `grenades` INT NOT NULL DEFAULT 0,
- `mvp` INT NOT NULL DEFAULT 0,
- `round_win` INT NOT NULL DEFAULT 0,
- `round_lose` INT NOT NULL DEFAULT 0,
- `game_win` INT NOT NULL DEFAULT 0,
- `game_lose` INT NOT NULL DEFAULT 0,
- UNIQUE (`steam_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
+ `steam_id` VARCHAR(32) COLLATE 'utf8mb4_unicode_ci' UNIQUE NOT NULL,
+ `name` VARCHAR(255) COLLATE 'utf8mb4_unicode_ci' NOT NULL,
+ `lastseen` DATETIME NOT NULL,
+ `kills` INT NOT NULL DEFAULT 0,
+ `firstblood` INT NOT NULL DEFAULT 0,
+ `deaths` INT NOT NULL DEFAULT 0,
+ `assists` INT NOT NULL DEFAULT 0,
+ `shoots` INT NOT NULL DEFAULT 0,
+ `hits_taken` INT NOT NULL DEFAULT 0,
+ `hits_given` INT NOT NULL DEFAULT 0,
+ `headshots` INT NOT NULL DEFAULT 0,
+ `chest_hits` INT NOT NULL DEFAULT 0,
+ `stomach_hits` INT NOT NULL DEFAULT 0,
+ `left_arm_hits` INT NOT NULL DEFAULT 0,
+ `right_arm_hits` INT NOT NULL DEFAULT 0,
+ `left_leg_hits` INT NOT NULL DEFAULT 0,
+ `right_leg_hits` INT NOT NULL DEFAULT 0,
+ `neck_hits` INT NOT NULL DEFAULT 0,
+ `unused_hits` INT NOT NULL DEFAULT 0,
+ `gear_hits` INT NOT NULL DEFAULT 0,
+ `special_hits` INT NOT NULL DEFAULT 0,
+ `grenades` INT NOT NULL DEFAULT 0,
+ `mvp` INT NOT NULL DEFAULT 0,
+ `round_win` INT NOT NULL DEFAULT 0,
+ `round_lose` INT NOT NULL DEFAULT 0,
+ `game_win` INT NOT NULL DEFAULT 0,
+ `game_lose` INT NOT NULL DEFAULT 0,
+ `rounds_overall` INT NOT NULL DEFAULT 0,
+ `rounds_ct` INT NOT NULL DEFAULT 0,
+ `rounds_t` INT NOT NULL DEFAULT 0,
+ `bomb_planted` INT NOT NULL DEFAULT 0,
+ `bomb_defused` INT NOT NULL DEFAULT 0,
+ `hostage_rescued` INT NOT NULL DEFAULT 0,
+ `hostage_killed` INT NOT NULL DEFAULT 0,
+ `noscope_kill` INT NOT NULL DEFAULT 0,
+ `penetrated_kill` INT NOT NULL DEFAULT 0,
+ `thrusmoke_kill` INT NOT NULL DEFAULT 0,
+ `flashed_kill` INT NOT NULL DEFAULT 0,
+ `dominated_kill` INT NOT NULL DEFAULT 0,
+ `revenge_kill` INT NOT NULL DEFAULT 0,
+ `assist_flash` INT NOT NULL DEFAULT 0,
+ UNIQUE (`steam_id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
string ranksModuleTable = $@"CREATE TABLE IF NOT EXISTS `{this.Config.DatabaseSettings.TablePrefix}k4ranks` (
`steam_id` VARCHAR(32) COLLATE 'utf8mb4_unicode_ci' UNIQUE NOT NULL,
@@ -178,25 +193,26 @@ public async Task CreateMultipleTablesAsync()
`lastconnect` INT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
- await Database.Instance.ExecuteWithTransactionAsync(async (connection, transaction) =>
+ using (var connection = CreateConnection(Config))
{
- MySqlCommand? command1 = new MySqlCommand(timesModuleTable, connection, transaction);
- await command1.ExecuteNonQueryAsync();
+ await connection.OpenAsync();
- MySqlCommand? command2 = new MySqlCommand(statsModuleTable, connection, transaction);
- await command2.ExecuteNonQueryAsync();
+ using (var transaction = await connection.BeginTransactionAsync())
+ {
+ await connection.ExecuteAsync(timesModuleTable, transaction: transaction);
+ await connection.ExecuteAsync(statsModuleTable, transaction: transaction);
+ await connection.ExecuteAsync(ranksModuleTable, transaction: transaction);
- MySqlCommand? command3 = new MySqlCommand(ranksModuleTable, connection, transaction);
- await command3.ExecuteNonQueryAsync();
+ if (Config.GeneralSettings.LevelRanksCompatibility)
+ {
+ await connection.ExecuteAsync(lvlranksModuleTable, transaction: transaction);
+ }
- if (Config.GeneralSettings.LevelRanksCompatibility)
- {
- MySqlCommand? command4 = new MySqlCommand(lvlranksModuleTable, connection, transaction);
- await command4.ExecuteNonQueryAsync();
+ await transaction.CommitAsync();
}
- });
+ }
- await PurgeTableRows();
+ await PurgeTableRowsAsync();
return true;
}
}
diff --git a/K4-System/src/Plugin/PluginAPI.cs b/K4-System/src/Plugin/PluginAPI.cs
index 15ca47f..75e5655 100644
--- a/K4-System/src/Plugin/PluginAPI.cs
+++ b/K4-System/src/Plugin/PluginAPI.cs
@@ -1,61 +1,82 @@
namespace K4System
{
using K4SharedApi;
- using static K4System.ModuleRank;
-
- using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Capabilities;
- using CounterStrikeSharp.API.Modules.Commands;
- using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
public sealed partial class Plugin : BasePlugin
{
- public static PlayerCapability Capability_SharedAPI { get; } = new("k4-system:sharedapi");
+ public static PlayerCapability Capability_SharedPlayerAPI { get; } = new("k4-system:sharedapi-player");
public void Initialize_API()
{
- Capabilities.RegisterPlayerCapability(Capability_SharedAPI, player => new PlayerAPIHandler(player));
+ Capabilities.RegisterPlayerCapability(Capability_SharedPlayerAPI, player => new PlayerAPIHandler(player, this));
}
}
- public class PlayerAPIHandler : IK4SharedApi
+ public class PlayerAPIHandler : IPlayerAPI
{
- private readonly CCSPlayerController _player;
- private readonly PlayerCacheData? _playerCache;
-
- public PlayerAPIHandler(CCSPlayerController player)
+ private readonly K4Player? _player;
+ public PlayerAPIHandler(CCSPlayerController player, Plugin plugin)
{
- _player = player;
-
- if (PlayerCache.Instance.ContainsPlayer(_player))
- _playerCache = PlayerCache.Instance.GetPlayerData(_player);
+ _player = plugin.GetK4Player(player);
}
- public int PlayerPoints
+ public bool IsLoaded => _player is not null;
+ public bool IsValid => _player?.IsValid == true;
+ public bool IsPlayer => _player?.IsPlayer == true;
+ public CCSPlayerController Controller => _player?.Controller ?? throw new Exception("K4-SharedAPI > Controller > Player is not valid or is not a player.");
+
+ public int Points
{
- get => GetPlayerPoints();
+ get
+ {
+ if (_player is null || !_player.IsValid || !_player.IsPlayer || _player.rankData is null)
+ throw new Exception("K4-SharedAPI > Points (get) > Player is not valid or is not a player.");
+
+ return _player.rankData.Points;
+ }
+ set
+ {
+ if (_player is null || !_player.IsValid || !_player.IsPlayer || _player.rankData is null)
+ throw new Exception("K4-SharedAPI > Points (set) > Player is not valid or is not a player.");
+
+ _player.rankData.Points = value;
+ }
}
- public int PlayerRankID
+ public int RankID
{
- get => GetPlayerRankID();
+ get
+ {
+ if (_player is null || !_player.IsValid || !_player.IsPlayer || _player.rankData is null)
+ throw new Exception("K4-SharedAPI > RankID (get) > Player is not valid or is not a player.");
+
+ return _player.rankData.Rank.Id + 1;
+ }
}
- public int GetPlayerPoints()
+ public string RankName
{
- if (_playerCache?.rankData is null)
- return 0;
+ get
+ {
+ if (_player is null || !_player.IsValid || !_player.IsPlayer || _player.rankData is null)
+ throw new Exception("K4-SharedAPI > RankName (get) > Player is not valid or is not a player.");
- return _playerCache.rankData.Points;
+ return _player.rankData.Rank.Name;
+ }
}
- public int GetPlayerRankID()
+ public string RankClanTag
{
- if (_playerCache?.rankData is null)
- return 0;
+ get
+ {
+ if (_player is null || !_player.IsValid || !_player.IsPlayer || _player.rankData is null)
+ throw new Exception("K4-SharedAPI > RankClanTag (get) > Player is not valid or is not a player.");
- return _playerCache.rankData.Rank.Id + 1;
+ return _player.rankData.Rank.Tag ?? "";
+ }
}
}
}
\ No newline at end of file
diff --git a/K4-System/src/Plugin/PluginBasics.cs b/K4-System/src/Plugin/PluginBasics.cs
index 4018c50..726b0ba 100644
--- a/K4-System/src/Plugin/PluginBasics.cs
+++ b/K4-System/src/Plugin/PluginBasics.cs
@@ -4,8 +4,14 @@ namespace K4System
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
+ using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
+ using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Utils;
+ using K4System.Models;
+ using static K4System.ModuleRank;
+ using static K4System.ModuleStat;
+ using static K4System.ModuleTime;
public sealed partial class Plugin : BasePlugin
{
@@ -73,6 +79,13 @@ public void Initialize_Commands()
}
}
});
+
+ Config.CommandSettings.ResetMyCommands.ForEach(commandString =>
+ {
+ AddCommand($"css_{commandString}", "Resets the player's own points to zero", CallbackAnonymizer(OnCommandResetMyData));
+ });
+
+ AddCommand("css_resetdata", "Resets the targeted player's data to zero", CallbackAnonymizer(OnCommandResetData));
}
public void Initialize_Events()
@@ -81,39 +94,34 @@ public void Initialize_Events()
{
CCSPlayerController player = @event.Userid;
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid || player.IsBot || player.IsHLTV)
+ if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
return HookResult.Continue;
// Do not load the data, if the user is in the cache already
// This free up some resources and prevent plugin to load the same data twice
- if (PlayerCache.Instance.ContainsPlayer(player))
+ if (K4Players.Any(p => p.Controller == player))
return HookResult.Continue;
- LoadPlayerCache(player);
+ K4Player k4player = new K4Player(this, player);
+ Task.Run(() => LoadPlayerCacheAsync(k4player));
return HookResult.Continue;
});
RegisterEventHandler((EventPlayerDisconnect @event, GameEventInfo info) =>
{
- CCSPlayerController player = @event.Userid;
-
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- return HookResult.Continue;
-
- if (player.IsBot || player.IsHLTV)
- return HookResult.Continue;
+ K4Player? k4player = GetK4Player(@event.Userid);
- if (!PlayerCache.Instance.ContainsPlayer(player))
+ if (k4player is null || !k4player.IsValid || !k4player.IsPlayer)
return HookResult.Continue;
if (Config.GeneralSettings.ModuleTimes)
- ModuleTime.BeforeDisconnect(player);
+ ModuleTime.BeforeDisconnect(k4player);
// Do not save cache for each player on mapchange, because it's handled by an optimised query for all players
if (@event.Reason != 1)
{
- SavePlayerCache(player, true);
+ Task.Run(() => SavePlayerDataAsync(k4player, true));
}
return HookResult.Continue;
@@ -132,20 +140,15 @@ public void Initialize_Events()
lastRoundStartEventTime = DateTime.Now;
- List players = Utilities.GetPlayers();
-
- foreach (CCSPlayerController player in players)
+ foreach (K4Player k4Player in K4Players)
{
- if (player is null || !player.IsValid || !player.PlayerPawn.IsValid)
- continue;
-
- if (player.IsBot || player.IsHLTV)
+ if (!k4Player.IsValid || !k4Player.IsPlayer)
continue;
- if (player.SteamID.ToString().Length != 17)
+ if (k4Player.Controller.IsBot || k4Player.Controller.IsHLTV)
continue;
- player.PrintToChat($" {Localizer["k4.general.prefix"]} {ChatColors.Lime}{Localizer["k4.general.spawnmessage"]}");
+ k4Player.Controller.PrintToChat($" {Localizer["k4.general.prefix"]} {ChatColors.Lime}{Localizer["k4.general.spawnmessage"]}");
}
return HookResult.Continue;
@@ -159,8 +162,7 @@ public void Initialize_Events()
if (Config.GeneralSettings.ModuleRanks)
ModuleRank.BeforeRoundEnd(@event.Winner);
- SaveAllPlayersCache();
-
+ Task.Run(SaveAllPlayersDataAsync);
return HookResult.Continue;
}, HookMode.Post);
@@ -175,8 +177,162 @@ public void Initialize_Events()
RegisterListener(() =>
{
GameRules = null;
- Task.Run(PurgeTableRows).Wait();
+ Task.Run(PurgeTableRowsAsync);
});
}
+
+ public void OnCommandResetMyData(CCSPlayerController? player, CommandInfo info)
+ {
+ if (!CommandHelper(player, info, CommandUsage.CLIENT_ONLY, 1, "[all|time|stat|rank]"))
+ return;
+
+ string resetTarget = info.ArgByIndex(1);
+
+ if (resetTarget != "all" && resetTarget != "time" && resetTarget != "stat" && resetTarget != "rank")
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.commandhelp", info.ArgByIndex(0), "[all|time|stat|rank]"]}");
+ return;
+ }
+
+ K4Player? k4player = GetK4Player(player!);
+
+ if (k4player is null)
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.loading"]}");
+ return;
+ }
+
+ if (resetTarget == "all" || resetTarget == "time")
+ {
+ TimeData? playerData = k4player.timeData;
+
+ if (playerData is null)
+ return;
+
+ foreach (var field in playerData.TimeFields.Keys.ToList())
+ {
+ playerData.TimeFields[field] = 0;
+ }
+ }
+
+ if (resetTarget == "all" || resetTarget == "rank")
+ {
+ RankData? playerData = k4player.rankData;
+
+ if (playerData is null)
+ return;
+
+ playerData.RoundPoints -= playerData.Points;
+ playerData.Points = Config.RankSettings.StartPoints;
+ playerData.Rank = ModuleRank.GetNoneRank();
+ }
+
+ if (resetTarget == "all" || resetTarget == "stat")
+ {
+ StatData? playerData = k4player.statData;
+
+ if (playerData is null)
+ return;
+
+ foreach (var field in playerData.StatFields.Keys.ToList())
+ {
+ playerData.StatFields[field] = 0;
+ }
+ }
+
+ Server.PrintToChatAll($" {Localizer["k4.general.prefix"]} {Localizer["k4.ranks.resetmydata", player!.PlayerName]}");
+
+ Task.Run(() => SavePlayerDataAsync(k4player, false));
+ }
+
+ public void OnCommandResetData(CCSPlayerController? player, CommandInfo info)
+ {
+ if (!CommandHelper(player, info, CommandUsage.CLIENT_AND_SERVER, 2, " [all|time|stat|rank]", "@k4system/admin"))
+ return;
+
+ string resetTarget = info.ArgByIndex(1);
+
+ if (resetTarget != "all" && resetTarget != "time" && resetTarget != "stat" && resetTarget != "rank")
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.commandhelp", info.ArgByIndex(0), " [all|time|stat|rank]"]}");
+ return;
+ }
+
+ string playerName = player != null && player.IsValid && player.PlayerPawn.Value != null ? player.PlayerName : "SERVER";
+
+ TargetResult targetResult = info.GetArgTargetResult(1);
+
+ if (!targetResult.Any())
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.targetnotfound"]}");
+ return;
+ }
+
+ foreach (CCSPlayerController target in targetResult.Players)
+ {
+ K4Player? k4player = GetK4Player(target);
+
+ if (k4player is null || !k4player.IsValid)
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.targetloading", target.PlayerName]}");
+ continue;
+ }
+
+ if (!k4player.IsPlayer)
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.targetnobot", target.PlayerName]}");
+ continue;
+ }
+
+ if (!AdminManager.CanPlayerTarget(player, target))
+ {
+ info.ReplyToCommand($" {Localizer["k4.general.prefix"]} {Localizer["k4.general.targetimmunity", target.PlayerName]}");
+ continue;
+ }
+
+ if (resetTarget == "all" || resetTarget == "time")
+ {
+ TimeData? playerData = k4player.timeData;
+
+ if (playerData is null)
+ return;
+
+ foreach (var field in playerData.TimeFields.Keys.ToList())
+ {
+ playerData.TimeFields[field] = 0;
+ }
+ }
+
+ if (resetTarget == "all" || resetTarget == "rank")
+ {
+ RankData? playerData = k4player.rankData;
+
+ if (playerData is null)
+ return;
+
+ playerData.RoundPoints -= playerData.Points;
+ playerData.Points = Config.RankSettings.StartPoints;
+ playerData.Rank = ModuleRank.GetNoneRank();
+ }
+
+ if (resetTarget == "all" || resetTarget == "stat")
+ {
+ StatData? playerData = k4player.statData;
+
+ if (playerData is null)
+ return;
+
+ foreach (var field in playerData.StatFields.Keys.ToList())
+ {
+ playerData.StatFields[field] = 0;
+ }
+ }
+
+ if (playerName != "SERVER")
+ Server.PrintToChatAll($" {Localizer["k4.general.prefix"]} {Localizer["k4.ranks.resetdata", target.PlayerName, playerName]}");
+
+ Task.Run(() => SavePlayerDataAsync(k4player, false));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/K4-System/src/Plugin/PluginCache.cs b/K4-System/src/Plugin/PluginCache.cs
deleted file mode 100644
index 88f7465..0000000
--- a/K4-System/src/Plugin/PluginCache.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-
-namespace K4System
-{
- using CounterStrikeSharp.API.Core;
-
- using static K4System.ModuleRank;
- using static K4System.ModuleStat;
- using static K4System.ModuleTime;
-
- public class PlayerCacheData
- {
- public RankData? rankData { get; set; }
- public StatData? statData { get; set; }
- public TimeData? timeData { get; set; }
- }
-
- public class PlayerCache
- {
- private static readonly Lazy lazy = new Lazy(() => new PlayerCache());
- public static PlayerCache Instance => lazy.Value;
-
- private Dictionary cache = new Dictionary();
-
- private PlayerCache() { }
-
- public Dictionary Cache
- {
- get { return cache; }
- }
-
- private bool IsValidPlayer(CCSPlayerController player)
- {
- return player is { IsValid: true, IsHLTV: false, IsBot: false, UserId: not null };
- }
-
- public bool ContainsPlayer(CCSPlayerController player)
- {
- if (IsValidPlayer(player))
- {
- return ContainsPlayer(player.SteamID);
- }
- else
- throw new ArgumentException("The player is invalid");
- }
-
- public bool ContainsPlayer(ulong steamID)
- {
- if (steamID.ToString().Length != 17)
- return false;
-
- return cache.ContainsKey(steamID);
- }
-
- public PlayerCacheData GetPlayerData(CCSPlayerController player)
- {
- if (IsValidPlayer(player))
- {
- return GetPlayerData(player.SteamID);
- }
- else
- throw new ArgumentException("The player is invalid");
- }
-
- public PlayerCacheData GetPlayerData(ulong steamID)
- {
- if (steamID.ToString().Length != 17)
- throw new ArgumentException("The player is invalid");
-
- return cache[steamID];
- }
-
- public void AddOrUpdatePlayer(CCSPlayerController player, PlayerCacheData data)
- {
- if (IsValidPlayer(player))
- {
- AddOrUpdatePlayer(player.SteamID, data);
- }
- else
- throw new ArgumentException("The player is invalid");
- }
-
- public void AddOrUpdatePlayer(ulong steamID, PlayerCacheData data)
- {
- if (steamID.ToString().Length != 17)
- return;
-
- cache[steamID] = data;
- }
-
- public bool RemovePlayer(CCSPlayerController player)
- {
- if (IsValidPlayer(player))
- {
- return RemovePlayer(player.SteamID);
- }
- else
- throw new ArgumentException("The player is invalid");
- }
-
- public bool RemovePlayer(ulong steamID)
- {
- if (steamID.ToString().Length != 17)
- return false;
-
- return cache.Remove(steamID);
- }
- }
-}
\ No newline at end of file
diff --git a/K4-System/src/Plugin/PluginConfig.cs b/K4-System/src/Plugin/PluginConfig.cs
index 02a72d2..778ca57 100644
--- a/K4-System/src/Plugin/PluginConfig.cs
+++ b/K4-System/src/Plugin/PluginConfig.cs
@@ -81,7 +81,7 @@ public sealed class CommandSettings
[JsonPropertyName("resetmyrank-commands")]
public List ResetMyCommands { get; set; } = new List
{
- "resetmyrank"
+ "resetmydata"
};
[JsonPropertyName("ranks-commands")]
diff --git a/K4-System/src/Plugin/PluginDatabase.cs b/K4-System/src/Plugin/PluginDatabase.cs
index 5be6eb2..bda26fe 100644
--- a/K4-System/src/Plugin/PluginDatabase.cs
+++ b/K4-System/src/Plugin/PluginDatabase.cs
@@ -1,148 +1,499 @@
using System.Data;
+using CounterStrikeSharp.API;
+using CounterStrikeSharp.API.Core;
+using Dapper;
+using K4System.Models;
using Microsoft.Extensions.Logging;
using MySqlConnector;
+using static K4System.ModuleRank;
+using static K4System.ModuleStat;
+using static K4System.ModuleTime;
-namespace K4System
+namespace K4System;
+
+public sealed partial class Plugin : BasePlugin
{
- public sealed class Database
+ public MySqlConnection CreateConnection(PluginConfig config)
{
- private ILogger? _Logger;
- private static readonly Lazy instance = new Lazy(() => new Database());
- public static Database Instance => instance.Value;
-
- private string? connectionString;
- private Database() { }
+ DatabaseSettings _settings = config.DatabaseSettings;
- public void Initialize(ILogger logger, string server, string database, string userId, string password, int port = 3306, string sslMode = "None")
+ MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder
{
- _Logger = logger;
- connectionString = BuildConnectionString(server, database, userId, password, port, sslMode);
- }
+ Server = _settings.Host,
+ UserID = _settings.Username,
+ Password = _settings.Password,
+ Database = _settings.Database,
+ Port = (uint)_settings.Port,
+ SslMode = Enum.Parse(_settings.Sslmode, true),
+ };
+
+ return new MySqlConnection(builder.ToString());
+ }
- private static string BuildConnectionString(string server, string database, string userId, string password, int port, string sslMode)
+ public async Task PurgeTableRowsAsync()
+ {
+ if (Config.GeneralSettings.TablePurgeDays <= 0)
+ return;
+
+ using (var connection = CreateConnection(Config))
{
- MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder
+ await connection.OpenAsync();
+
+ var parameters = new DynamicParameters();
+ parameters.Add("@days", Config.GeneralSettings.TablePurgeDays);
+
+ string query = $@"
+ DELETE FROM `{Config.DatabaseSettings.TablePrefix}k4times` WHERE `lastseen` < NOW() - INTERVAL @days DAY AND `lastseen` != '0000-00-00';
+ DELETE FROM `{Config.DatabaseSettings.TablePrefix}k4stats` WHERE `lastseen` < NOW() - INTERVAL @days DAY AND `lastseen` != '0000-00-00';
+ DELETE FROM `{Config.DatabaseSettings.TablePrefix}k4ranks` WHERE `lastseen` < NOW() - INTERVAL @days DAY AND `lastseen` != '0000-00-00';
+ ";
+
+ if (Config.GeneralSettings.LevelRanksCompatibility)
{
- Server = server,
- Database = database,
- UserID = userId,
- Password = password,
- Port = (uint)port,
- SslMode = Enum.Parse(sslMode, true),
- // daffyy's solution to prevent crash from pooling runs out with default values
- Pooling = true,
- MinimumPoolSize = 0,
- MaximumPoolSize = 640,
- ConnectionIdleTimeout = 30
- };
+ query += $@"
+ DELETE FROM `{Config.DatabaseSettings.LvLRanksTableName}` WHERE `lastconnect` < UNIX_TIMESTAMP(NOW() - INTERVAL @days DAY);
+ ";
+ }
- return builder.ConnectionString;
+ await connection.ExecuteAsync(query, parameters);
}
+ }
- public async Task ExecuteNonQueryAsync(string query, params MySqlParameter[] parameters)
+ public async Task SaveAllPlayersDataAsync()
+ {
+ using (var connection = CreateConnection(Config))
{
- try
+ await connection.OpenAsync();
+
+ using (var transaction = await connection.BeginTransactionAsync())
{
- using (MySqlConnection connection = new MySqlConnection(connectionString))
+ foreach (K4Player k4player in K4Players)
{
- await connection.OpenAsync();
- using (MySqlCommand command = new MySqlCommand(query, connection))
+ try
+ {
+ if (k4player.rankData != null)
+ await ExecuteRankUpdateAsync(transaction, k4player);
+
+ if (k4player.statData != null)
+ await ExecuteStatUpdateAsync(transaction, k4player);
+
+ if (k4player.timeData != null)
+ await ExecuteTimeUpdateAsync(transaction, k4player);
+
+ if (Config.GeneralSettings.LevelRanksCompatibility)
+ await ExecuteLvlRanksUpdateAsync(transaction, k4player);
+
+ await transaction.CommitAsync();
+ }
+ catch (Exception)
{
- command.Parameters.AddRange(parameters);
- await command.ExecuteNonQueryAsync();
+ await transaction.RollbackAsync();
+ throw;
}
}
}
- catch (Exception ex)
+ }
+ }
+
+ public async Task SavePlayerDataAsync(K4Player k4player, bool remove)
+ {
+ using (var connection = CreateConnection(Config))
+ {
+ await connection.OpenAsync();
+
+ using (var transaction = await connection.BeginTransactionAsync())
{
- string errorMessage = $"An error occurred while executing SQL query: {query}. Error message: {ex.Message}";
- _Logger?.LogError(ex, errorMessage);
- throw;
+ try
+ {
+ if (k4player.rankData != null)
+ await ExecuteRankUpdateAsync(transaction, k4player);
+
+ if (k4player.statData != null)
+ await ExecuteStatUpdateAsync(transaction, k4player);
+
+ if (k4player.timeData != null)
+ await ExecuteTimeUpdateAsync(transaction, k4player);
+
+ if (Config.GeneralSettings.LevelRanksCompatibility)
+ await ExecuteLvlRanksUpdateAsync(transaction, k4player);
+
+ await transaction.CommitAsync();
+ }
+ catch (Exception)
+ {
+ await transaction.RollbackAsync();
+ throw;
+ }
}
}
+ if (remove)
+ K4Players.Remove(k4player);
+ }
+
+ private async Task ExecuteLvlRanksUpdateAsync(MySqlTransaction transaction, K4Player k4player)
+ {
+ if (transaction.Connection == null)
+ throw new InvalidOperationException("The transaction's connection is null.");
+
+ string query = $@"INSERT INTO `{Config.DatabaseSettings.LvLRanksTableName}`
+ (`steam`, `name`, `kills`, `deaths`, `shoots`, `hits`, `headshots`, `assists`, `round_win`, `round_lose`, `lastconnect`, `value`, `rank`, `playtime`)
+ VALUES
+ (@SteamId, @PlayerName, @Kills, @Deaths, @Shoots, @Hits, @Headshots, @Assists, @RoundWin, @RoundLose, UNIX_TIMESTAMP(), @Points, @Rank, @Playtime)
+ ON DUPLICATE KEY UPDATE
+ `name` = @PlayerName,
+ `kills` = @Kills,
+ `deaths` = @Deaths,
+ `shoots` = @Shoots,
+ `hits` = @Hits,
+ `headshots` = @Headshots,
+ `assists` = @Assists,
+ `round_win` = @RoundWin,
+ `round_lose` = @RoundLose,
+ `lastconnect` = UNIX_TIMESTAMP(),
+ `value` = @Points,
+ `rank` = @Rank,
+ `playtime` = @Playtime;";
+
+ var parameters = new
+ {
+ SteamId = k4player.SteamID.ToString().Replace("STEAM_0", "STEAM_1"),
+ k4player.PlayerName,
+ Kills = k4player.statData?.StatFields["kills"] ?? 0,
+ Deaths = k4player.statData?.StatFields["deaths"] ?? 0,
+ Shoots = k4player.statData?.StatFields["shoots"] ?? 0,
+ Hits = k4player.statData?.StatFields["hits_given"] ?? 0,
+ Headshots = k4player.statData?.StatFields["headshots"] ?? 0,
+ Assists = k4player.statData?.StatFields["assists"] ?? 0,
+ RoundWin = k4player.statData?.StatFields["round_win"] ?? 0,
+ RoundLose = k4player.statData?.StatFields["round_lose"] ?? 0,
+ Points = k4player.rankData?.Points ?? 0,
+ Rank = k4player.rankData?.Rank?.Id ?? -1,
+ Playtime = k4player.timeData?.TimeFields["all"] ?? 0
+ };
+
+ await transaction.Connection.ExecuteAsync(query, parameters, transaction);
+ }
+
+ private async Task ExecuteRankUpdateAsync(MySqlTransaction transaction, K4Player k4player)
+ {
+ if (transaction.Connection == null)
+ throw new InvalidOperationException("The transaction's connection is null.");
+
+ string query = $@"INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4ranks` (`name`, `steam_id`, `rank`, `points`, `lastseen`)
+ VALUES (@PlayerName, @SteamId, @Rank, @Points, CURRENT_TIMESTAMP)
+ ON DUPLICATE KEY UPDATE `name` = @PlayerName, `points` = @Points, `lastseen` = CURRENT_TIMESTAMP, `rank` = @Rank;";
+
+ var parameters = new
+ {
+ k4player.PlayerName,
+ SteamId = k4player.SteamID,
+ Rank = k4player.rankData!.Rank.Name,
+ k4player.rankData.Points
+ };
+
+ await transaction.Connection.ExecuteAsync(query, parameters, transaction);
+ }
+
+ private async Task ExecuteStatUpdateAsync(MySqlTransaction transaction, K4Player k4player)
+ {
+ if (transaction.Connection == null)
+ throw new InvalidOperationException("The transaction's connection is null.");
+
+ string fieldsForInsert = string.Join(", ", k4player.statData!.StatFields.Select(f => $"`{f.Key}`"));
+ string valuesForInsert = string.Join(", ", k4player.statData.StatFields.Keys.Select(f => $"@{f}"));
+ string onDuplicateKeyUpdate = string.Join(", ", k4player.statData.StatFields.Select(f => $"`{f.Key}` = @{f.Key}"));
+
+ string query = $@"INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4stats` (`name`, `steam_id`, `lastseen`, {fieldsForInsert})
+ VALUES (@PlayerName, @SteamId, CURRENT_TIMESTAMP, {valuesForInsert})
+ ON DUPLICATE KEY UPDATE `name` = @PlayerName, `lastseen` = CURRENT_TIMESTAMP, {onDuplicateKeyUpdate};";
+
+ var dynamicParameters = new DynamicParameters();
+ dynamicParameters.Add("@PlayerName", k4player.PlayerName);
+ dynamicParameters.Add("@SteamId", k4player.SteamID);
+ foreach (var field in k4player.statData.StatFields)
+ {
+ dynamicParameters.Add($"@{field.Key}", field.Value);
+ }
+
+ await transaction.Connection.ExecuteAsync(query, dynamicParameters, transaction);
+ }
+
+
+ private async Task ExecuteTimeUpdateAsync(MySqlTransaction transaction, K4Player k4player)
+ {
+ if (transaction.Connection == null)
+ throw new InvalidOperationException("The transaction's connection is null.");
+
+ string fieldsForInsert = string.Join(", ", k4player.timeData!.TimeFields.Select(f => $"`{f.Key}`"));
+ string valuesForInsert = string.Join(", ", k4player.timeData.TimeFields.Select(f => $"@{f.Key}"));
+ string onDuplicateKeyUpdate = string.Join(", ", k4player.timeData.TimeFields.Select(f => $"`{f.Key}` = @{f.Key}"));
+
+ string query = $@"INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4times` (`name`, `steam_id`, `lastseen`, {fieldsForInsert})
+ VALUES (@PlayerName, @SteamId, CURRENT_TIMESTAMP, {valuesForInsert})
+ ON DUPLICATE KEY UPDATE `name` = @PlayerName, `lastseen` = CURRENT_TIMESTAMP, {onDuplicateKeyUpdate};";
+
+ var dynamicParameters = new DynamicParameters();
+ dynamicParameters.Add("@PlayerName", k4player.PlayerName);
+ dynamicParameters.Add("@SteamId", k4player.SteamID);
+ foreach (var field in k4player.timeData.TimeFields)
+ {
+ dynamicParameters.Add($"@{field.Key}", field.Value);
+ }
+
+ await transaction.Connection.ExecuteAsync(query, dynamicParameters, transaction);
+ }
+
+ public async Task LoadPlayerCacheAsync(K4Player k4player)
+ {
+ string combinedQuery = $@"
+ INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4ranks` (`name`, `steam_id`, `rank`, `points`, `lastseen`)
+ VALUES (
+ @escapedName,
+ @steamid,
+ @noneRankName,
+ @startPoints,
+ CURRENT_TIMESTAMP
+ )
+ ON DUPLICATE KEY UPDATE
+ `name` = @escapedName,
+ `lastseen` = CURRENT_TIMESTAMP;
+
+ INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4stats` (`name`, `steam_id`, `lastseen`, `kills`, `firstblood`, `deaths`, `assists`, `shoots`, `hits_taken`, `hits_given`, `headshots`, `grenades`, `mvp`, `round_win`, `round_lose`, `game_win`, `game_lose`, `rounds_overall`, `rounds_ct`, `rounds_t`, `bomb_planted`, `bomb_defused`, `hostage_rescued`, `hostage_killed`)
+ VALUES (
+ @escapedName,
+ @steamid,
+ CURRENT_TIMESTAMP,
+ )
+ ON DUPLICATE KEY UPDATE
+ `name` = @escapedName,
+ `lastseen` = CURRENT_TIMESTAMP;
+
+ INSERT INTO `{Config.DatabaseSettings.TablePrefix}k4times` (`name`, `steam_id`, `lastseen`)
+ VALUES (
+ @escapedName,
+ @steamid,
+ CURRENT_TIMESTAMP
+ )
+ ON DUPLICATE KEY UPDATE
+ `name` = @escapedName,
+ `lastseen` = CURRENT_TIMESTAMP;
+
+ SELECT
+ r.`points`,
+ s.`kills`,
+ s.`firstblood`,
+ s.`deaths`,
+ s.`assists`,
+ s.`shoots`,
+ s.`hits_taken`,
+ s.`hits_given`,
+ s.`headshots`,
+ s.`grenades`,
+ s.`mvp`,
+ s.`round_win`,
+ s.`round_lose`,
+ s.`game_win`,
+ s.`game_lose`,
+ s.`rounds_overall`,
+ s.`rounds_ct`,
+ s.`rounds_t`,
+ s.`bomb_planted`,
+ s.`bomb_defused`,
+ s.`hostage_rescued`,
+ s.`hostage_killed`,
+ t.`all`,
+ t.`ct`,
+ t.`t`,
+ t.`spec`,
+ t.`alive`,
+ t.`dead`
+ FROM
+ `{Config.DatabaseSettings.TablePrefix}k4ranks` AS r
+ LEFT JOIN
+ `{Config.DatabaseSettings.TablePrefix}k4stats` AS s ON r.`steam_id` = s.`steam_id`
+ LEFT JOIN
+ `{Config.DatabaseSettings.TablePrefix}k4times` AS t ON r.`steam_id` = t.`steam_id`
+ WHERE
+ r.`steam_id` = @steamid;
+ ";
+
+ MySqlParameter[] parameters =
+ [
+ new MySqlParameter("@escapedName", k4player.PlayerName),
+ new MySqlParameter("@steamid", k4player.SteamID),
+ new MySqlParameter("@noneRankName", ModuleRank.GetNoneRank()?.Name ?? "none"),
+ new MySqlParameter("@startPoints", Config.RankSettings.StartPoints)
+ ];
- public async Task