From eba4ba08d282417e88f4da99fd5bfb9a08243af8 Mon Sep 17 00:00:00 2001 From: Dawid Bepierszcz <41084667+daffyyyy@users.noreply.github.com> Date: Sat, 19 Oct 2024 20:24:26 +0200 Subject: [PATCH] 2.9a - Team based items --- Commands.cs | 187 +++++--- Events.cs | 8 +- Utility.cs | 111 ++--- VERSION | 2 +- Variables.cs | 11 +- WeaponAction.cs | 38 +- WeaponPaints.cs | 17 +- WeaponSynchronization.cs | 981 +++++++++++++++++++++++---------------- 8 files changed, 814 insertions(+), 541 deletions(-) diff --git a/Commands.cs b/Commands.cs index fcee55aa..9a62bbdc 100644 --- a/Commands.cs +++ b/Commands.cs @@ -1,7 +1,9 @@ -using CounterStrikeSharp.API.Core; +using System.Collections.Concurrent; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Utils; using Newtonsoft.Json.Linq; namespace WeaponPaints; @@ -150,6 +152,11 @@ public partial class WeaponPaints { if (!Utility.IsPlayerValid(player)) return; + var playerKnives = GPlayersKnife.GetOrAdd(player.Slot, new ConcurrentDictionary()); + var teamsToCheck = player.TeamNum < 2 + ? new[] { CsTeam.Terrorist, CsTeam.CounterTerrorist } + : [player.Team]; + var knifeName = option.Text; var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key; if (string.IsNullOrEmpty(knifeKey)) return; @@ -172,14 +179,18 @@ public partial class WeaponPaints Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; - - GPlayersKnife[player.Slot] = knifeKey; - + + foreach (var team in teamsToCheck) + { + // Attempt to get the existing knives + playerKnives[team] = knifeKey; + } + if (_gBCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE) RefreshWeapons(player); if (WeaponSync != null) - _ = Task.Run(async () => await WeaponSync.SyncKnifeToDatabase(playerInfo, knifeKey)); + _ = Task.Run(async () => await WeaponSync.SyncKnifeToDatabase(playerInfo, knifeKey, teamsToCheck)); }; foreach (var knifePair in knivesOnly) { @@ -229,7 +240,7 @@ public partial class WeaponPaints var selectedWeapon = option.Text; if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return; - var skinsForSelectedWeapon = SkinsList?.Where(skin => + var skinsForSelectedWeapon = SkinsList.Where(skin => skin.TryGetValue("weapon_name", out var weaponName) && weaponName?.ToString() == selectedWeaponClassname )?.ToList(); @@ -241,8 +252,7 @@ public partial class WeaponPaints { if (!Utility.IsPlayerValid(p)) return; - var steamId = p.SteamID.ToString(); - var firstSkin = SkinsList?.FirstOrDefault(skin => + var firstSkin = SkinsList.FirstOrDefault(skin => { if (skin.TryGetValue("weapon_name", out var weaponName)) { @@ -259,29 +269,38 @@ public partial class WeaponPaints !int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) || !int.TryParse(selectedPaintId, out var paintId)) return; { - if (Config.Additional.ShowSkinImage && SkinsList != null) + if (Config.Additional.ShowSkinImage) { var foundSkin = SkinsList.FirstOrDefault(skin => - ((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex && - ((int?)skin?["paint"] ?? 0) == paintId && - skin?["image"] != null + ((int?)skin["weapon_defindex"] ?? 0) == weaponDefIndex && + ((int?)skin["paint"] ?? 0) == paintId && + skin["image"] != null ); var image = foundSkin?["image"]?.ToString() ?? ""; _playerWeaponImage[p.Slot] = image; - AddTimer(2.0f, () => _playerWeaponImage.Remove(p.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(2.0f, () => _playerWeaponImage.Remove(p.Slot), TimerFlags.STOP_ON_MAPCHANGE); } p.Print(Localizer["wp_skin_menu_select", selectedSkin]); + var playerSkins = GPlayerWeaponsInfo.GetOrAdd(p.Slot, new ConcurrentDictionary>()); - if (!GPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out var value)) + var teamsToCheck = p.TeamNum < 2 + ? new[] { CsTeam.Terrorist, CsTeam.CounterTerrorist } + : [p.Team]; + + foreach (var team in teamsToCheck) { - value = new WeaponInfo(); - GPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value; - } + // Ensure there's an entry for the team in playerSkins + var teamWeapons = playerSkins.GetOrAdd(team, _ => new ConcurrentDictionary()); - value.Paint = paintId; - value.Wear = 0.01f; - value.Seed = 0; + // Attempt to get or add the existing WeaponInfo + var value = teamWeapons.GetOrAdd(weaponDefIndex, _ => new WeaponInfo()); + + // Update the properties of WeaponInfo + value.Paint = paintId; + value.Wear = 0.01f; + value.Seed = 0; + } PlayerInfo playerInfo = new PlayerInfo { @@ -371,6 +390,11 @@ public partial class WeaponPaints if (!Utility.IsPlayerValid(player) || player is null) return; var selectedPaintName = option.Text; + + var playerGloves = GPlayersGlove.GetOrAdd(player.Slot, new ConcurrentDictionary()); + var teamsToCheck = player.TeamNum < 2 + ? new[] { CsTeam.Terrorist, CsTeam.CounterTerrorist } + : [player.Team]; var selectedGlove = GlovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName); var image = selectedGlove?["image"]?.ToString() ?? ""; @@ -397,15 +421,32 @@ public partial class WeaponPaints if (paint != 0) { - GPlayersGlove[player.Slot] = (ushort)weaponDefindex; - - if (!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex)) + // Ensure that player weapons info exists for the player + if (!GPlayerWeaponsInfo.ContainsKey(player.Slot)) { - WeaponInfo weaponInfo = new() + GPlayerWeaponsInfo[player.Slot] = new ConcurrentDictionary>(); + } + + // Ensure teams are initialized + foreach (var team in teamsToCheck) + { + if (!GPlayerWeaponsInfo[player.Slot].ContainsKey(team)) { - Paint = paint - }; - GPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo; + GPlayerWeaponsInfo[player.Slot][team] = new ConcurrentDictionary(); + } + + // Update the glove for the player in the specified team + playerGloves[team] = (ushort)weaponDefindex; + + // Check if the glove information already exists for the player + if (!GPlayerWeaponsInfo[player.Slot][team].ContainsKey(weaponDefindex)) + { + WeaponInfo weaponInfo = new() + { + Paint = paint + }; + GPlayerWeaponsInfo[player.Slot][team][weaponDefindex] = weaponInfo; + } } } else @@ -413,28 +454,30 @@ public partial class WeaponPaints GPlayersGlove.TryRemove(player.Slot, out _); } - if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"])) - { - player.Print(Localizer["wp_glove_menu_select", selectedPaintName]); - } - if (WeaponSync == null) return; - + _ = Task.Run(async () => { - await WeaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex); - - if (!GPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out var value)) + // Sync glove to database for all teams + foreach (var team in teamsToCheck) { - value = new WeaponInfo(); - GPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value; + await WeaponSync.SyncGloveToDatabase(playerInfo, (ushort)weaponDefindex, teamsToCheck); + + // Check if the weapon info exists for the glove + if (!GPlayerWeaponsInfo[playerInfo.Slot][team].TryGetValue(weaponDefindex, out var value)) + { + value = new WeaponInfo(); + GPlayerWeaponsInfo[playerInfo.Slot][team][weaponDefindex] = value; + } + + // Update weapon info + value.Paint = paint; + value.Wear = 0.00f; + value.Seed = 0; + + // Sync weapon paints to database + await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo); } - - value.Paint = paint; - value.Wear = 0.00f; - value.Seed = 0; - - await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo); }); AddTimer(0.1f, () => GivePlayerGloves(player)); @@ -596,6 +639,11 @@ public partial class WeaponPaints if (!Utility.IsPlayerValid(player) || player is null) return; var selectedPaintName = option.Text; + + var playerMusic = GPlayersMusic.GetOrAdd(player.Slot, new ConcurrentDictionary()); + var teamsToCheck = player.TeamNum < 2 + ? new[] { CsTeam.Terrorist, CsTeam.CounterTerrorist } + : [player.Team]; // Corrected array initializer var selectedMusic = MusicList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString() == selectedPaintName); if (selectedMusic != null) @@ -607,7 +655,7 @@ public partial class WeaponPaints if (Config.Additional.ShowSkinImage) { _playerWeaponImage[player.Slot] = image; - AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), TimerFlags.STOP_ON_MAPCHANGE); } PlayerInfo playerInfo = new PlayerInfo @@ -619,14 +667,20 @@ public partial class WeaponPaints Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; - + if (paint != 0) { - GPlayersMusic[player.Slot] = (ushort)paint; + foreach (var team in teamsToCheck) + { + playerMusic[team] = (ushort)paint; + } } else { - GPlayersMusic[player.Slot] = 0; + foreach (var team in teamsToCheck) + { + playerMusic[team] = 0; + } } if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"])) @@ -638,11 +692,9 @@ public partial class WeaponPaints { _ = Task.Run(async () => { - await WeaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint); + await WeaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint, teamsToCheck); }); } - - //RefreshGloves(player); } else { @@ -656,7 +708,10 @@ public partial class WeaponPaints IpAddress = player.IpAddress?.Split(":")[0] }; - GPlayersMusic[player.Slot] = 0; + foreach (var team in teamsToCheck) + { + playerMusic[team] = 0; + } if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"])) { @@ -667,7 +722,7 @@ public partial class WeaponPaints { _ = Task.Run(async () => { - await WeaponSync.SyncMusicToDatabase(playerInfo, 0); + await WeaponSync.SyncMusicToDatabase(playerInfo, 0, teamsToCheck); }); } } @@ -716,6 +771,11 @@ public partial class WeaponPaints var selectedPaintName = option.Text; + var playerPins = GPlayersPin.GetOrAdd(player.Slot, new ConcurrentDictionary()); + var teamsToCheck = player.TeamNum < 2 + ? new[] { CsTeam.Terrorist, CsTeam.CounterTerrorist } + : [player.Team]; + var selectedPin = PinsList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString() == selectedPaintName); if (selectedPin != null) { @@ -738,14 +798,20 @@ public partial class WeaponPaints Name = player.PlayerName, IpAddress = player.IpAddress?.Split(":")[0] }; - + if (paint != 0) { - GPlayersPin[player.Slot] = (ushort)paint; + foreach (var team in teamsToCheck) + { + playerPins[team] = (ushort)paint; // Set pin for each team + } } else { - GPlayersPin[player.Slot] = 0; + foreach (var team in teamsToCheck) + { + playerPins[team] = 0; // Set pin for each team + } } if (!string.IsNullOrEmpty(Localizer["wp_pins_menu_select"])) @@ -759,7 +825,7 @@ public partial class WeaponPaints { _ = Task.Run(async () => { - await WeaponSync.SyncPinToDatabase(playerInfo, (ushort)paint); + await WeaponSync.SyncPinToDatabase(playerInfo, (ushort)paint, teamsToCheck); }); } } @@ -775,7 +841,10 @@ public partial class WeaponPaints IpAddress = player.IpAddress?.Split(":")[0] }; - GPlayersPin[player.Slot] = 0; + foreach (var team in teamsToCheck) + { + playerPins[team] = 0; // Set music for each team + } if (!string.IsNullOrEmpty(Localizer["wp_pins_menu_select"])) { @@ -788,7 +857,7 @@ public partial class WeaponPaints { _ = Task.Run(async () => { - await WeaponSync.SyncPinToDatabase(playerInfo, 0); + await WeaponSync.SyncPinToDatabase(playerInfo, 0, teamsToCheck); }); } } diff --git a/Events.cs b/Events.cs index 1100c7f2..1f9d0382 100644 --- a/Events.cs +++ b/Events.cs @@ -81,7 +81,7 @@ namespace WeaponPaints return HookResult.Continue; if (WeaponSync != null) - _ = Task.Run(async () => await WeaponSync.SyncStatTrakToDatabase(playerInfo, weaponInfos)); + _ = Task.Run(async () => await WeaponSync.SyncStatTrakToDatabase(playerInfo)); if (Config.Additional.SkinEnabled) { @@ -253,9 +253,13 @@ namespace WeaponPaints private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) { CCSPlayerController? player = @event.Attacker; + CCSPlayerController? victim = @event.Userid; if (player is null || !player.IsValid) return HookResult.Continue; + + if (victim == null || victim == player) + return HookResult.Continue; if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return HookResult.Continue; @@ -265,7 +269,7 @@ namespace WeaponPaints int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; - if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var weaponInfo) || weaponInfo.Paint == 0) + if (!GPlayerWeaponsInfo[player.Slot][player.Team].TryGetValue(weaponDefIndex, out var weaponInfo) || weaponInfo.Paint == 0) return HookResult.Continue; if (!weaponInfo.StatTrak) return HookResult.Continue; diff --git a/Utility.cs b/Utility.cs index 1b505341..57a8fba1 100644 --- a/Utility.cs +++ b/Utility.cs @@ -24,58 +24,65 @@ namespace WeaponPaints { string[] createTableQueries = [ - """ - CREATE TABLE IF NOT EXISTS `wp_player_skins` ( - `steamid` varchar(18) NOT NULL, - `weapon_defindex` int(6) NOT NULL, - `weapon_paint_id` int(6) NOT NULL, - `weapon_wear` float NOT NULL DEFAULT 0.000001, - `weapon_seed` int(16) NOT NULL DEFAULT 0, - `weapon_nametag` VARCHAR(128) DEFAULT NULL, - `weapon_stattrak` tinyint(1) NOT NULL, - `weapon_stattrak_count` int(10) NOT NULL, - `weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_keychain`VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed' - ) ENGINE=InnoDB - """, - @"CREATE TABLE IF NOT EXISTS `wp_player_knife` ( - `steamid` varchar(18) NOT NULL, - `knife` varchar(64) NOT NULL, - UNIQUE (`steamid`) - ) ENGINE = InnoDB", - """ - CREATE TABLE IF NOT EXISTS `wp_player_gloves` ( - `steamid` varchar(18) NOT NULL, - `weapon_defindex` int(11) NOT NULL, - UNIQUE (`steamid`) - ) ENGINE=InnoDB - """, - """ - CREATE TABLE IF NOT EXISTS `wp_player_agents` ( - `steamid` varchar(18) NOT NULL, - `agent_ct` varchar(64) DEFAULT NULL, - `agent_t` varchar(64) DEFAULT NULL, - UNIQUE (`steamid`) - ) ENGINE=InnoDB - """, - """ - CREATE TABLE IF NOT EXISTS `wp_player_music` ( - `steamid` varchar(64) NOT NULL, - `music_id` int(11) NOT NULL, - UNIQUE (`steamid`) - ) ENGINE=InnoDB - """, - """ - CREATE TABLE IF NOT EXISTS `wp_player_pins` ( - `steamid` varchar(64) NOT NULL, - `id` int(11) NOT NULL, - UNIQUE (`steamid`) - ) ENGINE=InnoDB - """, + @" + CREATE TABLE IF NOT EXISTS `wp_player_skins` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `weapon_defindex` int(6) NOT NULL, + `weapon_paint_id` int(6) NOT NULL, + `weapon_wear` float NOT NULL DEFAULT 0.000001, + `weapon_seed` int(16) NOT NULL DEFAULT 0, + `weapon_nametag` VARCHAR(128) DEFAULT NULL, + `weapon_stattrak` tinyint(1) NOT NULL DEFAULT 0, + `weapon_stattrak_count` int(10) NOT NULL DEFAULT 0, + `weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_keychain` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed', + UNIQUE (`steamid`, `weapon_team`, `weapon_defindex`) -- Add unique constraint here + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_knife` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `knife` varchar(64) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) -- Unique constraint + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_gloves` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `weapon_defindex` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) -- Unique constraint + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_agents` ( + `steamid` varchar(18) NOT NULL, + `agent_ct` varchar(64) DEFAULT NULL, + `agent_t` varchar(64) DEFAULT NULL, + UNIQUE (`steamid`) -- Unique constraint + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_music` ( + `steamid` varchar(64) NOT NULL, + `weapon_team` int(1) NOT NULL, + `music_id` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) -- Unique constraint + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_pins` ( + `steamid` varchar(64) NOT NULL, + `weapon_team` int(1) NOT NULL, + `id` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) -- Unique constraint + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" ]; foreach (var query in createTableQueries) diff --git a/VERSION b/VERSION index 22230ccd..0d1ad2a0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.8c \ No newline at end of file +2.9a \ No newline at end of file diff --git a/Variables.cs b/Variables.cs index bfc21672..b901868f 100644 --- a/Variables.cs +++ b/Variables.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Capabilities; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; using MenuManager; using Microsoft.Extensions.Localization; using Newtonsoft.Json.Linq; @@ -72,12 +73,12 @@ public partial class WeaponPaints }; public static IStringLocalizer? _localizer; - internal static readonly ConcurrentDictionary GPlayersKnife = new(); - internal static readonly ConcurrentDictionary GPlayersGlove = new(); - internal static readonly ConcurrentDictionary GPlayersMusic = new(); - internal static readonly ConcurrentDictionary GPlayersPin = new(); + internal static readonly ConcurrentDictionary> GPlayersKnife = new(); + internal static readonly ConcurrentDictionary> GPlayersGlove = new(); + internal static readonly ConcurrentDictionary> GPlayersMusic = new(); + internal static readonly ConcurrentDictionary> GPlayersPin = new(); public static readonly ConcurrentDictionary GPlayersAgent = new(); - internal static readonly ConcurrentDictionary> GPlayerWeaponsInfo = new(); + internal static readonly ConcurrentDictionary>> GPlayerWeaponsInfo = new(); internal static List SkinsList = []; internal static List PinsList = []; internal static List GlovesList = []; diff --git a/WeaponAction.cs b/WeaponAction.cs index 568abfb3..68b26aa3 100644 --- a/WeaponAction.cs +++ b/WeaponAction.cs @@ -20,11 +20,12 @@ namespace WeaponPaints bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet"); - if (isKnife && !GPlayersKnife.ContainsKey(player.Slot) || isKnife && GPlayersKnife[player.Slot] == "weapon_knife") return; + if (isKnife && !GPlayersKnife.ContainsKey(player.Slot) || + isKnife && GPlayersKnife[player.Slot][player.Team] == "weapon_knife") return; if (isKnife) { - var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == GPlayersKnife[player.Slot]); + var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == GPlayersKnife[player.Slot][player.Team]); if (newDefIndex.Key == 0) return; if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key) @@ -47,7 +48,7 @@ namespace WeaponPaints bool isLegacyModel; if (_config.Additional.GiveRandomSkin && - !GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) + !GPlayerWeaponsInfo[player.Slot][player.Team].ContainsKey(weaponDefIndex)) { // Random skins weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); @@ -80,7 +81,7 @@ namespace WeaponPaints return; } - if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return; + if (!GPlayerWeaponsInfo[player.Slot][player.Team].TryGetValue(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]}"); @@ -131,7 +132,8 @@ namespace WeaponPaints { int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) || - !playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo) || + !playerWeapons.TryGetValue(player.Team, out var weaponInfoDict) || + !weaponInfoDict.TryGetValue(weaponDefIndex, out var weaponInfo) || weaponInfo.Stickers.Count <= 0) return; float wearIncrement = 0.001f; @@ -155,7 +157,7 @@ namespace WeaponPaints int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) || - !playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo)) + !playerWeapons[player.Team].TryGetValue(weaponDefIndex, out var weaponInfo)) { return; } @@ -197,7 +199,7 @@ namespace WeaponPaints int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeaponsInfo) || - !playerWeaponsInfo.TryGetValue(weaponDefIndex, out var value) || + !playerWeaponsInfo[player.Team].TryGetValue(weaponDefIndex, out var value) || value.KeyChain == null) return; var keyChain = value.KeyChain; @@ -263,8 +265,6 @@ namespace WeaponPaints if (player.Team is CsTeam.None or CsTeam.Spectator) return; - int playerTeam = player.TeamNum; - Dictionary> weaponsWithAmmo = []; foreach (var weapon in weapons) @@ -376,11 +376,12 @@ namespace WeaponPaints if (!player.PawnIsAlive) return; - if (!GPlayersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return; + if (!GPlayersGlove.TryGetValue(player.Slot, out var gloveInfo) || + !gloveInfo.TryGetValue(player.Team, out var gloveId) || gloveId == 0) return; - WeaponInfo weaponInfo = GPlayerWeaponsInfo[player.Slot][gloveInfo]; + WeaponInfo weaponInfo = GPlayerWeaponsInfo[player.Slot][player.Team][gloveId]; - item.ItemDefinitionIndex = gloveInfo; + item.ItemDefinitionIndex = gloveId; item.ItemIDLow = 16384 & 0xFFFFFFFF; item.ItemIDHigh = 16384; @@ -472,21 +473,24 @@ namespace WeaponPaints private static void GivePlayerMusicKit(CCSPlayerController player) { - if (!GPlayersMusic.TryGetValue(player.Slot, out var value)) return; + if (GPlayersMusic.TryGetValue(player.Slot, out var musicInfo) || musicInfo == null || + !musicInfo.TryGetValue(player.Team, out var musicId) || musicId == 0) return; + if (player.InventoryServices == null) return; - player.InventoryServices.MusicID = value; + player.InventoryServices.MusicID = musicId; Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices"); - player.MusicKitID = value; + player.MusicKitID = musicId; Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID"); } private static void GivePlayerPin(CCSPlayerController player) { - if (!GPlayersPin.TryGetValue(player.Slot, out var pin)) return; + if (!GPlayersPin.TryGetValue(player.Slot, out var pinInfo) || + !pinInfo.TryGetValue(player.Team, out var pinId)) return; if (player.InventoryServices == null) return; - player.InventoryServices.Rank[5] = pin > 0 ? (MedalRank_t)pin : MedalRank_t.MEDAL_RANK_NONE; + player.InventoryServices.Rank[5] = pinId > 0 ? (MedalRank_t)pinId : MedalRank_t.MEDAL_RANK_NONE; Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices"); } diff --git a/WeaponPaints.cs b/WeaponPaints.cs index 9c05255c..524f4d3c 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -16,7 +16,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig "Nereziel & daffyy"; public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based"; public override string ModuleName => "WeaponPaints"; - public override string ModuleVersion => "2.8c"; + public override string ModuleVersion => "2.9a"; public override void Load(bool hotReload) { @@ -25,19 +25,20 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig(Utilities.GetPlayers().TakeWhile(player => WeaponSync != null)) + .OfType(Utilities.GetPlayers().TakeWhile(_ => WeaponSync != null)) .Where(player => player.IsValid && !string.IsNullOrEmpty(player.IpAddress) && player is { IsBot: false, Connected: PlayerConnectedState.PlayerConnected })) { - GPlayerWeaponsInfo.TryRemove(player.Slot, out _); - GPlayersKnife.TryRemove(player.Slot, out _); - GPlayersGlove.TryRemove(player.Slot, out _); - GPlayersAgent.TryRemove(player.Slot, out _); - GPlayersPin.TryRemove(player.Slot, out _); - var playerInfo = new PlayerInfo { UserId = player.UserId, diff --git a/WeaponSynchronization.cs b/WeaponSynchronization.cs index 81c04f8f..40960d69 100644 --- a/WeaponSynchronization.cs +++ b/WeaponSynchronization.cs @@ -1,439 +1,626 @@ using Dapper; using MySqlConnector; using System.Collections.Concurrent; +using CounterStrikeSharp.API.Modules.Utils; -namespace WeaponPaints +namespace WeaponPaints; + +internal class WeaponSynchronization { - internal class WeaponSynchronization + private readonly WeaponPaintsConfig _config; + private readonly Database _database; + + internal WeaponSynchronization(Database database, WeaponPaintsConfig config) { - private readonly WeaponPaintsConfig _config; - private readonly Database _database; + _database = database; + _config = config; + } - internal WeaponSynchronization(Database database, WeaponPaintsConfig config) + internal async Task GetPlayerData(PlayerInfo? player) + { + try { - _database = database; - _config = config; + await using var connection = await _database.GetConnectionAsync(); + + if (_config.Additional.KnifeEnabled) + GetKnifeFromDatabase(player, connection); + if (_config.Additional.GloveEnabled) + GetGloveFromDatabase(player, connection); + if (_config.Additional.AgentEnabled) + GetAgentFromDatabase(player, connection); + if (_config.Additional.MusicEnabled) + GetMusicFromDatabase(player, connection); + if (_config.Additional.SkinEnabled) + GetWeaponPaintsFromDatabase(player, connection); + if (_config.Additional.PinsEnabled) + GetPinsFromDatabase(player, connection); } - - internal async Task GetPlayerData(PlayerInfo? player) + catch (Exception ex) { - try - { - await using var connection = await _database.GetConnectionAsync(); - - if (_config.Additional.KnifeEnabled) - GetKnifeFromDatabase(player, connection); - if (_config.Additional.GloveEnabled) - GetGloveFromDatabase(player, connection); - if (_config.Additional.AgentEnabled) - GetAgentFromDatabase(player, connection); - if (_config.Additional.MusicEnabled) - GetMusicFromDatabase(player, connection); - if (_config.Additional.SkinEnabled) - GetWeaponPaintsFromDatabase(player, connection); - if (_config.Additional.PinsEnabled) - GetPinsFromDatabase(player, connection); - } - catch (Exception ex) - { - // Log the exception or handle it appropriately - Console.WriteLine($"An error occurred: {ex.Message}"); - } + // Log the exception or handle it appropriately + Console.WriteLine($"An error occurred: {ex.Message}"); } + } - private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try { - try - { - if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId)) - return; - - const string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid"; - var playerKnife = connection.QueryFirstOrDefault(query, new { steamid = player.SteamId }); - - if (!string.IsNullOrEmpty(playerKnife)) - { - WeaponPaints.GPlayersKnife[player.Slot] = playerKnife; - } - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}"); - } - } - - private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection) - { - try - { - if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId)) - return; - - const string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid"; - var gloveData = connection.QueryFirstOrDefault(query, new { steamid = player.SteamId }); - - if (gloveData != null) - { - WeaponPaints.GPlayersGlove[player.Slot] = gloveData.Value; - } - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}"); - } - } - - private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection) - { - try - { - if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId)) - return; - - const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; - var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId }); - - if (agentData == default) return; - var agentCT = agentData.Item1; - var agentT = agentData.Item2; - - if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT)) - { - WeaponPaints.GPlayersAgent[player.Slot] = ( - agentCT, - agentT - ); - } - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}"); - } - } - - private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection) - { - try - { - if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) - return; - - var weaponInfos = new ConcurrentDictionary(); - - const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid"; - var playerSkins = connection.Query(query, new { steamid = player.SteamId }); - - foreach (var row in playerSkins) - { - int weaponDefIndex = row?.weapon_defindex ?? 0; - int weaponPaintId = row?.weapon_paint_id ?? 0; - float weaponWear = row?.weapon_wear ?? 0f; - int weaponSeed = row?.weapon_seed ?? 0; - string weaponNameTag = row?.weapon_nametag ?? ""; - bool weaponStatTrak = row?.weapon_stattrak ?? false; - int weaponStatTrakCount = row?.weapon_stattrak_count ?? 0; - - string[]? keyChainParts = row?.weapon_keychain?.ToString().Split(';'); - - KeyChainInfo keyChainInfo = new KeyChainInfo(); - - if (keyChainParts!.Length == 5 && - uint.TryParse(keyChainParts[0], out uint keyChainId) && - float.TryParse(keyChainParts[1], out float keyChainOffsetX) && - float.TryParse(keyChainParts[2], out float keyChainOffsetY) && - float.TryParse(keyChainParts[3], out float keyChainOffsetZ) && - uint.TryParse(keyChainParts[4], out uint keyChainSeed)) - { - // Successfully parsed the values - keyChainInfo.Id = keyChainId; - keyChainInfo.OffsetX = keyChainOffsetX; - keyChainInfo.OffsetY = keyChainOffsetY; - keyChainInfo.OffsetZ = keyChainOffsetZ; - keyChainInfo.Seed = keyChainSeed; - } - else - { - // Failed to parse the values, default to 0 - keyChainInfo.Id = 0; - keyChainInfo.OffsetX = 0f; - keyChainInfo.OffsetY = 0f; - keyChainInfo.OffsetZ = 0f; - keyChainInfo.Seed = 0; - } - - // Create the WeaponInfo object - WeaponInfo weaponInfo = new WeaponInfo - { - Paint = weaponPaintId, - Seed = weaponSeed, - Wear = weaponWear, - Nametag = weaponNameTag, - KeyChain = keyChainInfo, - StatTrak = weaponStatTrak, - StatTrakCount = weaponStatTrakCount, - }; - - // Retrieve and parse sticker data (up to 5 slots) - for (int i = 0; i <= 4; i++) - { - // Access the sticker data dynamically using reflection - string stickerColumn = $"weapon_sticker_{i}"; - var stickerData = ((IDictionary)row!)[stickerColumn]; // Safely cast row to a dictionary - - if (string.IsNullOrEmpty(stickerData.ToString())) continue; - - var parts = stickerData.ToString()!.Split(';'); - - //"id;schema;x;y;wear;scale;rotation" - if (parts.Length != 7 || - !uint.TryParse(parts[0], out uint stickerId) || - !uint.TryParse(parts[1], out uint stickerSchema) || - !float.TryParse(parts[2], out float stickerOffsetX) || - !float.TryParse(parts[3], out float stickerOffsetY) || - !float.TryParse(parts[4], out float stickerWear) || - !float.TryParse(parts[5], out float stickerScale) || - !float.TryParse(parts[6], out float stickerRotation)) continue; - - StickerInfo stickerInfo = new StickerInfo - { - Id = stickerId, - Schema = stickerSchema, - OffsetX = stickerOffsetX, - OffsetY = stickerOffsetY, - Wear = stickerWear, - Scale = stickerScale, - Rotation = stickerRotation - }; - - weaponInfo.Stickers.Add(stickerInfo); - } - - weaponInfos[weaponDefIndex] = weaponInfo; - } - - WeaponPaints.GPlayerWeaponsInfo[player.Slot] = weaponInfos; - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}"); - } - } - - private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection) - { - try - { - if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId)) - return; - - const string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid"; - var musicData = connection.QueryFirstOrDefault(query, new { steamid = player.SteamId }); - - if (musicData != null) - { - WeaponPaints.GPlayersMusic[player.Slot] = musicData.Value; - } - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}"); - } - } - - private void GetPinsFromDatabase(PlayerInfo? player, MySqlConnection connection) - { - try - { - if (string.IsNullOrEmpty(player?.SteamId)) - return; - - const string query = "SELECT `id` FROM `wp_player_pins` WHERE `steamid` = @steamid"; - var pinData = connection.QueryFirstOrDefault(query, new { steamid = player.SteamId }); - - if (pinData != null) - { - WeaponPaints.GPlayersPin[player.Slot] = pinData.Value; - } - } - catch (Exception ex) - { - Utility.Log($"An error occurred in GetPinsFromDatabase: {ex.Message}"); - } - } - - internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife) - { - if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return; - - const string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; - - try - { - await using var connection = await _database.GetConnectionAsync(); - await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife }); - } - catch (Exception e) - { - Utility.Log($"Error syncing knife to database: {e.Message}"); - } - } - - internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex) - { - if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId)) return; - - try - { - await using var connection = await _database.GetConnectionAsync(); - const string query = "INSERT INTO `wp_player_gloves` (`steamid`, `weapon_defindex`) VALUES(@steamid, @weapon_defindex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex"; - await connection.ExecuteAsync(query, new { steamid = player.SteamId, weapon_defindex = defindex }); - } - catch (Exception e) - { - Utility.Log($"Error syncing glove to database: {e.Message}"); - } - } - - internal async Task SyncAgentToDatabase(PlayerInfo player) - { - if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return; - - const string query = """ - INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`) - VALUES(@steamid, @agent_ct, @agent_t) - ON DUPLICATE KEY UPDATE - `agent_ct` = @agent_ct, - `agent_t` = @agent_t - """; - try - { - await using var connection = await _database.GetConnectionAsync(); - - await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T }); - } - catch (Exception e) - { - Utility.Log($"Error syncing agents to database: {e.Message}"); - } - } - - internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player) - { - if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo)) + if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId)) return; - try - { - await using var connection = await _database.GetConnectionAsync(); + const string query = "SELECT `knife`, `weapon_team` FROM `wp_player_knife` WHERE `steamid` = @steamid"; + var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player + foreach (var row in rows) + { + // Check if knife is null or empty + if (string.IsNullOrEmpty(row.knife)) continue; + + // Determine the weapon team based on the query result + CsTeam weaponTeam = (int)row.weapon_team switch + { + 0 => CsTeam.None, + 2 => CsTeam.Terrorist, + _ => CsTeam.CounterTerrorist + }; + + // Get or create entries for the player’s slot + var playerKnives = WeaponPaints.GPlayersKnife.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); + + if (weaponTeam == CsTeam.None) + { + // Assign knife to both teams if weaponTeam is None + playerKnives[CsTeam.Terrorist] = row.knife; + playerKnives[CsTeam.CounterTerrorist] = row.knife; + } + else + { + // Assign knife to the specific team + playerKnives[weaponTeam] = row.knife; + } + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}"); + } + } + + private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try + { + if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId)) + return; + + const string query = "SELECT `weapon_defindex`, `weapon_team` FROM `wp_player_gloves` WHERE `steamid` = @steamid"; + var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player + + foreach (var row in rows) + { + // Check if weapon_defindex is null + if (row.weapon_defindex == null) continue; + // Determine the weapon team based on the query result + var playerGloves = WeaponPaints.GPlayersGlove.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); + CsTeam weaponTeam = (int)row.weapon_team switch + { + 0 => CsTeam.None, + 2 => CsTeam.Terrorist, + _ => CsTeam.CounterTerrorist + }; + + // Get or create entries for the player’s slot + + if (weaponTeam == CsTeam.None) + { + // Assign glove ID to both teams if weaponTeam is None + playerGloves[CsTeam.Terrorist] = (ushort)row.weapon_defindex; + playerGloves[CsTeam.CounterTerrorist] = (ushort)row.weapon_defindex; + } + else + { + // Assign glove ID to the specific team + playerGloves[weaponTeam] = (ushort)row.weapon_defindex; + } + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetGlovesFromDatabase: {ex.Message}"); + } + } + + private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try + { + if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId)) + return; + + const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; + var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId }); + + if (agentData == default) return; + var agentCT = agentData.Item1; + var agentT = agentData.Item2; + + if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT)) + { + WeaponPaints.GPlayersAgent[player.Slot] = ( + agentCT, + agentT + ); + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}"); + } + } + + private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try + { + if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) + return; + + var playerWeapons = WeaponPaints.GPlayerWeaponsInfo.GetOrAdd(player.Slot, + _ => new ConcurrentDictionary>()); + + // var weaponInfos = new ConcurrentDictionary(); + + const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid"; + var playerSkins = connection.Query(query, new { steamid = player.SteamId }); + + foreach (var row in playerSkins) + { + int weaponDefIndex = row?.weapon_defindex ?? 0; + int weaponPaintId = row?.weapon_paint_id ?? 0; + float weaponWear = row?.weapon_wear ?? 0f; + int weaponSeed = row?.weapon_seed ?? 0; + string weaponNameTag = row?.weapon_nametag ?? ""; + bool weaponStatTrak = row?.weapon_stattrak ?? false; + int weaponStatTrakCount = row?.weapon_stattrak_count ?? 0; + + CsTeam weaponTeam = row?.weapon_team switch + { + null => CsTeam.None, + 0 => CsTeam.None, + 2 => CsTeam.Terrorist, + _ => CsTeam.CounterTerrorist + }; + + string[]? keyChainParts = row?.weapon_keychain?.ToString().Split(';'); + + KeyChainInfo keyChainInfo = new KeyChainInfo(); + + if (keyChainParts!.Length == 5 && + uint.TryParse(keyChainParts[0], out uint keyChainId) && + float.TryParse(keyChainParts[1], out float keyChainOffsetX) && + float.TryParse(keyChainParts[2], out float keyChainOffsetY) && + float.TryParse(keyChainParts[3], out float keyChainOffsetZ) && + uint.TryParse(keyChainParts[4], out uint keyChainSeed)) + { + // Successfully parsed the values + keyChainInfo.Id = keyChainId; + keyChainInfo.OffsetX = keyChainOffsetX; + keyChainInfo.OffsetY = keyChainOffsetY; + keyChainInfo.OffsetZ = keyChainOffsetZ; + keyChainInfo.Seed = keyChainSeed; + } + else + { + // Failed to parse the values, default to 0 + keyChainInfo.Id = 0; + keyChainInfo.OffsetX = 0f; + keyChainInfo.OffsetY = 0f; + keyChainInfo.OffsetZ = 0f; + keyChainInfo.Seed = 0; + } + + // Create the WeaponInfo object + WeaponInfo weaponInfo = new WeaponInfo + { + Paint = weaponPaintId, + Seed = weaponSeed, + Wear = weaponWear, + Nametag = weaponNameTag, + KeyChain = keyChainInfo, + StatTrak = weaponStatTrak, + StatTrakCount = weaponStatTrakCount, + }; + + // Retrieve and parse sticker data (up to 5 slots) + for (int i = 0; i <= 4; i++) + { + // Access the sticker data dynamically using reflection + string stickerColumn = $"weapon_sticker_{i}"; + var stickerData = ((IDictionary)row!)[stickerColumn]; // Safely cast row to a dictionary + + if (string.IsNullOrEmpty(stickerData.ToString())) continue; + + var parts = stickerData.ToString()!.Split(';'); + + //"id;schema;x;y;wear;scale;rotation" + if (parts.Length != 7 || + !uint.TryParse(parts[0], out uint stickerId) || + !uint.TryParse(parts[1], out uint stickerSchema) || + !float.TryParse(parts[2], out float stickerOffsetX) || + !float.TryParse(parts[3], out float stickerOffsetY) || + !float.TryParse(parts[4], out float stickerWear) || + !float.TryParse(parts[5], out float stickerScale) || + !float.TryParse(parts[6], out float stickerRotation)) continue; + + StickerInfo stickerInfo = new StickerInfo + { + Id = stickerId, + Schema = stickerSchema, + OffsetX = stickerOffsetX, + OffsetY = stickerOffsetY, + Wear = stickerWear, + Scale = stickerScale, + Rotation = stickerRotation + }; + + weaponInfo.Stickers.Add(stickerInfo); + } + + if (weaponTeam == CsTeam.None) + { + // Get or create entries for both teams + var terroristWeapons = playerWeapons.GetOrAdd(CsTeam.Terrorist, _ => new ConcurrentDictionary()); + var counterTerroristWeapons = playerWeapons.GetOrAdd(CsTeam.CounterTerrorist, _ => new ConcurrentDictionary()); + + // Add weaponInfo to both team weapon dictionaries + terroristWeapons[weaponDefIndex] = weaponInfo; + counterTerroristWeapons[weaponDefIndex] = weaponInfo; + } + else + { + // Add to the specific team + var teamWeapons = playerWeapons.GetOrAdd(weaponTeam, _ => new ConcurrentDictionary()); + teamWeapons[weaponDefIndex] = weaponInfo; + } + + // weaponInfos[weaponDefIndex] = weaponInfo; + } + + // WeaponPaints.GPlayerWeaponsInfo[player.Slot][weaponTeam] = weaponInfos; + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}"); + } + } + + private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try + { + if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId)) + return; + + const string query = "SELECT `music_id`, `weapon_team` FROM `wp_player_music` WHERE `steamid` = @steamid"; + var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player + + foreach (var row in rows) + { + // Check if music_id is null + if (row.music_id == null) continue; + + // Determine the weapon team based on the query result + CsTeam weaponTeam = (int)row.weapon_team switch + { + 0 => CsTeam.None, + 2 => CsTeam.Terrorist, + _ => CsTeam.CounterTerrorist + }; + + // Get or create entries for the player’s slot + var playerMusic = WeaponPaints.GPlayersMusic.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); + + if (weaponTeam == CsTeam.None) + { + // Assign music ID to both teams if weaponTeam is None + playerMusic[CsTeam.Terrorist] = row.music_id.Value; + playerMusic[CsTeam.CounterTerrorist] = row.music_id.Value; + } + else + { + // Assign music ID to the specific team + playerMusic[weaponTeam] = row.music_id.Value; + } + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}"); + } + } + + private void GetPinsFromDatabase(PlayerInfo? player, MySqlConnection connection) + { + try + { + if (string.IsNullOrEmpty(player?.SteamId)) + return; + + const string query = "SELECT `id`, `weapon_team` FROM `wp_player_pins` WHERE `steamid` = @steamid"; + var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player + + foreach (var row in rows) + { + // Check if id is null + if (row.id == null) continue; + + // Determine the weapon team based on the query result + CsTeam weaponTeam = (int)row.weapon_team switch + { + 0 => CsTeam.None, + 2 => CsTeam.Terrorist, + _ => CsTeam.CounterTerrorist + }; + + // Get or create entries for the player’s slot + var playerPins = WeaponPaints.GPlayersPin.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); + + if (weaponTeam == CsTeam.None) + { + // Assign pin ID to both teams if weaponTeam is None + playerPins[CsTeam.Terrorist] = (ushort)row.id; + playerPins[CsTeam.CounterTerrorist] = (ushort)row.id; + } + else + { + // Assign pin ID to the specific team + playerPins[weaponTeam] = (ushort)row.id; + } + } + } + catch (Exception ex) + { + Utility.Log($"An error occurred in GetPinsFromDatabase: {ex.Message}"); + } + } + + internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife, CsTeam[] teams) + { + if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife) || teams.Length == 0) return; + + const string query = "INSERT INTO `wp_player_knife` (`steamid`, `weapon_team`, `knife`) VALUES(@steamid, @team, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; + + try + { + await using var connection = await _database.GetConnectionAsync(); + + // Loop through each team and insert/update accordingly + foreach (var team in teams) + { + await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newKnife = knife }); + } + } + catch (Exception e) + { + Utility.Log($"Error syncing knife to database: {e.Message}"); + } + } + + internal async Task SyncGloveToDatabase(PlayerInfo player, ushort gloveDefIndex, CsTeam[] teams) + { + // Check if the necessary conditions are met + if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId) || teams.Length == 0) + return; + + const string query = @" + INSERT INTO `wp_player_gloves` (`steamid`, `weapon_team`, `weapon_defindex`) + VALUES(@steamid, @team, @gloveDefIndex) + ON DUPLICATE KEY UPDATE `weapon_defindex` = @gloveDefIndex"; + + try + { + // Get a database connection + await using var connection = await _database.GetConnectionAsync(); + + // Loop through each team and insert/update accordingly + foreach (var team in teams) + { + // Execute the SQL command for each team + await connection.ExecuteAsync(query, new { + steamid = player.SteamId, + team = (int)team, // Cast the CsTeam enum to int for insertion + gloveDefIndex + }); + } + } + catch (Exception e) + { + // Log any exceptions that occur + Utility.Log($"Error syncing glove to database: {e.Message}"); + } + } + + internal async Task SyncAgentToDatabase(PlayerInfo player) + { + if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return; + + const string query = """ + INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`) + VALUES(@steamid, @agent_ct, @agent_t) + ON DUPLICATE KEY UPDATE + `agent_ct` = @agent_ct, + `agent_t` = @agent_t + """; + try + { + await using var connection = await _database.GetConnectionAsync(); + + await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T }); + } + catch (Exception e) + { + Utility.Log($"Error syncing agents to database: {e.Message}"); + } + } + + internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player) + { + if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var teamWeaponInfos)) + return; + + try + { + await using var connection = await _database.GetConnectionAsync(); + + // Loop through each team (Terrorist and CounterTerrorist) + foreach (var (teamId, weaponsInfo) in teamWeaponInfos) + { foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo) { var paintId = weaponInfo.Paint; var wear = weaponInfo.Wear; var seed = weaponInfo.Seed; - const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; - - var existingRecordCount = await connection.ExecuteScalarAsync(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex }); + // Prepare the queries to check and update/insert weapon skin data + const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; + + var existingRecordCount = await connection.ExecuteScalarAsync( + queryCheckExistence, + new { steamid = player.SteamId, weaponDefIndex, weaponTeam = teamId } + ); string query; object parameters; if (existingRecordCount > 0) { - query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; - parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed }; + // Update existing record + query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed " + + "WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; + parameters = new { steamid = player.SteamId, weaponDefIndex, weaponTeam = (int)teamId, paintId, wear, seed }; } else { - query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + - "VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed)"; - parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed }; + // Insert new record + query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_team`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + + "VALUES (@steamid, @weaponDefIndex, @weaponTeam, @paintId, @wear, @seed)"; + parameters = new { steamid = player.SteamId, weaponDefIndex, weaponTeam = (int)teamId, paintId, wear, seed }; } await connection.ExecuteAsync(query, parameters); } } - catch (Exception e) - { - Utility.Log($"Error syncing weapon paints to database: {e.Message}"); - } } - - internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music) + catch (Exception e) { - if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return; - - try - { - await using var connection = await _database.GetConnectionAsync(); - const string query = "INSERT INTO `wp_player_music` (`steamid`, `music_id`) VALUES(@steamid, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; - await connection.ExecuteAsync(query, new { steamid = player.SteamId, newMusic = music }); - } - catch (Exception e) - { - Utility.Log($"Error syncing music kit to database: {e.Message}"); - } - } - - internal async Task SyncPinToDatabase(PlayerInfo player, ushort pin) - { - if (!_config.Additional.PinsEnabled || string.IsNullOrEmpty(player.SteamId)) return; - - try - { - await using var connection = await _database.GetConnectionAsync(); - const string query = "INSERT INTO `wp_player_pins` (`steamid`, `id`) VALUES(@steamid, @newPin) ON DUPLICATE KEY UPDATE `id` = @newPin"; - await connection.ExecuteAsync(query, new { steamid = player.SteamId, newPin = pin }); - } - catch (Exception e) - { - Utility.Log($"Error syncing pin to database: {e.Message}"); - } - } - - internal async Task SyncStatTrakToDatabase(PlayerInfo player, ConcurrentDictionary weaponInfos) - { - if (WeaponPaints.WeaponSync == null || weaponInfos.IsEmpty) return; - - var statTrakWeapons = weaponInfos - .Where(w => w.Value is { StatTrak: true, StatTrakCount: > 0 }) - .ToDictionary(w => w.Key, w => w.Value.StatTrakCount); - - if (statTrakWeapons.Count == 0) return; - - if (string.IsNullOrEmpty(player.SteamId)) - return; - - try - { - await using var connection = await _database.GetConnectionAsync(); - await using var transaction = await connection.BeginTransactionAsync(); - - foreach (var (defindex, statTrakCount) in statTrakWeapons) - { - const string query = @" - INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_stattrak_count`) - VALUES (@steamid, @weaponDefIndex, @StatTrakCount) - ON DUPLICATE KEY UPDATE `weapon_stattrak_count` = @StatTrakCount"; - - var parameters = new - { - steamid = player.SteamId, - weaponDefIndex = defindex, - StatTrakCount = statTrakCount - }; - - await connection.ExecuteAsync(query, parameters, transaction); - } - - await transaction.CommitAsync(); - } - catch (Exception e) - { - Utility.Log($"Error syncing stattrak to database: {e.Message}"); - } + Utility.Log($"Error syncing weapon paints to database: {e.Message}"); } } + + internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music, CsTeam[] teams) + { + if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return; + + const string query = "INSERT INTO `wp_player_music` (`steamid`, `weapon_team`, `music_id`) VALUES(@steamid, @team, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; + + try + { + await using var connection = await _database.GetConnectionAsync(); + + // Loop through each team and insert/update accordingly + foreach (var team in teams) + { + await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newMusic = music }); + } + } + catch (Exception e) + { + Utility.Log($"Error syncing music kit to database: {e.Message}"); + } + } + + internal async Task SyncPinToDatabase(PlayerInfo player, ushort pin, CsTeam[] teams) + { + if (!_config.Additional.PinsEnabled || string.IsNullOrEmpty(player.SteamId)) return; + + const string query = "INSERT INTO `wp_player_pins` (`steamid`, `weapon_team`, `id`) VALUES(@steamid, @team, @newPin) ON DUPLICATE KEY UPDATE `id` = @newPin"; + + try + { + await using var connection = await _database.GetConnectionAsync(); + + // Loop through each team and insert/update accordingly + foreach (var team in teams) + { + await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newPin = pin }); + } + } + catch (Exception e) + { + Utility.Log($"Error syncing pin to database: {e.Message}"); + } + } + + internal async Task SyncStatTrakToDatabase(PlayerInfo player) + { + if (WeaponPaints.WeaponSync == null || WeaponPaints.GPlayerWeaponsInfo.IsEmpty) return; + + if (string.IsNullOrEmpty(player.SteamId)) + return; + + try + { + await using var connection = await _database.GetConnectionAsync(); + await using var transaction = await connection.BeginTransactionAsync(); + + // Check if player's slot exists in GPlayerWeaponsInfo + if (!WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var teamWeaponsInfo)) + return; + + // Iterate through each team in the player's weapon info + foreach (var teamInfo in teamWeaponsInfo) + { + // Retrieve weaponInfos for the current team + var weaponInfos = teamInfo.Value; + + // Get StatTrak weapons for the current team + var statTrakWeapons = weaponInfos + .Where(w => w.Value is { StatTrak: true, StatTrakCount: > 0 }) + .ToDictionary(w => w.Key, w => w.Value.StatTrakCount); + + // Check if there are StatTrak weapons to sync + if (statTrakWeapons.Count == 0) continue; + + // Get the current team ID + int weaponTeam = (int)teamInfo.Key; + + // Sync StatTrak values for the current team + foreach (var (defindex, statTrakCount) in statTrakWeapons) + { + const string query = @" + INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_stattrak_count`, `weapon_team`) + VALUES (@steamid, @weaponDefIndex, @StatTrakCount, @weaponTeam) + ON DUPLICATE KEY UPDATE `weapon_stattrak_count` = @StatTrakCount"; + + var parameters = new + { + steamid = player.SteamId, + weaponDefIndex = defindex, + StatTrakCount = statTrakCount, + weaponTeam + }; + + await connection.ExecuteAsync(query, parameters, transaction); + } + } + + await transaction.CommitAsync(); + } + catch (Exception e) + { + Utility.Log($"Error syncing stattrak to database: {e.Message}"); + } + } } \ No newline at end of file