Compare commits

...

46 Commits

Author SHA1 Message Date
Nereziel
be4de02d50 Merge pull request #290 from rogeraabbccdd/dev
Some fixes and changes for dev branch.
2024-07-04 12:10:30 +02:00
rogeraabbccdd
52e4fd7195 Fixed pin not refreshed bug. 2024-07-03 00:59:04 +08:00
rogeraabbccdd
d7631c51b6 Fixed agent menu. 2024-07-03 00:51:35 +08:00
rogeraabbccdd
74aa5fa40c Fixed music kit menu. 2024-07-03 00:48:41 +08:00
rogeraabbccdd
2a1ef7b489 Fixed OnCommandRefresh conditions 2024-07-03 00:47:10 +08:00
rogeraabbccdd
a6f5eac440 Merge branch 'Nereziel/dev' into dev 2024-07-02 23:39:54 +08:00
Nereziel
deb18acb8f remove slot = 0 2024-07-02 17:35:26 +02:00
rogeraabbccdd
e6d935e16b Basic pin feature 2024-07-02 17:28:08 +08:00
rogeraabbccdd
c3d2209a13 Fix database queries 2024-07-02 17:24:41 +08:00
rogeraabbccdd
67b35d9117 !wp should also refresh music and agents 2024-07-01 13:58:27 +08:00
Dawid Bepierszcz
d102ac371b Merge pull request #277 from daffyyyy/dev
New, New, New
2024-06-12 09:53:09 +02:00
Dawid Bepierszcz
26a31d4bd7 New, new, new!
- Config changed
- Multiple commands (as i remember, wp command fucked now)
- Fixed tables
- Remove expired users
- CenterHtmlMenu - experimental
- Knife from string to defindex
2024-06-12 09:52:01 +02:00
Dawid Bepierszcz
4e9a4b2925 Merge pull request #276 from Nereziel/main
Gamedata
2024-06-10 10:33:23 +02:00
Dawid Bepierszcz
d6384f4ecf Merge pull request #270 from stefanx111/fix-sig
fix wildcard
2024-06-01 12:47:09 +02:00
StefanX
85fc0bd4bc fix wildcard 2024-06-01 13:44:33 +03:00
Dawid Bepierszcz
5c7df833cc Merge pull request #269 from stefanx111/fix-win
win sig mistake
2024-05-31 12:15:23 +02:00
StefanX
5640919b09 win sig mistake 2024-05-31 03:18:17 +03:00
Dawid Bepierszcz
0550ef68f4 Merge pull request #267 from stefanx111/sig-workground
sig workground
2024-05-31 01:08:58 +02:00
Dawid Bepierszcz
c0d42a3d9c Merge branch 'main' into sig-workground 2024-05-31 01:06:58 +02:00
StefanX
5636b401ea sig workground 2024-05-31 00:20:48 +03:00
Dawid Bepierszcz
06cfda21f2 Fix for gameupdate - linux only 2024-05-30 00:38:16 +02:00
Nereziel
c291005d4d next 2024-05-27 18:05:32 +02:00
Nereziel
322b1b425b part one 2024-05-26 19:28:36 +02:00
Dawid Bepierszcz
771a832ae8 Update weaponpaints.json 2024-05-25 20:58:48 +02:00
Dawid Bepierszcz
323c74b49c Merge pull request #261 from daffyyyy/main
2.5a
2024-05-25 15:32:04 +02:00
Dawid Bepierszcz
ee1dffa06b Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-05-25 15:30:49 +02:00
Dawid Bepierszcz
d90055ad89 2.5a
- Minor changes
- New gloves applied only on spawn (probably new cs2 update issue)
2024-05-25 15:30:47 +02:00
Dawid Bepierszcz
48854c4eaf Merge pull request #253 from daffyyyy/main
2.4e
2024-04-28 02:20:36 +02:00
Dawid Bepierszcz
c06f7ae3be Merge branch 'Nereziel:main' into main 2024-04-28 02:18:14 +02:00
Dawid Bepierszcz
29461e9de2 2.4e
- Minor changes
2024-04-28 02:17:24 +02:00
Dawid Bepierszcz
74ec584d9a Merge pull request #241 from daffyyyy/main
2.4d
2024-04-26 10:07:05 +02:00
Dawid Bepierszcz
ec0d4f4d5a 2.4d
- Updated for latest css
2024-04-26 10:02:32 +02:00
Dawid Bepierszcz
a8ba645292 Merge branch 'Nereziel:main' into main 2024-04-14 22:10:17 +02:00
Dawid Bepierszcz
e04dd312e8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-14 22:09:55 +02:00
Dawid Bepierszcz
702dea9450 2.4c
- Disable hooking giveitemfunc on windows (counterstrikesharp issue) (fix)
2024-04-14 22:09:53 +02:00
Dawid Bepierszcz
c594cd534e Merge pull request #237 from daffyyyy/main
2.4b
2024-04-08 21:31:43 +02:00
Dawid Bepierszcz
5aaf0e6f62 Merge branch 'Nereziel:main' into main 2024-04-08 21:30:46 +02:00
Dawid Bepierszcz
942e776688 2.4b
- Nothing big ;P
2024-04-08 21:30:22 +02:00
Dawid Bepierszcz
36046fee2d Merge pull request #231 from daffyyyy/main
2.4a
2024-04-03 01:35:07 +02:00
Dawid Bepierszcz
d6de0ce6c8 Merge branch 'Nereziel:main' into main 2024-04-03 01:33:52 +02:00
Dawid Bepierszcz
d2c19d8af8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-03 01:32:27 +02:00
Dawid Bepierszcz
0f6d334621 2.4a
- .NET8
- Mysql queries optimization
- CounterStrikeSharp updated
2024-04-03 01:32:24 +02:00
Dawid Bepierszcz
f99c9b2767 Merge pull request #226 from daffyyyy/main
2.3c
2024-03-27 23:20:43 +01:00
Dawid Bepierszcz
6a2d28c303 Merge branch 'Nereziel:main' into main 2024-03-27 23:19:42 +01:00
Dawid Bepierszcz
27a2ae5be9 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-27 23:19:26 +01:00
Dawid Bepierszcz
0af9177f07 2.3c
- Small change for mysql performance
2024-03-27 23:19:24 +01:00
29 changed files with 2173 additions and 1724 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
bin/ bin/
obj/ obj/
website/getskins.php website/getskins.php
.idea/

View File

@@ -1,4 +1,6 @@
using CounterStrikeSharp.API.Core; using System.Collections.Concurrent;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Menu;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -9,7 +11,7 @@ namespace WeaponPaints
{ {
private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command) private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command)
{ {
if (!Config.Additional.CommandWpEnabled || !Config.Additional.SkinEnabled || !g_bCommandsAllowed) return; if (Config.Additional.CommandsRefresh.Count == 0 || !Config.Additional.SkinEnabled || !g_bCommandsAllowed) return;
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return; if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return;
@@ -19,43 +21,28 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player?.SteamID.ToString(), SteamId = player.SteamID,
Name = player?.PlayerName, Name = player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0] IpAddress = player?.IpAddress?.Split(":")[0]
}; };
try try
{ {
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (player != null && !commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
if (weaponSync != null) if (weaponSync != null)
{ {
if (Config.Additional.SkinEnabled) _ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
{
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled)
{
_ = Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled)
{
_ = Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
}
if (Config.Additional.AgentEnabled)
{
_ = Task.Run(async () => await weaponSync.GetAgentFromDatabase(playerInfo));
}
if (Config.Additional.MusicEnabled)
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
RefreshGloves(player); GivePlayerGloves(player);
GivePlayerAgent(player);
GivePlayerMusicKit(player);
RefreshWeapons(player); RefreshWeapons(player);
AddTimer(0.1f, () => GivePlayerPin(player));
AddTimer(0.15f, () => GivePlayerPin(player));
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"])) if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"]))
@@ -104,7 +91,7 @@ namespace WeaponPaints
player!.Print(Localizer["wp_info_music"]); player!.Print(Localizer["wp_info_music"]);
} }
if (Config.Additional.KnifeEnabled) if (!Config.Additional.KnifeEnabled) return;
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"])) if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
{ {
player!.Print(Localizer["wp_info_knife"]); player!.Print(Localizer["wp_info_knife"]);
@@ -113,50 +100,58 @@ namespace WeaponPaints
private void RegisterCommands() private void RegisterCommands()
{ {
AddCommand($"css_{Config.Additional.CommandSkin}", "Skins info", (player, info) => Config.Additional.CommandsInfo.ForEach(c =>
{
AddCommand($"css_{c}", "Skins info", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
OnCommandWS(player, info); OnCommandWS(player, info);
}); });
AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) => });
Config.Additional.CommandsRefresh.ForEach(c =>
{
AddCommand($"css_{c}", "Skins refresh", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
OnCommandRefresh(player, info); OnCommandRefresh(player, info);
}); });
if (Config.Additional.CommandKillEnabled) });
Config.Additional.CommandsKill.ForEach(c =>
{ {
AddCommand($"css_{Config.Additional.CommandKill}", "kill yourself", (player, info) => AddCommand($"css_{c}", "kill yourself", (player, info) =>
{ {
if (player == null || !Utility.IsPlayerValid(player) || player.PlayerPawn.Value == null || !player!.PlayerPawn.IsValid) return; if (player == null || !Utility.IsPlayerValid(player) || player.PlayerPawn.Value == null || !player!.PlayerPawn.IsValid) return;
player.PlayerPawn.Value.CommitSuicide(true, false); player.PlayerPawn.Value.CommitSuicide(true, false);
}); });
} });
} }
private void SetupKnifeMenu() private void SetupKnifeMenu()
{ {
if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return; if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return;
var knivesOnly = weaponList var knivesOnly = WeaponList
.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")) .Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet"))
.ToDictionary(pair => pair.Key, pair => pair.Value); .ToDictionary(pair => pair.Key, pair => pair.Value);
var giveItemMenu = new ChatMenu(Localizer["wp_knife_menu_title"]); BaseMenu giveItemMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_knife_menu_title"], Instance) : new ChatMenu(Localizer["wp_knife_menu_title"]);
var handleGive = (CCSPlayerController player, ChatMenuOption option) => var handleGive = (CCSPlayerController player, ChatMenuOption option) =>
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
var knifeName = option.Text; var knifeName = option.Text;
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key; var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key;
if (!string.IsNullOrEmpty(knifeKey)) if (string.IsNullOrEmpty(knifeKey)) return;
{
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"])) if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"]))
{ {
player!.Print(Localizer["wp_knife_menu_select", knifeName]); player!.Print(Localizer["wp_knife_menu_select", knifeName]);
} }
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled) if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandsKill.Count > 0)
{ {
player!.Print(Localizer["wp_knife_menu_kill"]); player!.Print(Localizer["wp_knife_menu_kill"]);
} }
@@ -166,36 +161,45 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
g_playersKnife[player.Slot] = knifeKey; var knife = WeaponDefindex
.FirstOrDefault(entry => entry.Value.Equals(knifeKey, StringComparison.OrdinalIgnoreCase))
.Key;
g_playersKnife[player.Slot] = (ushort)knife;
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE) if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
RefreshWeapons(player); RefreshWeapons(player);
if (weaponSync != null) if (weaponSync == null) return;
_ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, knifeKey));
} _ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, (ushort)knife));
}; };
foreach (var knifePair in knivesOnly) foreach (var knifePair in knivesOnly)
{ {
giveItemMenu.AddMenuOption(knifePair.Value, handleGive); giveItemMenu.AddMenuOption(knifePair.Value, handleGive);
} }
AddCommand($"css_{Config.Additional.CommandKnife}", "Knife Menu", (player, info) =>
Config.Additional.CommandsKnife.ForEach(c =>
{
AddCommand($"css_{c}", "Knife Menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
giveItemMenu.PostSelectAction = PostSelectAction.Close; giveItemMenu.PostSelectAction = PostSelectAction.Close;
MenuManager.OpenChatMenu(player, giveItemMenu); giveItemMenu.Open(player);
//MenuManager.open(player, giveItemMenu);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
@@ -203,89 +207,87 @@ namespace WeaponPaints
player!.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
});
} }
private void SetupSkinsMenu() private void SetupSkinsMenu()
{ {
var classNamesByWeapon = weaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key); var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = new ChatMenu(Localizer["wp_skin_menu_weapon_title"]); BaseMenu weaponSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_weapon_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_weapon_title"]);
// Function to handle skin selection for a specific weapon // Function to handle skin selection for a specific weapon
var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) => var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
string selectedWeapon = option.Text; var selectedWeapon = option.Text;
if (classNamesByWeapon.TryGetValue(selectedWeapon, out string? selectedWeaponClassname)) if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return;
{
if (selectedWeaponClassname == null) return;
var skinsForSelectedWeapon = skinsList?.Where(skin => var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin != null &&
skin.TryGetValue("weapon_name", out var weaponName) && skin.TryGetValue("weapon_name", out var weaponName) &&
weaponName?.ToString() == selectedWeaponClassname weaponName?.ToString() == selectedWeaponClassname
)?.ToList(); )?.ToList();
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]); BaseMenu skinSubMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_skin_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_skin_title"]);
// Function to handle skin selection for the chosen weapon // Function to handle skin selection for the chosen weapon
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) => var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
{ {
if (!Utility.IsPlayerValid(p)) return; if (!Utility.IsPlayerValid(p)) return;
string steamId = p.SteamID.ToString(); var steamId = p.SteamID.ToString();
var firstSkin = skinsList?.FirstOrDefault(skin => var firstSkin = skinsList?.FirstOrDefault(skin =>
{ {
if (skin != null && skin.TryGetValue("weapon_name", out var weaponName)) if (skin.TryGetValue("weapon_name", out var weaponName))
{ {
return weaponName?.ToString() == selectedWeaponClassname; return weaponName?.ToString() == selectedWeaponClassname;
} }
return false; return false;
}); });
string selectedSkin = opt.Text; var selectedSkin = opt.Text;
string selectedPaintID = selectedSkin.Substring(selectedSkin.LastIndexOf('(') + 1).Trim(')'); var selectedPaintId = selectedSkin[(selectedSkin.LastIndexOf('(') + 1)..].Trim(')');
if (firstSkin != null && if (firstSkin == null ||
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) && !firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) ||
weaponDefIndexObj != null && !ushort.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) && !ushort.TryParse(selectedPaintId, out var paintId)) return;
int.TryParse(selectedPaintID, out var paintID))
{ {
if (Config.Additional.ShowSkinImage && skinsList != null) if (Config.Additional.ShowSkinImage && skinsList != null)
{ {
var foundSkin = skinsList.FirstOrDefault(skin => var foundSkin = skinsList.FirstOrDefault(skin =>
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex && ((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
((int?)skin?["paint"] ?? 0) == paintID && ((int?)skin?["paint"] ?? 0) == paintId &&
skin?["image"] != null skin?["image"] != null
); );
string image = foundSkin?["image"]?.ToString() ?? ""; var image = foundSkin?["image"]?.ToString() ?? "";
PlayerWeaponImage[p.Slot] = image; 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), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
} }
p.Print(Localizer["wp_skin_menu_select", selectedSkin]); p.Print(Localizer["wp_skin_menu_select", selectedSkin]);
if (!gPlayerWeaponsInfo[p.Slot].ContainsKey(weaponDefIndex)) if (!gPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out var value))
{ {
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = new WeaponInfo(); value = new WeaponInfo();
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
} }
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Paint = paintID; value.Paint = paintId;
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.01f; value.Wear = 0.01f;
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Seed = 0; value.Seed = 0;
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
{ {
UserId = p.UserId, UserId = p.UserId,
Slot = p.Slot, Slot = p.Slot,
Index = (int)p.Index, Index = (int)p.Index,
SteamId = p.SteamID.ToString(), SteamId = p.SteamID,
Name = p.PlayerName, Name = p.PlayerName,
IpAddress = p.IpAddress?.Split(":")[0] IpAddress = p.IpAddress?.Split(":")[0]
}; };
if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && weaponSync != null) if (!g_bCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
{ weaponSync == null) return;
RefreshWeapons(player); RefreshWeapons(player);
try try
@@ -297,16 +299,15 @@ namespace WeaponPaints
Utility.Log($"Error syncing weapon paints: {ex.Message}"); Utility.Log($"Error syncing weapon paints: {ex.Message}");
} }
} }
}
}; };
// Add skin options to the submenu for the selected weapon // Add skin options to the submenu for the selected weapon
if (skinsForSelectedWeapon != null) if (skinsForSelectedWeapon != null)
{ {
foreach (var skin in skinsForSelectedWeapon.Where(s => s != null)) foreach (var skin in skinsForSelectedWeapon)
{
if (skin.TryGetValue("paint_name", out var paintNameObj) && skin.TryGetValue("paint", out var paintObj))
{ {
if (!skin.TryGetValue("paint_name", out var paintNameObj) ||
!skin.TryGetValue("paint", out var paintObj)) continue;
var paintName = paintNameObj?.ToString(); var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString(); var paint = paintObj?.ToString();
@@ -316,30 +317,29 @@ namespace WeaponPaints
} }
} }
} }
}
if (player != null && Utility.IsPlayerValid(player)) if (player != null && Utility.IsPlayerValid(player))
MenuManager.OpenChatMenu(player, skinSubMenu); skinSubMenu.Open(player);
}
}; };
// Add weapon options to the weapon selection menu // Add weapon options to the weapon selection menu
foreach (var weaponClass in weaponList.Keys) foreach (var weaponName in WeaponList.Keys.Select(weaponClass => WeaponList[weaponClass]))
{ {
string weaponName = weaponList[weaponClass];
weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection); weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection);
} }
// Command to open the weapon selection menu for players // Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandSkinSelection}", "Skins selection menu", (player, info) => Config.Additional.CommandsSkinSelection.ForEach(c =>
{
AddCommand($"css_{c}", "Skins selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, weaponSelectionMenu); weaponSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
@@ -347,33 +347,28 @@ namespace WeaponPaints
player!.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
});
} }
private void SetupGlovesMenu() private void SetupGlovesMenu()
{ {
var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]); BaseMenu glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]);
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) => var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
if (!Utility.IsPlayerValid(player) || player is null) return; if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text; var selectedPaintName = option.Text;
var selectedGlove = glovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName); var selectedGlove = glovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName);
if (selectedGlove != null) var image = selectedGlove?["image"]?.ToString() ?? "";
{ if (selectedGlove == null ||
if ( !selectedGlove.ContainsKey("weapon_defindex") ||
selectedGlove != null && !selectedGlove.ContainsKey("paint") ||
selectedGlove.ContainsKey("weapon_defindex") && !int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out var weaponDefindex) ||
selectedGlove.ContainsKey("paint") && !int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return;
int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out int weaponDefindex) &&
int.TryParse(selectedGlove["paint"]?.ToString(), out int paint)
)
{
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
string image = selectedGlove["image"]?.ToString() ?? "";
PlayerWeaponImage[player.Slot] = image; 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), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
} }
@@ -383,7 +378,7 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
@@ -392,11 +387,20 @@ namespace WeaponPaints
{ {
g_playersGlove[player.Slot] = (ushort)weaponDefindex; g_playersGlove[player.Slot] = (ushort)weaponDefindex;
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex)) if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out var value))
{ {
WeaponInfo weaponInfo = new(); value = new ConcurrentDictionary<ushort, WeaponInfo>();
weaponInfo.Paint = paint;
gPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo; gPlayerWeaponsInfo[player.Slot] = value;
}
if (!value.ContainsKey((ushort)weaponDefindex))
{
WeaponInfo weaponInfo = new()
{
Paint = (ushort)paint
};
value[(ushort)weaponDefindex] = weaponInfo;
} }
} }
else else
@@ -409,52 +413,49 @@ namespace WeaponPaints
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]); player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
} }
if (weaponSync != null) if (weaponSync == null) return;
{
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex); await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out WeaponInfo? value)) if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue((ushort)weaponDefindex, out var value))
{ {
value = new WeaponInfo(); value = new WeaponInfo();
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value; gPlayerWeaponsInfo[playerInfo.Slot][(ushort)weaponDefindex] = value;
} }
value.Paint = paint; value.Paint = (ushort)paint;
value.Wear = 0.00f; value.Wear = 0.00f;
value.Seed = 0; value.Seed = 0;
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo); await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
}); });
}
RefreshGloves(player); AddTimer(0.1f, () => GivePlayerGloves(player));
} AddTimer(0.15f, () => GivePlayerGloves(player));
};
}; };
// Add weapon options to the weapon selection menu // Add weapon options to the weapon selection menu
foreach (var gloveObject in glovesList) foreach (var paintName in glovesList.Select(gloveObject => gloveObject["paint_name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{ {
string paintName = gloveObject["paint_name"]?.ToString() ?? "";
if (paintName.Length > 0)
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection); glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection);
} }
// Command to open the weapon selection menu for players // Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandGlove}", "Gloves selection menu", (player, info) => Config.Additional.CommandsGlove.ForEach(c =>
{
AddCommand($"css_{c}", "Gloves selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, glovesSelectionMenu); glovesSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
@@ -462,6 +463,7 @@ namespace WeaponPaints
player!.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
});
} }
private void SetupAgentsMenu() private void SetupAgentsMenu()
@@ -470,16 +472,15 @@ namespace WeaponPaints
{ {
if (!Utility.IsPlayerValid(player) || player is null) return; if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text; var selectedPaintName = option.Text;
var selectedAgent = agentsList.FirstOrDefault(g => var selectedAgent = agentsList.FirstOrDefault(g =>
g.ContainsKey("agent_name") && g.ContainsKey("agent_name") &&
g["agent_name"] != null && g["agent_name"]!.ToString() == selectedPaintName && g["agent_name"] != null && g["agent_name"]!.ToString().Contains(selectedPaintName) == true &&
g["team"] != null && (int)(g["team"]!) == player.TeamNum); g["team"] != null && (int)(g["team"]!) == player.TeamNum);
if (selectedAgent == null) return; if (selectedAgent == null) return;
if ( if (
selectedAgent != null &&
selectedAgent.ContainsKey("model") selectedAgent.ContainsKey("model")
) )
{ {
@@ -488,21 +489,21 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
string image = selectedAgent["image"]?.ToString() ?? ""; var image = selectedAgent["image"]?.ToString() ?? "";
PlayerWeaponImage[player.Slot] = image; 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), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
} }
if (!string.IsNullOrEmpty(Localizer["wp_agent_menu_select"])) if (!string.IsNullOrEmpty(Localizer["wp_agent_menu_select"]))
{ {
player!.Print(Localizer["wp_agent_menu_select", selectedPaintName]); player!.Print(Localizer["wp_agent_menu_select", selectedAgent?["agent_name"] ?? selectedPaintName]);
} }
if (player.TeamNum == 3) if (player.TeamNum == 3)
@@ -524,27 +525,29 @@ namespace WeaponPaints
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await weaponSync.SyncAgentToDatabase(playerInfo); await weaponSync.SyncAgentToDatabase(playerInfo);
GivePlayerAgent(player);
}); });
} }
}; };
}; };
// Command to open the weapon selection menu for players // Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandAgent}", "Agents selection menu", (player, info) => Config.Additional.CommandsAgent.ForEach(c =>
{
AddCommand($"css_{c}", "Agents selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
var agentsSelectionMenu = new ChatMenu(Localizer["wp_agent_menu_title"]); BaseMenu agentsSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_agent_menu_title"], Instance) : new ChatMenu(Localizer["wp_agent_menu_title"]);
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
var filteredAgents = agentsList.Where(agentObject => var filteredAgents = agentsList.Where(agentObject =>
{ {
if (agentObject["team"]?.Value<int>() is int teamNum) if (agentObject["team"]?.Value<int>() is { } teamNum)
{ {
return teamNum == player.TeamNum; return teamNum == player.TeamNum;
} }
@@ -558,14 +561,14 @@ namespace WeaponPaints
foreach (var agentObject in filteredAgents) foreach (var agentObject in filteredAgents)
{ {
string paintName = agentObject["agent_name"]?.ToString() ?? ""; var paintName = agentObject["agent_name"]?.ToString() ?? "";
if (paintName.Length > 0) if (paintName.Length > 0)
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection); agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
} }
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, agentsSelectionMenu); agentsSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
@@ -573,32 +576,28 @@ namespace WeaponPaints
player!.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
});
} }
private void SetupMusicMenu() private void SetupMusicMenu()
{ {
var musicSelectionMenu = new ChatMenu(Localizer["wp_music_menu_title"]); BaseMenu musicSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_music_menu_title"], Instance) : new ChatMenu(Localizer["wp_music_menu_title"]);
musicSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) => var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
if (!Utility.IsPlayerValid(player) || player is null) return; if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text; var selectedPaintName = option.Text;
var selectedMusic = musicList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString() == selectedPaintName); var selectedMusic = musicList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString().Contains(selectedPaintName) == true);
if (selectedMusic != null) if (selectedMusic != null)
{ {
if ( if (!selectedMusic.ContainsKey("id") ||
selectedMusic != null && !selectedMusic.ContainsKey("name") ||
selectedMusic.ContainsKey("id") && !int.TryParse(selectedMusic["id"]?.ToString(), out var paint)) return;
selectedMusic.ContainsKey("name") && var image = selectedMusic["image"]?.ToString() ?? "";
int.TryParse(selectedMusic["id"]?.ToString(), out int paint)
)
{
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
string image = selectedMusic["image"]?.ToString() ?? "";
PlayerWeaponImage[player.Slot] = image; 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), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
} }
@@ -608,7 +607,7 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
@@ -624,7 +623,7 @@ namespace WeaponPaints
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"])) if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{ {
player!.Print(Localizer["wp_music_menu_select", selectedPaintName]); player!.Print(Localizer["wp_music_menu_select", selectedMusic["name"] ?? selectedPaintName]);
} }
if (weaponSync != null) if (weaponSync != null)
@@ -637,7 +636,6 @@ namespace WeaponPaints
//RefreshGloves(player); //RefreshGloves(player);
} }
}
else else
{ {
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
@@ -645,7 +643,7 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
@@ -665,30 +663,31 @@ namespace WeaponPaints
}); });
} }
} }
GivePlayerMusicKit(player);
}; };
musicSelectionMenu.AddMenuOption(Localizer["None"], handleMusicSelection); musicSelectionMenu.AddMenuOption(Localizer["None"], handleMusicSelection);
// Add weapon options to the weapon selection menu // Add weapon options to the weapon selection menu
foreach (var musicObject in musicList) foreach (var paintName in musicList.Select(musicObject => musicObject["name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{ {
string paintName = musicObject["name"]?.ToString() ?? "";
if (paintName.Length > 0)
musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection); musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection);
} }
Config.Additional.CommandsMusic.ForEach(c =>
{
// Command to open the weapon selection menu for players // Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandMusic}", "Music selection menu", (player, info) => AddCommand($"css_{c}", "Music selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, musicSelectionMenu); musicSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
@@ -696,6 +695,7 @@ namespace WeaponPaints
player!.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
});
} }
} }
} }

View File

@@ -3,6 +3,24 @@ using System.Text.Json.Serialization;
namespace WeaponPaints namespace WeaponPaints
{ {
public class DatabaseCredentials
{
[JsonPropertyName("DatabaseHost")]
public string DatabaseHost { get; set; } = "";
[JsonPropertyName("DatabasePort")]
public int DatabasePort { get; set; } = 3306;
[JsonPropertyName("DatabaseUser")]
public string DatabaseUser { get; set; } = "";
[JsonPropertyName("DatabasePassword")]
public string DatabasePassword { get; set; } = "";
[JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; } = "";
}
public class Additional public class Additional
{ {
[JsonPropertyName("KnifeEnabled")] [JsonPropertyName("KnifeEnabled")]
@@ -20,35 +38,35 @@ namespace WeaponPaints
[JsonPropertyName("SkinEnabled")] [JsonPropertyName("SkinEnabled")]
public bool SkinEnabled { get; set; } = true; public bool SkinEnabled { get; set; } = true;
[JsonPropertyName("CommandWpEnabled")] [JsonPropertyName("NameTagEnabled")]
public bool CommandWpEnabled { get; set; } = true; public bool NameTagEnabled { get; set; } = true;
[JsonPropertyName("CommandKillEnabled")] [JsonPropertyName("PinEnabled")]
public bool CommandKillEnabled { get; set; } = true; public bool PinEnabled { get; set; } = true;
[JsonPropertyName("CommandKnife")] [JsonPropertyName("CommandsKnife")]
public string CommandKnife { get; set; } = "knife"; public List<string> CommandsKnife { get; set; } = ["knife", "knives"];
[JsonPropertyName("CommandMusic")] [JsonPropertyName("CommandsMusic")]
public string CommandMusic { get; set; } = "music"; public List<string> CommandsMusic { get; set; } = ["music", "musickits", "mkit"];
[JsonPropertyName("CommandGlove")] [JsonPropertyName("CommandsGlove")]
public string CommandGlove { get; set; } = "gloves"; public List<string> CommandsGlove { get; set; } = ["gloves", "glove"];
[JsonPropertyName("CommandAgent")] [JsonPropertyName("CommandsAgent")]
public string CommandAgent { get; set; } = "agents"; public List<string> CommandsAgent { get; set; } = ["agents", "agent"];
[JsonPropertyName("CommandSkin")] [JsonPropertyName("CommandsInfo")]
public string CommandSkin { get; set; } = "ws"; public List<string> CommandsInfo { get; set; } = ["ws", "skininfo"];
[JsonPropertyName("CommandSkinSelection")] [JsonPropertyName("CommandsSkinSelection")]
public string CommandSkinSelection { get; set; } = "skins"; public List<string> CommandsSkinSelection { get; set; } = ["skins", "skin"];
[JsonPropertyName("CommandRefresh")] [JsonPropertyName("CommandsRefresh")]
public string CommandRefresh { get; set; } = "wp"; public List<string> CommandsRefresh { get; set; } = ["wp", "refreshskins"];
[JsonPropertyName("CommandKill")] [JsonPropertyName("CommandsKill")]
public string CommandKill { get; set; } = "kill"; public List<string> CommandsKill { get; set; } = ["kill", "suicide"];
[JsonPropertyName("GiveRandomKnife")] [JsonPropertyName("GiveRandomKnife")]
public bool GiveRandomKnife { get; set; } = false; public bool GiveRandomKnife { get; set; } = false;
@@ -58,26 +76,20 @@ namespace WeaponPaints
[JsonPropertyName("ShowSkinImage")] [JsonPropertyName("ShowSkinImage")]
public bool ShowSkinImage { get; set; } = true; public bool ShowSkinImage { get; set; } = true;
[JsonPropertyName("UseHtmlMenu")]
public bool UseHtmlMenu { get; set; } = true;
[JsonPropertyName("ExpireOlderThan")]
public int ExpireOlderThan { get; set; } = 90;
} }
public class WeaponPaintsConfig : BasePluginConfig public class WeaponPaintsConfig : BasePluginConfig
{ {
public override int Version { get; set; } = 6; public override int Version { get; set; } = 7;
[JsonPropertyName("DatabaseHost")] [JsonPropertyName("DatabaseCredentials")]
public string DatabaseHost { get; set; } = ""; public DatabaseCredentials DatabaseCredentials { get; set; } = new();
[JsonPropertyName("DatabasePort")]
public int DatabasePort { get; set; } = 3306;
[JsonPropertyName("DatabaseUser")]
public string DatabaseUser { get; set; } = "";
[JsonPropertyName("DatabasePassword")]
public string DatabasePassword { get; set; } = "";
[JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; } = "";
[JsonPropertyName("CmdRefreshCooldownSeconds")] [JsonPropertyName("CmdRefreshCooldownSeconds")]
public int CmdRefreshCooldownSeconds { get; set; } = 60; public int CmdRefreshCooldownSeconds { get; set; } = 60;
@@ -89,6 +101,6 @@ namespace WeaponPaints
public string Website { get; set; } = "example.com/skins"; public string Website { get; set; } = "example.com/skins";
[JsonPropertyName("Additional")] [JsonPropertyName("Additional")]
public Additional Additional { get; set; } = new Additional(); public Additional Additional { get; set; } = new();
} }
} }

View File

@@ -1,26 +1,21 @@
using MySqlConnector; using Microsoft.Extensions.Logging;
using MySqlConnector;
namespace WeaponPaints namespace WeaponPaints
{ {
public class Database public class Database(string dbConnectionString)
{ {
private readonly string _dbConnectionString;
public Database(string dbConnectionString)
{
_dbConnectionString = dbConnectionString;
}
public async Task<MySqlConnection> GetConnectionAsync() public async Task<MySqlConnection> GetConnectionAsync()
{ {
try try
{ {
var connection = new MySqlConnection(_dbConnectionString); var connection = new MySqlConnection(dbConnectionString);
await connection.OpenAsync(); await connection.OpenAsync();
return connection; return connection;
} }
catch (Exception) catch (Exception ex)
{ {
WeaponPaints.Instance.Logger.LogError($"Unable to connect to database: {ex.Message}");
throw; throw;
} }
} }

192
Events.cs
View File

@@ -1,7 +1,10 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using System.Runtime.InteropServices;
namespace WeaponPaints namespace WeaponPaints
{ {
@@ -12,7 +15,7 @@ namespace WeaponPaints
{ {
CCSPlayerController? player = @event.Userid; CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot || player.IsHLTV || player.SteamID.ToString().Length != 17 || if (player is null || !player.IsValid || player.IsBot ||
weaponSync == null || _database == null) return HookResult.Continue; weaponSync == null || _database == null) return HookResult.Continue;
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
@@ -20,13 +23,15 @@ namespace WeaponPaints
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player.SteamID.ToString(), SteamId = player.SteamID,
Name = player.PlayerName, Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
try try
{ {
_ = Task.Run(async () => await weaponSync.GetPlayerDatabaseIndex(playerInfo));
/*
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
{ {
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo)); _ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
@@ -47,9 +52,11 @@ namespace WeaponPaints
{ {
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo)); _ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
} }
*/
} }
catch (Exception) catch (Exception)
{ {
return HookResult.Continue;
} }
return HookResult.Continue; return HookResult.Continue;
@@ -58,20 +65,11 @@ namespace WeaponPaints
[GameEventHandler] [GameEventHandler]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info) public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
{ {
CCSPlayerController player = @event.Userid; CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot || if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue;
player.IsHLTV || player.SteamID.ToString().Length != 17) return HookResult.Continue;
PlayerInfo playerInfo = new PlayerInfo g_playersDatabaseIndex.TryRemove(player.Slot, out _);
{
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
{ {
@@ -93,116 +91,32 @@ namespace WeaponPaints
{ {
g_playersMusic.TryRemove(player.Slot, out _); g_playersMusic.TryRemove(player.Slot, out _);
} }
if (Config.Additional.PinEnabled)
{
g_playersPin.TryRemove(player.Slot, out _);
}
commandsCooldown.Remove(player.Slot); commandsCooldown.Remove(player.Slot);
return HookResult.Continue; return HookResult.Continue;
} }
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (!Config.Additional.SkinEnabled) return;
if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return;
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;
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
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 weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0;
if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
{
// 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;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
return;
}
if (!gPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out WeaponInfo? value) || value.Paint == 0) return;
WeaponInfo 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]}");
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;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
}
private void OnMapStart(string mapName) private void OnMapStart(string mapName)
{ {
if (!Config.Additional.KnifeEnabled && !Config.Additional.SkinEnabled && !Config.Additional.GloveEnabled) return; if (Config.Additional is { KnifeEnabled: false, SkinEnabled: false, GloveEnabled: false }) return;
if (_database != null) if (_database != null)
weaponSync = new WeaponSynchronization(_database, Config); weaponSync = new WeaponSynchronization(_database, Config);
if (weaponSync != null)
Task.Run(async () => await weaponSync.PurgeExpiredUsers());
} }
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
{ {
CCSPlayerController? player = @event.Userid; CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || !Config.Additional.KnifeEnabled && !Config.Additional.GloveEnabled) if (player is null || !player.IsValid || Config.Additional is { KnifeEnabled: false, GloveEnabled: false })
return HookResult.Continue; return HookResult.Continue;
CCSPlayerPawn? pawn = player.PlayerPawn.Value; CCSPlayerPawn? pawn = player.PlayerPawn.Value;
@@ -214,10 +128,8 @@ namespace WeaponPaints
GivePlayerMusicKit(player); GivePlayerMusicKit(player);
GivePlayerAgent(player); GivePlayerAgent(player);
Server.NextFrame(() => GivePlayerGloves(player);
{ GivePlayerPin(player);
RefreshGloves(player);
});
return HookResult.Continue; return HookResult.Continue;
} }
@@ -231,33 +143,29 @@ namespace WeaponPaints
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) 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; g_bCommandsAllowed = true;
return HookResult.Continue; return HookResult.Continue;
} }
/*
public HookResult OnGiveNamedItemPost(DynamicHook hook) public HookResult OnGiveNamedItemPost(DynamicHook hook)
{
try
{ {
var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0); var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
var weapon = hook.GetReturn<CBasePlayerWeapon>(0); var weapon = hook.GetReturn<CBasePlayerWeapon>();
if (!weapon.DesignerName.Contains("weapon")) if (!weapon.DesignerName.Contains("weapon"))
return HookResult.Continue; return HookResult.Continue;
var player = GetPlayerFromItemServices(itemServices); var player = GetPlayerFromItemServices(itemServices);
if (player != null) if (player != null)
GivePlayerWeaponSkin(player, weapon); GivePlayerWeaponSkin(player, weapon);
}
catch { }
return HookResult.Continue; return HookResult.Continue;
} }
*/
public void OnEntitySpawned(CEntityInstance entity) public void OnEntityCreated(CEntityInstance entity)
{ {
var designerName = entity.DesignerName; var designerName = entity.DesignerName;
@@ -266,7 +174,7 @@ namespace WeaponPaints
Server.NextFrame(() => Server.NextFrame(() =>
{ {
var weapon = new CBasePlayerWeapon(entity.Handle); var weapon = new CBasePlayerWeapon(entity.Handle);
if (weapon == null || !weapon.IsValid || weapon.OwnerEntity.Value == null) return; if (!weapon.IsValid) return;
try try
{ {
@@ -279,7 +187,7 @@ namespace WeaponPaints
if (_steamid != null && _steamid.IsValid()) if (_steamid != null && _steamid.IsValid())
{ {
player = Utilities.GetPlayers().Where(p => p is not null && p.IsValid && p.SteamID == _steamid.SteamId64).FirstOrDefault(); player = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == _steamid.SteamId64);
if (player == null) if (player == null)
player = Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow); player = Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow);
@@ -291,7 +199,7 @@ namespace WeaponPaints
} }
if (string.IsNullOrEmpty(player?.PlayerName)) return; if (string.IsNullOrEmpty(player?.PlayerName)) return;
if (player is null || !Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
GivePlayerWeaponSkin(player, weapon); GivePlayerWeaponSkin(player, weapon);
} }
@@ -305,30 +213,50 @@ namespace WeaponPaints
private void OnTick() private void OnTick()
{ {
if (!Config.Additional.ShowSkinImage) return;
foreach (var player in Utilities.GetPlayers().Where(p => foreach (var player in Utilities.GetPlayers().Where(p =>
p is not null && p.IsValid && p.PlayerPawn != null && p.PlayerPawn.IsValid && p is { IsValid: true, PlayerPawn.IsValid: true } &&
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && p.SteamID.ToString().Length == 17 (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE
&& !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && p is { Connected: PlayerConnectedState.PlayerConnected }
) )
) )
{ {
if (Config.Additional.ShowSkinImage && PlayerWeaponImage.TryGetValue(player.Slot, out string? value) && !string.IsNullOrEmpty(value)) if (PlayerWeaponImage.TryGetValue(player.Slot, out var value) && !string.IsNullOrEmpty(value))
{ {
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", value)); player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", value));
} }
} }
} }
[GameEventHandler]
public HookResult OnItemPickup(EventItemPickup @event, GameEventInfo _)
{
if (!IsWindows) return HookResult.Continue;
var player = @event.Userid;
if (player != null && player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true, PlayerPawn.IsValid: true })
{
GiveOnItemPickup(player);
}
return HookResult.Continue;
}
private void RegisterListeners() private void RegisterListeners()
{ {
RegisterListener<Listeners.OnMapStart>(OnMapStart); RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn); RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre); RegisterEventHandler<EventRoundStart>(OnRoundStart);
RegisterEventHandler<EventRoundEnd>(OnRoundEnd); RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawned); RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated);
if (Config.Additional.ShowSkinImage)
RegisterListener<Listeners.OnTick>(OnTick); RegisterListener<Listeners.OnTick>(OnTick);
//VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
if (!IsWindows)
VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
} }
} }
} }

View File

@@ -8,6 +8,7 @@ public static class PlayerExtensions
public static void Print(this CCSPlayerController controller, string message) public static void Print(this CCSPlayerController controller, string message)
{ {
if (WeaponPaints._localizer == null) return; if (WeaponPaints._localizer == null) return;
StringBuilder _message = new(WeaponPaints._localizer["wp_prefix"]); StringBuilder _message = new(WeaponPaints._localizer["wp_prefix"]);
_message.Append(message); _message.Append(message);
controller.PrintToChat(_message.ToString()); controller.PrintToChat(_message.ToString());

View File

@@ -3,9 +3,9 @@
public class PlayerInfo public class PlayerInfo
{ {
public int Index { get; set; } public int Index { get; set; }
public int Slot { get; set; } public int Slot { get; init; }
public int? UserId { get; set; } public int? UserId { get; set; }
public string? SteamId { get; set; } public ulong? SteamId { get; init; }
public string? Name { get; set; } public string? Name { get; set; }
public string? IpAddress { get; set; } public string? IpAddress { get; set; }
} }

View File

@@ -1,11 +1,9 @@
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Core.Translations;
using Dapper; using Dapper;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MySqlConnector;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Reflection;
namespace WeaponPaints namespace WeaponPaints
{ {
@@ -13,22 +11,6 @@ namespace WeaponPaints
{ {
internal static WeaponPaintsConfig? Config { get; set; } internal static WeaponPaintsConfig? Config { get; set; }
internal static string BuildDatabaseConnectionString()
{
if (Config == null) return string.Empty;
var builder = new MySqlConnectionStringBuilder
{
Server = Config.DatabaseHost,
UserID = Config.DatabaseUser,
Password = Config.DatabasePassword,
Database = Config.DatabaseName,
Port = (uint)Config.DatabasePort,
Pooling = true
};
return builder.ConnectionString;
}
internal static async Task CheckDatabaseTables() internal static async Task CheckDatabaseTables()
{ {
if (WeaponPaints._database is null) return; if (WeaponPaints._database is null) return;
@@ -41,36 +23,15 @@ namespace WeaponPaints
try try
{ {
string[] createTableQueries = new[] var createTableQueries = new[]
{ {
@"CREATE TABLE IF NOT EXISTS `wp_player_skins` ( "CREATE TABLE IF NOT EXISTS `wp_users` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `steamid` BIGINT UNSIGNED NOT NULL, `last_online` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_steamid` (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
`steamid` varchar(18) NOT NULL, "CREATE TABLE IF NOT EXISTS `wp_users_skins` (`user_id` INT UNSIGNED NOT NULL, `weapon` SMALLINT UNSIGNED NOT NULL, `paint` SMALLINT UNSIGNED NOT NULL, `wear` FLOAT NOT NULL DEFAULT 0.001, `seed` SMALLINT UNSIGNED NOT NULL DEFAULT 0, `nametag` VARCHAR(20) DEFAULT NULL, `stattrack` INT UNSIGNED NOT NULL DEFAULT 0, `stattrack_enabled` SMALLINT NOT NULL DEFAULT 0, `quality` SMALLINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`user_id`,`weapon`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
`weapon_defindex` int(6) NOT NULL, "CREATE TABLE IF NOT EXISTS `wp_users_knives` (`user_id` INT UNSIGNED NOT NULL, `knife` SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
`weapon_paint_id` int(6) NOT NULL, "CREATE TABLE IF NOT EXISTS `wp_users_gloves` (`user_id` INT UNSIGNED NOT NULL, `weapon_defindex` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
`weapon_wear` float NOT NULL DEFAULT 0.000001, "CREATE TABLE IF NOT EXISTS `wp_users_musics` (`user_id` INT UNSIGNED NOT NULL, `music` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
`weapon_seed` int(16) NOT NULL DEFAULT 0 "CREATE TABLE IF NOT EXISTS `wp_users_agents` (`user_id` INT UNSIGNED NOT NULL,`agent_ct` varchar(64) DEFAULT NULL,`agent_t` varchar(64) DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
) ENGINE=InnoDB", "CREATE TABLE IF NOT EXISTS `wp_users_pins` (`user_id` INT UNSIGNED NOT NULL, `pin` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
@"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",
}; };
foreach (var query in createTableQueries) foreach (var query in createTableQueries)
@@ -96,62 +57,62 @@ namespace WeaponPaints
{ {
if (player is null || WeaponPaints.weaponSync is null) return false; if (player is null || WeaponPaints.weaponSync is null) return false;
return (player.IsValid && !player.IsBot && !player.IsHLTV && player.UserId.HasValue); return player is { IsValid: true, IsBot: false, IsHLTV: false, UserId: not null };
} }
internal static void LoadSkinsFromFile(string filePath) internal static void LoadSkinsFromFile(string filePath, ILogger logger)
{ {
var json = File.ReadAllText(filePath);
try try
{ {
string json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json); var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.skinsList = deserializedSkins ?? new List<JObject>(); WeaponPaints.skinsList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
throw; logger?.LogError("Not found \"skins.json\" file");
} }
} }
internal static void LoadGlovesFromFile(string filePath) internal static void LoadGlovesFromFile(string filePath, ILogger logger)
{ {
try try
{ {
string json = File.ReadAllText(filePath); var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json); var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.glovesList = deserializedSkins ?? new List<JObject>(); WeaponPaints.glovesList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
throw; logger?.LogError("Not found \"gloves.json\" file");
} }
} }
internal static void LoadAgentsFromFile(string filePath) internal static void LoadAgentsFromFile(string filePath, ILogger logger)
{ {
try try
{ {
string json = File.ReadAllText(filePath); var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json); var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.agentsList = deserializedSkins ?? new List<JObject>(); WeaponPaints.agentsList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
throw; logger?.LogError("Not found \"agents.json\" file");
} }
} }
internal static void LoadMusicFromFile(string filePath) internal static void LoadMusicFromFile(string filePath, ILogger logger)
{ {
try try
{ {
string json = File.ReadAllText(filePath); var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json); var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.musicList = deserializedSkins ?? new List<JObject>(); WeaponPaints.musicList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
throw; logger?.LogError("Not found \"music.json\" file");
} }
} }
@@ -165,53 +126,35 @@ namespace WeaponPaints
internal static string ReplaceTags(string message) internal static string ReplaceTags(string message)
{ {
if (message.Contains('{')) return message.ReplaceColorTags();
{
string modifiedValue = message;
if (Config != null)
{
modifiedValue = modifiedValue.Replace("{WEBSITE}", Config.Website);
}
foreach (FieldInfo field in typeof(ChatColors).GetFields())
{
string pattern = $"{{{field.Name}}}";
if (message.Contains(pattern, StringComparison.OrdinalIgnoreCase))
{
modifiedValue = modifiedValue.Replace(pattern, field.GetValue(null)!.ToString(), StringComparison.OrdinalIgnoreCase);
}
}
return modifiedValue;
}
return message;
} }
internal static async Task CheckVersion(string version, ILogger logger) internal static async Task CheckVersion(string version, ILogger logger)
{ {
using (HttpClient client = new HttpClient()) using HttpClient client = new();
{
try try
{ {
HttpResponseMessage response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false); var response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
string remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
remoteVersion = remoteVersion.Trim(); remoteVersion = remoteVersion.Trim();
int comparisonResult = string.Compare(version, remoteVersion); var comparisonResult = string.CompareOrdinal(version, remoteVersion);
if (comparisonResult < 0) switch (comparisonResult)
{ {
case < 0:
logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints"); logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints");
} break;
else if (comparisonResult > 0) case > 0:
{
logger.LogInformation("Probably dev version detected"); logger.LogInformation("Probably dev version detected");
} break;
else default:
{
logger.LogInformation("Plugin is up to date"); logger.LogInformation("Plugin is up to date");
break;
} }
} }
else else
@@ -228,7 +171,6 @@ namespace WeaponPaints
logger.LogError(ex, "An error occurred while checking version."); logger.LogError(ex, "An error occurred while checking version.");
} }
} }
}
internal static void ShowAd(string moduleVersion) internal static void ShowAd(string moduleVersion)
{ {

View File

@@ -1 +1 @@
2.3b 2.5a

View File

@@ -1,113 +1,199 @@
using CounterStrikeSharp.API; using System.Diagnostics;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
namespace WeaponPaints namespace WeaponPaints;
{
public partial class WeaponPaints public partial class WeaponPaints
{ {
internal static void GiveKnifeToPlayer(CCSPlayerController? player) private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (!Config.Additional.SkinEnabled) return;
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
var isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if ((isKnife && !g_playersKnife.ContainsKey(player.Slot)) ||
(isKnife && g_playersKnife[player.Slot] < 500)) return;
int[] newPaints =
[1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173];
if (isKnife)
{
//var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
//if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != g_playersKnife[player.Slot])
SubclassChange(weapon, (ushort)g_playersKnife[player.Slot]);
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)g_playersKnife[player.Slot];
weapon.AttributeManager.Item.EntityQuality = 3;
}
UpdatePlayerEconItemId(weapon.AttributeManager.Item);
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
var fallbackPaintKit = 0;
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[player.Slot].ContainsKey((ushort)weaponDefIndex))
{
// Random skins
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
weapon.FallbackSeed = 0;
weapon.FallbackWear = 0.01f;
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
CAttributeListSetOrAddAttributeValueByName.Invoke(
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
GetRandomPaint(weaponDefIndex));
CAttributeListSetOrAddAttributeValueByName.Invoke(
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture wear", 0.01f);
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
"set item texture prefab", GetRandomPaint(weaponDefIndex));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
"set item texture seed", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
"set item texture wear", 0.01f);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (isKnife) return;
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
return;
}
if (!gPlayerWeaponsInfo[player.Slot].TryGetValue((ushort)weaponDefIndex, out var value) || value.Paint == 0) return;
var weaponInfo = value;
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
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;
CAttributeListSetOrAddAttributeValueByName.Invoke(
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (isKnife) return;
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
}
private static void GiveKnifeToPlayer(CCSPlayerController? player)
{ {
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return; if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
if (PlayerHasKnife(player)) return; if (PlayerHasKnife(player)) return;
string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife"; //string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
player.GiveNamedItem(CsItem.Knife); player.GiveNamedItem(CsItem.Knife);
} }
internal static bool PlayerHasKnife(CCSPlayerController? player) private static bool PlayerHasKnife(CCSPlayerController? player)
{ {
if (!_config.Additional.KnifeEnabled) return false; if (!_config.Additional.KnifeEnabled) return false;
if (player == null || !player.IsValid || player.PlayerPawn == null || !player.PlayerPawn.IsValid) if (player == null || !player.IsValid || !player.PlayerPawn.IsValid) return false;
{
return false;
}
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null ||
player.PlayerPawn.Value.ItemServices == null)
return false; return false;
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons; var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
if (weapons == null) return false; if (weapons == null) return false;
foreach (var weapon in weapons) foreach (var weapon in weapons)
{ {
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid) if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue;
{
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet")) if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
return true; return true;
} }
}
}
return false; return false;
} }
internal void RefreshWeapons(CCSPlayerController? player) private void RefreshWeapons(CCSPlayerController? player)
{ {
if (!g_bCommandsAllowed) return; if (!g_bCommandsAllowed) return;
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) if (player == null || !player.IsValid || player.PlayerPawn?.Value == null ||
(LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE)
return; return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
return; return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons == null || weapons.Count == 0) if (weapons.Count == 0)
return; return;
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator) if (player.Team is CsTeam.None or CsTeam.Spectator)
return; return;
int playerTeam = player.TeamNum; int playerTeam = player.TeamNum;
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>(); Dictionary<string, List<(int, int)>> weaponsWithAmmo = [];
foreach (var weapon in weapons) foreach (var weapon in weapons)
{ {
if (weapon == null || !weapon.IsValid || weapon.Value == null || if (!weapon.IsValid || weapon.Value == null ||
!weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_")) !weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
continue; continue;
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>(); var gun = weapon.Value.As<CCSWeaponBaseGun>();
if (weapon.Value.Entity == null) continue; if (weapon.Value.Entity == null) continue;
if (weapon.Value.OwnerEntity == null) continue;
if (!weapon.Value.OwnerEntity.IsValid) continue; if (!weapon.Value.OwnerEntity.IsValid) continue;
if (gun == null) continue;
if (gun.Entity == null) continue; if (gun.Entity == null) continue;
if (!gun.IsValid) continue; if (!gun.IsValid) continue;
if (!gun.VisibleinPVS) continue; if (!gun.VisibleinPVS) continue;
try try
{ {
string? weaponByDefindex = null; var weaponData = weapon.Value.As<CCSWeaponBase>().VData;
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weaponData == null) continue; if (weaponData == null) continue;
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_RIFLE || weaponData.GearSlot == gear_slot_t.GEAR_SLOT_PISTOL) if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_RIFLE ||
weaponData.GearSlot == gear_slot_t.GEAR_SLOT_PISTOL)
{ {
if (!WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex, out weaponByDefindex)) if (!WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex,
out var weaponByDefindex))
continue; continue;
int clip1 = weapon.Value.Clip1; var clip1 = weapon.Value.Clip1;
int reservedAmmo = weapon.Value.ReserveAmmo[0]; var reservedAmmo = weapon.Value.ReserveAmmo[0];
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out List<(int, int)>? value)) if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
{ {
value = new List<(int, int)>(); value = [];
weaponsWithAmmo.Add(weaponByDefindex, value); weaponsWithAmmo.Add(weaponByDefindex, value);
} }
value.Add((clip1, reservedAmmo)); value.Add((clip1, reservedAmmo));
if (gun == null || gun.VData == null) return; if (gun.VData == null) return;
weapon.Value.Remove(); weapon.Value.Remove();
} }
@@ -115,7 +201,6 @@ namespace WeaponPaints
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning(ex.Message); Logger.LogWarning(ex.Message);
continue;
} }
} }
@@ -125,12 +210,12 @@ namespace WeaponPaints
player.ExecuteClientCommand("slot 3"); player.ExecuteClientCommand("slot 3");
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon; var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon;
if (weapon is null || !weapon.IsValid || weapon.Value == null) return; if (!weapon.IsValid || weapon.Value == null) return;
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData; var weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{ {
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>(); CCSWeaponBaseGun gun;
AddTimer(0.3f, () => AddTimer(0.3f, () =>
{ {
@@ -144,7 +229,7 @@ namespace WeaponPaints
{ {
if (player.TeamNum != playerTeam) return; if (player.TeamNum != playerTeam) return;
if (gun == null || !gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return; if (!gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return;
gun.Remove(); gun.Remove();
}); });
@@ -163,39 +248,34 @@ namespace WeaponPaints
if (!g_bCommandsAllowed) return; if (!g_bCommandsAllowed) return;
foreach (var entry in weaponsWithAmmo) foreach (var entry in weaponsWithAmmo)
{
foreach (var ammo in entry.Value) foreach (var ammo in entry.Value)
{ {
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key)); var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
Server.NextFrame(() => Server.NextFrame(() =>
{ {
try try
{
if (newWeapon != null)
{ {
newWeapon.Clip1 = ammo.Item1; newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2; newWeapon.ReserveAmmo[0] = ammo.Item2;
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogWarning("Error setting weapon properties: " + ex.Message); Logger.LogWarning("Error setting weapon properties: " + ex.Message);
} }
}); });
} }
}
}, TimerFlags.STOP_ON_MAPCHANGE); }, TimerFlags.STOP_ON_MAPCHANGE);
} }
private static void RefreshGloves(CCSPlayerController player) private void GivePlayerGloves(CCSPlayerController player)
{ {
if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return; if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return;
CCSPlayerPawn? pawn = player.PlayerPawn.Value; var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) if (pawn == null || !pawn.IsValid)
return; return;
string model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty; var model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
if (!string.IsNullOrEmpty(model)) if (!string.IsNullOrEmpty(model))
{ {
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl"); pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
@@ -204,46 +284,46 @@ namespace WeaponPaints
Instance.AddTimer(0.06f, () => Instance.AddTimer(0.06f, () =>
{ {
var item = pawn.EconGloves;
try try
{ {
if (player == null || !player.IsValid) if (!player.IsValid)
return; return;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) if (!player.PawnIsAlive)
return; return;
if (g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) && gloveInfo != 0) if (!g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
{
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
return;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo]; var weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
CEconItemView item = pawn.EconGloves;
item.ItemDefinitionIndex = gloveInfo; item.ItemDefinitionIndex = gloveInfo;
item.ItemIDLow = 16384 & 0xFFFFFFFF; item.ItemIDLow = 16384 & 0xFFFFFFFF;
item.ItemIDHigh = 16384; item.ItemIDHigh = 16384;
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weaponInfo.Paint); CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle,
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture seed", weaponInfo.Seed); "set item texture prefab", weaponInfo.Paint);
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture wear", weaponInfo.Wear); CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle,
"set item texture seed", weaponInfo.Seed);
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle,
"set item texture wear", weaponInfo.Wear);
item.Initialized = true; item.Initialized = true;
CBaseModelEntity_SetBodygroup.Invoke(pawn, "default_gloves", 1); SetBodygroup(pawn.Handle, "default_gloves", 1);
} }
catch (Exception)
{
} }
catch (Exception) { }
}, TimerFlags.STOP_ON_MAPCHANGE); }, TimerFlags.STOP_ON_MAPCHANGE);
} }
private static int GetRandomPaint(int defindex) private static int GetRandomPaint(int defindex)
{ {
if (skinsList == null || skinsList.Count == 0) if (skinsList.Count == 0)
return 0; return 0;
Random rnd = new Random(); var rnd = new Random();
// Filter weapons by the provided defindex // Filter weapons by the provided defindex
var filteredWeapons = skinsList.Where(w => w["weapon_defindex"]?.ToString() == defindex.ToString()).ToList(); var filteredWeapons = skinsList.Where(w => w["weapon_defindex"]?.ToString() == defindex.ToString()).ToList();
@@ -253,55 +333,44 @@ namespace WeaponPaints
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)]; var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
if (int.TryParse(randomWeapon["paint"]?.ToString(), out int paintValue)) return int.TryParse(randomWeapon["paint"]?.ToString(), out var paintValue) ? paintValue : 0;
return paintValue;
return 0;
} }
public static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD) private static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
{ {
var SubclassChangeFunc = VirtualFunction.Create<nint, string, int>( var subclassChangeFunc = VirtualFunction.Create<nint, string, int>(
GameData.GetSignature("ChangeSubclass") GameData.GetSignature("ChangeSubclass")
); );
SubclassChangeFunc(weapon.Handle, itemD.ToString()); subclassChangeFunc(weapon.Handle, itemD.ToString());
} }
public static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false) private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
{
if (weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{ {
if (weapon.CBodyComponent?.SceneNode == null) return;
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance(); var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
if (skeleton != null)
{
var value = (ulong)(isLegacy ? 2 : 1); var value = (ulong)(isLegacy ? 2 : 1);
if (skeleton.ModelState.MeshGroupMask != value) if (skeleton.ModelState.MeshGroupMask != value) skeleton.ModelState.MeshGroupMask = value;
{
skeleton.ModelState.MeshGroupMask = value;
}
}
}
} }
public static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy) private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon,
bool isLegacy)
{ {
UpdateWeaponMeshGroupMask(weapon, isLegacy); UpdateWeaponMeshGroupMask(weapon, isLegacy);
var viewModel = GetPlayerViewModel(player); var viewModel = GetPlayerViewModel(player);
if (viewModel != null && viewModel.Weapon.Value != null && viewModel.Weapon.Value.Index == weapon.Index) if (viewModel == null || viewModel.Weapon.Value == null ||
{ viewModel.Weapon.Value.Index != weapon.Index) return;
UpdateWeaponMeshGroupMask(viewModel, isLegacy); UpdateWeaponMeshGroupMask(viewModel, isLegacy);
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent"); Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
} }
}
public static void GivePlayerAgent(CCSPlayerController player) private static void GivePlayerAgent(CCSPlayerController player)
{ {
if (!g_playersAgent.ContainsKey(player.Slot)) return; if (!g_playersAgent.TryGetValue(player.Slot, out var value)) return;
string? model = player.TeamNum == 3 ? g_playersAgent[player.Slot].CT : g_playersAgent[player.Slot].T; var model = player.TeamNum == 3 ? value.CT : value.T;
if (string.IsNullOrEmpty(model)) return; if (string.IsNullOrEmpty(model)) return;
if (player.PlayerPawn.Value == null) if (player.PlayerPawn.Value == null)
@@ -321,48 +390,80 @@ namespace WeaponPaints
} }
} }
public static void GivePlayerMusicKit(CCSPlayerController player) private static void GivePlayerMusicKit(CCSPlayerController player)
{ {
if (!g_playersMusic.ContainsKey(player.Slot)) return; if (!g_playersMusic.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return; if (player.InventoryServices == null) return;
Console.WriteLine(g_playersMusic[player.Slot]); player.InventoryServices.MusicID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
player.InventoryServices.MusicID = g_playersMusic[player.Slot]; player.MusicKitID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID");
} }
public static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices) private static void GivePlayerPin(CCSPlayerController player)
{
if (!g_playersPin.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return;
for (var index = 0; index < player.InventoryServices.Rank.Length; index++)
{
player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)value : MedalRank_t.MEDAL_RANK_NONE;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
}
}
private void GiveOnItemPickup(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null) return;
var myWeapons = pawn.WeaponServices?.MyWeapons;
if (myWeapons == null) return;
foreach (var handle in myWeapons)
{
var weapon = handle.Value;
if (weapon != null && weapon.DesignerName.Contains("knife")) GivePlayerWeaponSkin(player, weapon);
}
}
private void UpdatePlayerEconItemId(CEconItemView econItemView)
{
var itemId = _nextItemId++;
econItemView.ItemID = itemId;
econItemView.ItemIDLow = (uint)itemId & 0xFFFFFFFF;
econItemView.ItemIDHigh = (uint)itemId >> 32;
}
private static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
{ {
var pawn = itemServices.Pawn.Value; var pawn = itemServices.Pawn.Value;
if (pawn == null || !pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null; if (!pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
var player = new CCSPlayerController(pawn.Controller.Value.Handle); var player = new CCSPlayerController(pawn.Controller.Value.Handle);
if (!Utility.IsPlayerValid(player)) return null; return !Utility.IsPlayerValid(player) ? null : player;
return player;
} }
private static unsafe CBaseViewModel? GetPlayerViewModel(CCSPlayerController player) private static CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
{ {
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null; if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle); CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
nint ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel"); var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
var references = MemoryMarshal.CreateSpan(ref ptr, 3); var references = MemoryMarshal.CreateSpan(ref ptr, 3);
var viewModel = (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!; var viewModel =
if (viewModel == null || viewModel.Value == null) return null; (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
return viewModel.Value; return viewModel.Value == null ? null : viewModel.Value;
} }
public static unsafe T[] GetFixedArray<T>(nint pointer, string @class, string member, int length) where T : CHandle<CBaseViewModel> public static T[] GetFixedArray<T>(nint pointer, string @class, string member, int length)
where T : CHandle<CBaseViewModel>
{ {
nint ptr = pointer + Schema.GetSchemaOffset(@class, member); var ptr = pointer + Schema.GetSchemaOffset(@class, member);
Span<nint> references = MemoryMarshal.CreateSpan(ref ptr, length); var references = MemoryMarshal.CreateSpan(ref ptr, length);
T[] values = new T[length]; var values = new T[length];
for (int i = 0; i < length; i++) for (var i = 0; i < length; i++) values[i] = (T)Activator.CreateInstance(typeof(T), references[i])!;
{
values[i] = (T)Activator.CreateInstance(typeof(T), references[i])!;
}
return values; return values;
} }
} }
}

View File

@@ -2,8 +2,12 @@
{ {
public class WeaponInfo public class WeaponInfo
{ {
public int Paint { get; set; } public ushort Paint { get; set; }
public int Seed { get; set; } = 0; public ushort Seed { get; set; } = 0;
public float Wear { get; set; } = 0f; public float Wear { get; set; } = 0f;
public string? NameTag { get; set; }
public ushort Quality { get; set; }
public uint StatTrack { get; set; }
public bool StatTrackEnabled { get; set; }
} }
} }

View File

@@ -7,15 +7,17 @@ using Microsoft.Extensions.Logging;
using MySqlConnector; using MySqlConnector;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API.Modules.Entities.Constants;
namespace WeaponPaints; namespace WeaponPaints;
[MinimumApiVersion(195)] [MinimumApiVersion(238)]
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig> public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{ {
internal static WeaponPaints Instance { get; private set; } = new(); internal static WeaponPaints Instance { get; private set; } = new();
internal static readonly Dictionary<string, string> weaponList = new() private static readonly Dictionary<string, string> WeaponList = new()
{ {
{"weapon_deagle", "Desert Eagle"}, {"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"}, {"weapon_elite", "Dual Berettas"},
@@ -75,29 +77,36 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ "weapon_knife_kukri", "Kukri Knife" } { "weapon_knife_kukri", "Kukri Knife" }
}; };
internal static WeaponPaintsConfig _config = new(); private static WeaponPaintsConfig _config = new();
internal static IStringLocalizer? _localizer; internal static IStringLocalizer? _localizer;
internal static Dictionary<int, int> g_knifePickupCount = new(); private static Dictionary<int, int> g_knifePickupCount = new();
internal static ConcurrentDictionary<int, string> g_playersKnife = new(); internal static ConcurrentDictionary<int, ushort> g_playersKnife = new();
internal static ConcurrentDictionary<int, ushort> g_playersGlove = new(); internal static ConcurrentDictionary<int, ushort> g_playersGlove = new();
internal static ConcurrentDictionary<int, ushort> g_playersMusic = new(); internal static ConcurrentDictionary<int, ushort> g_playersMusic = new();
internal static ConcurrentDictionary<int, ushort> g_playersPin = new();
internal static ConcurrentDictionary<int, (string? CT, string? T)> g_playersAgent = new(); internal static ConcurrentDictionary<int, (string? CT, string? T)> g_playersAgent = new();
internal static ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new(); internal static ConcurrentDictionary<int, ConcurrentDictionary<ushort, WeaponInfo>> gPlayerWeaponsInfo = new();
internal static List<JObject> skinsList = new(); internal static ConcurrentDictionary<int, int> g_playersDatabaseIndex = new();
internal static List<JObject> glovesList = new();
internal static List<JObject> agentsList = new();
internal static List<JObject> musicList = new();
internal static WeaponSynchronization? weaponSync;
public static bool g_bCommandsAllowed = true;
internal Dictionary<int, string> PlayerWeaponImage = new();
internal static Dictionary<int, DateTime> commandsCooldown = new(); internal static List<JObject> skinsList = [];
internal static List<JObject> glovesList = [];
internal static List<JObject> agentsList = [];
internal static List<JObject> musicList = [];
internal static WeaponSynchronization? weaponSync;
private static bool g_bCommandsAllowed = true;
private Dictionary<int, string> PlayerWeaponImage = new();
private static Dictionary<int, DateTime> commandsCooldown = new();
internal static Database? _database; internal static Database? _database;
internal static MemoryFunctionVoid<nint, string, float> CAttributeList_SetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName")); private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
internal static MemoryFunctionVoid<CBaseModelEntity, string, UInt64> CBaseModelEntity_SetBodygroup = new(GameData.GetSignature("CBaseModelEntity_SetBodygroup"));
public static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string> private static readonly MemoryFunctionWithReturn<nint, string, int, int> SetBodygroupFunc = new(
GameData.GetSignature("CBaseModelEntity_SetBodygroup"));
private static readonly Func<nint, string, int, int> SetBodygroup = SetBodygroupFunc.Invoke;
private static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string>
{ {
{ 1, "weapon_deagle" }, { 1, "weapon_deagle" },
{ 2, "weapon_elite" }, { 2, "weapon_elite" },
@@ -155,17 +164,15 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ 525, "weapon_knife_skeleton" }, { 525, "weapon_knife_skeleton" },
{ 526, "weapon_knife_kukri" } { 526, "weapon_knife_kukri" }
}; };
private const ulong MinimumCustomItemId = 65578;
private ulong _nextItemId = MinimumCustomItemId;
public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public WeaponPaintsConfig Config { get; set; } = new(); public WeaponPaintsConfig Config { get; set; } = new();
public override string ModuleAuthor => "Nereziel & daffyy"; public override string ModuleAuthor => "Nereziel & daffyy";
public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based"; public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based";
public override string ModuleName => "WeaponPaints"; public override string ModuleName => "WeaponPaints";
public override string ModuleVersion => "2.3b"; public override string ModuleVersion => "2.5a";
public static WeaponPaintsConfig GetWeaponPaintsConfig()
{
return _config;
}
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
@@ -175,58 +182,39 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ {
OnMapStart(string.Empty); OnMapStart(string.Empty);
foreach (var player in Utilities.GetPlayers()) foreach (var player in Enumerable
.OfType<CCSPlayerController>(Utilities.GetPlayers().TakeWhile(player => weaponSync != null))
.Where(player => player.IsValid &&
!string.IsNullOrEmpty(player.IpAddress) && player is
{ IsBot: false, Connected: PlayerConnectedState.PlayerConnected }))
{ {
if (weaponSync == null)
break;
if (player is null || !player.IsValid || player.SteamID.ToString().Length != 17 || string.IsNullOrEmpty(player.IpAddress) || player.IsBot ||
player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected)
continue;
g_knifePickupCount[player.Slot] = 0; g_knifePickupCount[player.Slot] = 0;
gPlayerWeaponsInfo.TryRemove(player.Slot, out _); gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
g_playersKnife.TryRemove(player.Slot, out _); g_playersKnife.TryRemove(player.Slot, out _);
g_playersGlove.TryRemove(player.Slot, out _); g_playersGlove.TryRemove(player.Slot, out _);
g_playersAgent.TryRemove(player.Slot, out _); g_playersAgent.TryRemove(player.Slot, out _);
PlayerInfo playerInfo = new PlayerInfo PlayerInfo? playerInfo = new PlayerInfo
{ {
UserId = player.UserId, UserId = player.UserId,
Slot = player.Slot, Slot = player.Slot,
Index = (int)player.Index, Index = (int)player.Index,
SteamId = player?.SteamID.ToString(), SteamId = player?.SteamID,
Name = player?.PlayerName, Name = player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0] IpAddress = player?.IpAddress?.Split(":")[0]
}; };
if (Config.Additional.SkinEnabled) _ = Task.Run(async () =>
{ {
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo)); if (weaponSync != null) await weaponSync.GetPlayerDatabaseIndex(playerInfo);
} });
if (Config.Additional.KnifeEnabled)
{
_ = Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled)
{
_ = Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
}
if (Config.Additional.AgentEnabled)
{
_ = Task.Run(async () => await weaponSync.GetAgentFromDatabase(playerInfo));
}
if (Config.Additional.MusicEnabled)
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
} }
} }
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json"); Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json", Logger);
Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json"); Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json", Logger);
Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json"); Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json", Logger);
Utility.LoadMusicFromFile(ModuleDirectory + "/music.json"); Utility.LoadMusicFromFile(ModuleDirectory + "/music.json", Logger);
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
SetupKnifeMenu(); SetupKnifeMenu();
@@ -245,23 +233,32 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
public void OnConfigParsed(WeaponPaintsConfig config) public void OnConfigParsed(WeaponPaintsConfig config)
{ {
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1) if (config.DatabaseCredentials.DatabaseHost.Length < 1 || config.DatabaseCredentials.DatabaseName.Length < 1 || config.DatabaseCredentials.DatabaseUser.Length < 1)
{ {
Logger.LogError("You need to setup Database credentials in config!"); Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
throw new Exception("[WeaponPaints] You need to setup Database credentials in config!"); Unload(false);
return;
}
if (!File.Exists(Path.GetDirectoryName(Path.GetDirectoryName(ModuleDirectory)) + "/gamedata/weaponpaints.json"))
{
Logger.LogError("You need to upload \"weaponpaints.json\" to \"gamedata directory\"!");
Unload(false);
return;
} }
var builder = new MySqlConnectionStringBuilder var builder = new MySqlConnectionStringBuilder
{ {
Server = config.DatabaseHost, Server = config.DatabaseCredentials.DatabaseHost,
UserID = config.DatabaseUser, UserID = config.DatabaseCredentials.DatabaseUser,
Password = config.DatabasePassword, Password = config.DatabaseCredentials.DatabasePassword,
Database = config.DatabaseName, Database = config.DatabaseCredentials.DatabaseName,
Port = (uint)config.DatabasePort, Port = (uint)config.DatabaseCredentials.DatabasePort,
Pooling = true Pooling = true,
MaximumPoolSize = 640,
}; };
_database = new(builder.ConnectionString); _database = new Database(builder.ConnectionString);
_ = Utility.CheckDatabaseTables(); _ = Utility.CheckDatabaseTables();

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@@ -9,9 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.193" /> <PackageReference Include="CounterStrikeSharp.API" Version="1.0.233" />
<PackageReference Include="Dapper" Version="2.1.35" /> <PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.3.5" /> <PackageReference Include="MySqlConnector" Version="2.3.7" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>

View File

@@ -1,8 +1,9 @@
using Dapper;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Dapper;
using MySqlConnector;
namespace WeaponPaints;
namespace WeaponPaints
{
internal class WeaponSynchronization internal class WeaponSynchronization
{ {
private readonly WeaponPaintsConfig _config; private readonly WeaponPaintsConfig _config;
@@ -14,21 +15,84 @@ namespace WeaponPaints
_config = config; _config = config;
} }
internal async Task GetKnifeFromDatabase(PlayerInfo player) internal async Task GetPlayerDatabaseIndex(PlayerInfo playerInfo)
{
if (playerInfo.SteamId == null) return;
Console.WriteLine("test");
try
{
await using var connection = await _database.GetConnectionAsync();
var query = "SELECT `id` FROM `wp_users` WHERE `steamid` = @steamid";
var databaseIndex =
await connection.QueryFirstOrDefaultAsync<int?>(query, new { steamid = playerInfo.SteamId });
if (databaseIndex != null)
{
WeaponPaints.g_playersDatabaseIndex[playerInfo.Slot] = (int)databaseIndex;
query = "UPDATE `wp_users` SET `last_online` = @lastUpdate WHERE `id` = @databaseIndex";
await connection.ExecuteAsync(query, new
{
lastUpdate = DateTime.Now,
databaseIndex
});
}
else
{
Console.WriteLine("test");
const string insertQuery = "INSERT INTO `wp_users` (`steamid`) VALUES (@steamid)";
await connection.ExecuteAsync(insertQuery, new { steamid = playerInfo.SteamId });
Console.WriteLine("SQL Insert Query: " + insertQuery);
databaseIndex =
await connection.QueryFirstOrDefaultAsync<int?>(query, new { steamid = playerInfo.SteamId });
WeaponPaints.g_playersDatabaseIndex[playerInfo.Slot] = (int)databaseIndex;
}
await GetPlayerData(playerInfo);
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetPlayerDatabaseIndex: {ex.Message}");
}
}
internal async Task GetPlayerData(PlayerInfo? player)
{ {
try try
{ {
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId)) 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.PinEnabled)
GetPinFromDatabase(player, connection);
}
catch (Exception ex)
{
// Log the exception or handle it appropriately
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
await using var connection = await _database.GetConnectionAsync(); const string query = "SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = @userId";
string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid"; var playerKnife = connection.QueryFirstOrDefault<int>(query,
string? playerKnife = await connection.QueryFirstOrDefaultAsync<string>(query, new { steamid = player.SteamId }); new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (!string.IsNullOrEmpty(playerKnife)) WeaponPaints.g_playersKnife[player.Slot] = (ushort)playerKnife;
{
WeaponPaints.g_playersKnife[player.Slot] = playerKnife;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -36,21 +100,17 @@ namespace WeaponPaints
} }
} }
internal async Task GetGloveFromDatabase(PlayerInfo player) private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
{ {
try try
{ {
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
await using var connection = await _database.GetConnectionAsync(); const string query = "SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = @userId";
string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid"; var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
ushort? gloveData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
if (gloveData != null) if (gloveData != null) WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
{
WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -58,68 +118,59 @@ namespace WeaponPaints
} }
} }
internal async Task GetAgentFromDatabase(PlayerInfo player) private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
{ {
try try
{ {
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
await using var connection = await _database.GetConnectionAsync(); const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_users_agents` WHERE `user_id` = @userId";
string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
var agentData = await connection.QueryFirstOrDefaultAsync<(string, string)>(query, new { steamid = player.SteamId });
if (agentData != default) if (agentData == default) return;
{ var agentCT = agentData.Item1;
string agentCT = agentData.Item1; var agentT = agentData.Item2;
string agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT)) if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
WeaponPaints.g_playersAgent[player.Slot] = ( WeaponPaints.g_playersAgent[player.Slot] = (
agentCT, agentCT,
agentT agentT
); );
} }
}
}
catch (Exception ex) catch (Exception ex)
{ {
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}"); Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
} }
} }
internal async Task GetWeaponPaintsFromDatabase(PlayerInfo player) private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
{ {
try try
{ {
if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId.ToString()))
return; return;
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>(); var weaponInfos = new ConcurrentDictionary<ushort, WeaponInfo>();
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = await connection.QueryAsync<dynamic>(query, new { steamid = player.SteamId });
if (playerSkins == null) const string query = "SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_skins` WHERE `user_id` = @userId";
{ var playerSkins = connection.Query<dynamic>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
return;
}
foreach (var row in playerSkins) foreach (var row in playerSkins)
{ {
int weaponDefIndex = row?.weapon_defindex ?? 0; ushort weaponDefIndex = (ushort)(row.weapon ?? 0);
int weaponPaintId = row?.weapon_paint_id ?? 0; ushort weaponPaintId = (ushort)(row.paint ?? 0);
float weaponWear = row?.weapon_wear ?? 0f; float weaponWear = row.wear ?? 0f;
int weaponSeed = row?.weapon_seed ?? 0; ushort weaponSeed = (ushort)(row.seed ?? 0);
string weaponNameTag = row.nametag ?? string.Empty;
WeaponInfo weaponInfo = new WeaponInfo var weaponInfo = new WeaponInfo
{ {
Paint = weaponPaintId, Paint = weaponPaintId,
Seed = weaponSeed, Seed = weaponSeed,
Wear = weaponWear Wear = weaponWear,
NameTag = weaponNameTag
}; };
weaponInfos[weaponDefIndex] = weaponInfo; weaponInfos[weaponDefIndex] = weaponInfo;
@@ -133,20 +184,85 @@ namespace WeaponPaints
} }
} }
internal async Task GetMusicFromDatabase(PlayerInfo player) private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection)
{ {
try try
{ {
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
await using var connection = await _database.GetConnectionAsync(); const string query = "SELECT `music` FROM `wp_users_musics` WHERE `user_id` = @userId";
string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid"; var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
ushort? musicData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
if (musicData != null) if (musicData != null) WeaponPaints.g_playersMusic[player.Slot] = musicData.Value;
}
catch (Exception ex)
{ {
WeaponPaints.g_playersMusic[player.Slot] = musicData.Value; Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}");
}
}
private void GetPinFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.PinEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return;
const string query = "SELECT `pin` FROM `wp_users_pins` WHERE `user_id` = @userId";
var pinData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (pinData != null) WeaponPaints.g_playersPin[player.Slot] = pinData.Value;
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetPinFromDatabase: {ex.Message}");
}
}
internal async Task PurgeExpiredUsers()
{
try
{
await using var connection = await _database.GetConnectionAsync();
await using var transaction = await connection.BeginTransactionAsync();
var userIds = await connection.QueryAsync<int>(
$"SELECT id FROM wp_users WHERE last_online < NOW() - INTERVAL {_config.Additional.ExpireOlderThan} DAY",
transaction: transaction
);
var ids = string.Join(",", userIds);
string query;
if (userIds.AsList().Count > 0)
{
// Step 2: Delete related records in other tables using the retrieved IDs
query = $"DELETE FROM wp_users_agents WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
query = $"DELETE FROM wp_users_gloves WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
query = $"DELETE FROM wp_users_skins WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
query = $"DELETE FROM wp_users_knives WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
query = $"DELETE FROM wp_users_musics WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
query = $"DELETE FROM wp_users_pins WHERE user_id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
// Step 3: Delete users from wp_users
query = $"DELETE FROM wp_users WHERE id IN ({ids})";
await connection.ExecuteAsync(query, transaction: transaction);
// Commit transaction
await transaction.CommitAsync();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -155,15 +271,17 @@ namespace WeaponPaints
} }
} }
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife) internal async Task SyncKnifeToDatabase(PlayerInfo player, ushort knife)
{ {
if (!_config.Additional.KnifeEnabled || player == null || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return; if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
const string query =
"INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(@userId, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], newKnife = knife });
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife });
} }
catch (Exception e) catch (Exception e)
{ {
@@ -173,13 +291,14 @@ namespace WeaponPaints
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex) internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
{ {
if (!_config.Additional.GloveEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return; if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_gloves` (`steamid`, `weapon_defindex`) VALUES(@steamid, @weapon_defindex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex"; const string query =
await connection.ExecuteAsync(query, new { steamid = player.SteamId, weapon_defindex = defindex }); "INSERT INTO `wp_users_gloves` (`user_id`, `weapon_defindex`) VALUES(@userId, @weapon_defindex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex";
await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weapon_defindex = defindex });
} }
catch (Exception e) catch (Exception e)
{ {
@@ -189,19 +308,25 @@ namespace WeaponPaints
internal async Task SyncAgentToDatabase(PlayerInfo player) internal async Task SyncAgentToDatabase(PlayerInfo player)
{ {
if (!_config.Additional.AgentEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return; if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
const string query = """
INSERT INTO `wp_users_agents` (`user_id`, `agent_ct`, `agent_t`)
VALUES(@userId, @agent_ct, @agent_t)
ON DUPLICATE KEY UPDATE
`agent_ct` = @agent_ct,
`agent_t` = @agent_t
""";
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
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";
await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.g_playersAgent[player.Slot].CT, agent_t = WeaponPaints.g_playersAgent[player.Slot].T }); await connection.ExecuteAsync(query,
new
{
userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], agent_ct = WeaponPaints.g_playersAgent[player.Slot].CT,
agent_t = WeaponPaints.g_playersAgent[player.Slot].T
});
} }
catch (Exception e) catch (Exception e)
{ {
@@ -211,38 +336,41 @@ namespace WeaponPaints
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player) internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
{ {
if (player == null || string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo)) if (string.IsNullOrEmpty(player.SteamId.ToString()) ||
!WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
return; return;
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
foreach (var weaponInfoPair in weaponsInfo) foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo)
{ {
int weaponDefIndex = weaponInfoPair.Key; var paintId = weaponInfo.Paint;
WeaponInfo weaponInfo = weaponInfoPair.Value; var wear = weaponInfo.Wear;
var seed = weaponInfo.Seed;
int paintId = weaponInfo.Paint; const string queryCheckExistence =
float wear = weaponInfo.Wear; "SELECT COUNT(*) FROM `wp_users_skins` WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex";
int seed = weaponInfo.Seed;
string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence,
new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex });
int existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex });
string query; string query;
object parameters; object parameters;
if (existingRecordCount > 0) 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"; query =
parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed }; "UPDATE `wp_users_skins` SET `paint` = @paintId, `wear` = @wear, `seed` = @seed WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex";
parameters = new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex, paintId, wear, seed };
} }
else else
{ {
query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + query =
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed)"; "INSERT INTO `wp_users_skins` (`user_id`, `weapon`, `paint`, `wear`, `seed`) " +
parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed }; "VALUES (@userId, @weaponDefIndex, @paintId, @wear, @seed)";
parameters = new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex, paintId, wear, seed };
} }
await connection.ExecuteAsync(query, parameters); await connection.ExecuteAsync(query, parameters);
@@ -256,13 +384,14 @@ namespace WeaponPaints
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music) internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
{ {
if (!_config.Additional.MusicEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return; if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_music` (`steamid`, `music_id`) VALUES(@steamid, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; const string query =
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newMusic = music }); "INSERT INTO `wp_users_musics` (`user_id`, `music`) VALUES(@userId, @newMusic) ON DUPLICATE KEY UPDATE `music` = @newMusic";
await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], newMusic = music });
} }
catch (Exception e) catch (Exception e)
{ {
@@ -270,4 +399,3 @@ namespace WeaponPaints
} }
} }
} }
}

View File

@@ -2,22 +2,22 @@
"ChangeSubclass": { "ChangeSubclass": {
"signatures": { "signatures": {
"library": "server", "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", "windows": "40 57 48 83 EC 20 48 8B F9 41 B0 01",
"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" "linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 45 31 E4 53 48 81 EC 98 00 00 00"
} }
}, },
"CAttributeList_SetOrAddAttributeValueByName": { "CAttributeList_SetOrAddAttributeValueByName": {
"signatures": { "signatures": {
"library": "server", "library": "server",
"windows": "\\x40\\x53\\x41\\x56\\x41\\x57\\x48\\x81\\xEC\\x90\\x00\\x00\\x00\\x0F\\x29\\x74\\x24\\x70", "windows": "40 53 41 56 41 57 48 81 EC 90 00 00 00 0F 29 74 24 70",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78" "linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 49 89 F4 53 48 83 EC 78"
} }
}, },
"CBaseModelEntity_SetBodygroup": { "CBaseModelEntity_SetBodygroup": {
"signatures": { "signatures": {
"library": "server", "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", "windows": "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 41 8B F8 48 8B F2 48 8B D9 E8 ? ? ? ?",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08" "linux": "55 48 89 E5 41 56 49 89 F6 41 55 41 89 D5 41 54 49 89 FC 48 83 EC 08"
} }
} }
} }

View File

@@ -1,29 +1,66 @@
<?php <?php
/**
* Class DataBase
*
* This class handles database operations using PDO.
*/
class DataBase { class DataBase {
/**
* @var PDO The PDO instance for database connection.
*/
private $PDO; private $PDO;
/**
* Constructor method to initialize the database connection.
*/
public function __construct() { public function __construct() {
try { try {
$this->PDO = new PDO("mysql:host=".DB_HOST."; port=".DB_PORT."; dbname=".DB_NAME, DB_USER, DB_PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); // Establish a connection to the database using PDO
$this->PDO = new PDO(
"mysql:host=".DB_HOST.";port=".DB_PORT.";dbname=".DB_NAME,
DB_USER,
DB_PASS
);
// Set the connection to use utf8 encoding
$this->PDO->exec("SET NAMES utf8");
} }
catch(PDOException $ex) catch(PDOException $ex) {
{ // Display error message if connection fails
echo "<div style='display: flex; flex-direction: column;align-items: center;justify-content: center;text-align: center;'><h2>Problem with database!</h2>"; echo "<div style='display: flex; flex-direction: column;align-items: center;justify-content: center;text-align: center;'><h2>Problem with database!</h2>";
die("<pre style='padding: 10px;text-wrap: balance; border: 2px solid #ed6bd3;background: #252525; color: #ed6bd3; width: 50%;'>" . $ex . "</pre>"); die("<pre style='padding: 10px;text-wrap: balance; border: 2px solid #ed6bd3;background: #252525; color: #ed6bd3; width: 50%;'>" . $ex . "</pre>");
} }
} }
public function select($query, $bindings = []) {
/**
* Perform a SELECT query on the database.
*
* @param string $query The SQL query to execute.
* @param array $bindings An associative array of parameters and their values.
* @return array|false Returns an array of rows as associative arrays or false if no results are found.
*/
public function select($query, $bindings = array()) {
// Prepare and execute the SQL query
$STH = $this->PDO->prepare($query); $STH = $this->PDO->prepare($query);
$STH->execute($bindings); $STH->execute($bindings);
// Fetch the results as associative arrays
$result = $STH->fetchAll(PDO::FETCH_ASSOC); $result = $STH->fetchAll(PDO::FETCH_ASSOC);
$result ??= false; if ($result === false) {
$result = array(); // Set $result to an empty array if no results found
}
return $result; return $result;
} }
public function query($query, $bindings = []){ /**
* Perform a non-query SQL statement on the database.
*
* @param string $query The SQL query to execute.
* @param array $bindings An associative array of parameters and their values.
* @return bool Returns true on success or false on failure.
*/
public function query($query, $bindings = array()) {
// Prepare and execute the SQL query
$STH = $this->PDO->prepare($query); $STH = $this->PDO->prepare($query);
return $STH->execute($bindings); return $STH->execute($bindings);
} }
} }

78
website/class/header.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Set security headers to enhance security
// header("X-Frame-Options: SAMEORIGIN");
// header("X-XSS-Protection: 1; mode=block");
// header("X-Content-Type-Options: nosniff");
// header("Referrer-Policy: no-referrer-when-downgrade");
// header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://code.jquery.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https://cdn.jsdelivr.net https://steamcommunity-a.akamaihd.net https://raw.githubusercontent.com;");
// Include necessary classes and files
require 'class/config.php';
require 'class/database.php';
require 'steamauth/steamauth.php';
require 'class/utils.php';
// Create a database instance
$db = new DataBase();
// Check if the user is logged in
if (isset($_SESSION['steamid'])) {
// Insert or update user's Steam ID in the database
$steamid = $_SESSION['steamid'];
$db->query("INSERT INTO `wp_users` (`steamid`) VALUES ('{$steamid}') ON DUPLICATE KEY UPDATE `updated_at` = CURRENT_TIMESTAMP");
// Get user's database index
$userInfoQuery = $db->select("SELECT `id` FROM `wp_users` WHERE `steamid` = :steamid", ["steamid" => $steamid]);
$_SESSION['userDbIndex'] = $userDbIndex = (int)$userInfoQuery[0]['id'];
// Get weapons and skins information
$weapons = UtilsClass::getWeaponsFromArray();
$skins = UtilsClass::skinsFromJson();
$gloves = UtilsClass::glovesFromJson();
// Retrieve user's selected skins and knife
$querySelected = $db->select("SELECT `weapon`, `paint`, `wear`, `seed`, `nametag` FROM `wp_users_skins` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]);
$selectedSkins = UtilsClass::getSelectedSkins($querySelected);
$selectedKnifeResult = $db->select("SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]);
$selectedGlovesResult = $db->select("SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = :user_id", ["user_id" => $userDbIndex]);
$selectedGloves = !empty($selectedGlovesResult) ? $selectedGlovesResult[0] : $gloves[0][0];
// Determine user's selected knife or set default knife
if (!empty($selectedKnifeResult)) {
$selectedKnife = $selectedKnifeResult[0]['knife'];
} else {
$selectedKnife = "weapon_knife";
}
$knifes = UtilsClass::getKnifeTypes();
// Handle form submission
if (isset($_POST['forma'])) {
$ex = explode("-", $_POST['forma']);
// Handle knife selection
if ($ex[0] == "knife") {
$db->query("INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(:user_id, :knife) ON DUPLICATE KEY UPDATE `knife` = :knife", ["user_id" => $userDbIndex, "knife" => $knifes[$ex[1]]['weapon_name']]);
} else {
// Handle skin selection
if (array_key_exists($ex[1], $skins[$ex[0]]) && isset($_POST['wear']) && $_POST['wear'] >= 0.00 && $_POST['wear'] <= 1.00 && isset($_POST['seed'])) {
$wear = floatval($_POST['wear']); // wear
$seed = intval($_POST['seed']); // seed
// Check if the skin is already selected and update or insert accordingly
if (array_key_exists($ex[0], $selectedSkins)) {
$db->query("UPDATE wp_users_skins SET paint = :weapon_paint_id, wear = :weapon_wear, seed = :weapon_seed WHERE user_id = :user_id AND weapon = :weapon_defindex", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
} else {
$db->query("INSERT INTO wp_users_skins (`user_id`, `weapon`, `paint`, `wear`, `seed`) VALUES (:user_id, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed)", ["user_id" => $userDbIndex, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
}
}
}
// Redirect to the same page after form submission
header("Location: {$_SERVER['PHP_SELF']}");
}
}
?>

View File

@@ -1,99 +1,158 @@
<?php <?php
/**
* Class UtilsClass
*
* Provides utility methods for handling skin and weapon data.
*/
class UtilsClass class UtilsClass
{ {
public static function skinsFromJson(): array /**
* Retrieve skins data from the JSON file.
*
* @return array An associative array containing skin data.
*/
public static function skinsFromJson()
{ {
$skins = []; $skins = array();
$json = json_decode(file_get_contents(__DIR__ . "/../data/skins.json"), true); $jsonFilePath = __DIR__ . "/../data/skins.json";
if (file_exists($jsonFilePath) && is_readable($jsonFilePath)) {
$json = json_decode(file_get_contents($jsonFilePath), true);
foreach ($json as $skin) { foreach ($json as $skin) {
$skins[(int) $skin['weapon_defindex']][(int) $skin['paint']] = [ $skins[(int) $skin['weapon_defindex']][(int) $skin['paint']] = array(
'weapon_name' => $skin['weapon_name'], 'weapon_name' => $skin['weapon_name'],
'paint_name' => $skin['paint_name'], 'paint_name' => $skin['paint_name'],
'image_url' => $skin['image'], 'image_url' => $skin['image'],
]; );
}
} else {
// Handle file not found or unreadable error
// You can throw an exception or log an error message
} }
return $skins; return $skins;
} }
/**
* Retrieve music data from the JSON file.
*
* @return array An associative array containing music data.
*/
public static function musicFromJson()
{
$music = array();
$jsonFilePath = __DIR__ . "/../data/music.json";
if (file_exists($jsonFilePath) && is_readable($jsonFilePath)) {
$json = json_decode(file_get_contents($jsonFilePath), true);
foreach ($json as $track) {
$music[$track['id']] = array(
'name' => $track['name'],
'image' => $track['image'],
);
}
} else {
// Handle file not found or unreadable error
// You can throw an exception or log an error message
}
return $music;
}
public static function glovesFromJson()
{
$gloves = array();
$jsonFilePath = __DIR__ . "/../data/gloves.json";
if (file_exists($jsonFilePath) && is_readable($jsonFilePath)) {
$json = json_decode(file_get_contents($jsonFilePath), true);
foreach ($json as $glove) {
$gloves[$glove['weapon_defindex']][$glove['paint']] = array(
'paint_name' => $glove['paint_name'],
'image_url' => $glove['image'],
);
}
} else {
// Handle file not found or unreadable error
// You can throw an exception or log an error message
}
return $gloves;
}
/**
* Retrieve weapons data from the skin data array.
*
* @return array An associative array containing weapon data.
*/
public static function getWeaponsFromArray() public static function getWeaponsFromArray()
{ {
$weapons = []; $weapons = array();
$temp = self::skinsFromJson(); $skinsData = self::skinsFromJson();
foreach ($temp as $key => $value) { foreach ($skinsData as $key => $value) {
if (key_exists($key, $weapons)) $weapons[$key] = array(
continue;
$weapons[$key] = [
'weapon_name' => $value[0]['weapon_name'], 'weapon_name' => $value[0]['weapon_name'],
'paint_name' => $value[0]['paint_name'], 'paint_name' => $value[0]['paint_name'],
'image_url' => $value[0]['image_url'], 'image_url' => $value[0]['image_url'],
]; );
} }
return $weapons; return $weapons;
} }
/**
* Retrieve knife types from the weapon data array.
*
* @return array An associative array containing knife types data.
*/
public static function getKnifeTypes() public static function getKnifeTypes()
{ {
$knifes = []; $knifes = array();
$temp = self::getWeaponsFromArray(); $weaponsData = self::getWeaponsFromArray();
foreach ($temp as $key => $weapon) { $allowedKnifeKeys = array(
if ( 500, 503, 505, 506, 507, 508, 509, 512, 514, 515,
!in_array($key, [ 516, 517, 518, 519, 520, 521, 522, 523, 525
500, );
503,
505,
506,
507,
508,
509,
512,
514,
515,
516,
517,
518,
519,
520,
521,
522,
523,
525,
526
])
)
continue;
$knifes[$key] = [ foreach ($weaponsData as $key => $weapon) {
if (in_array($key, $allowedKnifeKeys)) {
$knifes[$key] = array(
'weapon_name' => $weapon['weapon_name'], 'weapon_name' => $weapon['weapon_name'],
'paint_name' => rtrim(explode("|", $weapon['paint_name'])[0]), 'paint_name' => rtrim(explode("|", $weapon['paint_name'])[0]),
'image_url' => $weapon['image_url'], 'image_url' => $weapon['image_url'],
]; );
$knifes[0] = [ }
}
// Add default knife
$knifes[0] = array(
'weapon_name' => "weapon_knife", 'weapon_name' => "weapon_knife",
'paint_name' => "Default knife", 'paint_name' => "Default knife",
'image_url' => "https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/website/img/skins/weapon_knife.png", 'image_url' => "https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/website/img/skins/weapon_knife.png",
]; );
}
ksort($knifes); ksort($knifes);
return $knifes; return $knifes;
} }
public static function getSelectedSkins(array $temp) /**
* Retrieve selected skins data from the database result.
*
* @param array $temp An array containing the selected skins data.
* @return array An associative array containing selected skins data.
*/
public static function getSelectedSkins($temp)
{ {
$selected = []; $selected = array();
foreach ($temp as $weapon) { foreach ($temp as $weapon) {
$selected[$weapon['weapon_defindex']] = [ $selected[$weapon['weapon']] = array(
'weapon_paint_id' => $weapon['weapon_paint_id'], 'weapon_paint_id' => $weapon['paint'],
'weapon_seed' => $weapon['weapon_seed'], 'weapon_seed' => $weapon['seed'],
'weapon_wear' => $weapon['weapon_wear'], 'weapon_wear' => $weapon['wear'],
]; );
} }
return $selected; return $selected;

54
website/db-sqlite.sql Normal file
View File

@@ -0,0 +1,54 @@
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS `wp_players` (
`user_id` INTEGER PRIMARY KEY AUTOINCREMENT,
`steamid` INTEGER NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(`steamid`)
);
CREATE TABLE IF NOT EXISTS `wp_player_skins` (
`user_id` INTEGER NOT NULL,
`team` INTEGER NOT NULL,
`weapon_defindex` INTEGER NOT NULL,
`paint` INTEGER NOT NULL,
`wear` REAL NOT NULL DEFAULT 0.001,
`seed` INTEGER NOT NULL DEFAULT 0,
`nametag` TEXT DEFAULT NULL,
`stattrack` INTEGER NOT NULL DEFAULT 0,
`stattrack_enabled` INTEGER NOT NULL DEFAULT 0,
`quality` INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (`user_id`,`team`,`weapon_defindex`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS `wp_players_knife` (
`user_id` INTEGER NOT NULL,
`knife` TEXT DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS `wp_players_gloves` (
`user_id` INTEGER NOT NULL,
`weapon_defindex` INTEGER DEFAULT NULL,
`team` INTEGER DEFAULT NULL,
PRIMARY KEY (`user_id`,`team`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS `wp_players_music` (
`user_id` INTEGER NOT NULL,
`music` INTEGER DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS `wp_players_agents` (
`user_id` INTEGER NOT NULL,
`agent_ct` TEXT DEFAULT NULL,
`agent_t` TEXT DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
);

53
website/db.sql Normal file
View File

@@ -0,0 +1,53 @@
CREATE TABLE IF NOT EXISTS `wp_players` (
`user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`steamid` BIGINT UNSIGNED NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `unique_steamid` (`steamid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `wp_player_skins` (
`user_id` INT UNSIGNED NOT NULL,
`team` SMALLINT UNSIGNED NOT NULL,
`weapon_defindex` SMALLINT UNSIGNED NOT NULL,
`paint` SMALLINT UNSIGNED NOT NULL,
`wear` FLOAT NOT NULL DEFAULT 0.001,
`seed` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
`nametag` VARCHAR(20) DEFAULT NULL,
`stattrack` INT UNSIGNED NOT NULL DEFAULT 0,
`stattrack_enabled` SMALLINT NOT NULL DEFAULT 0,
`quality` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`user_id`,`team`,`weapon_defindex`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `wp_players_knife` (
`user_id` INT UNSIGNED NOT NULL,
`knife` VARCHAR(32) DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `wp_players_gloves` (
`user_id` INT UNSIGNED NOT NULL,
`weapon_defindex` SMALLINT UNSIGNED DEFAULT NULL,
`team` SMALLINT UNSIGNED DEFAULT NULL,
PRIMARY KEY (`user_id`,`team`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `wp_players_music` (
`user_id` INT UNSIGNED NOT NULL,
`music` SMALLINT UNSIGNED DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `wp_players_agents` (
`user_id` INT UNSIGNED NOT NULL,
`agent_ct` varchar(64) DEFAULT NULL,
`agent_t` varchar(64) DEFAULT NULL,
PRIMARY KEY (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `wp_players`(`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -8,7 +8,7 @@ $weapons = array (
"weapon_aug" => 8, "weapon_aug" => 8,
"weapon_awp" => 9, "weapon_awp" => 9,
"weapon_famas" => 10, "weapon_famas" => 10,
"weapon_g3sg1" => 11, "weapon_g3sg1" => 10,
"weapon_galilar" => 13, "weapon_galilar" => 13,
"weapon_m249" => 14, "weapon_m249" => 14,
"weapon_m4a1" => 16, "weapon_m4a1" => 16,
@@ -53,14 +53,7 @@ $weapons = array (
"weapon_knife_stiletto" => 522, "weapon_knife_stiletto" => 522,
"weapon_knife_widowmaker" => 523, "weapon_knife_widowmaker" => 523,
"weapon_knife_skeleton" => 525); "weapon_knife_skeleton" => 525);
$json = json_decode(file_get_contents('skins.json'));
$
$json = json_decode(file_get_contents('https://bymykel.github.io/CSGO-API/api/en/skins.json'));
die(var_dump($json));
echo "<pre>"; echo "<pre>";
foreach($json as $skin) foreach($json as $skin)
{ {

View File

@@ -1,261 +1,39 @@
<?php <?php
require_once 'class/config.php'; require 'class/header.php';
require_once 'class/database.php';
require_once 'steamauth/steamauth.php';
require_once 'class/utils.php';
$db = new DataBase();
if (isset($_SESSION['steamid'])) {
$steamid = $_SESSION['steamid'];
$weapons = UtilsClass::getWeaponsFromArray();
$skins = UtilsClass::skinsFromJson();
$querySelected = $db->select("SELECT `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed` FROM `wp_player_skins` WHERE `wp_player_skins`.`steamid` = :steamid", ["steamid" => $steamid]);
$selectedSkins = UtilsClass::getSelectedSkins($querySelected);
$selectedKnife = $db->select("SELECT * FROM `wp_player_knife` WHERE `wp_player_knife`.`steamid` = :steamid", ["steamid" => $steamid]);
$knifes = UtilsClass::getKnifeTypes();
if (isset($_POST['forma'])) {
$ex = explode("-", $_POST['forma']);
if ($ex[0] == "knife") {
$db->query("INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(:steamid, :knife) ON DUPLICATE KEY UPDATE `knife` = :knife", ["steamid" => $steamid, "knife" => $knifes[$ex[1]]['weapon_name']]);
} else {
if (array_key_exists($ex[1], $skins[$ex[0]]) && isset($_POST['wear']) && $_POST['wear'] >= 0.00 && $_POST['wear'] <= 1.00 && isset($_POST['seed'])) {
$wear = floatval($_POST['wear']); // wear
$seed = intval($_POST['seed']); // seed
if (array_key_exists($ex[0], $selectedSkins)) {
$db->query("UPDATE wp_player_skins SET weapon_paint_id = :weapon_paint_id, weapon_wear = :weapon_wear, weapon_seed = :weapon_seed WHERE steamid = :steamid AND weapon_defindex = :weapon_defindex", ["steamid" => $steamid, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
} else {
$db->query("INSERT INTO wp_player_skins (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) VALUES (:steamid, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed)", ["steamid" => $steamid, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
}
}
}
header("Location: {$_SERVER['PHP_SELF']}");
}
}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" <?php if (WEB_STYLE_DARK) echo 'data-bs-theme="dark"' ?>> <html lang="en" <?php if (WEB_STYLE_DARK) echo 'data-bs-theme="dark"' ?>>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title>CS2 Simple Weapon Paints</title> <title>CS2 Simple Weapon Paints</title>
</head> </head>
<body> <body>
<?php if (!isset($_SESSION['steamid'])) : ?>
<?php <div class='bg-primary'><h2>To choose weapon paints loadout, you need to <?php loginbutton("rectangle"); ?></h2></div>
if (!isset($_SESSION['steamid'])) {
echo "<div class='bg-primary'><h2>To choose weapon paints loadout, you need to ";
loginbutton("rectangle");
echo "</h2></div>";
} else {
echo "<div class='bg-primary'><h2>Your current weapon skin loadout <a class='btn btn-danger' href='{$_SERVER['PHP_SELF']}?logout'>Logout</a></h2> </div>";
echo "<div class='card-group mt-2'>";
?>
<div class="col-sm-2">
<div class="card text-center mb-3 border border-primary">
<div class="card-body">
<?php
$actualKnife = $knifes[0];
if ($selectedKnife != null)
{
foreach ($knifes as $knife) {
if ($selectedKnife[0]['knife'] == $knife['weapon_name']) {
$actualKnife = $knife;
break;
}
}
}
echo "<div class='card-header'>";
echo "<h6 class='card-title item-name'>Knife type</h6>";
echo "<h5 class='card-title item-name'>{$actualKnife["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$actualKnife["image_url"]}' class='skin-image'>";
?>
</div>
<div class="card-footer">
<form action="" method="POST">
<select name="forma" class="form-control select" onchange="this.form.submit()" class="SelectWeapon">
<option disabled>Select knife</option>
<?php
foreach ($knifes as $knifeKey => $knife) {
if ($selectedKnife[0]['knife'] == $knife['weapon_name'])
echo "<option selected value=\"knife-{$knifeKey}\">{$knife['paint_name']}</option>";
else
echo "<option value=\"knife-{$knifeKey}\">{$knife['paint_name']}</option>";
}
?>
</select>
</form>
</div>
</div>
</div>
<?php
foreach ($weapons as $defindex => $default) { ?>
<div class="col-sm-2">
<div class="card text-center mb-3">
<div class="card-body">
<?php
if (array_key_exists($defindex, $selectedSkins)) {
echo "<div class='card-header'>";
echo "<h5 class='card-title item-name'>{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]['image_url']}' class='skin-image'>";
} else {
echo "<div class='card-header'>";
echo "<h5 class='card-title item-name'>{$default["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$default["image_url"]}' class='skin-image'>";
}
?>
</div>
<div class="card-footer">
<form action="" method="POST">
<select name="forma" class="form-control select" onchange="this.form.submit()" class="SelectWeapon">
<option disabled>Select skin</option>
<?php
foreach ($skins[$defindex] as $paintKey => $paint) {
if (array_key_exists($defindex, $selectedSkins) && $selectedSkins[$defindex]['weapon_paint_id'] == $paintKey)
echo "<option selected value=\"{$defindex}-{$paintKey}\">{$paint['paint_name']}</option>";
else
echo "<option value=\"{$defindex}-{$paintKey}\">{$paint['paint_name']}</option>";
}
?>
</select>
<br></br>
<?php
$selectedSkinInfo = isset($selectedSkins[$defindex]) ? $selectedSkins[$defindex] : null;
$steamid = $_SESSION['steamid'];
if ($selectedSkinInfo) :
?>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#weaponModal<?php echo $defindex ?>">
Settings
</button>
<?php else : ?> <?php else : ?>
<button type="button" class="btn btn-primary" onclick="showSkinSelectionAlert()"> <div class='bg-primary'><h2>Your current weapon skin loadout <a class='btn btn-danger' href='<?php echo $_SERVER['PHP_SELF']; ?>?logout'>Logout</a></h2> </div>
Settings <div class='card-group mt-2'>
</button> <!-- Display user's selected knife -->
<script> <?php require_once 'view/display_knife.php'; ?>
function showSkinSelectionAlert() { <!-- Display user's selected gloves -->
alert("You need to select a skin first."); <?php require_once 'view/display_gloves.php'; ?>
} <!-- Display user's selected skins for different weapons -->
</script> <?php require_once 'view/display_weapons.php'; ?>
</div>
<?php endif; ?> <?php endif; ?>
<!-- Footer section -->
</div>
<?php
// wear value
$selectedSkinInfo = isset($selectedSkins[$defindex]['weapon_paint_id']) ? $selectedSkins[$defindex] : null;
$queryWear = $selectedSkins[$defindex]['weapon_wear'] ?? 1.0;
$initialWearValue = isset($selectedSkinInfo['weapon_wear']) ? $selectedSkinInfo['weapon_wear'] : (isset($queryWear[0]['weapon_wear']) ? $queryWear[0] : 0.0);
// seed value
$querySeed = $selectedSkins[$defindex]['weapon_seed'] ?? 0;
$initialSeedValue = isset($selectedSkinInfo['weapon_seed']) ? $selectedSkinInfo['weapon_seed'] : 0;
?>
<div class="modal fade" id="weaponModal<?php echo $defindex ?>" tabindex="-1" role="dialog" aria-labelledby="weaponModalLabel<?php echo $defindex ?>" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class='card-title item-name'>
<?php
if (array_key_exists($defindex, $selectedSkins)) {
echo "{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]["paint_name"]} Settings";
} else {
echo "{$default["paint_name"]} Settings";
}
?>
</h5>
</div>
<div class="modal-body">
<div class="form-group">
<select class="form-select" id="wearSelect<?php echo $defindex ?>" name="wearSelect" onchange="updateWearValue<?php echo $defindex ?>(this.value)">
<option disabled>Select Wear</option>
<option value="0.00" <?php echo ($initialWearValue == 0.00) ? 'selected' : ''; ?>>Factory New</option>
<option value="0.07" <?php echo ($initialWearValue == 0.07) ? 'selected' : ''; ?>>Minimal Wear</option>
<option value="0.15" <?php echo ($initialWearValue == 0.15) ? 'selected' : ''; ?>>Field-Tested</option>
<option value="0.38" <?php echo ($initialWearValue == 0.38) ? 'selected' : ''; ?>>Well-Worn</option>
<option value="0.45" <?php echo ($initialWearValue == 0.45) ? 'selected' : ''; ?>>Battle-Scarred</option>
</select>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="wear">Wear:</label>
<input type="text" value="<?php echo $initialWearValue; ?>" class="form-control" id="wear<?php echo $defindex ?>" name="wear">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="seed">Seed:</label>
<input type="text" value="<?php echo $initialSeedValue; ?>" class="form-control" id="seed<?php echo $defindex ?>" name="seed" oninput="validateSeed(this)">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">Use</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// wear
function updateWearValue<?php echo $defindex ?>(selectedValue) {
var wearInputElement = document.getElementById("wear<?php echo $defindex ?>");
wearInputElement.value = selectedValue;
}
function validateWear(inputElement) {
inputElement.value = inputElement.value.replace(/[^0-9]/g, '');
}
// seed
function validateSeed(input) {
// Check entered value
var inputValue = input.value.replace(/[^0-9]/g, ''); // Just get the numbers
if (inputValue === "") {
input.value = 0; // Set to 0 if empty or no numbers
} else {
var numericValue = parseInt(inputValue);
numericValue = Math.min(1000, Math.max(1, numericValue)); // Interval control
input.value = numericValue;
}
}
</script>
<?php } ?>
<?php } ?>
</div>
</div>
<div class="container"> <div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top"> <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<div class="col-md-4 d-flex align-items-center"> <div class="col-md-4 d-flex align-items-center">
<span class="mb-3 mb-md-0 text-body-secondary">© 2023 <a href="https://github.com/Nereziel/cs2-WeaponPaints">Nereziel/cs2-WeaponPaints</a></span> <span class="mb-3 mb-md-0 text-body-secondary">© 2024 <a href="https://github.com/Nereziel/cs2-WeaponPaints">Nereziel/cs2-WeaponPaints</a></span>
</div> </div>
</footer> </footer>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Benjamin Smith
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,9 +1,11 @@
<?php <?php
ob_start(); //ob_start();
if (session_status() === PHP_SESSION_NONE) {
session_start(); session_start();
}
function logoutbutton() { function logoutbutton() {
echo "<form action='' method='get'><button class='btn btn-secondary' name='logout' type='submit'>Logout</button></form>"; //logout button echo "<form><button class='btn btn-secondary' name='logout' type='submit'>Logout</button></form>"; //logout button
} }
function loginbutton($buttonstyle = "square") { function loginbutton($buttonstyle = "square") {

View File

@@ -7,7 +7,6 @@ if (empty($_SESSION['steam_uptodate']) or empty($_SESSION['steam_personaname']))
$_SESSION['steam_communityvisibilitystate'] = $content['response']['players'][0]['communityvisibilitystate']; $_SESSION['steam_communityvisibilitystate'] = $content['response']['players'][0]['communityvisibilitystate'];
$_SESSION['steam_profilestate'] = $content['response']['players'][0]['profilestate']; $_SESSION['steam_profilestate'] = $content['response']['players'][0]['profilestate'];
$_SESSION['steam_personaname'] = $content['response']['players'][0]['personaname']; $_SESSION['steam_personaname'] = $content['response']['players'][0]['personaname'];
$_SESSION['steam_lastlogoff'] = $content['response']['players'][0]['lastlogoff'];
$_SESSION['steam_profileurl'] = $content['response']['players'][0]['profileurl']; $_SESSION['steam_profileurl'] = $content['response']['players'][0]['profileurl'];
$_SESSION['steam_avatar'] = $content['response']['players'][0]['avatar']; $_SESSION['steam_avatar'] = $content['response']['players'][0]['avatar'];
$_SESSION['steam_avatarmedium'] = $content['response']['players'][0]['avatarmedium']; $_SESSION['steam_avatarmedium'] = $content['response']['players'][0]['avatarmedium'];
@@ -27,7 +26,6 @@ $steamprofile['steamid'] = $_SESSION['steam_steamid'];
$steamprofile['communityvisibilitystate'] = $_SESSION['steam_communityvisibilitystate']; $steamprofile['communityvisibilitystate'] = $_SESSION['steam_communityvisibilitystate'];
$steamprofile['profilestate'] = $_SESSION['steam_profilestate']; $steamprofile['profilestate'] = $_SESSION['steam_profilestate'];
$steamprofile['personaname'] = $_SESSION['steam_personaname']; $steamprofile['personaname'] = $_SESSION['steam_personaname'];
$steamprofile['lastlogoff'] = $_SESSION['steam_lastlogoff'];
$steamprofile['profileurl'] = $_SESSION['steam_profileurl']; $steamprofile['profileurl'] = $_SESSION['steam_profileurl'];
$steamprofile['avatar'] = $_SESSION['steam_avatar']; $steamprofile['avatar'] = $_SESSION['steam_avatar'];
$steamprofile['avatarmedium'] = $_SESSION['steam_avatarmedium']; $steamprofile['avatarmedium'] = $_SESSION['steam_avatarmedium'];

View File

@@ -0,0 +1,71 @@
<div class="col-sm-2">
<div class="card text-center mb-3 border border-primary">
<div class="card-body">
<?php
// Determine the user's selected knife
$actualGloves = $selectedGloves;
/*if ($selectedGloves != null) {
foreach ($gloves as $glove) {
if ($selectedGloves == $glove['weapon_defindex']) {
$actualGloves = $glove;
break;
}
}
}*/
// Display user's selected knife information
echo "<div class='card-header'>";
echo "<h5 class='card-title item-name'>{$actualGloves["paint_name"]}</h5>";
echo "</div>";
echo "<img id='glove-image' src='{$actualGloves["image_url"]}' class='skin-image'>";
?>
</div>
<div class="card-footer">
<div class="form-group">
<label for="glovesSelect">Select Gloves:</label>
<select id="glovesSelect" class="form-control" onchange="updateGlovePaints(this.value)">
<option disabled selected>Select Gloves</option>
<?php
foreach ($gloves as $weapon_defindex => $glove) {
echo "<option value=\"{$weapon_defindex}\">{$weapon_defindex}</option>";
}
?>
</select>
</div>
<div class="form-group">
<label for="paintSelect">Select Paint:</label>
<select id="paintSelect" class="form-control" onchange="updateGloveImage(this)" >
<option disabled selected>Select Paint</option>
</select>
</div>
<script>
var gloves = <?php echo json_encode($gloves); ?>;
function updateGlovePaints(weapon_defindex) {
var paintSelect = document.getElementById('paintSelect');
paintSelect.innerHTML = ""; // Clear the select options
for (var defindex in gloves) {
if (defindex == weapon_defindex) {
for (var paint in gloves[defindex]) {
var option = document.createElement('option');
option.value = paint;
option.text = gloves[defindex][paint].paint_name;
paintSelect.appendChild(option);
document.getElementById('glove-image').src = gloves[defindex][paint].image_url;
}
}
}
}
function updateGloveImage(select) {
// here it will update glove-image with the selected paint from updateGlovePaints
var weapon_defindex = document.getElementById('glovesSelect').value;
var paint = select.value;
document.getElementById('glove-image').src = gloves[weapon_defindex][paint].image_url;
}
</script>
</div>
</div>
</div>

View File

@@ -0,0 +1,42 @@
<div class="col-sm-2">
<div class="card text-center mb-3 border border-primary">
<div class="card-body">
<?php
// Determine the user's selected knife
$actualKnife = $knifes[0];
if ($selectedKnife != null) {
foreach ($knifes as $knife) {
if ($selectedKnife == $knife['weapon_name']) {
$actualKnife = $knife;
break;
}
}
}
// Display user's selected knife information
echo "<div class='card-header'>";
echo "<h6 class='card-title item-name'>Knife type</h6>";
echo "<h5 class='card-title item-name'>{$actualKnife["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$actualKnife["image_url"]}' class='skin-image'>";
?>
</div>
<div class="card-footer">
<!-- Form for selecting user's knife -->
<form action="" method="POST">
<select name="forma" class="form-control select" onchange="this.form.submit()" class="SelectWeapon">
<option disabled>Select knife</option>
<?php
// Display options for selecting different knives
foreach ($knifes as $knifeKey => $knife) {
if ($selectedKnife == $knife['weapon_name'])
echo "<option selected value=\"knife-{$knifeKey}\">{$knife['paint_name']}</option>";
else
echo "<option value=\"knife-{$knifeKey}\">{$knife['paint_name']}</option>";
}
?>
</select>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,154 @@
<?php
// Display user's selected skins for different weapons
foreach ($weapons as $defindex => $default) {
?>
<div class="col-sm-2">
<div class="card text-center mb-3">
<div class="card-body">
<?php
// Determine the skin to display for the current weapon
if (array_key_exists($defindex, $selectedSkins)) {
echo "<div class='card-header'>";
echo "<h5 class='card-title item-name'>{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]['image_url']}' class='skin-image'>";
} else {
echo "<div class='card-header'>";
echo "<h5 class='card-title item-name'>{$default["paint_name"]}</h5>";
echo "</div>";
echo "<img src='{$default["image_url"]}' class='skin-image'>";
}
?>
</div>
<div class="card-footer">
<!-- Form for selecting user's skin and settings -->
<form action="" method="POST">
<select name="forma" class="form-control select" onchange="this.form.submit()" class="SelectWeapon">
<option disabled>Select skin</option>
<?php
// Display options for selecting different skins
foreach ($skins[$defindex] as $paintKey => $paint) {
if (array_key_exists($defindex, $selectedSkins) && $selectedSkins[$defindex]['weapon_paint_id'] == $paintKey)
echo "<option selected value=\"{$defindex}-{$paintKey}\">{$paint['paint_name']}</option>";
else
echo "<option value=\"{$defindex}-{$paintKey}\">{$paint['paint_name']}</option>";
}
?>
</select>
<br></br>
<?php
// Display settings button for selected skin
$selectedSkinInfo = isset($selectedSkins[$defindex]) ? $selectedSkins[$defindex] : null;
$steamid = $_SESSION['steamid'];
if ($selectedSkinInfo) :
?>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#weaponModal<?php echo $defindex ?>">
Settings
</button>
<?php else : ?>
<!-- Display message if skin is not selected -->
<button type="button" class="btn btn-primary" onclick="showSkinSelectionAlert()">
Settings
</button>
<script>
function showSkinSelectionAlert() {
alert("You need to select a skin first.");
}
</script>
<?php endif; ?>
</div>
<?php
// Display modal for adjusting wear and seed values
$selectedSkinInfo = isset($selectedSkins[$defindex]['weapon_paint_id']) ? $selectedSkins[$defindex] : null;
$queryWear = $selectedSkins[$defindex]['weapon_wear'] ?? 1.0;
$initialWearValue = isset($selectedSkinInfo['weapon_wear']) ? $selectedSkinInfo['weapon_wear'] : (isset($queryWear[0]['weapon_wear']) ? $queryWear[0] : 0.0);
$querySeed = $selectedSkins[$defindex]['weapon_seed'] ?? 0;
$initialSeedValue = isset($selectedSkinInfo['weapon_seed']) ? $selectedSkinInfo['weapon_seed'] : 0;
?>
<!-- Modal for adjusting wear and seed values -->
<div class="modal fade" id="weaponModal<?php echo $defindex ?>" tabindex="-1" role="dialog" aria-labelledby="weaponModalLabel<?php echo $defindex ?>" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<!-- Modal header -->
<div class="modal-header">
<h5 class='card-title item-name'>
<?php
if (array_key_exists($defindex, $selectedSkins)) {
echo "{$skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]["paint_name"]} Settings";
} else {
echo "{$default["paint_name"]} Settings";
}
?>
</h5>
</div>
<!-- Modal body -->
<div class="modal-body">
<!-- Form for adjusting wear and seed values -->
<div class="form-group">
<select class="form-select" id="wearSelect<?php echo $defindex ?>" name="wearSelect" onchange="updateWearValue<?php echo $defindex ?>(this.value)">
<option disabled>Select Wear</option>
<option value="0.00" <?php echo ($initialWearValue == 0.00) ? 'selected' : ''; ?>>Factory New</option>
<option value="0.07" <?php echo ($initialWearValue == 0.07) ? 'selected' : ''; ?>>Minimal Wear</option>
<option value="0.15" <?php echo ($initialWearValue == 0.15) ? 'selected' : ''; ?>>Field-Tested</option>
<option value="0.38" <?php echo ($initialWearValue == 0.38) ? 'selected' : ''; ?>>Well-Worn</option>
<option value="0.45" <?php echo ($initialWearValue == 0.45) ? 'selected' : ''; ?>>Battle-Scarred</option>
</select>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="wear">Wear:</label>
<input type="text" value="<?php echo $initialWearValue; ?>" class="form-control" id="wear<?php echo $defindex ?>" name="wear">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="seed">Seed:</label>
<input type="text" value="<?php echo $initialSeedValue; ?>" class="form-control" id="seed<?php echo $defindex ?>" name="seed" oninput="validateSeed(this)">
</div>
</div>
</div>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">Use</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- JavaScript functions for updating wear and seed values -->
<script>
// wear
function updateWearValue<?php echo $defindex ?>(selectedValue) {
var wearInputElement = document.getElementById("wear<?php echo $defindex ?>");
wearInputElement.value = selectedValue;
}
function validateWear(inputElement) {
inputElement.value = inputElement.value.replace(/[^0-9]/g, '');
}
// seed
function validateSeed(input) {
// Check entered value
var inputValue = input.value.replace(/[^0-9]/g, ''); // Just get the numbers
if (inputValue === "") {
input.value = 0; // Set to 0 if empty or no numbers
} else {
var numericValue = parseInt(inputValue);
numericValue = Math.min(1000, Math.max(1, numericValue)); // Interval control
input.value = numericValue;
}
}
</script>
<?php
}
?>