From 26a31d4bd76245d29308c2c8c0cafe6d8158b91d Mon Sep 17 00:00:00 2001 From: Dawid Bepierszcz <41084667+daffyyyy@users.noreply.github.com> Date: Wed, 12 Jun 2024 09:52:01 +0200 Subject: [PATCH] New, new, new! - Config changed - Multiple commands (as i remember, wp command fucked now) - Fixed tables - Remove expired users - CenterHtmlMenu - experimental - Knife from string to defindex --- Commands.cs | 315 +++++++++++++++++++++------------------ Config.cs | 82 +++++----- Database.cs | 4 +- Events.cs | 3 + Utility.cs | 8 +- WeaponAction.cs | 16 +- WeaponPaints.cs | 28 ++-- WeaponSynchronization.cs | 104 ++++++++++--- website/class/header.php | 10 +- 9 files changed, 332 insertions(+), 238 deletions(-) diff --git a/Commands.cs b/Commands.cs index 74930422..ddc2c6e9 100644 --- a/Commands.cs +++ b/Commands.cs @@ -1,4 +1,5 @@ -using CounterStrikeSharp.API; +using System.Collections.Concurrent; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Menu; @@ -10,17 +11,17 @@ namespace WeaponPaints { private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command) { - if (!Config.Additional.CommandWpEnabled || !Config.Additional.SkinEnabled || !g_bCommandsAllowed) return; + if (Config.Additional.CommandsRefresh.Count > 0 || !Config.Additional.SkinEnabled || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player)) return; if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return; - PlayerInfo? playerInfo = new PlayerInfo + PlayerInfo playerInfo = new PlayerInfo { UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player?.SteamID.ToString(), + SteamId = player.SteamID, Name = player?.PlayerName, IpAddress = player?.IpAddress?.Split(":")[0] }; @@ -95,25 +96,33 @@ namespace WeaponPaints private void RegisterCommands() { - AddCommand($"css_{Config.Additional.CommandSkin}", "Skins info", (player, info) => + Config.Additional.CommandsInfo.ForEach(c => { - if (!Utility.IsPlayerValid(player)) return; - OnCommandWS(player, info); + AddCommand($"css_{c}", "Skins info", (player, info) => + { + if (!Utility.IsPlayerValid(player)) return; + OnCommandWS(player, info); + }); }); - AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) => + + Config.Additional.CommandsRefresh.ForEach(c => { - if (!Utility.IsPlayerValid(player)) return; - OnCommandRefresh(player, info); - }); - if (Config.Additional.CommandKillEnabled) + AddCommand($"css_{c}", "Skins refresh", (player, info) => + { + if (!Utility.IsPlayerValid(player)) return; + OnCommandRefresh(player, info); + }); + }); + + Config.Additional.CommandsKill.ForEach(c => { - AddCommand($"css_{Config.Additional.CommandKill}", "kill yourself", (player, info) => + AddCommand($"css_{c}", "kill yourself", (player, info) => { if (player == null || !Utility.IsPlayerValid(player) || player.PlayerPawn.Value == null || !player!.PlayerPawn.IsValid) return; player.PlayerPawn.Value.CommitSuicide(true, false); }); - } + }); } private void SetupKnifeMenu() @@ -124,7 +133,8 @@ namespace WeaponPaints .Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")) .ToDictionary(pair => pair.Key, pair => pair.Value); - var giveItemMenu = new ChatMenu(Localizer["wp_knife_menu_title"]); + BaseMenu giveItemMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_knife_menu_title"], Instance) : new ChatMenu(Localizer["wp_knife_menu_title"]); + var handleGive = (CCSPlayerController player, ChatMenuOption option) => { if (!Utility.IsPlayerValid(player)) return; @@ -137,7 +147,7 @@ namespace WeaponPaints player!.Print(Localizer["wp_knife_menu_select", knifeName]); } - if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled) + if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandsKill.Count > 0) { player!.Print(Localizer["wp_knife_menu_kill"]); } @@ -147,48 +157,59 @@ namespace WeaponPaints UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player.SteamID.ToString(), + SteamId = player.SteamID, Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; + + var knife = WeaponDefindex + .FirstOrDefault(entry => entry.Value.Equals(knifeKey, StringComparison.OrdinalIgnoreCase)) + .Key; - g_playersKnife[player.Slot] = knifeKey; + g_playersKnife[player.Slot] = (ushort)knife; if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE) RefreshWeapons(player); - if (weaponSync != null) - _ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, knifeKey)); + if (weaponSync == null) return; + + _ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, (ushort)knife)); }; + foreach (var knifePair in knivesOnly) { giveItemMenu.AddMenuOption(knifePair.Value, handleGive); } - AddCommand($"css_{Config.Additional.CommandKnife}", "Knife Menu", (player, info) => + + Config.Additional.CommandsKnife.ForEach(c => { - if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; - - if (player == null || player.UserId == null) return; - - if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || - DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + AddCommand($"css_{c}", "Knife Menu", (player, info) => { - commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); - giveItemMenu.PostSelectAction = PostSelectAction.Close; - MenuManager.OpenChatMenu(player, giveItemMenu); - return; - } - if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) - { - player!.Print(Localizer["wp_command_cooldown"]); - } + if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; + + if (player == null || player.UserId == null) return; + + if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || + DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + { + commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); + giveItemMenu.PostSelectAction = PostSelectAction.Close; + giveItemMenu.Open(player); + //MenuManager.open(player, giveItemMenu); + return; + } + if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) + { + player!.Print(Localizer["wp_command_cooldown"]); + } + }); }); } private void SetupSkinsMenu() { var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key); - var weaponSelectionMenu = new ChatMenu(Localizer["wp_skin_menu_weapon_title"]); + BaseMenu weaponSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_weapon_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_weapon_title"]); // Function to handle skin selection for a specific weapon var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) => @@ -202,7 +223,7 @@ namespace WeaponPaints weaponName?.ToString() == selectedWeaponClassname )?.ToList(); - var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]); + BaseMenu skinSubMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_skin_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_skin_title"]); // Function to handle skin selection for the chosen weapon var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) => @@ -256,7 +277,7 @@ namespace WeaponPaints UserId = p.UserId, Slot = p.Slot, Index = (int)p.Index, - SteamId = p.SteamID.ToString(), + SteamId = p.SteamID, Name = p.PlayerName, IpAddress = p.IpAddress?.Split(":")[0] }; @@ -293,7 +314,7 @@ namespace WeaponPaints } } if (player != null && Utility.IsPlayerValid(player)) - MenuManager.OpenChatMenu(player, skinSubMenu); + skinSubMenu.Open(player); }; // Add weapon options to the weapon selection menu @@ -302,32 +323,32 @@ namespace WeaponPaints weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection); } // Command to open the weapon selection menu for players - AddCommand($"css_{Config.Additional.CommandSkinSelection}", "Skins selection menu", (player, info) => + Config.Additional.CommandsSkinSelection.ForEach(c => + { + AddCommand($"css_{c}", "Skins selection menu", (player, info) => + { + if (!Utility.IsPlayerValid(player)) return; + + if (player == null || player.UserId == null) return; + + if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || + DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) { - if (!Utility.IsPlayerValid(player)) return; - - if (player == null || player.UserId == null) return; - - if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || - DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) - { - commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); - MenuManager.OpenChatMenu(player, weaponSelectionMenu); - return; - } - if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) - { - player!.Print(Localizer["wp_command_cooldown"]); - } - }); + commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); + weaponSelectionMenu.Open(player); + return; + } + if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) + { + player!.Print(Localizer["wp_command_cooldown"]); + } + }); + }); } private void SetupGlovesMenu() { - var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]) - { - PostSelectAction = PostSelectAction.Close - }; + BaseMenu glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]); var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) => { @@ -353,7 +374,7 @@ namespace WeaponPaints UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player.SteamID.ToString(), + SteamId = player.SteamID, Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; @@ -361,14 +382,21 @@ namespace WeaponPaints if (paint != 0) { g_playersGlove[player.Slot] = (ushort)weaponDefindex; + + if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out var value)) + { + value = new ConcurrentDictionary(); + + gPlayerWeaponsInfo[player.Slot] = value; + } - if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex)) + if (!value.ContainsKey((ushort)weaponDefindex)) { WeaponInfo weaponInfo = new() { - Paint = paint + Paint = (ushort)paint }; - gPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo; + value[(ushort)weaponDefindex] = weaponInfo; } } else @@ -387,13 +415,13 @@ namespace WeaponPaints { await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex); - if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out var value)) + if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue((ushort)weaponDefindex, out var value)) { value = new WeaponInfo(); - gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value; + gPlayerWeaponsInfo[playerInfo.Slot][(ushort)weaponDefindex] = value; } - value.Paint = paint; + value.Paint = (ushort)paint; value.Wear = 0.00f; value.Seed = 0; @@ -411,24 +439,27 @@ namespace WeaponPaints } // Command to open the weapon selection menu for players - AddCommand($"css_{Config.Additional.CommandGlove}", "Gloves selection menu", (player, info) => - { - if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; + Config.Additional.CommandsGlove.ForEach(c => + { + AddCommand($"css_{c}", "Gloves selection menu", (player, info) => + { + if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; - if (player == null || player.UserId == null) return; + if (player == null || player.UserId == null) return; - if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || - DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) - { - commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); - MenuManager.OpenChatMenu(player, glovesSelectionMenu); - return; - } - if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) - { - player!.Print(Localizer["wp_command_cooldown"]); - } - }); + if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || + DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + { + commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); + glovesSelectionMenu.Open(player); + return; + } + if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) + { + player!.Print(Localizer["wp_command_cooldown"]); + } + }); + }); } private void SetupAgentsMenu() @@ -454,7 +485,7 @@ namespace WeaponPaints UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player.SteamID.ToString(), + SteamId = player.SteamID, Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; @@ -496,59 +527,56 @@ namespace WeaponPaints }; // Command to open the weapon selection menu for players - AddCommand($"css_{Config.Additional.CommandAgent}", "Agents selection menu", (player, info) => + Config.Additional.CommandsAgent.ForEach(c => { - if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; - - if (player == null || player.UserId == null) return; - - if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || - DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + AddCommand($"css_{c}", "Agents selection menu", (player, info) => { - var agentsSelectionMenu = new ChatMenu(Localizer["wp_agent_menu_title"]) - { - PostSelectAction = PostSelectAction.Close - }; + if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; - var filteredAgents = agentsList.Where(agentObject => + if (player == null || player.UserId == null) return; + + if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || + DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) { - if (agentObject["team"]?.Value() is { } teamNum) + BaseMenu agentsSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_agent_menu_title"], Instance) : new ChatMenu(Localizer["wp_agent_menu_title"]); + + var filteredAgents = agentsList.Where(agentObject => { - return teamNum == player.TeamNum; - } - else + if (agentObject["team"]?.Value() is { } teamNum) + { + return teamNum == player.TeamNum; + } + else + { + return false; + } + }); + + // Add weapon options to the weapon selection menu + + foreach (var agentObject in filteredAgents) { - return false; + var paintName = agentObject["agent_name"]?.ToString() ?? ""; + + if (paintName.Length > 0) + agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection); } - }); - // Add weapon options to the weapon selection menu - - foreach (var agentObject in filteredAgents) - { - var paintName = agentObject["agent_name"]?.ToString() ?? ""; - - if (paintName.Length > 0) - agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection); + commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); + agentsSelectionMenu.Open(player); + return; } - - commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); - MenuManager.OpenChatMenu(player, agentsSelectionMenu); - return; - } - if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) - { - player!.Print(Localizer["wp_command_cooldown"]); - } + if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) + { + player!.Print(Localizer["wp_command_cooldown"]); + } + }); }); } private void SetupMusicMenu() { - var musicSelectionMenu = new ChatMenu(Localizer["wp_music_menu_title"]) - { - PostSelectAction = PostSelectAction.Close - }; + BaseMenu musicSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_music_menu_title"], Instance) : new ChatMenu(Localizer["wp_music_menu_title"]); var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) => { @@ -574,7 +602,7 @@ namespace WeaponPaints UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player.SteamID.ToString(), + SteamId = player.SteamID, Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; @@ -610,7 +638,7 @@ namespace WeaponPaints UserId = player.UserId, Slot = player.Slot, Index = (int)player.Index, - SteamId = player.SteamID.ToString(), + SteamId = player.SteamID, Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; @@ -639,24 +667,27 @@ namespace WeaponPaints musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection); } - // Command to open the weapon selection menu for players - AddCommand($"css_{Config.Additional.CommandMusic}", "Music selection menu", (player, info) => + Config.Additional.CommandsMusic.ForEach(c => { - if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; - - if (player == null || player.UserId == null) return; - - if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || - DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + // Command to open the weapon selection menu for players + AddCommand($"css_{c}", "Music selection menu", (player, info) => { - commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); - MenuManager.OpenChatMenu(player, musicSelectionMenu); - return; - } - if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) - { - player!.Print(Localizer["wp_command_cooldown"]); - } + if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; + + if (player == null || player.UserId == null) return; + + if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || + DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) + { + commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); + musicSelectionMenu.Open(player); + return; + } + if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) + { + player!.Print(Localizer["wp_command_cooldown"]); + } + }); }); } } diff --git a/Config.cs b/Config.cs index 929760b0..60801e50 100644 --- a/Config.cs +++ b/Config.cs @@ -3,6 +3,24 @@ using System.Text.Json.Serialization; namespace WeaponPaints { + public class DatabaseCredentials + { + [JsonPropertyName("DatabaseHost")] + public string DatabaseHost { get; set; } = ""; + + [JsonPropertyName("DatabasePort")] + public int DatabasePort { get; set; } = 3306; + + [JsonPropertyName("DatabaseUser")] + public string DatabaseUser { get; set; } = ""; + + [JsonPropertyName("DatabasePassword")] + public string DatabasePassword { get; set; } = ""; + + [JsonPropertyName("DatabaseName")] + public string DatabaseName { get; set; } = ""; + } + public class Additional { [JsonPropertyName("KnifeEnabled")] @@ -23,35 +41,29 @@ namespace WeaponPaints [JsonPropertyName("NameTagEnabled")] public bool NameTagEnabled { get; set; } = true; - [JsonPropertyName("CommandWpEnabled")] - public bool CommandWpEnabled { get; set; } = true; + [JsonPropertyName("CommandsKnife")] + public List CommandsKnife { get; set; } = ["knife", "knives"]; - [JsonPropertyName("CommandKillEnabled")] - public bool CommandKillEnabled { get; set; } = true; + [JsonPropertyName("CommandsMusic")] + public List CommandsMusic { get; set; } = ["music", "musickits", "mkit"]; - [JsonPropertyName("CommandKnife")] - public string CommandKnife { get; set; } = "knife"; + [JsonPropertyName("CommandsGlove")] + public List CommandsGlove { get; set; } = ["gloves", "glove"]; - [JsonPropertyName("CommandMusic")] - public string CommandMusic { get; set; } = "music"; + [JsonPropertyName("CommandsAgent")] + public List CommandsAgent { get; set; } = ["agents", "agent"]; - [JsonPropertyName("CommandGlove")] - public string CommandGlove { get; set; } = "gloves"; + [JsonPropertyName("CommandsInfo")] + public List CommandsInfo { get; set; } = ["ws", "skininfo"]; - [JsonPropertyName("CommandAgent")] - public string CommandAgent { get; set; } = "agents"; + [JsonPropertyName("CommandsSkinSelection")] + public List CommandsSkinSelection { get; set; } = ["skins", "skin"]; - [JsonPropertyName("CommandSkin")] - public string CommandSkin { get; set; } = "ws"; + [JsonPropertyName("CommandsRefresh")] + public List CommandsRefresh { get; set; } = ["wp", "refreshskins"]; - [JsonPropertyName("CommandSkinSelection")] - public string CommandSkinSelection { get; set; } = "skins"; - - [JsonPropertyName("CommandRefresh")] - public string CommandRefresh { get; set; } = "wp"; - - [JsonPropertyName("CommandKill")] - public string CommandKill { get; set; } = "kill"; + [JsonPropertyName("CommandsKill")] + public List CommandsKill { get; set; } = ["kill", "suicide"]; [JsonPropertyName("GiveRandomKnife")] public bool GiveRandomKnife { get; set; } = false; @@ -61,27 +73,21 @@ namespace WeaponPaints [JsonPropertyName("ShowSkinImage")] public bool ShowSkinImage { get; set; } = true; + + [JsonPropertyName("UseHtmlMenu")] + public bool UseHtmlMenu { get; set; } = true; + + [JsonPropertyName("ExpireOlderThan")] + public int ExpireOlderThan { get; set; } = 90; } public class WeaponPaintsConfig : BasePluginConfig { public override int Version { get; set; } = 7; - - [JsonPropertyName("DatabaseHost")] - public string DatabaseHost { get; set; } = ""; - - [JsonPropertyName("DatabasePort")] - public int DatabasePort { get; set; } = 3306; - - [JsonPropertyName("DatabaseUser")] - public string DatabaseUser { get; set; } = ""; - - [JsonPropertyName("DatabasePassword")] - public string DatabasePassword { get; set; } = ""; - - [JsonPropertyName("DatabaseName")] - public string DatabaseName { get; set; } = ""; - + + [JsonPropertyName("DatabaseCredentials")] + public DatabaseCredentials DatabaseCredentials { get; set; } = new(); + [JsonPropertyName("CmdRefreshCooldownSeconds")] public int CmdRefreshCooldownSeconds { get; set; } = 60; diff --git a/Database.cs b/Database.cs index 456d9af2..08d69d54 100644 --- a/Database.cs +++ b/Database.cs @@ -5,13 +5,11 @@ namespace WeaponPaints { public class Database(string dbConnectionString) { - private readonly string _dbConnectionString = dbConnectionString; - public async Task GetConnectionAsync() { try { - var connection = new MySqlConnection(_dbConnectionString); + var connection = new MySqlConnection(dbConnectionString); await connection.OpenAsync(); return connection; } diff --git a/Events.cs b/Events.cs index 53488a4e..0fc1ee36 100644 --- a/Events.cs +++ b/Events.cs @@ -103,6 +103,9 @@ namespace WeaponPaints if (_database != null) weaponSync = new WeaponSynchronization(_database, Config); + + if (weaponSync != null) + Task.Run(async () => await weaponSync.PurgeExpiredUsers()); } private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) diff --git a/Utility.cs b/Utility.cs index 1ea1b914..9d28d341 100644 --- a/Utility.cs +++ b/Utility.cs @@ -25,11 +25,11 @@ namespace WeaponPaints { var createTableQueries = new[] { - "CREATE TABLE IF NOT EXISTS `wp_users` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `steamid` BIGINT UNSIGNED NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_steamid` (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", - "CREATE TABLE IF NOT EXISTS `wp_users_items` (`user_id` INT UNSIGNED NOT NULL, `weapon` SMALLINT UNSIGNED NOT NULL, `paint` SMALLINT UNSIGNED NOT NULL, `wear` FLOAT NOT NULL DEFAULT 0.001, `seed` SMALLINT UNSIGNED NOT NULL DEFAULT 0, `nametag` VARCHAR(20) DEFAULT NULL, `stattrack` INT UNSIGNED NOT NULL DEFAULT 0, `stattrack_enabled` SMALLINT NOT NULL DEFAULT 0, `quality` SMALLINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`user_id`,`weapon`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", - "CREATE TABLE IF NOT EXISTS `wp_users_knife` (`user_id` INT UNSIGNED NOT NULL, `knife` VARCHAR(32) DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", + "CREATE TABLE IF NOT EXISTS `wp_users` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `steamid` BIGINT UNSIGNED NOT NULL, `last_online` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_steamid` (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", + "CREATE TABLE IF NOT EXISTS `wp_users_skins` (`user_id` INT UNSIGNED NOT NULL, `weapon` SMALLINT UNSIGNED NOT NULL, `paint` SMALLINT UNSIGNED NOT NULL, `wear` FLOAT NOT NULL DEFAULT 0.001, `seed` SMALLINT UNSIGNED NOT NULL DEFAULT 0, `nametag` VARCHAR(20) DEFAULT NULL, `stattrack` INT UNSIGNED NOT NULL DEFAULT 0, `stattrack_enabled` SMALLINT NOT NULL DEFAULT 0, `quality` SMALLINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`user_id`,`weapon`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", + "CREATE TABLE IF NOT EXISTS `wp_users_knives` (`user_id` INT UNSIGNED NOT NULL, `knife` SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", "CREATE TABLE IF NOT EXISTS `wp_users_gloves` (`user_id` INT UNSIGNED NOT NULL, `weapon_defindex` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", - "CREATE TABLE IF NOT EXISTS `wp_users_music` (`user_id` INT UNSIGNED NOT NULL, `music` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", + "CREATE TABLE IF NOT EXISTS `wp_users_musics` (`user_id` INT UNSIGNED NOT NULL, `music` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;", "CREATE TABLE IF NOT EXISTS `wp_users_agents` (`user_id` INT UNSIGNED NOT NULL,`agent_ct` varchar(64) DEFAULT NULL,`agent_t` varchar(64) DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;" }; diff --git a/WeaponAction.cs b/WeaponAction.cs index fe3225bf..d77637c2 100644 --- a/WeaponAction.cs +++ b/WeaponAction.cs @@ -21,20 +21,20 @@ public partial class WeaponPaints var isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet"); if ((isKnife && !g_playersKnife.ContainsKey(player.Slot)) || - (isKnife && g_playersKnife[player.Slot] == "weapon_knife")) return; + (isKnife && g_playersKnife[player.Slot] < 500)) return; int[] newPaints = [1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173]; if (isKnife) { - var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]); - if (newDefIndex.Key == 0) return; + //var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]); + //if (newDefIndex.Key == 0) return; - if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key) - SubclassChange(weapon, (ushort)newDefIndex.Key); + if (weapon.AttributeManager.Item.ItemDefinitionIndex != g_playersKnife[player.Slot]) + SubclassChange(weapon, (ushort)g_playersKnife[player.Slot]); - weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key; + weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)g_playersKnife[player.Slot]; weapon.AttributeManager.Item.EntityQuality = 3; } @@ -46,7 +46,7 @@ public partial class WeaponPaints weapon.AttributeManager.Item.AccountID = (uint)player.SteamID; if (_config.Additional.GiveRandomSkin && - !gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) + !gPlayerWeaponsInfo[player.Slot].ContainsKey((ushort)weaponDefIndex)) { // Random skins weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); @@ -80,7 +80,7 @@ public partial class WeaponPaints return; } - if (!gPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return; + if (!gPlayerWeaponsInfo[player.Slot].TryGetValue((ushort)weaponDefIndex, out var value) || value.Paint == 0) return; var weaponInfo = value; //Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}"); diff --git a/WeaponPaints.cs b/WeaponPaints.cs index cb4a0a51..6021328e 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -8,10 +8,11 @@ using MySqlConnector; using Newtonsoft.Json.Linq; using System.Collections.Concurrent; using System.Runtime.InteropServices; +using CounterStrikeSharp.API.Modules.Entities.Constants; namespace WeaponPaints; -[MinimumApiVersion(230)] +[MinimumApiVersion(238)] public partial class WeaponPaints : BasePlugin, IPluginConfig { internal static WeaponPaints Instance { get; private set; } = new(); @@ -79,17 +80,17 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig g_knifePickupCount = new(); - internal static ConcurrentDictionary g_playersKnife = new(); + internal static ConcurrentDictionary g_playersKnife = new(); internal static ConcurrentDictionary g_playersGlove = new(); internal static ConcurrentDictionary g_playersMusic = new(); internal static ConcurrentDictionary g_playersAgent = new(); internal static ConcurrentDictionary> gPlayerWeaponsInfo = new(); internal static ConcurrentDictionary g_playersDatabaseIndex = new(); - internal static List skinsList = new(); - internal static List glovesList = new(); - internal static List agentsList = new(); - internal static List musicList = new(); + internal static List skinsList = []; + internal static List glovesList = []; + internal static List agentsList = []; + internal static List musicList = []; internal static WeaponSynchronization? weaponSync; private static bool g_bCommandsAllowed = true; private Dictionary PlayerWeaponImage = new(); @@ -162,7 +163,6 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig(Utilities.GetPlayers().TakeWhile(player => weaponSync != null)) .Where(player => player.IsValid && @@ -232,7 +232,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig(query, new { steamid = playerInfo.SteamId }); if (databaseIndex != null) { WeaponPaints.g_playersDatabaseIndex[playerInfo.Slot] = (int)databaseIndex; + query = "UPDATE `wp_users` SET `last_update` = @lastUpdate WHERE `id` = @databaseIndex"; + await connection.ExecuteAsync(query, new + { + lastUpdate = DateTime.Now, + databaseIndex + }); } else { + Console.WriteLine("test"); const string insertQuery = "INSERT INTO `wp_users` (`steamid`) VALUES (@steamid)"; await connection.ExecuteAsync(insertQuery, new { steamid = playerInfo.SteamId }); Console.WriteLine("SQL Insert Query: " + insertQuery); @@ -39,7 +47,7 @@ internal class WeaponSynchronization WeaponPaints.g_playersDatabaseIndex[playerInfo.Slot] = (int)databaseIndex; } - await GetPlayerData(playerInfo, connection); + await GetPlayerData(playerInfo); } catch (Exception ex) { @@ -47,10 +55,12 @@ internal class WeaponSynchronization } } - internal async Task GetPlayerData(PlayerInfo? player, MySqlConnection connection) + internal async Task GetPlayerData(PlayerInfo? player) { try { + await using var connection = await _database.GetConnectionAsync(); + if (_config.Additional.KnifeEnabled) GetKnifeFromDatabase(player, connection); if (_config.Additional.GloveEnabled) @@ -76,11 +86,11 @@ internal class WeaponSynchronization if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId.ToString())) return; - const string query = "SELECT `knife` FROM `wp_users_knife` WHERE `user_id` = @userId"; - var playerKnife = connection.QueryFirstOrDefault(query, + const string query = "SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = @userId"; + var playerKnife = connection.QueryFirstOrDefault(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] }); - if (!string.IsNullOrEmpty(playerKnife)) WeaponPaints.g_playersKnife[player.Slot] = playerKnife; + WeaponPaints.g_playersKnife[player.Slot] = (ushort)playerKnife; } catch (Exception ex) { @@ -95,7 +105,7 @@ internal class WeaponSynchronization if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId.ToString())) return; - const string query = "SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `userId` = @userId"; + const string query = "SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = @userId"; var gloveData = connection.QueryFirstOrDefault(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] }); if (gloveData != null) WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value; @@ -142,16 +152,16 @@ internal class WeaponSynchronization var weaponInfos = new ConcurrentDictionary(); - const string query = "SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_items` WHERE `user_id` = @userId"; - var playerSkins = connection.Query(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Index] }); + const string query = "SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_skins` WHERE `user_id` = @userId"; + var playerSkins = connection.Query(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] }); foreach (var row in playerSkins) { - ushort weaponDefIndex = row?.weapon_defindex ?? 0; - ushort weaponPaintId = row?.weapon_paint_id ?? 0; - float weaponWear = row?.weapon_wear ?? 0f; - ushort weaponSeed = row?.weapon_seed ?? 0; - string weaponNameTag = row?.nametag ?? string.Empty; + ushort weaponDefIndex = (ushort)(row.weapon ?? 0); + ushort weaponPaintId = (ushort)(row.paint ?? 0); + float weaponWear = row.wear ?? 0f; + ushort weaponSeed = (ushort)(row.seed ?? 0); + string weaponNameTag = row.nametag ?? string.Empty; var weaponInfo = new WeaponInfo { @@ -179,7 +189,7 @@ internal class WeaponSynchronization if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId.ToString())) return; - const string query = "SELECT `music` FROM `wp_users_music` WHERE `user_id` = @userId"; + const string query = "SELECT `music` FROM `wp_users_musics` WHERE `user_id` = @userId"; var musicData = connection.QueryFirstOrDefault(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] }); if (musicData != null) WeaponPaints.g_playersMusic[player.Slot] = musicData.Value; @@ -190,14 +200,60 @@ internal class WeaponSynchronization } } - - internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife) + internal async Task PurgeExpiredUsers() { - if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId.ToString()) || - string.IsNullOrEmpty(knife)) return; + try + { + await using var connection = await _database.GetConnectionAsync(); + await using var transaction = await connection.BeginTransactionAsync(); + + var userIds = await connection.QueryAsync( + $"SELECT id FROM wp_users WHERE last_update < NOW() - INTERVAL {_config.Additional.ExpireOlderThan} DAY", + transaction: transaction + ); + + var ids = string.Join(",", userIds); + + string query; + + if (userIds.AsList().Count > 0) + { + // Step 2: Delete related records in other tables using the retrieved IDs + query = $"DELETE FROM wp_users_agents WHERE user_id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + query = $"DELETE FROM wp_users_gloves WHERE user_id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + query = $"DELETE FROM wp_users_skins WHERE user_id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + query = $"DELETE FROM wp_users_knives WHERE user_id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + query = $"DELETE FROM wp_users_musics WHERE user_id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + // Step 3: Delete users from wp_users + query = $"DELETE FROM wp_users WHERE id IN ({ids})"; + await connection.ExecuteAsync(query, transaction: transaction); + + // Commit transaction + await transaction.CommitAsync(); + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}"); + } + } + + internal async Task SyncKnifeToDatabase(PlayerInfo player, ushort knife) + { + if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return; const string query = - "INSERT INTO `wp_users_knife` (`user_id`, `knife`) VALUES(@userId, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; + "INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(@userId, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; try { @@ -272,7 +328,7 @@ internal class WeaponSynchronization var seed = weaponInfo.Seed; const string queryCheckExistence = - "SELECT COUNT(*) FROM `wp_users_items` WHERE `user_id` = @userId AND `weapon_defindex` = @weaponDefIndex"; + "SELECT COUNT(*) FROM `wp_users_skins` WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex"; var existingRecordCount = await connection.ExecuteScalarAsync(queryCheckExistence, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex }); @@ -283,13 +339,13 @@ internal class WeaponSynchronization if (existingRecordCount > 0) { query = - "UPDATE `wp_users_items` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `user_id` = @userId AND `weapon_defindex` = @weaponDefIndex"; + "UPDATE `wp_users_skins` SET `paint` = @paintId, `wear` = @wear, `seed` = @seed WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex"; parameters = new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex, paintId, wear, seed }; } else { query = - "INSERT INTO `wp_users_items` (`user_id`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + + "INSERT INTO `wp_users_skins` (`user_id`, `weapon`, `paint`, `wear`, `seed`) " + "VALUES (@userId, @weaponDefIndex, @paintId, @wear, @seed)"; parameters = new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex, paintId, wear, seed }; } @@ -311,7 +367,7 @@ internal class WeaponSynchronization { await using var connection = await _database.GetConnectionAsync(); const string query = - "INSERT INTO `wp_users_music` (`user_id`, `music_id`) VALUES(@userId, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; + "INSERT INTO `wp_users_musics` (`user_id`, `music_id`) VALUES(@userId, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], newMusic = music }); } catch (Exception e) diff --git a/website/class/header.php b/website/class/header.php index e3cb6ccf..93fe4d12 100644 --- a/website/class/header.php +++ b/website/class/header.php @@ -36,9 +36,9 @@ if (isset($_SESSION['steamid'])) { $gloves = UtilsClass::glovesFromJson(); // Retrieve user's selected skins and knife - $querySelected = $db->select("SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_items` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]); + $querySelected = $db->select("SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_skins` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]); $selectedSkins = UtilsClass::getSelectedSkins($querySelected); - $selectedKnifeResult = $db->select("SELECT `knife` FROM `wp_users_knife` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]); + $selectedKnifeResult = $db->select("SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]); $selectedGlovesResult = $db->select("SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]); $selectedGloves = !empty($selectedGlovesResult) ? $selectedGlovesResult[0] : $gloves[0][0]; @@ -56,7 +56,7 @@ if (isset($_SESSION['steamid'])) { // Handle knife selection if ($ex[0] == "knife") { - $db->query("INSERT INTO `wp_users_knife` (`user_id`, `knife`) VALUES(:user_id, :knife) ON DUPLICATE KEY UPDATE `knife` = :knife", ["user_id" => $userDbIndex, "knife" => $knifes[$ex[1]]['weapon_name']]); + $db->query("INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(:user_id, :knife) ON DUPLICATE KEY UPDATE `knife` = :knife", ["user_id" => $userDbIndex, "knife" => $knifes[$ex[1]]['weapon_name']]); } else { // Handle skin selection if (array_key_exists($ex[1], $skins[$ex[0]]) && isset($_POST['wear']) && $_POST['wear'] >= 0.00 && $_POST['wear'] <= 1.00 && isset($_POST['seed'])) { @@ -65,9 +65,9 @@ if (isset($_SESSION['steamid'])) { // Check if the skin is already selected and update or insert accordingly if (array_key_exists($ex[0], $selectedSkins)) { - $db->query("UPDATE wp_users_items SET paint = :weapon_paint_id, wear = :weapon_wear, seed = :weapon_seed WHERE user_id = :user_id AND weapon = :weapon_defindex", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]); + $db->query("UPDATE wp_users_skins SET paint = :weapon_paint_id, wear = :weapon_wear, seed = :weapon_seed WHERE user_id = :user_id AND weapon = :weapon_defindex", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]); } else { - $db->query("INSERT INTO wp_users_items (`user_id`, `weapon`, `paint`, `wear`, `seed`) VALUES (:user_id, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed)", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]); + $db->query("INSERT INTO wp_users_skins (`user_id`, `weapon`, `paint`, `wear`, `seed`) VALUES (:user_id, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed)", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]); } } }