From 2852623936e10c31a385192ec4b1c43871aa4717 Mon Sep 17 00:00:00 2001 From: originalaidn <45371311+originalaidn@users.noreply.github.com> Date: Fri, 18 Oct 2024 23:00:07 +0200 Subject: [PATCH] added pins and stattrak pins only from website / database: no command now stattrak enabling only from website / database: no command now --- Commands.cs | 4 +++ Config.cs | 3 +++ Events.cs | 51 +++++++++++++++++++++++++++++++++++ Utility.cs | 9 +++++++ Variables.cs | 1 + WeaponAction.cs | 33 +++++++++++++++++++++++ WeaponInfo.cs | 2 ++ WeaponPaints.cs | 1 + WeaponSynchronization.cs | 58 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 162 insertions(+) diff --git a/Commands.cs b/Commands.cs index ca1e5c67..47c2a8fc 100644 --- a/Commands.cs +++ b/Commands.cs @@ -37,6 +37,10 @@ namespace WeaponPaints GivePlayerGloves(player); RefreshWeapons(player); + GivePlayerAgent(player); + GivePlayerMusicKit(player); + AddTimer(0.1f, () => GivePlayerPin(player)); + AddTimer(0.15f, () => GivePlayerPin(player)); } if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"])) diff --git a/Config.cs b/Config.cs index 752c7c0f..a5ad70a3 100644 --- a/Config.cs +++ b/Config.cs @@ -20,6 +20,9 @@ namespace WeaponPaints [JsonPropertyName("SkinEnabled")] public bool SkinEnabled { get; set; } = true; + [JsonPropertyName("PinsEnabled")] + public bool PinsEnabled { get; set; } = true; + [JsonPropertyName("CommandWpEnabled")] public bool CommandWpEnabled { get; set; } = true; diff --git a/Events.cs b/Events.cs index 0da98ea6..049e154a 100644 --- a/Events.cs +++ b/Events.cs @@ -88,6 +88,10 @@ namespace WeaponPaints { GPlayersMusic.TryRemove(player.Slot, out _); } + if (Config.Additional.PinsEnabled) + { + GPlayersPin.TryRemove(player.Slot, out _); + } _temporaryPlayerWeaponWear.TryRemove(player.Slot, out _); @@ -231,6 +235,52 @@ namespace WeaponPaints return HookResult.Continue; } + private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) + { + CCSPlayerController? player = @event.Attacker; + + if (player is null || !player.IsValid) + return HookResult.Continue; + + if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return HookResult.Continue; + + CBasePlayerWeapon? weapon = player.PlayerPawn.Value?.WeaponServices?.ActiveWeapon.Value; + + if (weapon == null) return HookResult.Continue; + + int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; + + if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return HookResult.Continue; + + var weaponInfo = value; + + if (weaponInfo.StatTrak) + { + weaponInfo.StatTrakCount += 1; + + var playerInfo = new PlayerInfo + { + UserId = player.UserId, + Slot = player.Slot, + Index = (int)player.Index, + SteamId = player.SteamID.ToString(), + Name = player.PlayerName, + IpAddress = player.IpAddress?.Split(":")[0] + }; + + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater", ViewAsFloatKillStreak(weaponInfo.StatTrakCount)); + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater score type", 0); + + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater", ViewAsFloatKillStreak(weaponInfo.StatTrakCount)); + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater score type", 0); + + if (WeaponSync != null) + _ = Task.Run(async () => await WeaponSync.SyncStatTrakToDatabase(playerInfo, weaponInfo.StatTrakCount, weaponDefIndex)); + } + + return HookResult.Continue; + } + private void RegisterListeners() { RegisterListener(OnMapStart); @@ -239,6 +289,7 @@ namespace WeaponPaints RegisterEventHandler(OnRoundStart); RegisterEventHandler(OnRoundEnd); RegisterListener(OnEntityCreated); + RegisterEventHandler(OnPlayerDeath); if (Config.Additional.ShowSkinImage) RegisterListener(OnTick); diff --git a/Utility.cs b/Utility.cs index c66b4a6b..0a59459b 100644 --- a/Utility.cs +++ b/Utility.cs @@ -33,6 +33,8 @@ namespace WeaponPaints `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', @@ -68,6 +70,13 @@ namespace WeaponPaints 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 + """, ]; foreach (var query in createTableQueries) diff --git a/Variables.cs b/Variables.cs index 27422bf5..7df322a1 100644 --- a/Variables.cs +++ b/Variables.cs @@ -75,6 +75,7 @@ public partial class WeaponPaints 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 List SkinsList = []; diff --git a/WeaponAction.cs b/WeaponAction.cs index 369fd69d..d471fe00 100644 --- a/WeaponAction.cs +++ b/WeaponAction.cs @@ -87,6 +87,15 @@ namespace WeaponPaints weapon.FallbackWear = weaponInfo.Wear; CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); + if (weaponInfo.StatTrak) + { + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater", ViewAsFloatKillStreak(weaponInfo.StatTrakCount)); + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater score type", 0); + + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater", ViewAsFloatKillStreak(weaponInfo.StatTrakCount)); + CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater score type", 0); + } + fallbackPaintKit = weapon.FallbackPaintKit; if (fallbackPaintKit == 0) @@ -451,6 +460,19 @@ namespace WeaponPaints player.MusicKitID = value; Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID"); } + + private static void GivePlayerPin(CCSPlayerController player) + { + if (!GPlayersPin.TryGetValue(player.Slot, out var pin)) return; + + if (player.InventoryServices == null) return; + + for (var index = 0; index < player.InventoryServices.Rank.Length; index++) + { + player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)pin : MedalRank_t.MEDAL_RANK_NONE; + Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices"); + } + } private void GiveOnItemPickup(CCSPlayerController player) { @@ -514,5 +536,16 @@ namespace WeaponPaints { return BitConverter.Int32BitsToSingle((int)value); } + + public float ViewAsFloatKillStreak(T value) where T : struct + { + byte[] bytes = value switch + { + int intValue => BitConverter.GetBytes(intValue), + uint uintValue => BitConverter.GetBytes(uintValue), + _ => throw new ArgumentException("Unsupported type") + }; + return BitConverter.ToSingle(bytes, 0); + } } } \ No newline at end of file diff --git a/WeaponInfo.cs b/WeaponInfo.cs index ffdabfd7..7f89ebb3 100644 --- a/WeaponInfo.cs +++ b/WeaponInfo.cs @@ -6,6 +6,8 @@ public int Seed { get; set; } = 0; public float Wear { get; set; } = 0f; public string Nametag { get; set; } = ""; + public bool StatTrak { get; set; } = false; + public int StatTrakCount { get; set; } = 0; public KeyChainInfo? KeyChain { get; set; } public List Stickers { get; set; } = new List(); } diff --git a/WeaponPaints.cs b/WeaponPaints.cs index 544bdf3a..f9e75230 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -36,6 +36,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig(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; @@ -349,5 +372,40 @@ namespace WeaponPaints Utility.Log($"Error syncing music kit to database: {e.Message}"); } } + + internal async Task SyncStatTrakToDatabase(PlayerInfo player, int StatTrakCount, int defindex) + { + if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo)) + return; + + try + { + await using var connection = await _database.GetConnectionAsync(); + + 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 = defindex }); + + string query = string.Empty; + object? parameters = null; + + if (existingRecordCount > 0) + { + query = "UPDATE `wp_player_skins` SET `weapon_stattrak_count` = @StatTrakCount WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; + parameters = new { steamid = player.SteamId, weaponDefIndex = defindex, StatTrakCount }; + } + else + { + query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_stattrak_count`) VALUES (@steamid, @weaponDefIndex, @StatTrakCount)"; + parameters = new { steamid = player.SteamId, weaponDefIndex = defindex, StatTrakCount }; + } + + await connection.ExecuteAsync(query, parameters); + } + catch (Exception e) + { + Utility.Log($"Error syncing weapon paints to database: {e.Message}"); + } + } } } \ No newline at end of file