From f000c13e513100b8cb17180f410c1fd475445285 Mon Sep 17 00:00:00 2001 From: Nereziel Date: Tue, 14 Nov 2023 16:24:30 +0100 Subject: [PATCH] kinder surprise --- WeaponPaints.cs | 232 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 201 insertions(+), 31 deletions(-) diff --git a/WeaponPaints.cs b/WeaponPaints.cs index 85b570b6..fb67cf21 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -4,9 +4,10 @@ using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Utils; using Nexd.MySQL; -using static CounterStrikeSharp.API.Core.Listeners; +using System.Runtime.ExceptionServices; namespace WeaponPaints; public class WeaponPaints : BasePlugin, IPluginConfig @@ -14,15 +15,18 @@ public class WeaponPaints : BasePlugin, IPluginConfig public override string ModuleName => "WeaponPaints"; public override string ModuleDescription => "Connector for web-based player chosen wepaon paints."; public override string ModuleAuthor => "Nereziel"; - public override string ModuleVersion => "0.7"; + public override string ModuleVersion => "0.8"; + public WeaponPaintsConfig Config { get; set; } = new(); MySqlDb? MySql = null; - public DateTime[] commandCooldown = new DateTime[Server.MaxPlayers]; - private Dictionary> gPlayerWeaponPaints = new Dictionary>(); - private Dictionary> gPlayerWeaponSeed = new Dictionary>(); - private Dictionary> gPlayerWeaponWear = new Dictionary>(); - private static Dictionary knifeTypes = new Dictionary() + private DateTime[] commandCooldown = new DateTime[Server.MaxPlayers]; + private static string PluginPrefix = $" {ChatColors.Green}[WeaponPaints]{ChatColors.White}"; + private Dictionary> gPlayerWeaponPaints = new(); + private Dictionary> gPlayerWeaponSeed = new(); + private Dictionary> gPlayerWeaponWear = new(); + private Dictionary g_playersKife = new(); + private static readonly Dictionary knifeTypes = new() { { "m9", "weapon_knife_m9_bayonet" }, { "karambit", "weapon_knife_karambit" }, @@ -45,7 +49,7 @@ public class WeaponPaints : BasePlugin, IPluginConfig { "skeleton", "weapon_knife_skeleton" }, { "default", "weapon_knife" } }; - private static List weaponList = new List() + private static readonly List weaponList = new() { "weapon_deagle", "weapon_elite", "weapon_fiveseven", "weapon_glock", "weapon_ak47", "weapon_aug", "weapon_awp", "weapon_famas", @@ -57,30 +61,82 @@ public class WeaponPaints : BasePlugin, IPluginConfig "weapon_sg556", "weapon_ssg08", "weapon_m4a1_silencer", "weapon_usp_silencer", "weapon_cz75a", "weapon_revolver", "weapon_bayonet", "weapon_knife" }; - public override void Load(bool hotReload) { - MySql = new MySqlDb(Config.DatabaseHost!, Config.DatabaseUser!, Config.DatabasePassword!, Config.DatabaseName!, Config.DatabasePort); + base.Load(hotReload); + SetGlobalExceptionHandler(); + MySql = new MySqlDb(Config.DatabaseHost, Config.DatabaseUser, Config.DatabasePassword, Config.DatabaseName!, Config.DatabasePort); RegisterListener(OnEntitySpawned); RegisterListener(OnClientAuthorized); RegisterListener(OnClientDisconnect); + RegisterListener(OnMapStart); + RegisterEventHandler(OnPlayerSpawn); + //RegisterEventHandler(OnRoundPreStart); + SetupMenus(); } public void OnConfigParsed(WeaponPaintsConfig config) { Config = config; } - private void OnClientAuthorized(int playerSlot, SteamID steamId) + // TODO: fix for map which change mp_t_default_melee + /*private HookResult OnRoundPreStart(EventRoundPrestart @event, GameEventInfo info) + { + NativeAPI.IssueServerCommand("mp_t_default_melee \"\""); + NativeAPI.IssueServerCommand("mp_ct_default_melee \"\""); + return HookResult.Continue; + } + */ + public override void Unload(bool hotReload) + { + RemoveGlobalExceptionHandler(); + base.Unload(hotReload); + } + private void GlobalExceptionHandler(object? sender, FirstChanceExceptionEventArgs @event) + { + Log(@event.Exception.ToString()); + } + private void SetGlobalExceptionHandler() + { + AppDomain.CurrentDomain.FirstChanceException += this.GlobalExceptionHandler; + } + private void RemoveGlobalExceptionHandler() + { + AppDomain.CurrentDomain.FirstChanceException -= this.GlobalExceptionHandler; + } + private void OnMapStart(string mapName) + { + // TODO + // needed for now + base.AddTimer(2.0f, () => { + NativeAPI.IssueServerCommand("mp_t_default_melee \"\""); + NativeAPI.IssueServerCommand("mp_ct_default_melee \"\""); + }); + } + private void OnClientAuthorized(int playerSlot, SteamID steamId) { - int slot = playerSlot; - Server.NextFrame(() => + int playerIndex = playerSlot + 1; + Task.Run(async () => { - Task.Run(() => GetWeaponPaintsFromDatabase(slot)); + await GetKnifeFromDatabase(playerIndex); + await GetWeaponPaintsFromDatabase(playerIndex); }); } private void OnClientDisconnect(int playerSlot) { - // Clean up after player + // TODO: Clean up after player + } + + private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) + { + var player = @event.Userid; + if (!player.IsValid || !player.PlayerPawn.IsValid || player.IsBot) + { + return HookResult.Continue; + } + if (!PlayerHasKnife(player)) player.GiveNamedItem(g_playersKife[(int)player.EntityIndex!.Value.Value]); + + return HookResult.Continue; } private void OnEntitySpawned(CEntityInstance entity) { @@ -88,6 +144,7 @@ private void OnEntitySpawned(CEntityInstance entity) if (!weaponList.Contains(designerName)) return; bool isKnife = false; var weapon = new CBasePlayerWeapon(entity.Handle); + if (designerName.Contains("knife") || designerName.Contains("bayonet")) { isKnife = true; @@ -103,11 +160,19 @@ private void OnEntitySpawned(CEntityInstance entity) var playerIndex = (int)pawn.Controller.Value.EntityIndex!.Value.Value; var player = Utilities.GetPlayerFromIndex(playerIndex); if (player == null || !player.IsValid || player.IsBot) return; + // TODO: Remove knife crashes here, needs another solution + /*if (isKnife && g_playersKife[(int)player.EntityIndex!.Value.Value] != "weapon_knife" && (weapon.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.AttributeManager.Item.ItemDefinitionIndex == 59)) + { + RemoveKnifeFromPlayer(player); + return; + }*/ var steamId = new SteamID(player.SteamID); if (!gPlayerWeaponPaints.ContainsKey(steamId.SteamId64)) return; if (!gPlayerWeaponPaints[steamId.SteamId64].ContainsKey(weapon.AttributeManager.Item.ItemDefinitionIndex)) return; - weapon.AttributeManager.Item.ItemIDLow = unchecked((uint)-1); - weapon.AttributeManager.Item.ItemIDHigh = unchecked((uint)-1); + //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]}"); + weapon.AttributeManager.Item.ItemID = 16384; + weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF; + weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32; weapon.FallbackPaintKit = gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]; weapon.FallbackSeed = gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]; weapon.FallbackWear = gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]; @@ -118,28 +183,82 @@ private void OnEntitySpawned(CEntityInstance entity) } }); } - [ConsoleCommand("css_ws", "weaponskins")] - public void OnCommandWS(CCSPlayerController? player, CommandInfo command) + public void RemoveKnifeFromPlayer(CCSPlayerController player) { - if (player == null) return; - player.PrintToChat($"Change weapon skins at {ChatColors.Purple}{Config.WebSite}"); - player.PrintToChat($"To synchronize weapon paints type {ChatColors.Purple}!wp"); + if (!player.PawnIsAlive) return; + var weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons; + foreach (var weapon in weapons) + { + if (weapon.IsValid && weapon.Value.IsValid) + { + //if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59) + if (weapon.Value.DesignerName.Contains("knife")) + { + weapon.Value.Remove(); + player.GiveNamedItem(g_playersKife[(int)player.EntityIndex!.Value.Value]); + break; + } + } + } + } + public static bool PlayerHasKnife(CCSPlayerController player) + { + if (!player.PawnIsAlive) return false; + var weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons; + foreach (var weapon in weapons) + { + if (weapon.IsValid && weapon.Value.IsValid) + { + if (weapon.Value.DesignerName.Contains("knife")) + { + return true; + } + } + } + return false; + } + private void SetupMenus() + { + var giveItemMenu = new ChatMenu("Knife Menu"); + var handleGive = (CCSPlayerController player, ChatMenuOption option) => + { + if (knifeTypes.TryGetValue(option.Text, out var knife)) + { + Task.Run(() => SyncKnifeToDatabase((int)player.EntityIndex!.Value.Value, knife)); + g_playersKife[(int)player.EntityIndex!.Value.Value] = knifeTypes[option.Text]; + player.PrintToChat($"You have chosen {option.Text} as your knife."); + RemoveKnifeFromPlayer(player); + } + }; + foreach (var knife in knifeTypes) + { + giveItemMenu.AddMenuOption(knife.Key, handleGive); + } + AddCommand("css_knife", "Knife Menu", (player, info) => { if (player == null) return; ChatMenus.OpenMenu(player, giveItemMenu); }); } [ConsoleCommand("css_wp", "refreshskins")] public void OnCommandRefresh(CCSPlayerController? player, CommandInfo command) { if (player == null) return; - int playerSlot = (int)player.EntityIndex!.Value.Value - 1; - if (DateTime.UtcNow >= commandCooldown[playerSlot].AddSeconds(Config.CmdRefreshCooldownSeconds)) + int playerIndex = (int)player.EntityIndex!.Value.Value; + if (DateTime.UtcNow >= commandCooldown[playerIndex].AddSeconds(Config.CmdRefreshCooldownSeconds)) { - commandCooldown[playerSlot] = DateTime.UtcNow; - Task.Run(async () => await GetWeaponPaintsFromDatabase(playerSlot)); - player.PrintToChat("Refreshed weapon paints."); + commandCooldown[playerIndex] = DateTime.UtcNow; + Task.Run(async () => await GetWeaponPaintsFromDatabase(playerIndex)); + player.PrintToChat($"{PluginPrefix} Refreshing weapon paints."); return; } - player.PrintToChat("You can't refresh weapon paints right now."); + player.PrintToChat($"{PluginPrefix} You can't refresh weapon paints right now."); + } + [ConsoleCommand("css_ws", "weaponskins")] + public void OnCommandWS(CCSPlayerController? player, CommandInfo command) + { + if (player == null) return; + player.PrintToChat($"{PluginPrefix} Visit {ChatColors.Purple}{Config.WebSite} {ChatColors.White}where you can change skins."); + player.PrintToChat($"{PluginPrefix} Type {ChatColors.Purple}!wp {ChatColors.White}in chat to synchronize chosen skins."); + player.PrintToChat($"{PluginPrefix} Type {ChatColors.Purple}!knife {ChatColors.White}in chat to open knife menu."); } - public CSkeletonInstance GetSkeletonInstance(CGameSceneNode node) + public static CSkeletonInstance GetSkeletonInstance(CGameSceneNode node) { Func GetSkeletonInstance = VirtualFunction.Create(node.Handle, 8); return new CSkeletonInstance(GetSkeletonInstance(node.Handle)); @@ -182,10 +301,61 @@ private async Task GetWeaponPaintsFromDatabase(int playerIndex) gPlayerWeaponSeed[steamId.SteamId64][WeaponDefIndex] = Seed; }); } + catch (Exception) + { + return; + } + } + private async Task GetKnifeFromDatabase(int playerIndex) + { + try + { + CCSPlayerController player = Utilities.GetPlayerFromIndex(playerIndex); + if (player == null || !player.IsValid) return; + var steamId = new SteamID(player.SteamID); + MySqlQueryCondition conditions = new MySqlQueryCondition() + .Add("steamid", "=", steamId.SteamId64.ToString()); + + MySqlQueryResult result = await MySql!.Table("wp_player_knife").Where(conditions).SelectAsync(); + + string knife = result.Get(0, "knife"); + if (knife != null) + { + g_playersKife[playerIndex] = knife; + } + else + { + g_playersKife[playerIndex] = "weapon_knife"; + } + //Log($"{player.PlayerName} has this knife -> {g_playersKife[playerIndex]}"); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + return; + } + } + private async Task SyncKnifeToDatabase(int playerIndex, string knife) + { + try + { + CCSPlayerController player = Utilities.GetPlayerFromIndex(playerIndex); + if (player == null || !player.IsValid) return; + var steamId = new SteamID(player.SteamID); + await MySql!.ExecuteNonQueryAsync($"INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES('{steamId.SteamId64}', '{knife}') ON DUPLICATE KEY UPDATE `knife` = '{knife}';"); + } catch (Exception ex) { - Console.WriteLine(ex); + Log(ex.Message); return; } } -} + + private static void Log(string message) + { + Console.BackgroundColor = ConsoleColor.DarkGray; + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(message); + Console.ResetColor(); + } +} \ No newline at end of file