Compare commits

..

15 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
Nereziel
c291005d4d next 2024-05-27 18:05:32 +02:00
Nereziel
322b1b425b part one 2024-05-26 19:28:36 +02:00
213 changed files with 15260 additions and 1936 deletions

View File

@@ -58,8 +58,14 @@ jobs:
${{ env.OUTPUT_PATH }}/McMaster.NETCore.Plugins.dll \ ${{ env.OUTPUT_PATH }}/McMaster.NETCore.Plugins.dll \
${{ env.OUTPUT_PATH }}/Microsoft.DotNet.PlatformAbstractions.dll \ ${{ env.OUTPUT_PATH }}/Microsoft.DotNet.PlatformAbstractions.dll \
${{ env.OUTPUT_PATH }}/Microsoft.Extensions.DependencyModel.dll \ ${{ env.OUTPUT_PATH }}/Microsoft.Extensions.DependencyModel.dll \
- name: Copy skins - name: Copy skins.json
run: cp -R website/data ${{ env.OUTPUT_PATH }} run: cp website/data/skins.json ${{ env.OUTPUT_PATH }}/skins.json
- name: Copy gloves.json
run: cp website/data/gloves.json ${{ env.OUTPUT_PATH }}/gloves.json
- name: Copy agents.json
run: cp website/data/agents.json ${{ env.OUTPUT_PATH }}/agents.json
- name: Copy music.json
run: cp website/data/music.json ${{ env.OUTPUT_PATH }}/music.json
- name: Zip - name: Zip
run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/ run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
- name: Clean files Website - name: Clean files Website

Binary file not shown.

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,42 +11,43 @@ namespace WeaponPaints
{ {
private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command) private void OnCommandRefresh(CCSPlayerController? player, CommandInfo command)
{ {
if (!Config.Additional.CommandWpEnabled || !Config.Additional.SkinEnabled || !_gBCommandsAllowed) 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;
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]
}; };
try try
{ {
if (player != null && !CommandsCooldown.TryGetValue(player.Slot, out var 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)
{ {
_ = Task.Run(async () => await WeaponSync.GetPlayerData(playerInfo)); _ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
GivePlayerGloves(player); GivePlayerGloves(player);
RefreshWeapons(player);
GivePlayerAgent(player); GivePlayerAgent(player);
GivePlayerMusicKit(player); GivePlayerMusicKit(player);
RefreshWeapons(player);
AddTimer(0.1f, () => GivePlayerPin(player));
AddTimer(0.15f, () => GivePlayerPin(player)); AddTimer(0.15f, () => GivePlayerPin(player));
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"])) if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"]))
{ {
player.Print(Localizer["wp_command_refresh_done"]); player!.Print(Localizer["wp_command_refresh_done"]);
} }
return; return;
} }
@@ -97,7 +100,7 @@ namespace WeaponPaints
private void RegisterCommands() private void RegisterCommands()
{ {
_config.Additional.CommandSkin.ForEach(c => Config.Additional.CommandsInfo.ForEach(c =>
{ {
AddCommand($"css_{c}", "Skins info", (player, info) => AddCommand($"css_{c}", "Skins info", (player, info) =>
{ {
@@ -106,7 +109,7 @@ namespace WeaponPaints
}); });
}); });
_config.Additional.CommandRefresh.ForEach(c => Config.Additional.CommandsRefresh.ForEach(c =>
{ {
AddCommand($"css_{c}", "Skins refresh", (player, info) => AddCommand($"css_{c}", "Skins refresh", (player, info) =>
{ {
@@ -115,29 +118,26 @@ namespace WeaponPaints
}); });
}); });
if (Config.Additional.CommandKillEnabled) Config.Additional.CommandsKill.ForEach(c =>
{ {
_config.Additional.CommandKill.ForEach(c => AddCommand($"css_{c}", "kill yourself", (player, info) =>
{ {
AddCommand($"css_{c}", "kill yourself", (player, _) => 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 || !_gBCommandsAllowed) 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 = MenuApi?.NewMenu(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) =>
{ {
@@ -148,12 +148,12 @@ namespace WeaponPaints
if (string.IsNullOrEmpty(knifeKey)) return; 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"]);
} }
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
@@ -161,45 +161,50 @@ 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]
}; };
GPlayersKnife[player.Slot] = knifeKey; var knife = WeaponDefindex
.FirstOrDefault(entry => entry.Value.Equals(knifeKey, StringComparison.OrdinalIgnoreCase))
.Key;
if (_gBCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE) g_playersKnife[player.Slot] = (ushort)knife;
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);
} }
_config.Additional.CommandKnife.ForEach(c =>
Config.Additional.CommandsKnife.ForEach(c =>
{ {
AddCommand($"css_{c}", "Knife Menu", (player, _) => AddCommand($"css_{c}", "Knife Menu", (player, info) =>
{ {
if (giveItemMenu == null) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
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;
giveItemMenu.Open(player); giveItemMenu.Open(player);
//MenuManager.open(player, giveItemMenu);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{ {
player.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
}); });
@@ -207,12 +212,8 @@ namespace WeaponPaints
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 classNamesByWeapon = WeaponList BaseMenu weaponSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_weapon_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_weapon_title"]);
.Except([new KeyValuePair<string, string>("weapon_knife", "Default Knife")])
.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = MenuApi?.NewMenu(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) =>
@@ -220,14 +221,13 @@ namespace WeaponPaints
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
var selectedWeapon = option.Text; var selectedWeapon = option.Text;
if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return; if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return;
var skinsForSelectedWeapon = SkinsList?.Where(skin => var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin.TryGetValue("weapon_name", out var weaponName) && skin.TryGetValue("weapon_name", out var weaponName) &&
weaponName?.ToString() == selectedWeaponClassname weaponName?.ToString() == selectedWeaponClassname
)?.ToList(); )?.ToList();
var skinSubMenu = MenuApi?.NewMenu(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) =>
@@ -235,7 +235,7 @@ namespace WeaponPaints
if (!Utility.IsPlayerValid(p)) return; if (!Utility.IsPlayerValid(p)) return;
var steamId = p.SteamID.ToString(); var steamId = p.SteamID.ToString();
var firstSkin = SkinsList?.FirstOrDefault(skin => var firstSkin = skinsList?.FirstOrDefault(skin =>
{ {
if (skin.TryGetValue("weapon_name", out var weaponName)) if (skin.TryGetValue("weapon_name", out var weaponName))
{ {
@@ -249,27 +249,27 @@ namespace WeaponPaints
if (firstSkin == null || if (firstSkin == null ||
!firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) || !firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) ||
!int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) || !ushort.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
!int.TryParse(selectedPaintId, out var paintId)) return; !ushort.TryParse(selectedPaintId, out var paintId)) return;
{ {
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
); );
var 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].TryGetValue(weaponDefIndex, out var value)) if (!gPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out var value))
{ {
value = new WeaponInfo(); value = new WeaponInfo();
GPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value; gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
} }
value.Paint = paintId; value.Paint = paintId;
@@ -281,18 +281,18 @@ namespace WeaponPaints
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 (!_gBCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE || if (!g_bCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
WeaponSync == null) return; weaponSync == null) return;
RefreshWeapons(player); RefreshWeapons(player);
try try
{ {
_ = Task.Run(async () => await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo)); _ = Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -313,41 +313,38 @@ namespace WeaponPaints
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint)) if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{ {
skinSubMenu?.AddMenuOption($"{paintName} ({paint})", handleSkinSelection); skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
} }
} }
} }
if (player != null && Utility.IsPlayerValid(player)) if (player != null && Utility.IsPlayerValid(player))
skinSubMenu?.Open(player); skinSubMenu.Open(player);
}; };
// Add weapon options to the weapon selection menu // Add weapon options to the weapon selection menu
foreach (var weaponName in WeaponList foreach (var weaponName in WeaponList.Keys.Select(weaponClass => WeaponList[weaponClass]))
.Where(kvp => kvp.Key != "weapon_knife")
.Select(kvp => kvp.Value))
{ {
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
Config.Additional.CommandsSkinSelection.ForEach(c =>
_config.Additional.CommandSkinSelection.ForEach(c =>
{ {
AddCommand($"css_{c}", "Skins selection menu", (player, _) => 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 (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
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);
weaponSelectionMenu?.Open(player); weaponSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{ {
player.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
}); });
@@ -355,9 +352,7 @@ namespace WeaponPaints
private void SetupGlovesMenu() private void SetupGlovesMenu()
{ {
var glovesSelectionMenu = MenuApi?.NewMenu(Localizer["wp_glove_menu_title"]); BaseMenu glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]);
if (glovesSelectionMenu == null) return;
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) => var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
@@ -365,7 +360,7 @@ namespace WeaponPaints
var 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);
var image = selectedGlove?["image"]?.ToString() ?? ""; var image = selectedGlove?["image"]?.ToString() ?? "";
if (selectedGlove == null || if (selectedGlove == null ||
!selectedGlove.ContainsKey("weapon_defindex") || !selectedGlove.ContainsKey("weapon_defindex") ||
@@ -374,8 +369,8 @@ namespace WeaponPaints
!int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return; !int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return;
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
_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);
} }
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
@@ -383,82 +378,89 @@ 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 (paint != 0) if (paint != 0)
{ {
GPlayersGlove[player.Slot] = (ushort)weaponDefindex; g_playersGlove[player.Slot] = (ushort)weaponDefindex;
if (!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex)) if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out var value))
{
value = new ConcurrentDictionary<ushort, WeaponInfo>();
gPlayerWeaponsInfo[player.Slot] = value;
}
if (!value.ContainsKey((ushort)weaponDefindex))
{ {
WeaponInfo weaponInfo = new() WeaponInfo weaponInfo = new()
{ {
Paint = paint Paint = (ushort)paint
}; };
GPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo; value[(ushort)weaponDefindex] = weaponInfo;
} }
} }
else else
{ {
GPlayersGlove.TryRemove(player.Slot, out _); g_playersGlove.TryRemove(player.Slot, out _);
} }
if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"])) if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"]))
{ {
player.Print(Localizer["wp_glove_menu_select", selectedPaintName]); player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
} }
if (WeaponSync == null) return; 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 var 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);
}); });
AddTimer(0.1f, () => GivePlayerGloves(player)); AddTimer(0.1f, () => GivePlayerGloves(player));
AddTimer(0.25f, () => 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 paintName in GlovesList.Select(gloveObject => gloveObject["paint_name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0)) foreach (var paintName in glovesList.Select(gloveObject => gloveObject["paint_name"]?.ToString() ?? "").Where(paintName => 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
_config.Additional.CommandGlove.ForEach(c => Config.Additional.CommandsGlove.ForEach(c =>
{ {
AddCommand($"css_{c}", "Gloves selection menu", (player, info) => AddCommand($"css_{c}", "Gloves selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
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);
glovesSelectionMenu?.Open(player); glovesSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{ {
player.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
}); });
@@ -471,9 +473,9 @@ namespace WeaponPaints
if (!Utility.IsPlayerValid(player) || player is null) return; if (!Utility.IsPlayerValid(player) || player is null) return;
var 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;
@@ -487,7 +489,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]
}; };
@@ -495,56 +497,55 @@ namespace WeaponPaints
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
var 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)
{ {
GPlayersAgent.AddOrUpdate(player.Slot, g_playersAgent.AddOrUpdate(player.Slot,
key => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), null), key => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), null),
(key, oldValue) => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), oldValue.T)); (key, oldValue) => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), oldValue.T));
} }
else else
{ {
GPlayersAgent.AddOrUpdate(player.Slot, g_playersAgent.AddOrUpdate(player.Slot,
key => (null, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString()), key => (null, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString()),
(key, oldValue) => (oldValue.CT, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString()) (key, oldValue) => (oldValue.CT, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString())
); );
} }
if (WeaponSync != null) if (weaponSync != null)
{ {
_ = 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
_config.Additional.CommandAgent.ForEach(c => Config.Additional.CommandsAgent.ForEach(c =>
{ {
AddCommand($"css_{c}", "Agents selection menu", (player, info) => AddCommand($"css_{c}", "Agents selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
var agentsSelectionMenu = MenuApi?.NewMenu(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"]);
if (agentsSelectionMenu == null) return;
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
var filteredAgents = AgentsList.Where(agentObject => var filteredAgents = agentsList.Where(agentObject =>
{ {
if (agentObject["team"]?.Value<int>() is { } teamNum) if (agentObject["team"]?.Value<int>() is { } teamNum)
{ {
@@ -566,13 +567,13 @@ namespace WeaponPaints
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection); agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
} }
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
agentsSelectionMenu.Open(player); agentsSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{ {
player.Print(Localizer["wp_command_cooldown"]); player!.Print(Localizer["wp_command_cooldown"]);
} }
}); });
}); });
@@ -580,9 +581,7 @@ namespace WeaponPaints
private void SetupMusicMenu() private void SetupMusicMenu()
{ {
var musicSelectionMenu = MenuApi?.NewMenu(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"]);
if (musicSelectionMenu == null) return;
musicSelectionMenu.PostSelectAction = PostSelectAction.Close;
var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) => var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
@@ -590,7 +589,7 @@ namespace WeaponPaints
var 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 (!selectedMusic.ContainsKey("id") || if (!selectedMusic.ContainsKey("id") ||
@@ -599,8 +598,8 @@ namespace WeaponPaints
var image = selectedMusic["image"]?.ToString() ?? ""; var image = selectedMusic["image"]?.ToString() ?? "";
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
{ {
_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);
} }
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo
@@ -608,30 +607,30 @@ 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 (paint != 0) if (paint != 0)
{ {
GPlayersMusic[player.Slot] = (ushort)paint; g_playersMusic[player.Slot] = (ushort)paint;
} }
else else
{ {
GPlayersMusic[player.Slot] = 0; g_playersMusic[player.Slot] = 0;
} }
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)
{ {
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await WeaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint); await weaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
}); });
} }
@@ -644,54 +643,56 @@ 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]
}; };
GPlayersMusic[player.Slot] = 0; g_playersMusic[player.Slot] = 0;
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"])) if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{ {
player.Print(Localizer["wp_music_menu_select", Localizer["None"]]); player!.Print(Localizer["wp_music_menu_select", Localizer["None"]]);
} }
if (WeaponSync != null) if (weaponSync != null)
{ {
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await WeaponSync.SyncMusicToDatabase(playerInfo, 0); await weaponSync.SyncMusicToDatabase(playerInfo, 0);
}); });
} }
} }
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 paintName in MusicList.Select(musicObject => musicObject["name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0)) foreach (var paintName in musicList.Select(musicObject => musicObject["name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{ {
musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection); musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection);
} }
// Command to open the weapon selection menu for players Config.Additional.CommandsMusic.ForEach(c =>
_config.Additional.CommandMusic.ForEach(c =>
{ {
// Command to open the weapon selection menu for players
AddCommand($"css_{c}", "Music selection menu", (player, info) => AddCommand($"css_{c}", "Music selection menu", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return; if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (player == null || player.UserId == null) return;
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) || if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
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);
musicSelectionMenu.Open(player); musicSelectionMenu.Open(player);
return; return;
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{ {
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,38 +38,35 @@ namespace WeaponPaints
[JsonPropertyName("SkinEnabled")] [JsonPropertyName("SkinEnabled")]
public bool SkinEnabled { get; set; } = true; public bool SkinEnabled { get; set; } = true;
[JsonPropertyName("PinsEnabled")] [JsonPropertyName("NameTagEnabled")]
public bool PinsEnabled { get; set; } = true; public bool NameTagEnabled { get; set; } = true;
[JsonPropertyName("CommandWpEnabled")] [JsonPropertyName("PinEnabled")]
public bool CommandWpEnabled { get; set; } = true; public bool PinEnabled { get; set; } = true;
[JsonPropertyName("CommandKillEnabled")] [JsonPropertyName("CommandsKnife")]
public bool CommandKillEnabled { get; set; } = true; public List<string> CommandsKnife { get; set; } = ["knife", "knives"];
[JsonPropertyName("CommandKnife")] [JsonPropertyName("CommandsMusic")]
public List<string> CommandKnife { get; set; } = ["knife"]; public List<string> CommandsMusic { get; set; } = ["music", "musickits", "mkit"];
[JsonPropertyName("CommandMusic")] [JsonPropertyName("CommandsGlove")]
public List<string> CommandMusic { get; set; } = ["music"]; public List<string> CommandsGlove { get; set; } = ["gloves", "glove"];
[JsonPropertyName("CommandGlove")] [JsonPropertyName("CommandsAgent")]
public List<string> CommandGlove { get; set; } = ["gloves"]; public List<string> CommandsAgent { get; set; } = ["agents", "agent"];
[JsonPropertyName("CommandAgent")] [JsonPropertyName("CommandsInfo")]
public List<string> CommandAgent { get; set; } = ["agents"]; public List<string> CommandsInfo { get; set; } = ["ws", "skininfo"];
[JsonPropertyName("CommandSkin")] [JsonPropertyName("CommandsSkinSelection")]
public List<string> CommandSkin { get; set; } = ["ws"]; public List<string> CommandsSkinSelection { get; set; } = ["skins", "skin"];
[JsonPropertyName("CommandSkinSelection")] [JsonPropertyName("CommandsRefresh")]
public List<string> CommandSkinSelection { get; set; } = ["skins"]; public List<string> CommandsRefresh { get; set; } = ["wp", "refreshskins"];
[JsonPropertyName("CommandRefresh")] [JsonPropertyName("CommandsKill")]
public List<string> CommandRefresh { get; set; } = ["wp"]; public List<string> CommandsKill { get; set; } = ["kill", "suicide"];
[JsonPropertyName("CommandKill")]
public List<string> CommandKill { get; set; } = ["kill"];
[JsonPropertyName("GiveRandomKnife")] [JsonPropertyName("GiveRandomKnife")]
public bool GiveRandomKnife { get; set; } = false; public bool GiveRandomKnife { get; set; } = false;
@@ -61,32 +76,26 @@ 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
{ {
[JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 8; public override int Version { get; set; } = 7;
[JsonPropertyName("SkinsLanguage")] [JsonPropertyName("DatabaseCredentials")]
public string SkinsLanguage { get; set; } = "en"; public DatabaseCredentials DatabaseCredentials { get; set; } = new();
[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; } = "";
[JsonPropertyName("CmdRefreshCooldownSeconds")] [JsonPropertyName("CmdRefreshCooldownSeconds")]
public int CmdRefreshCooldownSeconds { get; set; } = 10; public int CmdRefreshCooldownSeconds { get; set; } = 60;
[JsonPropertyName("Prefix")]
public string Prefix { get; set; } = "[WeaponPaints]";
[JsonPropertyName("Website")] [JsonPropertyName("Website")]
public string Website { get; set; } = "example.com/skins"; public string Website { get; set; } = "example.com/skins";

106
Events.cs
View File

@@ -1,9 +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;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using System.Runtime.InteropServices;
namespace WeaponPaints namespace WeaponPaints
{ {
@@ -15,21 +16,21 @@ namespace WeaponPaints
CCSPlayerController? player = @event.Userid; CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot || if (player is null || !player.IsValid || player.IsBot ||
WeaponSync == null || Database == null) return HookResult.Continue; weaponSync == null || _database == null) return HookResult.Continue;
var 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]
}; };
try try
{ {
_ = Task.Run(async () => await WeaponSync.GetPlayerData(playerInfo)); _ = Task.Run(async () => await weaponSync.GetPlayerDatabaseIndex(playerInfo));
/* /*
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
{ {
@@ -53,8 +54,9 @@ namespace WeaponPaints
} }
*/ */
} }
catch catch (Exception)
{ {
return HookResult.Continue;
} }
return HookResult.Continue; return HookResult.Continue;
@@ -67,49 +69,34 @@ namespace WeaponPaints
if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue; if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue;
var 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 (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponInfos))
return HookResult.Continue;
if (WeaponSync != null)
_ = Task.Run(async () => await WeaponSync.SyncStatTrakToDatabase(playerInfo, weaponInfos));
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
{ {
GPlayerWeaponsInfo.TryRemove(player.Slot, out _); gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
} }
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
{ {
GPlayersKnife.TryRemove(player.Slot, out _); g_playersKnife.TryRemove(player.Slot, out _);
} }
if (Config.Additional.GloveEnabled) if (Config.Additional.GloveEnabled)
{ {
GPlayersGlove.TryRemove(player.Slot, out _); g_playersGlove.TryRemove(player.Slot, out _);
} }
if (Config.Additional.AgentEnabled) if (Config.Additional.AgentEnabled)
{ {
GPlayersAgent.TryRemove(player.Slot, out _); g_playersAgent.TryRemove(player.Slot, out _);
} }
if (Config.Additional.MusicEnabled) if (Config.Additional.MusicEnabled)
{ {
GPlayersMusic.TryRemove(player.Slot, out _); g_playersMusic.TryRemove(player.Slot, out _);
} }
if (Config.Additional.PinsEnabled) if (Config.Additional.PinEnabled)
{ {
GPlayersPin.TryRemove(player.Slot, out _); g_playersPin.TryRemove(player.Slot, out _);
} }
_temporaryPlayerWeaponWear.TryRemove(player.Slot, out _); commandsCooldown.Remove(player.Slot);
CommandsCooldown.Remove(player.Slot);
return HookResult.Continue; return HookResult.Continue;
} }
@@ -118,8 +105,11 @@ namespace WeaponPaints
{ {
if (Config.Additional is { KnifeEnabled: false, SkinEnabled: false, GloveEnabled: false }) 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)
@@ -134,23 +124,26 @@ namespace WeaponPaints
if (pawn == null || !pawn.IsValid) if (pawn == null || !pawn.IsValid)
return HookResult.Continue; return HookResult.Continue;
g_knifePickupCount[player.Slot] = 0;
GivePlayerMusicKit(player); GivePlayerMusicKit(player);
GivePlayerAgent(player); GivePlayerAgent(player);
GivePlayerGloves(player); GivePlayerGloves(player);
GivePlayerPin(player);
return HookResult.Continue; return HookResult.Continue;
} }
private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info)
{ {
_gBCommandsAllowed = false; g_bCommandsAllowed = false;
return HookResult.Continue; return HookResult.Continue;
} }
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
{ {
_gBCommandsAllowed = true; g_bCommandsAllowed = true;
return HookResult.Continue; return HookResult.Continue;
} }
@@ -185,16 +178,16 @@ namespace WeaponPaints
try try
{ {
SteamID? steamid = null; SteamID? _steamid = null;
if (weapon.OriginalOwnerXuidLow > 0) if (weapon.OriginalOwnerXuidLow > 0)
steamid = new SteamID(weapon.OriginalOwnerXuidLow); _steamid = new(weapon.OriginalOwnerXuidLow);
CCSPlayerController? player; CCSPlayerController? player = null;
if (steamid != null && steamid.IsValid()) if (_steamid != null && _steamid.IsValid())
{ {
player = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == steamid.SteamId64); 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);
@@ -212,6 +205,7 @@ namespace WeaponPaints
} }
catch (Exception) catch (Exception)
{ {
return;
} }
}); });
} }
@@ -228,7 +222,7 @@ namespace WeaponPaints
) )
) )
{ {
if (_playerWeaponImage.TryGetValue(player.Slot, out var 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));
} }
@@ -249,37 +243,6 @@ namespace WeaponPaints
return HookResult.Continue; return HookResult.Continue;
} }
private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
{
CCSPlayerController? player = @event.Attacker;
if (player is null || !player.IsValid)
return HookResult.Continue;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return HookResult.Continue;
CBasePlayerWeapon? weapon = player.PlayerPawn.Value?.WeaponServices?.ActiveWeapon.Value;
if (weapon == null) return HookResult.Continue;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var weaponInfo) || weaponInfo.Paint == 0)
return HookResult.Continue;
if (!weaponInfo.StatTrak) return HookResult.Continue;
weaponInfo.StatTrakCount += 1;
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater", ViewAsFloat((uint)weaponInfo.StatTrakCount));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater score type", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater", ViewAsFloat((uint)weaponInfo.StatTrakCount));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater score type", 0);
return HookResult.Continue;
}
private void RegisterListeners() private void RegisterListeners()
{ {
RegisterListener<Listeners.OnMapStart>(OnMapStart); RegisterListener<Listeners.OnMapStart>(OnMapStart);
@@ -288,7 +251,6 @@ namespace WeaponPaints
RegisterEventHandler<EventRoundStart>(OnRoundStart); RegisterEventHandler<EventRoundStart>(OnRoundStart);
RegisterEventHandler<EventRoundEnd>(OnRoundEnd); RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated); RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated);
RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
if (Config.Additional.ShowSkinImage) if (Config.Additional.ShowSkinImage)
RegisterListener<Listeners.OnTick>(OnTick); RegisterListener<Listeners.OnTick>(OnTick);

View File

@@ -5,7 +5,7 @@
public int Index { get; set; } public int Index { get; set; }
public int Slot { get; init; } public int Slot { get; init; }
public int? UserId { get; set; } public int? UserId { get; set; }
public string? SteamId { get; init; } 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

@@ -19,21 +19,12 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
- Added command **`!agents`** to show menu with agents - Added command **`!agents`** to show menu with agents
- Translations support, submit a PR if you want to share your translation - Translations support, submit a PR if you want to share your translation
## ⚙️ Requirements
**Ensure all the following dependencies are installed before proceeding**
- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp)
- [PlayerSettings](https://github.com/NickFox007/PlayerSettingsCS2) - Required by MenuManagerCS2
- [AnyBaseLibCS2](https://github.com/NickFox007/AnyBaseLibCS2) - Required by PlayerSettings
- [MenuManagerCS2](https://github.com/NickFox007/MenuManagerCS2)
- MySQL database
## CS2 Server ## CS2 Server
- Have working CounterStrikeSharp (**with RUNTIME!**) - Have working CounterStrikeSharp (**with RUNTIME!**)
- Download from Release and copy plugin to plugins - Download from Release and copy plugin to plugins
- Run server with plugin, **it will generate config if installed correctly!** - Run server with plugin, **it will generate config if installed correctly!**
- Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials - Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`** - In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
- Copy from plugins folder gamedata file **`weaponpaints.json`** to folder **`addons/counterstrikesharp/gamedata/`**
## Plugin Configuration ## Plugin Configuration
<details> <details>
@@ -74,11 +65,13 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
"GiveRandomKnife": false, // Give random knife to players if they didn't choose "GiveRandomKnife": false, // Give random knife to players if they didn't choose
"GiveRandomSkins": false // Give random skins to players if they didn't choose "GiveRandomSkins": false // Give random skins to players if they didn't choose
}, },
</pre></code>
"ConfigVersion": 4 // Don't touch
}</pre></code>
</details> </details>
## Web install ## Web install
- Requires PHP >= 7.4 with curl and pdo_mysql ***(Tested on php ver **`8.2.3`** and nginx webserver)*** - Requires PHP >= 7.4 ***(Tested on php ver **`8.2.3`** and nginx webserver)***
- **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website. - **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website.
- Copy website to web server ***(Folder `img` not needed)*** - Copy website to web server ***(Folder `img` not needed)***
- Get [Steam API Key](https://steamcommunity.com/dev/apikey) - Get [Steam API Key](https://steamcommunity.com/dev/apikey)

24
SchemaString.cs Normal file
View File

@@ -0,0 +1,24 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Modules.Memory;
using System.Runtime.CompilerServices;
using System.Text;
namespace WeaponPaints;
public class SchemaString<TSchemaClass> : NativeObject where TSchemaClass : NativeObject
{
internal SchemaString(TSchemaClass instance, string member) : base(Schema.GetSchemaValue<nint>(instance.Handle, typeof(TSchemaClass).Name!, member))
{ }
internal unsafe void Set(string str)
{
var bytes = Encoding.UTF8.GetBytes(str);
for (var i = 0; i < bytes.Length; i++)
{
Unsafe.Write((void*)(Handle.ToInt64() + i), bytes[i]);
}
Unsafe.Write((void*)(Handle.ToInt64() + bytes.Length), 0);
}
}

View File

@@ -1,4 +1,4 @@
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Translations; using CounterStrikeSharp.API.Core.Translations;
using Dapper; using Dapper;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -13,71 +13,26 @@ namespace WeaponPaints
internal static async Task CheckDatabaseTables() internal static async Task CheckDatabaseTables()
{ {
if (WeaponPaints.Database is null) return; if (WeaponPaints._database is null) return;
try try
{ {
await using var connection = await WeaponPaints.Database.GetConnectionAsync(); await using var connection = await WeaponPaints._database.GetConnectionAsync();
await using var transaction = await connection.BeginTransactionAsync(); await using var transaction = await connection.BeginTransactionAsync();
try try
{ {
string[] createTableQueries = var createTableQueries = new[]
[ {
""" "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;",
CREATE TABLE IF NOT EXISTS `wp_player_skins` ( "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;",
`steamid` varchar(18) 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_defindex` 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_paint_id` int(6) NOT NULL, "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_wear` float NOT NULL DEFAULT 0.000001, "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;",
`weapon_seed` int(16) NOT NULL DEFAULT 0, "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;",
`weapon_nametag` VARCHAR(128) DEFAULT NULL, };
`weapon_stattrak` tinyint(1) NOT NULL,
`weapon_stattrak_count` int(10) NOT NULL,
`weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
`weapon_keychain`VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed'
) ENGINE=InnoDB
""",
@"CREATE TABLE IF NOT EXISTS `wp_player_knife` (
`steamid` varchar(18) NOT NULL,
`knife` varchar(64) NOT NULL,
UNIQUE (`steamid`)
) ENGINE = InnoDB",
"""
CREATE TABLE IF NOT EXISTS `wp_player_gloves` (
`steamid` varchar(18) NOT NULL,
`weapon_defindex` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_agents` (
`steamid` varchar(18) NOT NULL,
`agent_ct` varchar(64) DEFAULT NULL,
`agent_t` varchar(64) DEFAULT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_music` (
`steamid` varchar(64) NOT NULL,
`music_id` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_pins` (
`steamid` varchar(64) NOT NULL,
`id` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
];
foreach (var query in createTableQueries) foreach (var query in createTableQueries)
{ {
@@ -100,7 +55,7 @@ namespace WeaponPaints
internal static bool IsPlayerValid(CCSPlayerController? player) internal static bool IsPlayerValid(CCSPlayerController? player)
{ {
if (player is null || WeaponPaints.WeaponSync is null) return false; if (player is null || WeaponPaints.weaponSync is null) return false;
return player is { IsValid: true, IsBot: false, IsHLTV: false, UserId: not null }; return player is { IsValid: true, IsBot: false, IsHLTV: false, UserId: not null };
} }
@@ -111,7 +66,7 @@ namespace WeaponPaints
try try
{ {
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json); var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.SkinsList = deserializedSkins ?? []; WeaponPaints.skinsList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@@ -125,7 +80,7 @@ namespace WeaponPaints
{ {
var 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 ?? []; WeaponPaints.glovesList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@@ -139,7 +94,7 @@ namespace WeaponPaints
{ {
var 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 ?? []; WeaponPaints.agentsList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@@ -153,7 +108,7 @@ namespace WeaponPaints
{ {
var 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 ?? []; WeaponPaints.musicList = deserializedSkins ?? [];
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {

View File

@@ -1 +1 @@
2.7a 2.5a

View File

@@ -1,166 +0,0 @@
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using MenuManager;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json.Linq;
namespace WeaponPaints;
public partial class WeaponPaints
{
private static readonly Dictionary<string, string> WeaponList = new()
{
{"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"},
{"weapon_fiveseven", "Five-SeveN"},
{"weapon_glock", "Glock-18"},
{"weapon_ak47", "AK-47"},
{"weapon_aug", "AUG"},
{"weapon_awp", "AWP"},
{"weapon_famas", "FAMAS"},
{"weapon_g3sg1", "G3SG1"},
{"weapon_galilar", "Galil AR"},
{"weapon_m249", "M249"},
{"weapon_m4a1", "M4A1"},
{"weapon_mac10", "MAC-10"},
{"weapon_p90", "P90"},
{"weapon_mp5sd", "MP5-SD"},
{"weapon_ump45", "UMP-45"},
{"weapon_xm1014", "XM1014"},
{"weapon_bizon", "PP-Bizon"},
{"weapon_mag7", "MAG-7"},
{"weapon_negev", "Negev"},
{"weapon_sawedoff", "Sawed-Off"},
{"weapon_tec9", "Tec-9"},
{"weapon_taser", "Zeus x27"},
{"weapon_hkp2000", "P2000"},
{"weapon_mp7", "MP7"},
{"weapon_mp9", "MP9"},
{"weapon_nova", "Nova"},
{"weapon_p250", "P250"},
{"weapon_scar20", "SCAR-20"},
{"weapon_sg556", "SG 553"},
{"weapon_ssg08", "SSG 08"},
{"weapon_m4a1_silencer", "M4A1-S"},
{"weapon_usp_silencer", "USP-S"},
{"weapon_cz75a", "CZ75-Auto"},
{"weapon_revolver", "R8 Revolver"},
{ "weapon_knife", "Default Knife" },
{ "weapon_knife_m9_bayonet", "M9 Bayonet" },
{ "weapon_knife_karambit", "Karambit" },
{ "weapon_bayonet", "Bayonet" },
{ "weapon_knife_survival_bowie", "Bowie Knife" },
{ "weapon_knife_butterfly", "Butterfly Knife" },
{ "weapon_knife_falchion", "Falchion Knife" },
{ "weapon_knife_flip", "Flip Knife" },
{ "weapon_knife_gut", "Gut Knife" },
{ "weapon_knife_tactical", "Huntsman Knife" },
{ "weapon_knife_push", "Shadow Daggers" },
{ "weapon_knife_gypsy_jackknife", "Navaja Knife" },
{ "weapon_knife_stiletto", "Stiletto Knife" },
{ "weapon_knife_widowmaker", "Talon Knife" },
{ "weapon_knife_ursus", "Ursus Knife" },
{ "weapon_knife_css", "Classic Knife" },
{ "weapon_knife_cord", "Paracord Knife" },
{ "weapon_knife_canis", "Survival Knife" },
{ "weapon_knife_outdoor", "Nomad Knife" },
{ "weapon_knife_skeleton", "Skeleton Knife" },
{ "weapon_knife_kukri", "Kukri Knife" }
};
public static IStringLocalizer? _localizer;
internal static readonly ConcurrentDictionary<int, string> GPlayersKnife = new();
internal static readonly ConcurrentDictionary<int, ushort> GPlayersGlove = new();
internal static readonly ConcurrentDictionary<int, ushort> GPlayersMusic = new();
internal static readonly ConcurrentDictionary<int, ushort> GPlayersPin = new();
public static readonly ConcurrentDictionary<int, (string? CT, string? T)> GPlayersAgent = new();
internal static readonly ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> GPlayerWeaponsInfo = 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 _gBCommandsAllowed = true;
private readonly Dictionary<int, string> _playerWeaponImage = new();
private static readonly Dictionary<int, DateTime> CommandsCooldown = new();
internal static Database? Database;
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
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()
{
{ 1, "weapon_deagle" },
{ 2, "weapon_elite" },
{ 3, "weapon_fiveseven" },
{ 4, "weapon_glock" },
{ 7, "weapon_ak47" },
{ 8, "weapon_aug" },
{ 9, "weapon_awp" },
{ 10, "weapon_famas" },
{ 11, "weapon_g3sg1" },
{ 13, "weapon_galilar" },
{ 14, "weapon_m249" },
{ 16, "weapon_m4a1" },
{ 17, "weapon_mac10" },
{ 19, "weapon_p90" },
{ 23, "weapon_mp5sd" },
{ 24, "weapon_ump45" },
{ 25, "weapon_xm1014" },
{ 26, "weapon_bizon" },
{ 27, "weapon_mag7" },
{ 28, "weapon_negev" },
{ 29, "weapon_sawedoff" },
{ 30, "weapon_tec9" },
{ 31, "weapon_taser" },
{ 32, "weapon_hkp2000" },
{ 33, "weapon_mp7" },
{ 34, "weapon_mp9" },
{ 35, "weapon_nova" },
{ 36, "weapon_p250" },
{ 38, "weapon_scar20" },
{ 39, "weapon_sg556" },
{ 40, "weapon_ssg08" },
{ 60, "weapon_m4a1_silencer" },
{ 61, "weapon_usp_silencer" },
{ 63, "weapon_cz75a" },
{ 64, "weapon_revolver" },
{ 500, "weapon_bayonet" },
{ 503, "weapon_knife_css" },
{ 505, "weapon_knife_flip" },
{ 506, "weapon_knife_gut" },
{ 507, "weapon_knife_karambit" },
{ 508, "weapon_knife_m9_bayonet" },
{ 509, "weapon_knife_tactical" },
{ 512, "weapon_knife_falchion" },
{ 514, "weapon_knife_survival_bowie" },
{ 515, "weapon_knife_butterfly" },
{ 516, "weapon_knife_push" },
{ 517, "weapon_knife_cord" },
{ 518, "weapon_knife_canis" },
{ 519, "weapon_knife_ursus" },
{ 520, "weapon_knife_gypsy_jackknife" },
{ 521, "weapon_knife_outdoor" },
{ 522, "weapon_knife_stiletto" },
{ 523, "weapon_knife_widowmaker" },
{ 525, "weapon_knife_skeleton" },
{ 526, "weapon_knife_kukri" }
};
private const ulong MinimumCustomItemId = 65578;
private ulong _nextItemId = MinimumCustomItemId;
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private readonly ConcurrentDictionary<int, ConcurrentDictionary<int, float>> _temporaryPlayerWeaponWear = new();
internal static IMenuApi? MenuApi;
private static readonly PluginCapability<IMenuApi> MenuCapability = new("menu:nfcore");
}

View File

@@ -1,51 +1,52 @@
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.Collections.Concurrent;
using System.Runtime.InteropServices;
namespace WeaponPaints namespace WeaponPaints;
{
public partial class WeaponPaints public partial class WeaponPaints
{ {
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon) private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{ {
if (!Config.Additional.SkinEnabled) return; if (!Config.Additional.SkinEnabled) return;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return; if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet"); var isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if (isKnife && !GPlayersKnife.ContainsKey(player.Slot) || isKnife && GPlayersKnife[player.Slot] == "weapon_knife") return; if ((isKnife && !g_playersKnife.ContainsKey(player.Slot)) ||
(isKnife && g_playersKnife[player.Slot] < 500)) return;
int[] newPaints = { 106, 112, 113, 114, 115, 117, 118, 120, 121, 123, 126, 127, 128, 129, 130, 131, 133, 134, 137, 138, 139, 140, 142, 144, 145, 146, 152, 160, 161, 163, 173, 239, 292, 324, 331, 412, 461, 513, 766, 768, 770, 773, 774, 830, 831, 832, 834, 874, 875, 877, 878, 882, 883, 901, 912, 936, 937, 938, 939, 940, 1054, 1062, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1177, 1178, 1179, 1180 }; int[] newPaints =
[1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173];
if (isKnife) if (isKnife)
{ {
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == GPlayersKnife[player.Slot]); //var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return; //if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key) if (weapon.AttributeManager.Item.ItemDefinitionIndex != g_playersKnife[player.Slot])
{ SubclassChange(weapon, (ushort)g_playersKnife[player.Slot]);
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key; weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)g_playersKnife[player.Slot];
weapon.AttributeManager.Item.EntityQuality = 3; weapon.AttributeManager.Item.EntityQuality = 3;
} }
UpdatePlayerEconItemId(weapon.AttributeManager.Item); UpdatePlayerEconItemId(weapon.AttributeManager.Item);
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0; var fallbackPaintKit = 0;
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID; weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
if (_config.Additional.GiveRandomSkin && if (_config.Additional.GiveRandomSkin &&
!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) !gPlayerWeaponsInfo[player.Slot].ContainsKey((ushort)weaponDefIndex))
{ {
// Random skins // Random skins
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
@@ -53,14 +54,21 @@ namespace WeaponPaints
weapon.FallbackWear = 0.01f; weapon.FallbackWear = 0.01f;
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll(); weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", GetRandomPaint(weaponDefIndex)); CAttributeListSetOrAddAttributeValueByName.Invoke(
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0); weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture wear", 0.01f); 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(); 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,
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture seed", 0); "set item texture prefab", GetRandomPaint(weaponDefIndex));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture wear", 0.01f); 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; fallbackPaintKit = weapon.FallbackPaintKit;
@@ -72,28 +80,19 @@ namespace WeaponPaints
return; return;
} }
if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return; if (!gPlayerWeaponsInfo[player.Slot].TryGetValue((ushort)weaponDefIndex, out var value) || value.Paint == 0) return;
var weaponInfo = value; 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]}"); //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.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF; weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32; weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.AttributeManager.Item.CustomName = weaponInfo.Nametag;
weapon.FallbackPaintKit = weaponInfo.Paint; weapon.FallbackPaintKit = weaponInfo.Paint;
weapon.FallbackSeed = weaponInfo.Seed; weapon.FallbackSeed = weaponInfo.Seed;
weapon.FallbackWear = weaponInfo.Wear; weapon.FallbackWear = weaponInfo.Wear;
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit); CAttributeListSetOrAddAttributeValueByName.Invoke(
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
if (weaponInfo.StatTrak) weapon.FallbackPaintKit);
{
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater", ViewAsFloat((uint)weaponInfo.StatTrakCount));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "kill eater score type", 0);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater", ViewAsFloat((uint)weaponInfo.StatTrakCount));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "kill eater score type", 0);
}
fallbackPaintKit = weapon.FallbackPaintKit; fallbackPaintKit = weapon.FallbackPaintKit;
@@ -101,97 +100,9 @@ namespace WeaponPaints
return; return;
if (isKnife) return; if (isKnife) return;
if (weaponInfo.Stickers.Count > 0) SetStickers(player, weapon);
if (weaponInfo.KeyChain != null) SetKeychain(player, weapon);
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit)); UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
} }
// silly method to update sticker when call RefreshWeapons()
private void IncrementWearForWeaponWithStickers(CCSPlayerController player, CBasePlayerWeapon weapon)
{
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) ||
!playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo) ||
weaponInfo.Stickers.Count <= 0) return;
float wearIncrement = 0.001f;
float currentWear = weaponInfo.Wear;
var playerWear = _temporaryPlayerWeaponWear.GetOrAdd(player.Slot, _ => new ConcurrentDictionary<int, float>());
float incrementedWear = playerWear.AddOrUpdate(
weaponDefIndex,
currentWear + wearIncrement,
(_, oldWear) => Math.Min(oldWear + wearIncrement, 1.0f)
);
weapon.FallbackWear = incrementedWear;
}
private void SetStickers(CCSPlayerController? player, CBasePlayerWeapon weapon)
{
if (player == null || !player.IsValid) return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeapons) ||
!playerWeapons.TryGetValue(weaponDefIndex, out var weaponInfo))
{
return;
}
foreach (var sticker in weaponInfo.Stickers)
{
int stickerSlot = weaponInfo.Stickers.IndexOf(sticker);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} id", ViewAsFloat(sticker.Id));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} schema", sticker.Schema);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} offset x", sticker.OffsetX);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} offset y", sticker.OffsetY);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} wear", sticker.Wear);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} scale", sticker.Scale);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
$"sticker slot {stickerSlot} rotation", sticker.Rotation);
}
if (_temporaryPlayerWeaponWear.TryGetValue(player.Slot, out var playerWear) &&
playerWear.TryGetValue(weaponDefIndex, out float storedWear))
{
weapon.FallbackWear = storedWear;
}
}
private void SetKeychain(CCSPlayerController? player, CBasePlayerWeapon weapon)
{
if (player == null || !player.IsValid) return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out var playerWeaponsInfo) ||
!playerWeaponsInfo.TryGetValue(weaponDefIndex, out var value) ||
value.KeyChain == null) return;
var keyChain = value.KeyChain;
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 id", ViewAsFloat(keyChain.Id));
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset x", keyChain.OffsetX);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset y", keyChain.OffsetY);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 offset z", keyChain.OffsetZ);
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle,
"keychain slot 0 seed", keyChain.Seed);
}
private static void GiveKnifeToPlayer(CCSPlayerController? player) private static void GiveKnifeToPlayer(CCSPlayerController? player)
{ {
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return; if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
@@ -206,12 +117,10 @@ namespace WeaponPaints
{ {
if (!_config.Additional.KnifeEnabled) return false; if (!_config.Additional.KnifeEnabled) return false;
if (player == null || !player.IsValid || !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;
@@ -220,17 +129,17 @@ namespace WeaponPaints
{ {
if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue; 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;
} }
private void RefreshWeapons(CCSPlayerController? player) private void RefreshWeapons(CCSPlayerController? player)
{ {
if (!_gBCommandsAllowed) 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;
@@ -252,7 +161,7 @@ namespace WeaponPaints
!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.IsValid) continue; if (!weapon.Value.OwnerEntity.IsValid) continue;
@@ -262,17 +171,19 @@ namespace WeaponPaints
try try
{ {
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData; var weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weaponData == null) continue; if (weaponData == null) continue;
if (weaponData.GearSlot is gear_slot_t.GEAR_SLOT_RIFLE or 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 var 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 var value)) if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
{ {
@@ -284,12 +195,7 @@ namespace WeaponPaints
if (gun.VData == null) return; if (gun.VData == null) return;
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f); weapon.Value.Remove();
}
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -298,15 +204,50 @@ namespace WeaponPaints
} }
} }
AddTimer(0.23f, () => try
{ {
if (!_gBCommandsAllowed) return; player.ExecuteClientCommand("slot 3");
player.ExecuteClientCommand("slot 3");
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon;
if (!weapon.IsValid || weapon.Value == null) return;
var weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{
CCSWeaponBaseGun gun;
AddTimer(0.3f, () =>
{
if (player.TeamNum != playerTeam) return;
player.ExecuteClientCommand("slot 3");
gun = weapon.Value.As<CCSWeaponBaseGun>();
player.DropActiveWeapon();
AddTimer(0.7f, () =>
{
if (player.TeamNum != playerTeam) return;
if (!gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return;
gun.Remove();
});
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player); GiveKnifeToPlayer(player);
});
}
}
catch (Exception ex)
{
Logger.LogWarning($"Cannot remove knife: {ex.Message}");
}
AddTimer(0.6f, () =>
{
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));
@@ -316,8 +257,6 @@ namespace WeaponPaints
{ {
newWeapon.Clip1 = ammo.Item1; newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2; newWeapon.ReserveAmmo[0] = ammo.Item2;
IncrementWearForWeaponWithStickers(player, newWeapon);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -325,7 +264,6 @@ namespace WeaponPaints
} }
}); });
} }
}
}, TimerFlags.STOP_ON_MAPCHANGE); }, TimerFlags.STOP_ON_MAPCHANGE);
} }
@@ -333,7 +271,7 @@ namespace WeaponPaints
{ {
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) if (pawn == null || !pawn.IsValid)
return; return;
@@ -344,9 +282,9 @@ namespace WeaponPaints
pawn.SetModel(model); pawn.SetModel(model);
} }
Instance.AddTimer(0.08f, () => Instance.AddTimer(0.06f, () =>
{ {
CEconItemView item = pawn.EconGloves; var item = pawn.EconGloves;
try try
{ {
if (!player.IsValid) if (!player.IsValid)
@@ -355,35 +293,40 @@ namespace WeaponPaints
if (!player.PawnIsAlive) if (!player.PawnIsAlive)
return; return;
if (!GPlayersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return; if (!g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
WeaponInfo weaponInfo = GPlayerWeaponsInfo[player.Slot][gloveInfo]; var weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
item.ItemDefinitionIndex = gloveInfo; item.ItemDefinitionIndex = gloveInfo;
item.ItemIDLow = 16384 & 0xFFFFFFFF; item.ItemIDLow = 16384 & 0xFFFFFFFF;
item.ItemIDHigh = 16384; item.ItemIDHigh = 16384;
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weaponInfo.Paint); CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle,
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture seed", weaponInfo.Seed); "set item texture prefab", weaponInfo.Paint);
CAttributeListSetOrAddAttributeValueByName.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;
SetBodygroup(pawn.Handle, "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.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();
if (filteredWeapons.Count == 0) if (filteredWeapons.Count == 0)
return 0; return 0;
@@ -408,13 +351,11 @@ namespace WeaponPaints
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance(); var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
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;
}
} }
private 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);
@@ -427,7 +368,7 @@ namespace WeaponPaints
private static void GivePlayerAgent(CCSPlayerController player) private static void GivePlayerAgent(CCSPlayerController player)
{ {
if (!GPlayersAgent.TryGetValue(player.Slot, out var value)) return; if (!g_playersAgent.TryGetValue(player.Slot, out var value)) return;
var model = player.TeamNum == 3 ? value.CT : value.T; var model = player.TeamNum == 3 ? value.CT : value.T;
if (string.IsNullOrEmpty(model)) return; if (string.IsNullOrEmpty(model)) return;
@@ -451,7 +392,7 @@ namespace WeaponPaints
private static void GivePlayerMusicKit(CCSPlayerController player) private static void GivePlayerMusicKit(CCSPlayerController player)
{ {
if (!GPlayersMusic.TryGetValue(player.Slot, out var value)) return; if (!g_playersMusic.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return; if (player.InventoryServices == null) return;
player.InventoryServices.MusicID = value; player.InventoryServices.MusicID = value;
@@ -462,13 +403,12 @@ namespace WeaponPaints
private static void GivePlayerPin(CCSPlayerController player) private static void GivePlayerPin(CCSPlayerController player)
{ {
if (!GPlayersPin.TryGetValue(player.Slot, out var pin)) return; if (!g_playersPin.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return; if (player.InventoryServices == null) return;
for (var index = 0; index < player.InventoryServices.Rank.Length; index++) for (var index = 0; index < player.InventoryServices.Rank.Length; index++)
{ {
player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)pin : MedalRank_t.MEDAL_RANK_NONE; player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)value : MedalRank_t.MEDAL_RANK_NONE;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices"); Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
} }
} }
@@ -483,10 +423,7 @@ namespace WeaponPaints
foreach (var handle in myWeapons) foreach (var handle in myWeapons)
{ {
var weapon = handle.Value; var weapon = handle.Value;
if (weapon != null && weapon.DesignerName.Contains("knife")) if (weapon != null && weapon.DesignerName.Contains("knife")) GivePlayerWeaponSkin(player, weapon);
{
GivePlayerWeaponSkin(player, weapon);
}
} }
} }
@@ -507,19 +444,26 @@ namespace WeaponPaints
return !Utility.IsPlayerValid(player) ? null : player; return !Utility.IsPlayerValid(player) ? null : 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);
var 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 =
(CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
return viewModel.Value == null ? null : viewModel.Value; return viewModel.Value == null ? null : viewModel.Value;
} }
private static float ViewAsFloat(uint value) public static T[] GetFixedArray<T>(nint pointer, string @class, string member, int length)
where T : CHandle<CBaseViewModel>
{ {
return BitConverter.Int32BitsToSingle((int)value); var ptr = pointer + Schema.GetSchemaOffset(@class, member);
} var references = MemoryMarshal.CreateSpan(ref ptr, length);
var values = new T[length];
for (var i = 0; i < length; i++) values[i] = (T)Activator.CreateInstance(typeof(T), references[i])!;
return values;
} }
} }

View File

@@ -2,33 +2,12 @@
{ {
public class WeaponInfo public class WeaponInfo
{ {
public int Paint { get; set; } public ushort Paint { get; set; }
public int Seed { get; set; } public ushort Seed { get; set; } = 0;
public float Wear { get; set; } public float Wear { get; set; } = 0f;
public string Nametag { get; set; } = ""; public string? NameTag { get; set; }
public bool StatTrak { get; set; } = false; public ushort Quality { get; set; }
public int StatTrakCount { get; set; } public uint StatTrack { get; set; }
public KeyChainInfo? KeyChain { get; set; } public bool StatTrackEnabled { get; set; }
public List<StickerInfo> Stickers { get; set; } = new();
}
public class StickerInfo
{
public uint Id { get; set; }
public uint Schema { get; set; }
public float OffsetX { get; set; }
public float OffsetY { get; set; }
public float Wear { get; set; }
public float Scale { get; set; }
public float Rotation { get; set; }
}
public class KeyChainInfo
{
public uint Id { get; set; }
public float OffsetX { get; set; }
public float OffsetY { get; set; }
public float OffsetZ { get; set; }
public uint Seed { get; set; }
} }
} }

View File

@@ -1,22 +1,178 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MySqlConnector; using MySqlConnector;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using CounterStrikeSharp.API.Modules.Entities.Constants;
namespace WeaponPaints; namespace WeaponPaints;
[MinimumApiVersion(276)] [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();
private static readonly Dictionary<string, string> WeaponList = new()
{
{"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"},
{"weapon_fiveseven", "Five-SeveN"},
{"weapon_glock", "Glock-18"},
{"weapon_ak47", "AK-47"},
{"weapon_aug", "AUG"},
{"weapon_awp", "AWP"},
{"weapon_famas", "FAMAS"},
{"weapon_g3sg1", "G3SG1"},
{"weapon_galilar", "Galil AR"},
{"weapon_m249", "M249"},
{"weapon_m4a1", "M4A1"},
{"weapon_mac10", "MAC-10"},
{"weapon_p90", "P90"},
{"weapon_mp5sd", "MP5-SD"},
{"weapon_ump45", "UMP-45"},
{"weapon_xm1014", "XM1014"},
{"weapon_bizon", "PP-Bizon"},
{"weapon_mag7", "MAG-7"},
{"weapon_negev", "Negev"},
{"weapon_sawedoff", "Sawed-Off"},
{"weapon_tec9", "Tec-9"},
{"weapon_taser", "Zeus x27"},
{"weapon_hkp2000", "P2000"},
{"weapon_mp7", "MP7"},
{"weapon_mp9", "MP9"},
{"weapon_nova", "Nova"},
{"weapon_p250", "P250"},
{"weapon_scar20", "SCAR-20"},
{"weapon_sg556", "SG 553"},
{"weapon_ssg08", "SSG 08"},
{"weapon_m4a1_silencer", "M4A1-S"},
{"weapon_usp_silencer", "USP-S"},
{"weapon_cz75a", "CZ75-Auto"},
{"weapon_revolver", "R8 Revolver"},
{ "weapon_knife", "Default Knife" },
{ "weapon_knife_m9_bayonet", "M9 Bayonet" },
{ "weapon_knife_karambit", "Karambit" },
{ "weapon_bayonet", "Bayonet" },
{ "weapon_knife_survival_bowie", "Bowie Knife" },
{ "weapon_knife_butterfly", "Butterfly Knife" },
{ "weapon_knife_falchion", "Falchion Knife" },
{ "weapon_knife_flip", "Flip Knife" },
{ "weapon_knife_gut", "Gut Knife" },
{ "weapon_knife_tactical", "Huntsman Knife" },
{ "weapon_knife_push", "Shadow Daggers" },
{ "weapon_knife_gypsy_jackknife", "Navaja Knife" },
{ "weapon_knife_stiletto", "Stiletto Knife" },
{ "weapon_knife_widowmaker", "Talon Knife" },
{ "weapon_knife_ursus", "Ursus Knife" },
{ "weapon_knife_css", "Classic Knife" },
{ "weapon_knife_cord", "Paracord Knife" },
{ "weapon_knife_canis", "Survival Knife" },
{ "weapon_knife_outdoor", "Nomad Knife" },
{ "weapon_knife_skeleton", "Skeleton Knife" },
{ "weapon_knife_kukri", "Kukri Knife" }
};
private static WeaponPaintsConfig _config = new();
internal static IStringLocalizer? _localizer;
private static Dictionary<int, int> g_knifePickupCount = new();
internal static ConcurrentDictionary<int, ushort> g_playersKnife = new();
internal static ConcurrentDictionary<int, ushort> g_playersGlove = 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, ConcurrentDictionary<ushort, WeaponInfo>> gPlayerWeaponsInfo = new();
internal static ConcurrentDictionary<int, int> g_playersDatabaseIndex = 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;
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
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" },
{ 2, "weapon_elite" },
{ 3, "weapon_fiveseven" },
{ 4, "weapon_glock" },
{ 7, "weapon_ak47" },
{ 8, "weapon_aug" },
{ 9, "weapon_awp" },
{ 10, "weapon_famas" },
{ 11, "weapon_g3sg1" },
{ 13, "weapon_galilar" },
{ 14, "weapon_m249" },
{ 16, "weapon_m4a1" },
{ 17, "weapon_mac10" },
{ 19, "weapon_p90" },
{ 23, "weapon_mp5sd" },
{ 24, "weapon_ump45" },
{ 25, "weapon_xm1014" },
{ 26, "weapon_bizon" },
{ 27, "weapon_mag7" },
{ 28, "weapon_negev" },
{ 29, "weapon_sawedoff" },
{ 30, "weapon_tec9" },
{ 31, "weapon_taser" },
{ 32, "weapon_hkp2000" },
{ 33, "weapon_mp7" },
{ 34, "weapon_mp9" },
{ 35, "weapon_nova" },
{ 36, "weapon_p250" },
{ 38, "weapon_scar20" },
{ 39, "weapon_sg556" },
{ 40, "weapon_ssg08" },
{ 60, "weapon_m4a1_silencer" },
{ 61, "weapon_usp_silencer" },
{ 63, "weapon_cz75a" },
{ 64, "weapon_revolver" },
{ 500, "weapon_bayonet" },
{ 503, "weapon_knife_css" },
{ 505, "weapon_knife_flip" },
{ 506, "weapon_knife_gut" },
{ 507, "weapon_knife_karambit" },
{ 508, "weapon_knife_m9_bayonet" },
{ 509, "weapon_knife_tactical" },
{ 512, "weapon_knife_falchion" },
{ 514, "weapon_knife_survival_bowie" },
{ 515, "weapon_knife_butterfly" },
{ 516, "weapon_knife_push" },
{ 517, "weapon_knife_cord" },
{ 518, "weapon_knife_canis" },
{ 519, "weapon_knife_ursus" },
{ 520, "weapon_knife_gypsy_jackknife" },
{ 521, "weapon_knife_outdoor" },
{ 522, "weapon_knife_stiletto" },
{ 523, "weapon_knife_widowmaker" },
{ 525, "weapon_knife_skeleton" },
{ 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();
private static 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.7a"; public override string ModuleVersion => "2.5a";
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
@@ -27,40 +183,38 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
OnMapStart(string.Empty); OnMapStart(string.Empty);
foreach (var player in Enumerable foreach (var player in Enumerable
.OfType<CCSPlayerController>(Utilities.GetPlayers().TakeWhile(player => WeaponSync != null)) .OfType<CCSPlayerController>(Utilities.GetPlayers().TakeWhile(player => weaponSync != null))
.Where(player => player.IsValid && .Where(player => player.IsValid &&
!string.IsNullOrEmpty(player.IpAddress) && player is !string.IsNullOrEmpty(player.IpAddress) && player is
{ IsBot: false, Connected: PlayerConnectedState.PlayerConnected })) { IsBot: false, Connected: PlayerConnectedState.PlayerConnected }))
{ {
GPlayerWeaponsInfo.TryRemove(player.Slot, out _); g_knifePickupCount[player.Slot] = 0;
GPlayersKnife.TryRemove(player.Slot, out _); gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
GPlayersGlove.TryRemove(player.Slot, out _); g_playersKnife.TryRemove(player.Slot, out _);
GPlayersAgent.TryRemove(player.Slot, out _); g_playersGlove.TryRemove(player.Slot, out _);
GPlayersPin.TryRemove(player.Slot, out _); g_playersAgent.TryRemove(player.Slot, out _);
var 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]
}; };
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
if (WeaponSync != null) await WeaponSync.GetPlayerData(playerInfo); if (weaponSync != null) await weaponSync.GetPlayerDatabaseIndex(playerInfo);
}); });
} }
AddTimer(2.0f, () => OnAllPluginsLoaded(hotReload));
} }
Utility.LoadSkinsFromFile(ModuleDirectory + $"/data/skins_{_config.SkinsLanguage}.json", Logger); Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json", Logger);
Utility.LoadGlovesFromFile(ModuleDirectory + $"/data/gloves_{_config.SkinsLanguage}.json", Logger); Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json", Logger);
Utility.LoadAgentsFromFile(ModuleDirectory + $"/data/agents_{_config.SkinsLanguage}.json", Logger); Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json", Logger);
Utility.LoadMusicFromFile(ModuleDirectory + $"/data/music_{_config.SkinsLanguage}.json", Logger); Utility.LoadMusicFromFile(ModuleDirectory + "/music.json", Logger);
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
SetupKnifeMenu(); SetupKnifeMenu();
@@ -79,10 +233,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
public void OnConfigParsed(WeaponPaintsConfig config) public void OnConfigParsed(WeaponPaintsConfig config)
{ {
Config = config; if (config.DatabaseCredentials.DatabaseHost.Length < 1 || config.DatabaseCredentials.DatabaseName.Length < 1 || config.DatabaseCredentials.DatabaseUser.Length < 1)
_config = config;
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{ {
Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!"); Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
Unload(false); Unload(false);
@@ -98,18 +249,21 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
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, MaximumPoolSize = 640,
}; };
Database = new Database(builder.ConnectionString); _database = new Database(builder.ConnectionString);
_ = Utility.CheckDatabaseTables(); _ = Utility.CheckDatabaseTables();
Config = config;
_config = config;
_localizer = Localizer; _localizer = Localizer;
Utility.Config = config; Utility.Config = config;
@@ -117,17 +271,8 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger)); Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger));
} }
public override void OnAllPluginsLoaded(bool hotReload) public override void Unload(bool hotReload)
{ {
try base.Unload(hotReload);
{
MenuApi = MenuCapability.Get();
}
catch (Exception)
{
MenuApi = null;
Logger.LogError("Error while loading required plugins");
throw;
}
} }
} }

View File

@@ -9,9 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.281" /> <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.4.0-beta.1" /> <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>
@@ -22,10 +22,4 @@
<ItemGroup> <ItemGroup>
<None Update="gamedata\*.*" CopyToOutputDirectory="PreserveNewest" /> <None Update="gamedata\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="MenuManagerApi">
<HintPath>3rd_party\MenuManagerApi.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

View File

@@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=C_003A_005CUsers_005Cxdaff_005CDocuments_005CGitHub_005Ccs2_002DWeaponPaints_005C3rd_005Fparty_005CMenuManagerApi_002Edll/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,10 +1,9 @@
using Dapper;
using MySqlConnector;
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;
@@ -16,6 +15,46 @@ namespace WeaponPaints
_config = config; _config = config;
} }
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) internal async Task GetPlayerData(PlayerInfo? player)
{ {
try try
@@ -32,8 +71,8 @@ namespace WeaponPaints
GetMusicFromDatabase(player, connection); GetMusicFromDatabase(player, connection);
if (_config.Additional.SkinEnabled) if (_config.Additional.SkinEnabled)
GetWeaponPaintsFromDatabase(player, connection); GetWeaponPaintsFromDatabase(player, connection);
if (_config.Additional.PinsEnabled) if (_config.Additional.PinEnabled)
GetPinsFromDatabase(player, connection); GetPinFromDatabase(player, connection);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -46,16 +85,14 @@ namespace WeaponPaints
{ {
try try
{ {
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
const string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid"; const string query = "SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = @userId";
var playerKnife = connection.QueryFirstOrDefault<string>(query, new { steamid = player.SteamId }); var playerKnife = connection.QueryFirstOrDefault<int>(query,
new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (!string.IsNullOrEmpty(playerKnife)) WeaponPaints.g_playersKnife[player.Slot] = (ushort)playerKnife;
{
WeaponPaints.GPlayersKnife[player.Slot] = playerKnife;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -67,16 +104,13 @@ namespace WeaponPaints
{ {
try try
{ {
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
const string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid"; const string query = "SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = @userId";
var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId }); var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (gloveData != null) if (gloveData != null) WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
{
WeaponPaints.GPlayersGlove[player.Slot] = gloveData.Value;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -88,24 +122,22 @@ namespace WeaponPaints
{ {
try try
{ {
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_users_agents` WHERE `user_id` = @userId";
var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId }); var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (agentData == default) return; if (agentData == default) return;
var agentCT = agentData.Item1; var agentCT = agentData.Item1;
var agentT = agentData.Item2; var agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT)) if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{ WeaponPaints.g_playersAgent[player.Slot] = (
WeaponPaints.GPlayersAgent[player.Slot] = (
agentCT, agentCT,
agentT agentT
); );
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}"); Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
@@ -116,99 +148,35 @@ namespace WeaponPaints
{ {
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>();
const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = connection.Query<dynamic>(query, new { steamid = player.SteamId }); 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] });
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?.weapon_nametag ?? ""; string weaponNameTag = row.nametag ?? string.Empty;
string[]? keyChainParts = row?.weapon_keychain?.ToString().Split(';'); var weaponInfo = new WeaponInfo
KeyChainInfo keyChainInfo = new KeyChainInfo();
if (keyChainParts!.Length == 5 &&
uint.TryParse(keyChainParts[0], out uint keyChainId) &&
float.TryParse(keyChainParts[1], out float keyChainOffsetX) &&
float.TryParse(keyChainParts[2], out float keyChainOffsetY) &&
float.TryParse(keyChainParts[3], out float keyChainOffsetZ) &&
uint.TryParse(keyChainParts[4], out uint keyChainSeed))
{
// Successfully parsed the values
keyChainInfo.Id = keyChainId;
keyChainInfo.OffsetX = keyChainOffsetX;
keyChainInfo.OffsetY = keyChainOffsetY;
keyChainInfo.OffsetZ = keyChainOffsetZ;
keyChainInfo.Seed = keyChainSeed;
}
else
{
// Failed to parse the values, default to 0
keyChainInfo.Id = 0;
keyChainInfo.OffsetX = 0f;
keyChainInfo.OffsetY = 0f;
keyChainInfo.OffsetZ = 0f;
keyChainInfo.Seed = 0;
}
// Create the WeaponInfo object
WeaponInfo weaponInfo = new WeaponInfo
{ {
Paint = weaponPaintId, Paint = weaponPaintId,
Seed = weaponSeed, Seed = weaponSeed,
Wear = weaponWear, Wear = weaponWear,
Nametag = weaponNameTag, NameTag = weaponNameTag
KeyChain = keyChainInfo
}; };
// Retrieve and parse sticker data (up to 5 slots)
for (int i = 0; i <= 4; i++)
{
// Access the sticker data dynamically using reflection
string stickerColumn = $"weapon_sticker_{i}";
var stickerData = ((IDictionary<string, object>)row!)[stickerColumn]; // Safely cast row to a dictionary
if (string.IsNullOrEmpty(stickerData.ToString())) continue;
var parts = stickerData.ToString()!.Split(';');
//"id;schema;x;y;wear;scale;rotation"
if (parts.Length != 7 ||
!uint.TryParse(parts[0], out uint stickerId) ||
!uint.TryParse(parts[1], out uint stickerSchema) ||
!float.TryParse(parts[2], out float stickerOffsetX) ||
!float.TryParse(parts[3], out float stickerOffsetY) ||
!float.TryParse(parts[4], out float stickerWear) ||
!float.TryParse(parts[5], out float stickerScale) ||
!float.TryParse(parts[6], out float stickerRotation)) continue;
StickerInfo stickerInfo = new StickerInfo
{
Id = stickerId,
Schema = stickerSchema,
OffsetX = stickerOffsetX,
OffsetY = stickerOffsetY,
Wear = stickerWear,
Scale = stickerScale,
Rotation = stickerRotation
};
weaponInfo.Stickers.Add(stickerInfo);
}
weaponInfos[weaponDefIndex] = weaponInfo; weaponInfos[weaponDefIndex] = weaponInfo;
} }
WeaponPaints.GPlayerWeaponsInfo[player.Slot] = weaponInfos; WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -220,15 +188,81 @@ namespace WeaponPaints
{ {
try try
{ {
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId)) if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
return; return;
const string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid"; const string query = "SELECT `music` FROM `wp_users_musics` WHERE `user_id` = @userId";
var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId }); var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
if (musicData != null) if (musicData != null) WeaponPaints.g_playersMusic[player.Slot] = musicData.Value;
}
catch (Exception ex)
{ {
WeaponPaints.GPlayersMusic[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)
@@ -237,37 +271,17 @@ namespace WeaponPaints
} }
} }
private void GetPinsFromDatabase(PlayerInfo? player, MySqlConnection connection) internal async Task SyncKnifeToDatabase(PlayerInfo player, ushort knife)
{ {
try if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
{
if (string.IsNullOrEmpty(player?.SteamId))
return;
const string query = "SELECT `id` FROM `wp_player_pins` WHERE `steamid` = @steamid"; const string query =
var pinData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId }); "INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(@userId, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
if (pinData != null)
{
WeaponPaints.GPlayersPin[player.Slot] = pinData.Value;
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetPinsFromDatabase: {ex.Message}");
}
}
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife)
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
const string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife }); await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], newKnife = knife });
} }
catch (Exception e) catch (Exception e)
{ {
@@ -277,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 || 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();
const 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)
{ {
@@ -293,11 +308,11 @@ namespace WeaponPaints
internal async Task SyncAgentToDatabase(PlayerInfo player) internal async Task SyncAgentToDatabase(PlayerInfo player)
{ {
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return; if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
const string query = """ const string query = """
INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`) INSERT INTO `wp_users_agents` (`user_id`, `agent_ct`, `agent_t`)
VALUES(@steamid, @agent_ct, @agent_t) VALUES(@userId, @agent_ct, @agent_t)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
`agent_ct` = @agent_ct, `agent_ct` = @agent_ct,
`agent_t` = @agent_t `agent_t` = @agent_t
@@ -306,7 +321,12 @@ namespace WeaponPaints
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T }); 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)
{ {
@@ -316,7 +336,8 @@ namespace WeaponPaints
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player) internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
{ {
if (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
@@ -329,23 +350,27 @@ namespace WeaponPaints
var wear = weaponInfo.Wear; var wear = weaponInfo.Wear;
var seed = weaponInfo.Seed; var seed = weaponInfo.Seed;
const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex"; const string queryCheckExistence =
"SELECT COUNT(*) FROM `wp_users_skins` WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex";
var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex }); var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence,
new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], 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 = 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 = 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);
@@ -359,61 +384,18 @@ namespace WeaponPaints
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music) internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
{ {
if (!_config.Additional.MusicEnabled || 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();
const 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)
{ {
Utility.Log($"Error syncing music kit to database: {e.Message}"); Utility.Log($"Error syncing music kit to database: {e.Message}");
} }
} }
internal async Task SyncStatTrakToDatabase(PlayerInfo player, ConcurrentDictionary<int,WeaponInfo> weaponInfos)
{
if (WeaponPaints.WeaponSync == null || weaponInfos.IsEmpty) return;
var statTrakWeapons = weaponInfos
.Where(w => w.Value is { StatTrak: true, StatTrakCount: > 0 })
.ToDictionary(w => w.Key, w => w.Value.StatTrakCount);
if (statTrakWeapons.Count == 0) return;
if (string.IsNullOrEmpty(player.SteamId))
return;
try
{
await using var connection = await _database.GetConnectionAsync();
await using var transaction = await connection.BeginTransactionAsync();
foreach (var (defindex, statTrakCount) in statTrakWeapons)
{
const string query = @"
INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_stattrak_count`)
VALUES (@steamid, @weaponDefIndex, @StatTrakCount)
ON DUPLICATE KEY UPDATE `weapon_stattrak_count` = @StatTrakCount";
var parameters = new
{
steamid = player.SteamId,
weaponDefIndex = defindex,
StatTrakCount = statTrakCount
};
await connection.ExecuteAsync(query, parameters, transaction);
}
await transaction.CommitAsync();
}
catch (Exception e)
{
Utility.Log($"Error syncing stattrak to database: {e.Message}");
}
}
}
} }

View File

@@ -2,8 +2,8 @@
"ChangeSubclass": { "ChangeSubclass": {
"signatures": { "signatures": {
"library": "server", "library": "server",
"windows": "48 89 6C 24 ? 56 48 83 EC ? 48 8B EA 48 8B F1 E8 ? ? ? ? 84 C0 0F 84", "windows": "40 57 48 83 EC 20 48 8B F9 41 B0 01",
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 F5 41 54 49 89 FC 53 48 81 EC A8 00 00 00" "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": {

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;

386
website/data/agents.json Normal file
View File

@@ -0,0 +1,386 @@
[
{
"team": 2,
"image": "",
"model": "null",
"agent_name": "Agent | Default"
},
{
"team": 3,
"image": "",
"model": "null",
"agent_name": "Agent | Default"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4619.png",
"model": "ctm_st6/ctm_st6_variantj",
"agent_name": "'Blueberries' Buckshot | NSWC SEAL"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4680.png",
"model": "ctm_st6/ctm_st6_variantl",
"agent_name": "'Two Times' McCoy | TACP Cavalry"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4711.png",
"model": "ctm_swat/ctm_swat_variante",
"agent_name": "Cmdr. Mae 'Dead Cold' Jamison | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4712.png",
"model": "ctm_swat/ctm_swat_variantf",
"agent_name": "1st Lieutenant Farlow | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4713.png",
"model": "ctm_swat/ctm_swat_variantg",
"agent_name": "John 'Van Healen' Kask | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4714.png",
"model": "ctm_swat/ctm_swat_varianth",
"agent_name": "Bio-Haz Specialist | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4715.png",
"model": "ctm_swat/ctm_swat_varianti",
"agent_name": "Sergeant Bombson | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4716.png",
"model": "ctm_swat/ctm_swat_variantj",
"agent_name": "Chem-Haz Specialist | SWAT"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4718.png",
"model": "tm_balkan/tm_balkan_variantk",
"agent_name": "Rezan the Redshirt | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4726.png",
"model": "tm_professional/tm_professional_varf",
"agent_name": "Sir Bloody Miami Darryl | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4727.png",
"model": "tm_professional/tm_professional_varg",
"agent_name": "Safecracker Voltzmann | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4728.png",
"model": "tm_professional/tm_professional_varh",
"agent_name": "Little Kev | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4730.png",
"model": "tm_professional/tm_professional_varj",
"agent_name": "Getaway Sally | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4732.png",
"model": "tm_professional/tm_professional_vari",
"agent_name": "Number K | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4733.png",
"model": "tm_professional/tm_professional_varf1",
"agent_name": "Sir Bloody Silent Darryl | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4734.png",
"model": "tm_professional/tm_professional_varf2",
"agent_name": "Sir Bloody Skullhead Darryl | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4735.png",
"model": "tm_professional/tm_professional_varf3",
"agent_name": "Sir Bloody Darryl Royale | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4736.png",
"model": "tm_professional/tm_professional_varf4",
"agent_name": "Sir Bloody Loudmouth Darryl | The Professionals"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4749.png",
"model": "ctm_gendarmerie/ctm_gendarmerie_varianta",
"agent_name": "Sous-Lieutenant Medic | Gendarmerie Nationale"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4750.png",
"model": "ctm_gendarmerie/ctm_gendarmerie_variantb",
"agent_name": "Chem-Haz Capitaine | Gendarmerie Nationale"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4751.png",
"model": "ctm_gendarmerie/ctm_gendarmerie_variantc",
"agent_name": "Chef d'Escadron Rouchard | Gendarmerie Nationale"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4752.png",
"model": "ctm_gendarmerie/ctm_gendarmerie_variantd",
"agent_name": "Aspirant | Gendarmerie Nationale"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4753.png",
"model": "ctm_gendarmerie/ctm_gendarmerie_variante",
"agent_name": "Officer Jacques Beltram | Gendarmerie Nationale"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4756.png",
"model": "ctm_swat/ctm_swat_variantk",
"agent_name": "Lieutenant 'Tree Hugger' Farlow | SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4757.png",
"model": "ctm_diver/ctm_diver_varianta",
"agent_name": "Cmdr. Davida 'Goggles' Fernandez | SEAL Frogman"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4771.png",
"model": "ctm_diver/ctm_diver_variantb",
"agent_name": "Cmdr. Frank 'Wet Sox' Baroud | SEAL Frogman"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4772.png",
"model": "ctm_diver/ctm_diver_variantc",
"agent_name": "Lieutenant Rex Krikey | SEAL Frogman"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4773.png",
"model": "tm_jungle_raider/tm_jungle_raider_varianta",
"agent_name": "Elite Trapper Solman | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4774.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantb",
"agent_name": "Crasswater The Forgotten | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4775.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantc",
"agent_name": "Arno The Overgrown | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4776.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantd",
"agent_name": "Col. Mangos Dabisi | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4777.png",
"model": "tm_jungle_raider/tm_jungle_raider_variante",
"agent_name": "Vypa Sista of the Revolution | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4778.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantf",
"agent_name": "Trapper Aggressor | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4780.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantb2",
"agent_name": "'Medium Rare' Crasswater | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4781.png",
"model": "tm_jungle_raider/tm_jungle_raider_variantf2",
"agent_name": "Trapper | Guerrilla Warfare"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5105.png",
"model": "tm_leet/tm_leet_variantg",
"agent_name": "Ground Rebel | Elite Crew"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5106.png",
"model": "tm_leet/tm_leet_varianth",
"agent_name": "Osiris | Elite Crew"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5107.png",
"model": "tm_leet/tm_leet_varianti",
"agent_name": "Prof. Shahmat | Elite Crew"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5108.png",
"model": "tm_leet/tm_leet_variantf",
"agent_name": "The Elite Mr. Muhlik | Elite Crew"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5109.png",
"model": "tm_leet/tm_leet_variantj",
"agent_name": "Jungle Rebel | Elite Crew"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5205.png",
"model": "tm_phoenix/tm_phoenix_varianth",
"agent_name": "Soldier | Phoenix"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5206.png",
"model": "tm_phoenix/tm_phoenix_variantf",
"agent_name": "Enforcer | Phoenix"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5207.png",
"model": "tm_phoenix/tm_phoenix_variantg",
"agent_name": "Slingshot | Phoenix"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5208.png",
"model": "tm_phoenix/tm_phoenix_varianti",
"agent_name": "Street Soldier | Phoenix"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5305.png",
"model": "ctm_fbi/ctm_fbi_variantf",
"agent_name": "Operator | FBI SWAT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5306.png",
"model": "ctm_fbi/ctm_fbi_variantg",
"agent_name": "Markus Delrow | FBI HRT"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5307.png",
"model": "ctm_fbi/ctm_fbi_varianth",
"agent_name": "Michael Syfers | FBI Sniper"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5308.png",
"model": "ctm_fbi/ctm_fbi_variantb",
"agent_name": "Special Agent Ava | FBI"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5400.png",
"model": "ctm_st6/ctm_st6_variantk",
"agent_name": "3rd Commando Company | KSK"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5401.png",
"model": "ctm_st6/ctm_st6_variante",
"agent_name": "Seal Team 6 Soldier | NSWC SEAL"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5402.png",
"model": "ctm_st6/ctm_st6_variantg",
"agent_name": "Buckshot | NSWC SEAL"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5403.png",
"model": "ctm_st6/ctm_st6_variantm",
"agent_name": "'Two Times' McCoy | USAF TACP"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5404.png",
"model": "ctm_st6/ctm_st6_varianti",
"agent_name": "Lt. Commander Ricksaw | NSWC SEAL"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5405.png",
"model": "ctm_st6/ctm_st6_variantn",
"agent_name": "Primeiro Tenente | Brazilian 1st Battalion"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5500.png",
"model": "tm_balkan/tm_balkan_variantf",
"agent_name": "Dragomir | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5501.png",
"model": "tm_balkan/tm_balkan_varianti",
"agent_name": "Maximus | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5502.png",
"model": "tm_balkan/tm_balkan_variantg",
"agent_name": "Rezan The Ready | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5503.png",
"model": "tm_balkan/tm_balkan_variantj",
"agent_name": "Blackwolf | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5504.png",
"model": "tm_balkan/tm_balkan_varianth",
"agent_name": "'The Doctor' Romanov | Sabre"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5505.png",
"model": "tm_balkan/tm_balkan_variantl",
"agent_name": "Dragomir | Sabre Footsoldier"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5601.png",
"model": "ctm_sas/ctm_sas_variantf",
"agent_name": "B Squadron Officer | SAS"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5602.png",
"model": "ctm_sas/ctm_sas_variantg",
"agent_name": "D Squadron Officer | NZSAS"
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

440
website/data/gloves.json Normal file
View File

@@ -0,0 +1,440 @@
[
{
"weapon_defindex": 0,
"paint": "0",
"image": "",
"paint_name": "Gloves | Default"
},
{
"weapon_defindex": 4725,
"paint": "10085",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_brokenfang_gloves-10085.png",
"paint_name": "★ Broken Fang Gloves | Jade"
},
{
"weapon_defindex": 4725,
"paint": "10086",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_brokenfang_gloves-10086.png",
"paint_name": "★ Broken Fang Gloves | Yellow-banded"
},
{
"weapon_defindex": 4725,
"paint": "10087",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_brokenfang_gloves-10087.png",
"paint_name": "★ Broken Fang Gloves | Needle Point"
},
{
"weapon_defindex": 4725,
"paint": "10088",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_brokenfang_gloves-10088.png",
"paint_name": "★ Broken Fang Gloves | Unhinged"
},
{
"weapon_defindex": 5027,
"paint": "10006",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_bloodhound_gloves-10006.png",
"paint_name": "★ Bloodhound Gloves | Charred"
},
{
"weapon_defindex": 5027,
"paint": "10007",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_bloodhound_gloves-10007.png",
"paint_name": "★ Bloodhound Gloves | Snakebite"
},
{
"weapon_defindex": 5027,
"paint": "10008",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_bloodhound_gloves-10008.png",
"paint_name": "★ Bloodhound Gloves | Bronzed"
},
{
"weapon_defindex": 5027,
"paint": "10039",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_bloodhound_gloves-10039.png",
"paint_name": "★ Bloodhound Gloves | Guerrilla"
},
{
"weapon_defindex": 5030,
"paint": "10018",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10018.png",
"paint_name": "★ Sport Gloves | Superconductor"
},
{
"weapon_defindex": 5030,
"paint": "10019",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10019.png",
"paint_name": "★ Sport Gloves | Arid"
},
{
"weapon_defindex": 5030,
"paint": "10037",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10037.png",
"paint_name": "★ Sport Gloves | Pandora's Box"
},
{
"weapon_defindex": 5030,
"paint": "10038",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10038.png",
"paint_name": "★ Sport Gloves | Hedge Maze"
},
{
"weapon_defindex": 5030,
"paint": "10045",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10045.png",
"paint_name": "★ Sport Gloves | Amphibious"
},
{
"weapon_defindex": 5030,
"paint": "10046",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10046.png",
"paint_name": "★ Sport Gloves | Bronze Morph"
},
{
"weapon_defindex": 5030,
"paint": "10047",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10047.png",
"paint_name": "★ Sport Gloves | Omega"
},
{
"weapon_defindex": 5030,
"paint": "10048",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10048.png",
"paint_name": "★ Sport Gloves | Vice"
},
{
"weapon_defindex": 5030,
"paint": "10073",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10073.png",
"paint_name": "★ Sport Gloves | Slingshot"
},
{
"weapon_defindex": 5030,
"paint": "10074",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10074.png",
"paint_name": "★ Sport Gloves | Big Game"
},
{
"weapon_defindex": 5030,
"paint": "10075",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10075.png",
"paint_name": "★ Sport Gloves | Scarlet Shamagh"
},
{
"weapon_defindex": 5030,
"paint": "10076",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/sporty_gloves-10076.png",
"paint_name": "★ Sport Gloves | Nocts"
},
{
"weapon_defindex": 5031,
"paint": "10013",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10013.png",
"paint_name": "★ Driver Gloves | Lunar Weave"
},
{
"weapon_defindex": 5031,
"paint": "10015",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10015.png",
"paint_name": "★ Driver Gloves | Convoy"
},
{
"weapon_defindex": 5031,
"paint": "10016",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10016.png",
"paint_name": "★ Driver Gloves | Crimson Weave"
},
{
"weapon_defindex": 5031,
"paint": "10040",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10040.png",
"paint_name": "★ Driver Gloves | Diamondback"
},
{
"weapon_defindex": 5031,
"paint": "10041",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10041.png",
"paint_name": "★ Driver Gloves | King Snake"
},
{
"weapon_defindex": 5031,
"paint": "10042",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10042.png",
"paint_name": "★ Driver Gloves | Imperial Plaid"
},
{
"weapon_defindex": 5031,
"paint": "10043",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10043.png",
"paint_name": "★ Driver Gloves | Overtake"
},
{
"weapon_defindex": 5031,
"paint": "10044",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10044.png",
"paint_name": "★ Driver Gloves | Racing Green"
},
{
"weapon_defindex": 5031,
"paint": "10069",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10069.png",
"paint_name": "★ Driver Gloves | Rezan the Red"
},
{
"weapon_defindex": 5031,
"paint": "10070",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10070.png",
"paint_name": "★ Driver Gloves | Snow Leopard"
},
{
"weapon_defindex": 5031,
"paint": "10071",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10071.png",
"paint_name": "★ Driver Gloves | Queen Jaguar"
},
{
"weapon_defindex": 5031,
"paint": "10072",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/slick_gloves-10072.png",
"paint_name": "★ Driver Gloves | Black Tie"
},
{
"weapon_defindex": 5032,
"paint": "10009",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10009.png",
"paint_name": "★ Hand Wraps | Leather"
},
{
"weapon_defindex": 5032,
"paint": "10010",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10010.png",
"paint_name": "★ Hand Wraps | Spruce DDPAT"
},
{
"weapon_defindex": 5032,
"paint": "10021",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10021.png",
"paint_name": "★ Hand Wraps | Slaughter"
},
{
"weapon_defindex": 5032,
"paint": "10036",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10036.png",
"paint_name": "★ Hand Wraps | Badlands"
},
{
"weapon_defindex": 5032,
"paint": "10053",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10053.png",
"paint_name": "★ Hand Wraps | Cobalt Skulls"
},
{
"weapon_defindex": 5032,
"paint": "10054",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10054.png",
"paint_name": "★ Hand Wraps | Overprint"
},
{
"weapon_defindex": 5032,
"paint": "10055",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10055.png",
"paint_name": "★ Hand Wraps | Duct Tape"
},
{
"weapon_defindex": 5032,
"paint": "10056",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10056.png",
"paint_name": "★ Hand Wraps | Arboreal"
},
{
"weapon_defindex": 5032,
"paint": "10081",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10081.png",
"paint_name": "★ Hand Wraps | Desert Shamagh"
},
{
"weapon_defindex": 5032,
"paint": "10082",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10082.png",
"paint_name": "★ Hand Wraps | Giraffe"
},
{
"weapon_defindex": 5032,
"paint": "10083",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10083.png",
"paint_name": "★ Hand Wraps | Constrictor"
},
{
"weapon_defindex": 5032,
"paint": "10084",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/leather_handwraps-10084.png",
"paint_name": "★ Hand Wraps | CAUTION!"
},
{
"weapon_defindex": 5033,
"paint": "10024",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10024.png",
"paint_name": "★ Moto Gloves | Eclipse"
},
{
"weapon_defindex": 5033,
"paint": "10026",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10026.png",
"paint_name": "★ Moto Gloves | Spearmint"
},
{
"weapon_defindex": 5033,
"paint": "10027",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10027.png",
"paint_name": "★ Moto Gloves | Boom!"
},
{
"weapon_defindex": 5033,
"paint": "10028",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10028.png",
"paint_name": "★ Moto Gloves | Cool Mint"
},
{
"weapon_defindex": 5033,
"paint": "10049",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10049.png",
"paint_name": "★ Moto Gloves | POW!"
},
{
"weapon_defindex": 5033,
"paint": "10050",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10050.png",
"paint_name": "★ Moto Gloves | Turtle"
},
{
"weapon_defindex": 5033,
"paint": "10051",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10051.png",
"paint_name": "★ Moto Gloves | Transport"
},
{
"weapon_defindex": 5033,
"paint": "10052",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10052.png",
"paint_name": "★ Moto Gloves | Polygon"
},
{
"weapon_defindex": 5033,
"paint": "10077",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10077.png",
"paint_name": "★ Moto Gloves | Finish Line"
},
{
"weapon_defindex": 5033,
"paint": "10078",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10078.png",
"paint_name": "★ Moto Gloves | Smoke Out"
},
{
"weapon_defindex": 5033,
"paint": "10079",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10079.png",
"paint_name": "★ Moto Gloves | Blood Pressure"
},
{
"weapon_defindex": 5033,
"paint": "10080",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/motorcycle_gloves-10080.png",
"paint_name": "★ Moto Gloves | 3rd Commando Company"
},
{
"weapon_defindex": 5034,
"paint": "10030",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10030.png",
"paint_name": "★ Specialist Gloves | Forest DDPAT"
},
{
"weapon_defindex": 5034,
"paint": "10033",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10033.png",
"paint_name": "★ Specialist Gloves | Crimson Kimono"
},
{
"weapon_defindex": 5034,
"paint": "10034",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10034.png",
"paint_name": "★ Specialist Gloves | Emerald Web"
},
{
"weapon_defindex": 5034,
"paint": "10035",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10035.png",
"paint_name": "★ Specialist Gloves | Foundation"
},
{
"weapon_defindex": 5034,
"paint": "10061",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10061.png",
"paint_name": "★ Specialist Gloves | Crimson Web"
},
{
"weapon_defindex": 5034,
"paint": "10062",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10062.png",
"paint_name": "★ Specialist Gloves | Buckshot"
},
{
"weapon_defindex": 5034,
"paint": "10063",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10063.png",
"paint_name": "★ Specialist Gloves | Fade"
},
{
"weapon_defindex": 5034,
"paint": "10064",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10064.png",
"paint_name": "★ Specialist Gloves | Mogul"
},
{
"weapon_defindex": 5034,
"paint": "10065",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10065.png",
"paint_name": "★ Specialist Gloves | Marble Fade"
},
{
"weapon_defindex": 5034,
"paint": "10066",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10066.png",
"paint_name": "★ Specialist Gloves | Lt. Commander"
},
{
"weapon_defindex": 5034,
"paint": "10067",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10067.png",
"paint_name": "★ Specialist Gloves | Tiger Strike"
},
{
"weapon_defindex": 5034,
"paint": "10068",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/specialist_gloves-10068.png",
"paint_name": "★ Specialist Gloves | Field Agent"
},
{
"weapon_defindex": 5035,
"paint": "10057",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_hydra_gloves-10057.png",
"paint_name": "★ Hydra Gloves | Emerald"
},
{
"weapon_defindex": 5035,
"paint": "10058",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_hydra_gloves-10058.png",
"paint_name": "★ Hydra Gloves | Mangrove"
},
{
"weapon_defindex": 5035,
"paint": "10059",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_hydra_gloves-10059.png",
"paint_name": "★ Hydra Gloves | Rattler"
},
{
"weapon_defindex": 5035,
"paint": "10060",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/studded_hydra_gloves-10060.png",
"paint_name": "★ Hydra Gloves | Case Hardened"
}
]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

View File

@@ -1 +0,0 @@
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]

367
website/data/music.json Normal file
View File

@@ -0,0 +1,367 @@
[
{
"id": "3",
"name": "Music Kit | Daniel Sadowski, Crimson Assault",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-3.png"
},
{
"id": "4",
"name": "Music Kit | Noisia, Sharpened",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-4.png"
},
{
"id": "5",
"name": "Music Kit | Robert Allaire, Insurgency",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-5.png"
},
{
"id": "6",
"name": "Music Kit | Sean Murray, A*D*8",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-6.png"
},
{
"id": "7",
"name": "Music Kit | Feed Me, High Noon",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-7.png"
},
{
"id": "8",
"name": "Music Kit | Dren, Death's Head Demolition",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-8.png"
},
{
"id": "9",
"name": "Music Kit | Austin Wintory, Desert Fire",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-9.png"
},
{
"id": "10",
"name": "Music Kit | Sasha, LNOE",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-10.png"
},
{
"id": "11",
"name": "Music Kit | Skog, Metal",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-11.png"
},
{
"id": "12",
"name": "Music Kit | Midnight Riders, All I Want for Christmas",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-12.png"
},
{
"id": "13",
"name": "Music Kit | Matt Lange, IsoRhythm",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-13.png"
},
{
"id": "14",
"name": "Music Kit | Mateo Messina, For No Mankind",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-14.png"
},
{
"id": "15",
"name": "Music Kit | Various Artists, Hotline Miami",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-15.png"
},
{
"id": "16",
"name": "Music Kit | Daniel Sadowski, Total Domination",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-16.png"
},
{
"id": "17",
"name": "Music Kit | Damjan Mravunac, The Talos Principle",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-17.png"
},
{
"id": "18",
"name": "Music Kit | Proxy, Battlepack",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-18.png"
},
{
"id": "19",
"name": "Music Kit | Ki:Theory, MOLOTOV",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-19.png"
},
{
"id": "20",
"name": "Music Kit | Troels Folmann, Uber Blasto Phone",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-20.png"
},
{
"id": "21",
"name": "Music Kit | Kelly Bailey, Hazardous Environments",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-21.png"
},
{
"id": "22",
"name": "Music Kit | Skog, II-Headshot",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-22.png"
},
{
"id": "23",
"name": "Music Kit | Daniel Sadowski, The 8-Bit Kit",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-23.png"
},
{
"id": "24",
"name": "Music Kit | AWOLNATION, I Am",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-24.png"
},
{
"id": "25",
"name": "Music Kit | Mord Fustang, Diamonds",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-25.png"
},
{
"id": "26",
"name": "Music Kit | Michael Bross, Invasion!",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-26.png"
},
{
"id": "27",
"name": "Music Kit | Ian Hultquist, Lion's Mouth",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-27.png"
},
{
"id": "28",
"name": "Music Kit | New Beat Fund, Sponge Fingerz",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-28.png"
},
{
"id": "29",
"name": "Music Kit | Beartooth, Disgusting",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-29.png"
},
{
"id": "30",
"name": "Music Kit | Lennie Moore, Java Havana Funkaloo",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-30.png"
},
{
"id": "31",
"name": "Music Kit | Darude, Moments CS:GO",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-31.png"
},
{
"id": "32",
"name": "Music Kit | Beartooth, Aggressive",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-32.png"
},
{
"id": "33",
"name": "Music Kit | Blitz Kids, The Good Youth",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-33.png"
},
{
"id": "34",
"name": "Music Kit | Hundredth, FREE",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-34.png"
},
{
"id": "35",
"name": "Music Kit | Neck Deep, Life's Not Out To Get You",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-35.png"
},
{
"id": "36",
"name": "Music Kit | Roam, Backbone",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-36.png"
},
{
"id": "37",
"name": "Music Kit | Twin Atlantic, GLA",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-37.png"
},
{
"id": "38",
"name": "Music Kit | Skog, III-Arena",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-38.png"
},
{
"id": "39",
"name": "Music Kit | The Verkkars, EZ4ENCE",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-39.png"
},
{
"id": "40",
"name": "Halo, The Master Chief Collection",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-40.png"
},
{
"id": "41",
"name": "Music Kit | Scarlxrd: King, Scar",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-41.png"
},
{
"id": "42",
"name": "Half-Life: Alyx, Anti-Citizen",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-42.png"
},
{
"id": "43",
"name": "Music Kit | Austin Wintory, Bachram",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-43.png"
},
{
"id": "44",
"name": "Music Kit | Dren, Gunman Taco Truck",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-44.png"
},
{
"id": "45",
"name": "Music Kit | Daniel Sadowski, Eye of the Dragon",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-45.png"
},
{
"id": "46",
"name": "Music Kit | Tree Adams and Ben Bromfield, M.U.D.D. FORCE",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-46.png"
},
{
"id": "47",
"name": "Music Kit | Tim Huling, Neo Noir",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-47.png"
},
{
"id": "48",
"name": "Music Kit | Sam Marshall, Bodacious",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-48.png"
},
{
"id": "49",
"name": "Music Kit | Matt Levine, Drifter",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-49.png"
},
{
"id": "50",
"name": "Music Kit | Amon Tobin, All for Dust",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-50.png"
},
{
"id": "51",
"name": "Darren Korb, Hades Music Kit",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-51.png"
},
{
"id": "52",
"name": "Music Kit | Neck Deep, The Lowlife Pack",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-52.png"
},
{
"id": "53",
"name": "Music Kit | Scarlxrd, CHAIN$AW.LXADXUT.",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-53.png"
},
{
"id": "54",
"name": "Music Kit | Austin Wintory, Mocha Petal",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-54.png"
},
{
"id": "55",
"name": "Music Kit | Chipzel, ~Yellow Magic~",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-55.png"
},
{
"id": "56",
"name": "Music Kit | Freaky DNA, Vici",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-56.png"
},
{
"id": "57",
"name": "Music Kit | Jesse Harlin, Astro Bellum",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-57.png"
},
{
"id": "58",
"name": "Music Kit | Laura Shigihara: Work Hard, Play Hard",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-58.png"
},
{
"id": "59",
"name": "Music Kit | Sarah Schachner, KOLIBRI",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-59.png"
},
{
"id": "60",
"name": "Music Kit | bbno$, u mad!",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-60.png"
},
{
"id": "61",
"name": "Music Kit | The Verkkars & n0thing, Flashbang Dance",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-61.png"
},
{
"id": "62",
"name": "Music Kit | 3kliksphilip, Heading for the Source",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-62.png"
},
{
"id": "63",
"name": "Music Kit | Humanity's Last Breath, Void",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-63.png"
},
{
"id": "64",
"name": "Music Kit | Juelz, Shooters",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-64.png"
},
{
"id": "65",
"name": "Music Kit | Knock2, dashstar*",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-65.png"
},
{
"id": "66",
"name": "Music Kit | Meechy Darko, Gothic Luxury",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-66.png"
},
{
"id": "67",
"name": "Music Kit | Sullivan King, Lock Me Up",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-67.png"
},
{
"id": "68",
"name": "Music Kit | Perfect World, 花脸 Hua Lian (Painted Face)",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-68.png"
},
{
"id": "69",
"name": "Music Kit | Denzel Curry, ULTIMATE",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-69.png"
},
{
"id": "71",
"name": "Music Kit | DRYDEN, Feel The Power",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-71.png"
},
{
"id": "72",
"name": "Music Kit | ISOxo, inhuman",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-72.png"
},
{
"id": "73",
"name": "Music Kit | KILL SCRIPT, All Night",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-73.png"
},
{
"id": "74",
"name": "Music Kit | Knock2, Make U SWEAT!",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-74.png"
},
{
"id": "75",
"name": "Music Kit | Rad Cat, Reason",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-75.png"
},
{
"id": "76",
"name": "Music Kit | TWERL, Ekko & Sidetrack, Under Bright Lights",
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/music_kit-76.png"
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More