From 8cf175d3369d9ceba74164a038092335aee878af Mon Sep 17 00:00:00 2001 From: Dawid Bepierszcz <41084667+daffyyyy@users.noreply.github.com> Date: Mon, 4 Mar 2024 21:47:54 +0100 Subject: [PATCH] 2.0a - New knife method - Minor commands changes - Remove OnTick event - Changed save place - New skins saving method - New gamedata file **IMPORTANT UPDATE** --- Commands.cs | 18 ++- Config.cs | 5 +- Events.cs | 300 ++++++++++++++++++------------------- README.md | 2 - VERSION | 2 +- WeaponAction.cs | 227 ++++++++++++++++++---------- WeaponPaints.cs | 4 +- WeaponPaints.csproj | 6 +- WeaponSynchronization.cs | 21 ++- gamedata/gloves.json | 16 -- gamedata/weaponpaints.json | 23 +++ 11 files changed, 353 insertions(+), 271 deletions(-) delete mode 100644 gamedata/gloves.json create mode 100644 gamedata/weaponpaints.json diff --git a/Commands.cs b/Commands.cs index f14d51fa..216d44a9 100644 --- a/Commands.cs +++ b/Commands.cs @@ -217,7 +217,6 @@ namespace WeaponPaints )?.ToList(); var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]); - skinSubMenu.PostSelectAction = PostSelectAction.Close; // Function to handle skin selection for the chosen weapon var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) => @@ -234,8 +233,9 @@ namespace WeaponPaints return false; }); + string selectedSkin = opt.Text; - string selectedPaintID = selectedSkin.Split('(')[1].Trim(')').Trim(); + string selectedPaintID = selectedSkin.Substring(selectedSkin.LastIndexOf('(') + 1).Trim(')'); if (firstSkin != null && firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) && @@ -263,21 +263,31 @@ namespace WeaponPaints } gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Paint = paintID; - gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.00f; + gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.01f; gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Seed = 0; PlayerInfo playerInfo = new PlayerInfo { UserId = p.UserId, + Slot = p.Slot, Index = (int)p.Index, SteamId = p.SteamID.ToString(), Name = p.PlayerName, IpAddress = p.IpAddress?.Split(":")[0] }; - if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE) + if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && weaponSync != null) { RefreshWeapons(player); + + try + { + Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo)); + } + catch (Exception ex) + { + Utility.Log($"Error syncing weapon paints: {ex.Message}"); + } } } }; diff --git a/Config.cs b/Config.cs index 159b6f4d..cc127c43 100644 --- a/Config.cs +++ b/Config.cs @@ -5,9 +5,6 @@ namespace WeaponPaints { public class Additional { - [JsonPropertyName("SkinVisibilityFix")] - public bool SkinVisibilityFix { get; set; } = true; - [JsonPropertyName("KnifeEnabled")] public bool KnifeEnabled { get; set; } = true; @@ -56,7 +53,7 @@ namespace WeaponPaints public class WeaponPaintsConfig : BasePluginConfig { - public override int Version { get; set; } = 4; + public override int Version { get; set; } = 5; [JsonPropertyName("DatabaseHost")] public string DatabaseHost { get; set; } = ""; diff --git a/Events.cs b/Events.cs index eab19e78..72575b61 100644 --- a/Events.cs +++ b/Events.cs @@ -1,6 +1,8 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; namespace WeaponPaints { @@ -73,110 +75,156 @@ namespace WeaponPaints IpAddress = player.IpAddress?.Split(":")[0] }; - if (weaponSync != null) + if (Config.Additional.SkinEnabled) { - Task.Run(async () => - { - try - { - await weaponSync.SyncWeaponPaintsToDatabase(playerInfo); - } - catch (Exception ex) - { - Utility.Log($"Error syncing weapon paints: {ex.Message}"); - } - - if (Config.Additional.SkinEnabled) - { - gPlayerWeaponsInfo.TryRemove(player.Slot, out _); - } - if (Config.Additional.KnifeEnabled) - { - g_playersKnife.TryRemove(player.Slot, out _); - } - if (Config.Additional.GloveEnabled) - { - g_playersGlove.TryRemove(player.Slot, out _); - } - }); + gPlayerWeaponsInfo.TryRemove(player.Slot, out _); + } + if (Config.Additional.KnifeEnabled) + { + g_playersKnife.TryRemove(player.Slot, out _); + } + if (Config.Additional.GloveEnabled) + { + g_playersGlove.TryRemove(player.Slot, out _); } - // Remove player's command cooldown commandsCooldown.Remove(player.Slot); return HookResult.Continue; } - private void OnEntityCreated(CEntityInstance entity) + private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon) { if (!Config.Additional.SkinEnabled) return; - if (entity == null || !entity.IsValid || string.IsNullOrEmpty(entity.DesignerName)) return; - string designerName = entity.DesignerName; - if (!weaponList.ContainsKey(designerName)) return; - bool isKnife = false; - var weapon = new CBasePlayerWeapon(entity.Handle); - if (designerName.Contains("knife") || designerName.Contains("bayonet")) - { - isKnife = true; - } + if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return; - Server.NextFrame(() => + if (!gPlayerWeaponsInfo.ContainsKey(player.Slot)) return; + + bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet"); + + if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return; + + if (isKnife) { - try + var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]); + if (newDefIndex.Key == 0) return; + + if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key) { - if (!weapon.IsValid) return; - if (weapon.OwnerEntity.Value == null) return; - if (weapon.OwnerEntity.Index <= 0) return; - int weaponOwner = (int)weapon.OwnerEntity.Index; - CBasePlayerPawn? pawn = Utilities.GetEntityFromIndex(weaponOwner); - if (!pawn.IsValid) return; - - var playerIndex = (int)pawn.Controller.Index; - var player = Utilities.GetPlayerFromIndex(playerIndex); - if (!Utility.IsPlayerValid(player)) return; - - ChangeWeaponAttributes(weapon, player, isKnife); + SubclassChange(weapon, (ushort)newDefIndex.Key); } - catch (Exception) { } - }); - } - public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay) - { - if (!Config.Additional.GiveKnifeAfterRemove) - return HookResult.Continue; - - CCSPlayerController? player = Utilities.GetEntityFromIndex((int)activator.Index).OriginalController.Value; - - if (player == null || player.IsBot || player.PlayerPawn == null || !player.PlayerPawn.IsValid || !player.PawnIsAlive || - player.SteamID.ToString().Length != 17 || !g_knifePickupCount.TryGetValue(player.Slot, out var pickupCount) || - !g_playersKnife.ContainsKey(player.Slot)) - { - return HookResult.Continue; + weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key; + weapon.AttributeManager.Item.EntityQuality = 3; } - CBasePlayerWeapon weapon = new(caller.Handle); + int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; + int fallbackPaintKit = 0; - if (weapon.AttributeManager.Item.ItemDefinitionIndex != 42 && weapon.AttributeManager.Item.ItemDefinitionIndex != 59) + if (_config.Additional.GiveRandomSkin && + !gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) { - return HookResult.Continue; + // Random skins + weapon.AttributeManager.Item.ItemID = 16384; + weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF; + weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32; + weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); + weapon.FallbackSeed = 0; + weapon.FallbackWear = 0.000001f; + CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); + + fallbackPaintKit = weapon.FallbackPaintKit; + + if (fallbackPaintKit == 0) + return; + + var foundSkin = skinsList.FirstOrDefault(skin => + ((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex && + ((int?)skin?["paint"] ?? 0) == fallbackPaintKit && + skin?["paint_name"] != null + ); + + if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) + { + var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); + + int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 }; + + if (newPaints.Contains(fallbackPaintKit)) + { + skeleton.ModelState.MeshGroupMask = 1; + } + else + { + if (skeleton.ModelState.MeshGroupMask != 2) + { + skeleton.ModelState.MeshGroupMask = 2; + } + } + } + + var viewModels = GetPlayerViewModels(player); + if (viewModels == null || viewModels.Length == 0) + return; + + var viewModel = viewModels[0]; + if (viewModel == null || viewModel.Value == null || viewModel.Value.Weapon == null || viewModel.Value.Weapon.Value == null) + return; + + Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent"); + + return; } - if (pickupCount >= 2) + if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) return; + WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][weaponDefIndex]; + //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 = weaponInfo.Paint; + weapon.FallbackSeed = weaponInfo.Seed; + weapon.FallbackWear = weaponInfo.Wear; + CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); + + fallbackPaintKit = weapon.FallbackPaintKit; + + if (fallbackPaintKit == 0) + return; + + var foundSkin1 = skinsList.FirstOrDefault(skin => + ((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex && + ((int?)skin?["paint"] ?? 0) == fallbackPaintKit && + skin?["paint_name"] != null + ); + + if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) { - return HookResult.Continue; + var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); + int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 }; + if (newPaints.Contains(fallbackPaintKit)) + { + skeleton.ModelState.MeshGroupMask = 1; + } + else + { + if (skeleton.ModelState.MeshGroupMask != 2) + { + skeleton.ModelState.MeshGroupMask = 2; + } + } } - if (g_playersKnife[player.Slot] != "weapon_knife") - { - pickupCount++; - g_knifePickupCount[player.Slot] = pickupCount; + var viewModels1 = GetPlayerViewModels(player); + if (viewModels1 == null || viewModels1.Length == 0) + return; - AddTimer(0.2f, () => RefreshWeapons(player)); - } + var viewModel1 = viewModels1[0]; + if (viewModel1 == null || viewModel1.Value == null || viewModel1.Value.Weapon == null || viewModel1.Value.Weapon.Value == null) + return; - return HookResult.Continue; + Utilities.SetStateChanged(viewModel1.Value, "CBaseEntity", "m_CBodyComponent"); } private void OnMapStart(string mapName) @@ -186,14 +234,18 @@ namespace WeaponPaints if (_database != null) weaponSync = new WeaponSynchronization(_database, Config); - // TODO + // needed for now + /* AddTimer(2.0f, () => { + NativeAPI.IssueServerCommand("mp_t_default_melee \"\""); NativeAPI.IssueServerCommand("mp_ct_default_melee \"\""); - NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0"); + + //NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0"); }); + */ } private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) @@ -210,8 +262,8 @@ namespace WeaponPaints g_knifePickupCount[player.Slot] = 0; - if (!PlayerHasKnife(player)) - GiveKnifeToPlayer(player); + //if (!PlayerHasKnife(player)) + //GiveKnifeToPlayer(player); Server.NextFrame(() => { @@ -230,101 +282,41 @@ namespace WeaponPaints private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) { + /* NativeAPI.IssueServerCommand("mp_t_default_melee \"\""); NativeAPI.IssueServerCommand("mp_ct_default_melee \"\""); NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0"); - + */ g_bCommandsAllowed = true; return HookResult.Continue; } - private void OnTick() + public HookResult OnGiveNamedItemPost(DynamicHook hook) { - foreach (var player in Utilities.GetPlayers().Where(p => - p is not null && p.IsValid && p.PlayerPawn != null && p.PlayerPawn.IsValid && - (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && p.SteamID.ToString().Length == 17 - && !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected - ) - ) - { - try - { - if (Config.Additional.ShowSkinImage && PlayerWeaponImage.ContainsKey(player.Slot) && !string.IsNullOrEmpty(PlayerWeaponImage[player.Slot])) - { - player.PrintToCenterHtml("".Replace("{PATH}", PlayerWeaponImage[player.Slot])); - } + var itemServices = hook.GetParam(0); + var weapon = hook.GetReturn(0); + if (!weapon.DesignerName.Contains("weapon")) + return HookResult.Continue; - if (player.PlayerPawn?.IsValid != true || player.PlayerPawn?.Value?.IsValid != true) - continue; + var player = GetPlayerFromItemServices(itemServices); + if (player != null) + GivePlayerWeaponSkin(player, weapon); - var viewModels = GetPlayerViewModels(player); - if (viewModels == null || viewModels.Length == 0) - continue; - - var viewModel = viewModels[0]; - if (viewModel == null || viewModel.Value == null || viewModel.Value.Weapon == null || viewModel.Value.Weapon.Value == null) - continue; - - var weapon = viewModel.Value.Weapon.Value; - if (weapon == null || !weapon.IsValid || weapon.FallbackPaintKit == 0) - continue; - - if (viewModel.Value.VMName.Contains("knife")) - continue; - - var sceneNode = viewModel.Value.CBodyComponent?.SceneNode; - if (sceneNode == null) - continue; - - var skeleton = GetSkeletonInstance(sceneNode); - if (skeleton == null) - continue; - - bool skeletonChange = false; - - int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 }; - if (newPaints.Contains(weapon.FallbackPaintKit)) - { - if (skeleton.ModelState.MeshGroupMask != 1) - { - skeleton.ModelState.MeshGroupMask = 1; - skeletonChange = true; - } - } - else - { - if (skeleton.ModelState.MeshGroupMask != 2) - { - skeleton.ModelState.MeshGroupMask = 2; - skeletonChange = true; - } - } - - if (skeletonChange) - Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent"); - } - catch (Exception) - { - } - } + return HookResult.Continue; } private void RegisterListeners() { - RegisterListener(OnEntityCreated); - //RegisterListener(OnClientPutInServer); - //RegisterListener(OnClientDisconnect); RegisterListener(OnMapStart); - //RegisterListener(OnTick); RegisterEventHandler(OnPlayerSpawn); RegisterEventHandler(OnRoundStart, HookMode.Pre); RegisterEventHandler(OnRoundEnd); - //RegisterEventHandler(OnItemPickup); + VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post); - HookEntityOutput("weapon_knife", "OnPlayerPickup", OnPickup); + //HookEntityOutput("weapon_knife", "OnPlayerPickup", OnPickup); } } } \ No newline at end of file diff --git a/README.md b/README.md index e1f1c414..3fd41c9c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin - Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)*** - Added command **`!ws`** to show website - Added command **`!knife`** to show menu with knives -- Knife change is now limited to have these cvars empty **`mp_t_default_melee ""`** and **`mp_ct_default_melee ""`** - Translations support, submit a PR if you want to share your translation ## CS2 Server @@ -52,7 +51,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin "SkinMenuTitle": "Select skin for {WEAPON}" // Menu title (!skins menu, after weapon select) }, "Additional": { - "SkinVisibilityFix": true, // Enable or disable fix for skin visibility "KnifeEnabled": true, // Enable or disable knife feature "SkinEnabled": true, // Enable or disable skin feature "CommandWpEnabled": true, // Enable or disable refreshing command diff --git a/VERSION b/VERSION index 09ebd8d1..e2861cd4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.9c \ No newline at end of file +2.0a \ No newline at end of file diff --git a/WeaponAction.cs b/WeaponAction.cs index 27bda95d..4aafc462 100644 --- a/WeaponAction.cs +++ b/WeaponAction.cs @@ -18,14 +18,22 @@ namespace WeaponPaints if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return; - int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; - if (isKnife) { + 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); + } + + weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key; weapon.AttributeManager.Item.EntityQuality = 3; } - int fallbackPaintKit = weapon.FallbackPaintKit; + int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; + int fallbackPaintKit = 0; if (_config.Additional.GiveRandomSkin && !gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) @@ -37,6 +45,7 @@ namespace WeaponPaints weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); weapon.FallbackSeed = 0; weapon.FallbackWear = 0.000001f; + CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); fallbackPaintKit = weapon.FallbackPaintKit; @@ -48,11 +57,11 @@ namespace WeaponPaints ((int?)skin?["paint"] ?? 0) == fallbackPaintKit && skin?["paint_name"] != null ); - - string skinName = foundSkin?["paint_name"]?.ToString() ?? ""; - if (!string.IsNullOrEmpty(skinName)) - new SchemaString(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName); - + /* + string skinName = foundSkin?["paint_name"]?.ToString() ?? ""; + if (!string.IsNullOrEmpty(skinName)) + new SchemaString(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName); + */ if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) { var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); @@ -94,6 +103,7 @@ namespace WeaponPaints weapon.FallbackPaintKit = weaponInfo.Paint; weapon.FallbackSeed = weaponInfo.Seed; weapon.FallbackWear = weaponInfo.Wear; + CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); fallbackPaintKit = weapon.FallbackPaintKit; @@ -106,10 +116,11 @@ namespace WeaponPaints skin?["paint_name"] != null ); + /* var skinName1 = foundSkin1?["paint_name"]?.ToString() ?? ""; if (!string.IsNullOrEmpty(skinName1)) new SchemaString(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName1); - + */ if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) { var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); @@ -142,36 +153,33 @@ namespace WeaponPaints { if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return; - Instance.AddTimer(1.0f, () => + if (PlayerHasKnife(player)) return; + + string knifeToGive; + if (g_playersKnife.TryGetValue(player.Slot, out var knife)) { - if (PlayerHasKnife(player)) return; + knifeToGive = knife; + } + else if (_config.Additional.GiveRandomKnife) + { + var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList(); - string knifeToGive; - if (g_playersKnife.TryGetValue(player.Slot, out var knife)) + if (knifeTypes.Count == 0) { - knifeToGive = knife; - } - else if (_config.Additional.GiveRandomKnife) - { - var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList(); - - if (knifeTypes.Count == 0) - { - Utility.Log("No valid knife types found."); - return; - } - - Random random = new(); - int index = random.Next(knifeTypes.Count); - knifeToGive = knifeTypes[index].Key; - } - else - { - knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife"; + Utility.Log("No valid knife types found."); + return; } - player.GiveNamedItem(knifeToGive); - }); + Random random = new(); + int index = random.Next(knifeTypes.Count); + knifeToGive = knifeTypes[index].Key; + } + else + { + knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife"; + } + + player.GiveNamedItem(knifeToGive); } internal static bool PlayerHasKnife(CCSPlayerController? player) @@ -203,6 +211,7 @@ namespace WeaponPaints internal void RefreshWeapons(CCSPlayerController? player) { + if (!g_bCommandsAllowed) return; if (player == null || !player.IsValid || player.PlayerPawn?.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return; if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) @@ -215,6 +224,8 @@ namespace WeaponPaints if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator) return; + int playerTeam = player.TeamNum; + //Dictionary weaponsWithAmmo = new Dictionary(); Dictionary> weaponsWithAmmo = new Dictionary>(); @@ -257,6 +268,10 @@ namespace WeaponPaints } weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo)); + + if (gun == null || gun.VData == null) return; + + weapon.Value.Remove(); } } catch (Exception ex) @@ -266,45 +281,55 @@ namespace WeaponPaints } } - for (int i = 1; i <= 3; i++) + try { - player.ExecuteClientCommand($"slot {i}"); - player.ExecuteClientCommand($"slot {i}"); + player.ExecuteClientCommand("slot 3"); + player.ExecuteClientCommand("slot 3"); - AddTimer(0.2f, () => + var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon; + if (weapon is null || !weapon.IsValid || weapon.Value == null) return; + CCSWeaponBaseVData? weaponData = weapon.Value.As().VData; + + if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) { - var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value; + CCSWeaponBaseGun gun = weapon.Value.As(); - if (weapon is null || !weapon.IsValid) return; - - CCSWeaponBaseGun gun = weapon.As(); - - if (gun == null || gun.VData == null) return; - - if (gun.VData.GearSlot == gear_slot_t.GEAR_SLOT_C4 || gun.VData.GearSlot == gear_slot_t.GEAR_SLOT_GRENADES) return; - - player.DropActiveWeapon(); - - AddTimer(0.25f, () => + AddTimer(0.3f, () => { - if (gun != null && gun.IsValid && gun.State == CSWeaponState_t.WEAPON_NOT_CARRIED) + if (player.TeamNum != playerTeam) return; + + player.ExecuteClientCommand("slot 3"); + gun = weapon.Value.As(); + player.DropActiveWeapon(); + + AddTimer(0.7f, () => { - weapon?.Remove(); - } + if (player.TeamNum != playerTeam) return; + + if (gun == null || !gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return; + + gun.Remove(); + }); + + GiveKnifeToPlayer(player); }); - }); + } + } + catch (Exception ex) + { + Logger.LogWarning($"Cannot remove knife: {ex.Message}"); } - AddTimer(1.2f, () => - { - GiveKnifeToPlayer(player); - - foreach (var entry in weaponsWithAmmo) - { - foreach (var ammo in entry.Value) + AddTimer(0.6f, () => { - var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key)); - Server.NextFrame(() => + if (!g_bCommandsAllowed) return; + + foreach (var entry in weaponsWithAmmo) + { + foreach (var ammo in entry.Value) + { + var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key)); + Server.NextFrame(() => { try { @@ -319,13 +344,16 @@ namespace WeaponPaints Logger.LogWarning("Error setting weapon properties: " + ex.Message); } }); - } - } - }, TimerFlags.STOP_ON_MAPCHANGE); + } + } + + }, TimerFlags.STOP_ON_MAPCHANGE); } + /* internal void RefreshKnife(CCSPlayerController? player) { + return; if (player == null || !player.IsValid || player.PlayerPawn?.Value == null) return; @@ -335,30 +363,45 @@ namespace WeaponPaints var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; if (weapons != null && weapons.Count > 0) { + try + { + player.ExecuteClientCommand("slot 3"); + player.ExecuteClientCommand("slot 3"); + + var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon; + if (weapon is null || !weapon.IsValid || weapon.Value == null) return; + CCSWeaponBaseVData? weaponData = weapon.Value.As().VData; + + if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) + { + AddTimer(0.2f, () => + { + player.ExecuteClientCommand("slot 3"); + player.DropActiveWeapon(); + + AddTimer(0.6f, () => + { + if (weapon.IsValid) + weapon.Value.Remove(); + GiveKnifeToPlayer(player); + }); + }); + } + } + catch (Exception ex) + { + Logger.LogWarning($"Cannot remove knife: {ex.Message}"); + } + return; foreach (var weapon in weapons) { if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid && weapon.Index > 0) { - try - { - CCSWeaponBaseVData? weaponData = weapon.Value.As().VData; - - if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) - { - player.ExecuteClientCommand("slot 3"); - - weapon.Value.Remove(); - GiveKnifeToPlayer(player); - } - } - catch (Exception ex) - { - Logger.LogWarning($"Cannot remove knife: {ex.Message}"); - } } } } } + */ private static void RefreshGloves(CCSPlayerController player) { @@ -432,6 +475,24 @@ namespace WeaponPaints return 0; } + public static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD) + { + var SubclassChangeFunc = VirtualFunction.Create( + GameData.GetSignature("ChangeSubclass") + ); + + SubclassChangeFunc(weapon.Handle, itemD.ToString()); + } + + public static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices) + { + var pawn = itemServices.Pawn.Value; + if (pawn == null || !pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null; + var player = new CCSPlayerController(pawn.Controller.Value.Handle); + if (!Utility.IsPlayerValid(player)) return null; + return player; + } + private static CSkeletonInstance GetSkeletonInstance(CGameSceneNode node) { Func GetSkeletonInstance = VirtualFunction.Create(node.Handle, 8); @@ -448,7 +509,7 @@ namespace WeaponPaints public static unsafe T[] GetFixedArray(nint pointer, string @class, string member, int length) where T : CHandle { nint ptr = pointer + Schema.GetSchemaOffset(@class, member); - Span references = MemoryMarshal.CreateSpan(ref ptr, length); + Span references = MemoryMarshal.CreateSpan(ref ptr, length); T[] values = new T[length]; for (int i = 0; i < length; i++) diff --git a/WeaponPaints.cs b/WeaponPaints.cs index 758bcad1..e5111f46 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -10,7 +10,7 @@ using System.Collections.Concurrent; namespace WeaponPaints; -[MinimumApiVersion(168)] +[MinimumApiVersion(178)] public partial class WeaponPaints : BasePlugin, IPluginConfig { internal static WeaponPaints Instance { get; private set; } = new(); @@ -156,7 +156,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig "Nereziel & daffyy"; public override string ModuleDescription => "Skin, gloves and knife selector, standalone and web-based"; public override string ModuleName => "WeaponPaints"; - public override string ModuleVersion => "1.9c"; + public override string ModuleVersion => "2.0a"; public static WeaponPaintsConfig GetWeaponPaintsConfig() { diff --git a/WeaponPaints.csproj b/WeaponPaints.csproj index 487d7fca..d5a83a91 100644 --- a/WeaponPaints.csproj +++ b/WeaponPaints.csproj @@ -9,7 +9,7 @@ - + @@ -18,4 +18,8 @@ + + + + diff --git a/WeaponSynchronization.cs b/WeaponSynchronization.cs index 7fcf3871..a619ee4e 100644 --- a/WeaponSynchronization.cs +++ b/WeaponSynchronization.cs @@ -149,11 +149,24 @@ namespace WeaponPaints float wear = weaponInfo.Wear; int seed = weaponInfo.Seed; - string query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + - "VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed) " + - "ON DUPLICATE KEY UPDATE `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed"; + string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; + + int existingRecordCount = await connection.ExecuteScalarAsync(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex }); + + 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, 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, paintId, wear, seed }; + } - var parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed }; await connection.ExecuteAsync(query, parameters); } } diff --git a/gamedata/gloves.json b/gamedata/gloves.json deleted file mode 100644 index 043048b1..00000000 --- a/gamedata/gloves.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "CAttributeList_SetOrAddAttributeValueByName": { - "signatures": { - "library": "server", - "windows": "\\x40\\x53\\x41\\x56\\x41\\x57\\x48\\x81\\xEC\\x90\\x00\\x00\\x00\\x0F\\x29\\x74\\x24\\x70", - "linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78" - } - }, - "CBaseModelEntity_SetBodygroup": { - "signatures": { - "library": "server", - "windows": "\\x48\\x89\\x5C\\x24\\x08\\x48\\x89\\x74\\x24\\x10\\x57\\x48\\x83\\xEC\\x20\\x41\\x8B\\xF8\\x48\\x8B\\xF2\\x48\\x8B\\xD9\\xE8\\x2A\\x2A\\x2A\\x2A", - "linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08" - } - } -} \ No newline at end of file diff --git a/gamedata/weaponpaints.json b/gamedata/weaponpaints.json new file mode 100644 index 00000000..e9422f6a --- /dev/null +++ b/gamedata/weaponpaints.json @@ -0,0 +1,23 @@ +{ + "ChangeSubclass": { + "signatures": { + "library": "server", + "windows": "\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x20\\x48\\x8B\\xDA\\x48\\x8B\\xF9\\xE8\\x2A\\x2A\\x2A\\x2A\\x84\\xC0\\x74\\x2A\\x41\\xB0\\x01", + "linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x49\\x89\\xF5\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x81\\xEC\\xA8\\x00\\x00\\x00" + } + }, + "CAttributeList_SetOrAddAttributeValueByName": { + "signatures": { + "library": "server", + "windows": "\\x40\\x53\\x41\\x56\\x41\\x57\\x48\\x81\\xEC\\x90\\x00\\x00\\x00\\x0F\\x29\\x74\\x24\\x70", + "linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78" + } + }, + "CBaseModelEntity_SetBodygroup": { + "signatures": { + "library": "server", + "windows": "\\x48\\x89\\x5C\\x24\\x08\\x48\\x89\\x74\\x24\\x10\\x57\\x48\\x83\\xEC\\x20\\x41\\x8B\\xF8\\x48\\x8B\\xF2\\x48\\x8B\\xD9\\xE8\\x2A\\x2A\\x2A\\x2A", + "linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08" + } + } +} \ No newline at end of file