mirror of
https://github.com/Nereziel/cs2-WeaponPaints.git
synced 2026-02-22 11:42:26 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be4de02d50 | ||
|
|
52e4fd7195 | ||
|
|
d7631c51b6 | ||
|
|
74aa5fa40c | ||
|
|
2a1ef7b489 | ||
|
|
a6f5eac440 | ||
|
|
deb18acb8f | ||
|
|
e6d935e16b | ||
|
|
c3d2209a13 | ||
|
|
67b35d9117 | ||
|
|
d102ac371b | ||
|
|
26a31d4bd7 | ||
|
|
4e9a4b2925 | ||
|
|
c291005d4d | ||
|
|
322b1b425b |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -58,8 +58,14 @@ jobs:
|
||||
${{ env.OUTPUT_PATH }}/McMaster.NETCore.Plugins.dll \
|
||||
${{ env.OUTPUT_PATH }}/Microsoft.DotNet.PlatformAbstractions.dll \
|
||||
${{ env.OUTPUT_PATH }}/Microsoft.Extensions.DependencyModel.dll \
|
||||
- name: Copy skins
|
||||
run: cp -R website/data ${{ env.OUTPUT_PATH }}
|
||||
- name: Copy skins.json
|
||||
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
|
||||
run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
|
||||
- name: Clean files Website
|
||||
|
||||
BIN
3rd_party/MenuManagerApi.dll
vendored
BIN
3rd_party/MenuManagerApi.dll
vendored
Binary file not shown.
317
Commands.cs
317
Commands.cs
@@ -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.Menu;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -9,42 +11,43 @@ namespace WeaponPaints
|
||||
{
|
||||
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 (player == null || !player.IsValid || player.UserId == null || player.IsBot) return;
|
||||
|
||||
PlayerInfo? playerInfo = new PlayerInfo
|
||||
PlayerInfo playerInfo = new PlayerInfo
|
||||
{
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player?.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player?.PlayerName,
|
||||
IpAddress = player?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (player != null && !CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
player != null && DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
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);
|
||||
RefreshWeapons(player);
|
||||
GivePlayerAgent(player);
|
||||
GivePlayerMusicKit(player);
|
||||
RefreshWeapons(player);
|
||||
AddTimer(0.1f, () => GivePlayerPin(player));
|
||||
AddTimer(0.15f, () => GivePlayerPin(player));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"]))
|
||||
{
|
||||
player.Print(Localizer["wp_command_refresh_done"]);
|
||||
player!.Print(Localizer["wp_command_refresh_done"]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -97,7 +100,7 @@ namespace WeaponPaints
|
||||
|
||||
private void RegisterCommands()
|
||||
{
|
||||
_config.Additional.CommandSkin.ForEach(c =>
|
||||
Config.Additional.CommandsInfo.ForEach(c =>
|
||||
{
|
||||
AddCommand($"css_{c}", "Skins info", (player, info) =>
|
||||
{
|
||||
@@ -106,39 +109,36 @@ namespace WeaponPaints
|
||||
});
|
||||
});
|
||||
|
||||
_config.Additional.CommandRefresh.ForEach(c =>
|
||||
Config.Additional.CommandsRefresh.ForEach(c =>
|
||||
{
|
||||
AddCommand($"css_{c}", "Skins refresh", (player, info) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player)) return;
|
||||
OnCommandRefresh(player, info);
|
||||
});
|
||||
});
|
||||
|
||||
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()
|
||||
{
|
||||
if (!Config.Additional.KnifeEnabled || !_gBCommandsAllowed) return;
|
||||
if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return;
|
||||
|
||||
var knivesOnly = WeaponList
|
||||
.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet"))
|
||||
.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) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player)) return;
|
||||
@@ -148,12 +148,12 @@ namespace WeaponPaints
|
||||
if (string.IsNullOrEmpty(knifeKey)) return;
|
||||
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
|
||||
@@ -161,45 +161,50 @@ namespace WeaponPaints
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
var knife = WeaponDefindex
|
||||
.FirstOrDefault(entry => entry.Value.Equals(knifeKey, StringComparison.OrdinalIgnoreCase))
|
||||
.Key;
|
||||
|
||||
GPlayersKnife[player.Slot] = knifeKey;
|
||||
g_playersKnife[player.Slot] = (ushort)knife;
|
||||
|
||||
if (_gBCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
|
||||
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
|
||||
RefreshWeapons(player);
|
||||
|
||||
if (WeaponSync != null)
|
||||
_ = Task.Run(async () => await WeaponSync.SyncKnifeToDatabase(playerInfo, knifeKey));
|
||||
if (weaponSync == null) return;
|
||||
|
||||
_ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, (ushort)knife));
|
||||
};
|
||||
|
||||
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) || !_gBCommandsAllowed) return;
|
||||
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
|
||||
|
||||
if (player == null || player.UserId == null) return;
|
||||
|
||||
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
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.Open(player);
|
||||
|
||||
//MenuManager.open(player, giveItemMenu);
|
||||
return;
|
||||
}
|
||||
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()
|
||||
{
|
||||
// var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
|
||||
var classNamesByWeapon = WeaponList
|
||||
.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"]);
|
||||
var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
|
||||
BaseMenu weaponSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_skin_menu_weapon_title"], Instance) : new ChatMenu(Localizer["wp_skin_menu_weapon_title"]);
|
||||
|
||||
// Function to handle skin selection for a specific weapon
|
||||
var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) =>
|
||||
@@ -220,14 +221,13 @@ namespace WeaponPaints
|
||||
if (!Utility.IsPlayerValid(player)) return;
|
||||
|
||||
var selectedWeapon = option.Text;
|
||||
|
||||
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) &&
|
||||
weaponName?.ToString() == selectedWeaponClassname
|
||||
)?.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
|
||||
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
|
||||
@@ -235,7 +235,7 @@ namespace WeaponPaints
|
||||
if (!Utility.IsPlayerValid(p)) return;
|
||||
|
||||
var steamId = p.SteamID.ToString();
|
||||
var firstSkin = SkinsList?.FirstOrDefault(skin =>
|
||||
var firstSkin = skinsList?.FirstOrDefault(skin =>
|
||||
{
|
||||
if (skin.TryGetValue("weapon_name", out var weaponName))
|
||||
{
|
||||
@@ -249,27 +249,27 @@ namespace WeaponPaints
|
||||
|
||||
if (firstSkin == null ||
|
||||
!firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) ||
|
||||
!int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
|
||||
!int.TryParse(selectedPaintId, out var paintId)) return;
|
||||
!ushort.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
|
||||
!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?["paint"] ?? 0) == paintId &&
|
||||
skin?["image"] != null
|
||||
);
|
||||
var image = foundSkin?["image"]?.ToString() ?? "";
|
||||
_playerWeaponImage[p.Slot] = image;
|
||||
AddTimer(2.0f, () => _playerWeaponImage.Remove(p.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
PlayerWeaponImage[p.Slot] = image;
|
||||
AddTimer(2.0f, () => PlayerWeaponImage.Remove(p.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
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();
|
||||
GPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
|
||||
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
|
||||
}
|
||||
|
||||
value.Paint = paintId;
|
||||
@@ -281,18 +281,18 @@ namespace WeaponPaints
|
||||
UserId = p.UserId,
|
||||
Slot = p.Slot,
|
||||
Index = (int)p.Index,
|
||||
SteamId = p.SteamID.ToString(),
|
||||
SteamId = p.SteamID,
|
||||
Name = p.PlayerName,
|
||||
IpAddress = p.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
if (!_gBCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
|
||||
WeaponSync == null) return;
|
||||
if (!g_bCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
|
||||
weaponSync == null) return;
|
||||
RefreshWeapons(player);
|
||||
|
||||
try
|
||||
{
|
||||
_ = Task.Run(async () => await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo));
|
||||
_ = Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -313,41 +313,38 @@ namespace WeaponPaints
|
||||
|
||||
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
|
||||
{
|
||||
skinSubMenu?.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
|
||||
skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (player != null && Utility.IsPlayerValid(player))
|
||||
skinSubMenu?.Open(player);
|
||||
skinSubMenu.Open(player);
|
||||
};
|
||||
|
||||
// Add weapon options to the weapon selection menu
|
||||
foreach (var weaponName in WeaponList
|
||||
.Where(kvp => kvp.Key != "weapon_knife")
|
||||
.Select(kvp => kvp.Value))
|
||||
{
|
||||
weaponSelectionMenu?.AddMenuOption(weaponName, handleWeaponSelection);
|
||||
// Add weapon options to the weapon selection menu
|
||||
foreach (var weaponName in WeaponList.Keys.Select(weaponClass => WeaponList[weaponClass]))
|
||||
{
|
||||
weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection);
|
||||
}
|
||||
// Command to open the weapon selection menu for players
|
||||
|
||||
_config.Additional.CommandSkinSelection.ForEach(c =>
|
||||
Config.Additional.CommandsSkinSelection.ForEach(c =>
|
||||
{
|
||||
AddCommand($"css_{c}", "Skins selection menu", (player, _) =>
|
||||
AddCommand($"css_{c}", "Skins selection menu", (player, info) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player)) return;
|
||||
|
||||
if (player == null || player.UserId == null) return;
|
||||
|
||||
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
{
|
||||
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
weaponSelectionMenu?.Open(player);
|
||||
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
weaponSelectionMenu.Open(player);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
|
||||
{
|
||||
player.Print(Localizer["wp_command_cooldown"]);
|
||||
player!.Print(Localizer["wp_command_cooldown"]);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -355,17 +352,15 @@ namespace WeaponPaints
|
||||
|
||||
private void SetupGlovesMenu()
|
||||
{
|
||||
var glovesSelectionMenu = MenuApi?.NewMenu(Localizer["wp_glove_menu_title"]);
|
||||
if (glovesSelectionMenu == null) return;
|
||||
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
|
||||
|
||||
BaseMenu glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]);
|
||||
|
||||
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player) || player is null) return;
|
||||
|
||||
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() ?? "";
|
||||
if (selectedGlove == null ||
|
||||
!selectedGlove.ContainsKey("weapon_defindex") ||
|
||||
@@ -374,8 +369,8 @@ namespace WeaponPaints
|
||||
!int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return;
|
||||
if (Config.Additional.ShowSkinImage)
|
||||
{
|
||||
_playerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
PlayerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = new PlayerInfo
|
||||
@@ -383,82 +378,89 @@ namespace WeaponPaints
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
if (paint != 0)
|
||||
{
|
||||
GPlayersGlove[player.Slot] = (ushort)weaponDefindex;
|
||||
g_playersGlove[player.Slot] = (ushort)weaponDefindex;
|
||||
|
||||
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out var value))
|
||||
{
|
||||
value = new ConcurrentDictionary<ushort, WeaponInfo>();
|
||||
|
||||
gPlayerWeaponsInfo[player.Slot] = value;
|
||||
}
|
||||
|
||||
if (!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex))
|
||||
if (!value.ContainsKey((ushort)weaponDefindex))
|
||||
{
|
||||
WeaponInfo weaponInfo = new()
|
||||
{
|
||||
Paint = paint
|
||||
Paint = (ushort)paint
|
||||
};
|
||||
GPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo;
|
||||
value[(ushort)weaponDefindex] = weaponInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GPlayersGlove.TryRemove(player.Slot, out _);
|
||||
g_playersGlove.TryRemove(player.Slot, out _);
|
||||
}
|
||||
|
||||
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 () =>
|
||||
{
|
||||
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();
|
||||
GPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value;
|
||||
gPlayerWeaponsInfo[playerInfo.Slot][(ushort)weaponDefindex] = value;
|
||||
}
|
||||
|
||||
value.Paint = paint;
|
||||
value.Paint = (ushort)paint;
|
||||
value.Wear = 0.00f;
|
||||
value.Seed = 0;
|
||||
|
||||
await WeaponSync.SyncWeaponPaintsToDatabase(playerInfo);
|
||||
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
|
||||
});
|
||||
|
||||
AddTimer(0.1f, () => GivePlayerGloves(player));
|
||||
AddTimer(0.25f, () => GivePlayerGloves(player));
|
||||
AddTimer(0.15f, () => GivePlayerGloves(player));
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
|
||||
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
|
||||
|
||||
if (player == null || player.UserId == null) return;
|
||||
|
||||
if (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
{
|
||||
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
glovesSelectionMenu?.Open(player);
|
||||
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
glovesSelectionMenu.Open(player);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
|
||||
var selectedPaintName = option.Text;
|
||||
var selectedAgent = AgentsList.FirstOrDefault(g =>
|
||||
var selectedAgent = agentsList.FirstOrDefault(g =>
|
||||
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);
|
||||
|
||||
if (selectedAgent == null) return;
|
||||
@@ -487,7 +489,7 @@ namespace WeaponPaints
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
@@ -495,56 +497,55 @@ namespace WeaponPaints
|
||||
if (Config.Additional.ShowSkinImage)
|
||||
{
|
||||
var image = selectedAgent["image"]?.ToString() ?? "";
|
||||
_playerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
PlayerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GPlayersAgent.AddOrUpdate(player.Slot,
|
||||
g_playersAgent.AddOrUpdate(player.Slot,
|
||||
key => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), null),
|
||||
(key, oldValue) => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), oldValue.T));
|
||||
}
|
||||
else
|
||||
{
|
||||
GPlayersAgent.AddOrUpdate(player.Slot,
|
||||
g_playersAgent.AddOrUpdate(player.Slot,
|
||||
key => (null, 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 () =>
|
||||
{
|
||||
await WeaponSync.SyncAgentToDatabase(playerInfo);
|
||||
await weaponSync.SyncAgentToDatabase(playerInfo);
|
||||
GivePlayerAgent(player);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 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) =>
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player) || !_gBCommandsAllowed) return;
|
||||
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
|
||||
|
||||
if (player == null || player.UserId == null) return;
|
||||
|
||||
if (!CommandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
{
|
||||
var agentsSelectionMenu = MenuApi?.NewMenu(Localizer["wp_agent_menu_title"]);
|
||||
if (agentsSelectionMenu == null) return;
|
||||
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
|
||||
BaseMenu agentsSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_agent_menu_title"], Instance) : new ChatMenu(Localizer["wp_agent_menu_title"]);
|
||||
|
||||
var filteredAgents = AgentsList.Where(agentObject =>
|
||||
var filteredAgents = agentsList.Where(agentObject =>
|
||||
{
|
||||
if (agentObject["team"]?.Value<int>() is { } teamNum)
|
||||
{
|
||||
@@ -566,23 +567,21 @@ namespace WeaponPaints
|
||||
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
|
||||
}
|
||||
|
||||
CommandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||
agentsSelectionMenu.Open(player);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
|
||||
{
|
||||
player.Print(Localizer["wp_command_cooldown"]);
|
||||
player!.Print(Localizer["wp_command_cooldown"]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupMusicMenu()
|
||||
{
|
||||
var musicSelectionMenu = MenuApi?.NewMenu(Localizer["wp_music_menu_title"]);
|
||||
if (musicSelectionMenu == null) return;
|
||||
musicSelectionMenu.PostSelectAction = PostSelectAction.Close;
|
||||
BaseMenu musicSelectionMenu = Config.Additional.UseHtmlMenu ? new CenterHtmlMenu(Localizer["wp_music_menu_title"], Instance) : new ChatMenu(Localizer["wp_music_menu_title"]);
|
||||
|
||||
var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) =>
|
||||
{
|
||||
@@ -590,7 +589,7 @@ namespace WeaponPaints
|
||||
|
||||
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.ContainsKey("id") ||
|
||||
@@ -599,8 +598,8 @@ namespace WeaponPaints
|
||||
var image = selectedMusic["image"]?.ToString() ?? "";
|
||||
if (Config.Additional.ShowSkinImage)
|
||||
{
|
||||
_playerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => _playerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
PlayerWeaponImage[player.Slot] = image;
|
||||
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = new PlayerInfo
|
||||
@@ -608,30 +607,30 @@ namespace WeaponPaints
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
if (paint != 0)
|
||||
{
|
||||
GPlayersMusic[player.Slot] = (ushort)paint;
|
||||
g_playersMusic[player.Slot] = (ushort)paint;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPlayersMusic[player.Slot] = 0;
|
||||
g_playersMusic[player.Slot] = 0;
|
||||
}
|
||||
|
||||
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 () =>
|
||||
{
|
||||
await WeaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
|
||||
await weaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -644,54 +643,56 @@ namespace WeaponPaints
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
GPlayersMusic[player.Slot] = 0;
|
||||
g_playersMusic[player.Slot] = 0;
|
||||
|
||||
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 () =>
|
||||
{
|
||||
await WeaponSync.SyncMusicToDatabase(playerInfo, 0);
|
||||
await weaponSync.SyncMusicToDatabase(playerInfo, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
GivePlayerMusicKit(player);
|
||||
};
|
||||
|
||||
musicSelectionMenu.AddMenuOption(Localizer["None"], handleMusicSelection);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Command to open the weapon selection menu for players
|
||||
_config.Additional.CommandMusic.ForEach(c =>
|
||||
Config.Additional.CommandsMusic.ForEach(c =>
|
||||
{
|
||||
// Command to open the weapon selection menu for players
|
||||
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 (!CommandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
DateTime.UtcNow >= (CommandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
|
||||
if (!commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
|
||||
{
|
||||
player.Print(Localizer["wp_command_cooldown"]);
|
||||
player!.Print(Localizer["wp_command_cooldown"]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
97
Config.cs
97
Config.cs
@@ -3,6 +3,24 @@ using System.Text.Json.Serialization;
|
||||
|
||||
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
|
||||
{
|
||||
[JsonPropertyName("KnifeEnabled")]
|
||||
@@ -20,38 +38,35 @@ namespace WeaponPaints
|
||||
[JsonPropertyName("SkinEnabled")]
|
||||
public bool SkinEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("PinsEnabled")]
|
||||
public bool PinsEnabled { get; set; } = true;
|
||||
[JsonPropertyName("NameTagEnabled")]
|
||||
public bool NameTagEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("CommandWpEnabled")]
|
||||
public bool CommandWpEnabled { get; set; } = true;
|
||||
[JsonPropertyName("PinEnabled")]
|
||||
public bool PinEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("CommandKillEnabled")]
|
||||
public bool CommandKillEnabled { get; set; } = true;
|
||||
[JsonPropertyName("CommandsKnife")]
|
||||
public List<string> CommandsKnife { get; set; } = ["knife", "knives"];
|
||||
|
||||
[JsonPropertyName("CommandKnife")]
|
||||
public List<string> CommandKnife { get; set; } = ["knife"];
|
||||
[JsonPropertyName("CommandsMusic")]
|
||||
public List<string> CommandsMusic { get; set; } = ["music", "musickits", "mkit"];
|
||||
|
||||
[JsonPropertyName("CommandMusic")]
|
||||
public List<string> CommandMusic { get; set; } = ["music"];
|
||||
[JsonPropertyName("CommandsGlove")]
|
||||
public List<string> CommandsGlove { get; set; } = ["gloves", "glove"];
|
||||
|
||||
[JsonPropertyName("CommandGlove")]
|
||||
public List<string> CommandGlove { get; set; } = ["gloves"];
|
||||
[JsonPropertyName("CommandsAgent")]
|
||||
public List<string> CommandsAgent { get; set; } = ["agents", "agent"];
|
||||
|
||||
[JsonPropertyName("CommandAgent")]
|
||||
public List<string> CommandAgent { get; set; } = ["agents"];
|
||||
[JsonPropertyName("CommandsInfo")]
|
||||
public List<string> CommandsInfo { get; set; } = ["ws", "skininfo"];
|
||||
|
||||
[JsonPropertyName("CommandSkin")]
|
||||
public List<string> CommandSkin { get; set; } = ["ws"];
|
||||
[JsonPropertyName("CommandsSkinSelection")]
|
||||
public List<string> CommandsSkinSelection { get; set; } = ["skins", "skin"];
|
||||
|
||||
[JsonPropertyName("CommandSkinSelection")]
|
||||
public List<string> CommandSkinSelection { get; set; } = ["skins"];
|
||||
[JsonPropertyName("CommandsRefresh")]
|
||||
public List<string> CommandsRefresh { get; set; } = ["wp", "refreshskins"];
|
||||
|
||||
[JsonPropertyName("CommandRefresh")]
|
||||
public List<string> CommandRefresh { get; set; } = ["wp"];
|
||||
|
||||
[JsonPropertyName("CommandKill")]
|
||||
public List<string> CommandKill { get; set; } = ["kill"];
|
||||
[JsonPropertyName("CommandsKill")]
|
||||
public List<string> CommandsKill { get; set; } = ["kill", "suicide"];
|
||||
|
||||
[JsonPropertyName("GiveRandomKnife")]
|
||||
public bool GiveRandomKnife { get; set; } = false;
|
||||
@@ -61,32 +76,26 @@ namespace WeaponPaints
|
||||
|
||||
[JsonPropertyName("ShowSkinImage")]
|
||||
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
|
||||
{
|
||||
[JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 8;
|
||||
|
||||
[JsonPropertyName("SkinsLanguage")]
|
||||
public string SkinsLanguage { get; set; } = "en";
|
||||
|
||||
[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 override int Version { get; set; } = 7;
|
||||
|
||||
[JsonPropertyName("DatabaseCredentials")]
|
||||
public DatabaseCredentials DatabaseCredentials { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("CmdRefreshCooldownSeconds")]
|
||||
public int CmdRefreshCooldownSeconds { get; set; } = 10;
|
||||
public int CmdRefreshCooldownSeconds { get; set; } = 60;
|
||||
|
||||
[JsonPropertyName("Prefix")]
|
||||
public string Prefix { get; set; } = "[WeaponPaints]";
|
||||
|
||||
[JsonPropertyName("Website")]
|
||||
public string Website { get; set; } = "example.com/skins";
|
||||
|
||||
112
Events.cs
112
Events.cs
@@ -1,9 +1,10 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WeaponPaints
|
||||
{
|
||||
@@ -15,21 +16,21 @@ namespace WeaponPaints
|
||||
CCSPlayerController? player = @event.Userid;
|
||||
|
||||
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,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
SteamId = player.SteamID,
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_ = Task.Run(async () => await WeaponSync.GetPlayerData(playerInfo));
|
||||
_ = Task.Run(async () => await weaponSync.GetPlayerDatabaseIndex(playerInfo));
|
||||
/*
|
||||
if (Config.Additional.SkinEnabled)
|
||||
{
|
||||
@@ -53,9 +54,10 @@ namespace WeaponPaints
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
@@ -67,49 +69,34 @@ namespace WeaponPaints
|
||||
|
||||
if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue;
|
||||
|
||||
var playerInfo = new PlayerInfo
|
||||
{
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
Name = player.PlayerName,
|
||||
IpAddress = player.IpAddress?.Split(":")[0]
|
||||
};
|
||||
g_playersDatabaseIndex.TryRemove(player.Slot, out _);
|
||||
|
||||
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)
|
||||
{
|
||||
GPlayersKnife.TryRemove(player.Slot, out _);
|
||||
g_playersKnife.TryRemove(player.Slot, out _);
|
||||
}
|
||||
if (Config.Additional.GloveEnabled)
|
||||
{
|
||||
GPlayersGlove.TryRemove(player.Slot, out _);
|
||||
g_playersGlove.TryRemove(player.Slot, out _);
|
||||
}
|
||||
if (Config.Additional.AgentEnabled)
|
||||
{
|
||||
GPlayersAgent.TryRemove(player.Slot, out _);
|
||||
g_playersAgent.TryRemove(player.Slot, out _);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -118,8 +105,11 @@ namespace WeaponPaints
|
||||
{
|
||||
if (Config.Additional is { KnifeEnabled: false, SkinEnabled: false, GloveEnabled: false }) return;
|
||||
|
||||
if (Database != null)
|
||||
WeaponSync = new WeaponSynchronization(Database, Config);
|
||||
if (_database != null)
|
||||
weaponSync = new WeaponSynchronization(_database, Config);
|
||||
|
||||
if (weaponSync != null)
|
||||
Task.Run(async () => await weaponSync.PurgeExpiredUsers());
|
||||
}
|
||||
|
||||
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
|
||||
@@ -134,23 +124,26 @@ namespace WeaponPaints
|
||||
if (pawn == null || !pawn.IsValid)
|
||||
return HookResult.Continue;
|
||||
|
||||
g_knifePickupCount[player.Slot] = 0;
|
||||
|
||||
GivePlayerMusicKit(player);
|
||||
GivePlayerAgent(player);
|
||||
GivePlayerGloves(player);
|
||||
GivePlayerPin(player);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info)
|
||||
{
|
||||
_gBCommandsAllowed = false;
|
||||
g_bCommandsAllowed = false;
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
|
||||
{
|
||||
_gBCommandsAllowed = true;
|
||||
g_bCommandsAllowed = true;
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -185,16 +178,16 @@ namespace WeaponPaints
|
||||
|
||||
try
|
||||
{
|
||||
SteamID? steamid = null;
|
||||
SteamID? _steamid = null;
|
||||
|
||||
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)
|
||||
player = Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow);
|
||||
@@ -212,6 +205,7 @@ namespace WeaponPaints
|
||||
}
|
||||
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));
|
||||
}
|
||||
@@ -249,37 +243,6 @@ namespace WeaponPaints
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
|
||||
{
|
||||
CCSPlayerController? player = @event.Attacker;
|
||||
|
||||
if (player is null || !player.IsValid)
|
||||
return HookResult.Continue;
|
||||
|
||||
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return HookResult.Continue;
|
||||
|
||||
CBasePlayerWeapon? weapon = player.PlayerPawn.Value?.WeaponServices?.ActiveWeapon.Value;
|
||||
|
||||
if (weapon == null) return HookResult.Continue;
|
||||
|
||||
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
|
||||
|
||||
if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var 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()
|
||||
{
|
||||
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||
@@ -288,7 +251,6 @@ namespace WeaponPaints
|
||||
RegisterEventHandler<EventRoundStart>(OnRoundStart);
|
||||
RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
|
||||
RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated);
|
||||
RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
|
||||
|
||||
if (Config.Additional.ShowSkinImage)
|
||||
RegisterListener<Listeners.OnTick>(OnTick);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
public int Index { get; set; }
|
||||
public int Slot { get; init; }
|
||||
public int? UserId { get; set; }
|
||||
public string? SteamId { get; init; }
|
||||
public ulong? SteamId { get; init; }
|
||||
public string? Name { get; set; }
|
||||
public string? IpAddress { get; set; }
|
||||
}
|
||||
|
||||
15
README.md
15
README.md
@@ -19,21 +19,12 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
||||
- Added command **`!agents`** to show menu with agents
|
||||
- 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
|
||||
- Have working CounterStrikeSharp (**with RUNTIME!**)
|
||||
- Download from Release and copy plugin to plugins
|
||||
- Run server with plugin, **it will generate config if installed correctly!**
|
||||
- Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials
|
||||
- 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
|
||||
<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
|
||||
"GiveRandomSkins": false // Give random skins to players if they didn't choose
|
||||
},
|
||||
</pre></code>
|
||||
|
||||
"ConfigVersion": 4 // Don't touch
|
||||
}</pre></code>
|
||||
</details>
|
||||
|
||||
## 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.
|
||||
- Copy website to web server ***(Folder `img` not needed)***
|
||||
- Get [Steam API Key](https://steamcommunity.com/dev/apikey)
|
||||
|
||||
24
SchemaString.cs
Normal file
24
SchemaString.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
83
Utility.cs
83
Utility.cs
@@ -1,4 +1,4 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -13,71 +13,26 @@ namespace WeaponPaints
|
||||
|
||||
internal static async Task CheckDatabaseTables()
|
||||
{
|
||||
if (WeaponPaints.Database is null) return;
|
||||
if (WeaponPaints._database is null) return;
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await WeaponPaints.Database.GetConnectionAsync();
|
||||
await using var connection = await WeaponPaints._database.GetConnectionAsync();
|
||||
|
||||
await using var transaction = await connection.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
string[] createTableQueries =
|
||||
[
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `wp_player_skins` (
|
||||
`steamid` varchar(18) NOT NULL,
|
||||
`weapon_defindex` int(6) NOT NULL,
|
||||
`weapon_paint_id` int(6) NOT NULL,
|
||||
`weapon_wear` float NOT NULL DEFAULT 0.000001,
|
||||
`weapon_seed` int(16) NOT NULL DEFAULT 0,
|
||||
`weapon_nametag` VARCHAR(128) DEFAULT NULL,
|
||||
`weapon_stattrak` tinyint(1) NOT NULL,
|
||||
`weapon_stattrak_count` int(10) NOT NULL,
|
||||
`weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
||||
`weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
||||
`weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation',
|
||||
`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
|
||||
""",
|
||||
];
|
||||
{
|
||||
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_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;",
|
||||
"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;",
|
||||
"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;",
|
||||
"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;",
|
||||
"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;",
|
||||
"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;",
|
||||
};
|
||||
|
||||
foreach (var query in createTableQueries)
|
||||
{
|
||||
@@ -100,7 +55,7 @@ namespace WeaponPaints
|
||||
|
||||
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 };
|
||||
}
|
||||
@@ -111,7 +66,7 @@ namespace WeaponPaints
|
||||
try
|
||||
{
|
||||
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
|
||||
WeaponPaints.SkinsList = deserializedSkins ?? [];
|
||||
WeaponPaints.skinsList = deserializedSkins ?? [];
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@@ -125,7 +80,7 @@ namespace WeaponPaints
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
|
||||
WeaponPaints.GlovesList = deserializedSkins ?? [];
|
||||
WeaponPaints.glovesList = deserializedSkins ?? [];
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@@ -139,7 +94,7 @@ namespace WeaponPaints
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
|
||||
WeaponPaints.AgentsList = deserializedSkins ?? [];
|
||||
WeaponPaints.agentsList = deserializedSkins ?? [];
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@@ -153,7 +108,7 @@ namespace WeaponPaints
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
|
||||
WeaponPaints.MusicList = deserializedSkins ?? [];
|
||||
WeaponPaints.musicList = deserializedSkins ?? [];
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
|
||||
166
Variables.cs
166
Variables.cs
@@ -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");
|
||||
}
|
||||
976
WeaponAction.cs
976
WeaponAction.cs
@@ -1,525 +1,469 @@
|
||||
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.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
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)
|
||||
{
|
||||
if (!Config.Additional.SkinEnabled) return;
|
||||
if (!GPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
|
||||
|
||||
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
|
||||
|
||||
if (isKnife && !GPlayersKnife.ContainsKey(player.Slot) || isKnife && GPlayersKnife[player.Slot] == "weapon_knife") 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 };
|
||||
|
||||
if (isKnife)
|
||||
{
|
||||
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == GPlayersKnife[player.Slot]);
|
||||
if (newDefIndex.Key == 0) return;
|
||||
|
||||
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
|
||||
{
|
||||
SubclassChange(weapon, (ushort)newDefIndex.Key);
|
||||
}
|
||||
|
||||
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
|
||||
weapon.AttributeManager.Item.EntityQuality = 3;
|
||||
}
|
||||
|
||||
UpdatePlayerEconItemId(weapon.AttributeManager.Item);
|
||||
|
||||
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
|
||||
int fallbackPaintKit = 0;
|
||||
|
||||
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
||||
|
||||
if (_config.Additional.GiveRandomSkin &&
|
||||
!GPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
|
||||
{
|
||||
// Random skins
|
||||
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
|
||||
weapon.FallbackSeed = 0;
|
||||
weapon.FallbackWear = 0.01f;
|
||||
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", GetRandomPaint(weaponDefIndex));
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0);
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture wear", 0.01f);
|
||||
|
||||
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture prefab", GetRandomPaint(weaponDefIndex));
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture seed", 0);
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle, "set item texture wear", 0.01f);
|
||||
|
||||
fallbackPaintKit = weapon.FallbackPaintKit;
|
||||
|
||||
if (fallbackPaintKit == 0)
|
||||
return;
|
||||
|
||||
if (isKnife) return;
|
||||
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out var value) || value.Paint == 0) return;
|
||||
|
||||
var weaponInfo = value;
|
||||
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
|
||||
|
||||
weapon.AttributeManager.Item.ItemID = 16384;
|
||||
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
||||
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
|
||||
weapon.AttributeManager.Item.CustomName = weaponInfo.Nametag;
|
||||
weapon.FallbackPaintKit = weaponInfo.Paint;
|
||||
weapon.FallbackSeed = weaponInfo.Seed;
|
||||
weapon.FallbackWear = weaponInfo.Wear;
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
||||
|
||||
if (weaponInfo.StatTrak)
|
||||
{
|
||||
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;
|
||||
|
||||
if (fallbackPaintKit == 0)
|
||||
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));
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
|
||||
|
||||
if (PlayerHasKnife(player)) return;
|
||||
|
||||
//string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
|
||||
player.GiveNamedItem(CsItem.Knife);
|
||||
}
|
||||
|
||||
private static bool PlayerHasKnife(CCSPlayerController? player)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled) return false;
|
||||
|
||||
if (player == null || !player.IsValid || !player.PlayerPawn.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
|
||||
return false;
|
||||
|
||||
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
|
||||
if (weapons == null) return false;
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue;
|
||||
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RefreshWeapons(CCSPlayerController? player)
|
||||
{
|
||||
if (!_gBCommandsAllowed) return;
|
||||
if (player == null || !player.IsValid || player.PlayerPawn.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
|
||||
return;
|
||||
|
||||
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
|
||||
|
||||
if (weapons.Count == 0)
|
||||
return;
|
||||
if (player.Team is CsTeam.None or CsTeam.Spectator)
|
||||
return;
|
||||
|
||||
int playerTeam = player.TeamNum;
|
||||
|
||||
Dictionary<string, List<(int, int)>> weaponsWithAmmo = [];
|
||||
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
if (!weapon.IsValid || weapon.Value == null ||
|
||||
!weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
|
||||
continue;
|
||||
|
||||
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>();
|
||||
|
||||
if (weapon.Value.Entity == null) continue;
|
||||
if (!weapon.Value.OwnerEntity.IsValid) continue;
|
||||
if (gun.Entity == null) continue;
|
||||
if (!gun.IsValid) continue;
|
||||
if (!gun.VisibleinPVS) continue;
|
||||
|
||||
try
|
||||
{
|
||||
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
|
||||
|
||||
if (weaponData == null) continue;
|
||||
|
||||
if (weaponData.GearSlot is gear_slot_t.GEAR_SLOT_RIFLE or gear_slot_t.GEAR_SLOT_PISTOL)
|
||||
{
|
||||
if (!WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex, out var weaponByDefindex))
|
||||
continue;
|
||||
|
||||
int clip1 = weapon.Value.Clip1;
|
||||
int reservedAmmo = weapon.Value.ReserveAmmo[0];
|
||||
|
||||
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
|
||||
{
|
||||
value = [];
|
||||
weaponsWithAmmo.Add(weaponByDefindex, value);
|
||||
}
|
||||
|
||||
value.Add((clip1, reservedAmmo));
|
||||
|
||||
if (gun.VData == null) return;
|
||||
|
||||
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f);
|
||||
}
|
||||
|
||||
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
|
||||
{
|
||||
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, null, "", 0.1f);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
AddTimer(0.23f, () =>
|
||||
{
|
||||
if (!_gBCommandsAllowed) return;
|
||||
|
||||
if (!PlayerHasKnife(player))
|
||||
GiveKnifeToPlayer(player);
|
||||
|
||||
foreach (var entry in weaponsWithAmmo)
|
||||
{
|
||||
foreach (var ammo in entry.Value)
|
||||
{
|
||||
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
newWeapon.Clip1 = ammo.Item1;
|
||||
newWeapon.ReserveAmmo[0] = ammo.Item2;
|
||||
|
||||
IncrementWearForWeaponWithStickers(player, newWeapon);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private void GivePlayerGloves(CCSPlayerController player)
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid)
|
||||
return;
|
||||
|
||||
var model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(model))
|
||||
{
|
||||
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
|
||||
pawn.SetModel(model);
|
||||
}
|
||||
|
||||
Instance.AddTimer(0.08f, () =>
|
||||
{
|
||||
CEconItemView item = pawn.EconGloves;
|
||||
try
|
||||
{
|
||||
if (!player.IsValid)
|
||||
return;
|
||||
|
||||
if (!player.PawnIsAlive)
|
||||
return;
|
||||
|
||||
if (!GPlayersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
|
||||
|
||||
WeaponInfo weaponInfo = GPlayerWeaponsInfo[player.Slot][gloveInfo];
|
||||
|
||||
item.ItemDefinitionIndex = gloveInfo;
|
||||
item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
||||
item.ItemIDHigh = 16384;
|
||||
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weaponInfo.Paint);
|
||||
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;
|
||||
|
||||
SetBodygroup(pawn.Handle, "default_gloves", 1);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private static int GetRandomPaint(int defindex)
|
||||
{
|
||||
if (SkinsList.Count == 0)
|
||||
return 0;
|
||||
|
||||
Random rnd = new Random();
|
||||
|
||||
// Filter weapons by the provided defindex
|
||||
var filteredWeapons = SkinsList.Where(w => w["weapon_defindex"]?.ToString() == defindex.ToString()).ToList();
|
||||
|
||||
if (filteredWeapons.Count == 0)
|
||||
return 0;
|
||||
|
||||
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
|
||||
|
||||
return int.TryParse(randomWeapon["paint"]?.ToString(), out var paintValue) ? paintValue : 0;
|
||||
}
|
||||
|
||||
private static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
|
||||
{
|
||||
var subclassChangeFunc = VirtualFunction.Create<nint, string, int>(
|
||||
GameData.GetSignature("ChangeSubclass")
|
||||
);
|
||||
|
||||
subclassChangeFunc(weapon.Handle, itemD.ToString());
|
||||
}
|
||||
|
||||
private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
|
||||
{
|
||||
if (weapon.CBodyComponent?.SceneNode == null) return;
|
||||
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
|
||||
var value = (ulong)(isLegacy ? 2 : 1);
|
||||
|
||||
if (skeleton.ModelState.MeshGroupMask != value)
|
||||
{
|
||||
skeleton.ModelState.MeshGroupMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy)
|
||||
{
|
||||
UpdateWeaponMeshGroupMask(weapon, isLegacy);
|
||||
|
||||
var viewModel = GetPlayerViewModel(player);
|
||||
if (viewModel == null || viewModel.Weapon.Value == null ||
|
||||
viewModel.Weapon.Value.Index != weapon.Index) return;
|
||||
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
|
||||
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
|
||||
}
|
||||
|
||||
private static void GivePlayerAgent(CCSPlayerController player)
|
||||
{
|
||||
if (!GPlayersAgent.TryGetValue(player.Slot, out var value)) return;
|
||||
|
||||
var model = player.TeamNum == 3 ? value.CT : value.T;
|
||||
if (string.IsNullOrEmpty(model)) return;
|
||||
|
||||
if (player.PlayerPawn.Value == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
player.PlayerPawn.Value.SetModel(
|
||||
$"characters/models/{model}.vmdl"
|
||||
);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static void GivePlayerMusicKit(CCSPlayerController player)
|
||||
{
|
||||
if (!GPlayersMusic.TryGetValue(player.Slot, out var value)) return;
|
||||
if (player.InventoryServices == null) return;
|
||||
|
||||
player.InventoryServices.MusicID = value;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
|
||||
player.MusicKitID = value;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID");
|
||||
}
|
||||
|
||||
private static void GivePlayerPin(CCSPlayerController player)
|
||||
{
|
||||
if (!GPlayersPin.TryGetValue(player.Slot, out var pin)) return;
|
||||
|
||||
if (player.InventoryServices == null) return;
|
||||
|
||||
for (var index = 0; index < player.InventoryServices.Rank.Length; index++)
|
||||
{
|
||||
player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)pin : MedalRank_t.MEDAL_RANK_NONE;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
|
||||
}
|
||||
}
|
||||
|
||||
private void GiveOnItemPickup(CCSPlayerController player)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null) return;
|
||||
|
||||
var myWeapons = pawn.WeaponServices?.MyWeapons;
|
||||
if (myWeapons == null) return;
|
||||
foreach (var handle in myWeapons)
|
||||
{
|
||||
var weapon = handle.Value;
|
||||
if (weapon != null && weapon.DesignerName.Contains("knife"))
|
||||
{
|
||||
GivePlayerWeaponSkin(player, weapon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerEconItemId(CEconItemView econItemView)
|
||||
{
|
||||
var itemId = _nextItemId++;
|
||||
econItemView.ItemID = itemId;
|
||||
|
||||
econItemView.ItemIDLow = (uint)itemId & 0xFFFFFFFF;
|
||||
econItemView.ItemIDHigh = (uint)itemId >> 32;
|
||||
}
|
||||
|
||||
private static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
|
||||
{
|
||||
var pawn = itemServices.Pawn.Value;
|
||||
if (!pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
|
||||
var player = new CCSPlayerController(pawn.Controller.Value.Handle);
|
||||
return !Utility.IsPlayerValid(player) ? null : player;
|
||||
}
|
||||
|
||||
private static unsafe CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
|
||||
{
|
||||
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
|
||||
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
|
||||
var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
|
||||
var references = MemoryMarshal.CreateSpan(ref ptr, 3);
|
||||
var viewModel = (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
|
||||
return viewModel.Value == null ? null : viewModel.Value;
|
||||
}
|
||||
|
||||
private static float ViewAsFloat(uint value)
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle((int)value);
|
||||
}
|
||||
}
|
||||
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
|
||||
{
|
||||
if (!Config.Additional.SkinEnabled) return;
|
||||
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
|
||||
|
||||
var isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
|
||||
|
||||
if ((isKnife && !g_playersKnife.ContainsKey(player.Slot)) ||
|
||||
(isKnife && g_playersKnife[player.Slot] < 500)) return;
|
||||
|
||||
int[] newPaints =
|
||||
[1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173];
|
||||
|
||||
if (isKnife)
|
||||
{
|
||||
//var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
|
||||
//if (newDefIndex.Key == 0) return;
|
||||
|
||||
if (weapon.AttributeManager.Item.ItemDefinitionIndex != g_playersKnife[player.Slot])
|
||||
SubclassChange(weapon, (ushort)g_playersKnife[player.Slot]);
|
||||
|
||||
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)g_playersKnife[player.Slot];
|
||||
weapon.AttributeManager.Item.EntityQuality = 3;
|
||||
}
|
||||
|
||||
UpdatePlayerEconItemId(weapon.AttributeManager.Item);
|
||||
|
||||
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
|
||||
var fallbackPaintKit = 0;
|
||||
|
||||
weapon.AttributeManager.Item.AccountID = (uint)player.SteamID;
|
||||
|
||||
if (_config.Additional.GiveRandomSkin &&
|
||||
!gPlayerWeaponsInfo[player.Slot].ContainsKey((ushort)weaponDefIndex))
|
||||
{
|
||||
// Random skins
|
||||
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
|
||||
weapon.FallbackSeed = 0;
|
||||
weapon.FallbackWear = 0.01f;
|
||||
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Attributes.RemoveAll();
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
|
||||
GetRandomPaint(weaponDefIndex));
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture seed", 0);
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture wear", 0.01f);
|
||||
|
||||
weapon.AttributeManager.Item.AttributeList.Attributes.RemoveAll();
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
|
||||
"set item texture prefab", GetRandomPaint(weaponDefIndex));
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
|
||||
"set item texture seed", 0);
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.AttributeList.Handle,
|
||||
"set item texture wear", 0.01f);
|
||||
|
||||
fallbackPaintKit = weapon.FallbackPaintKit;
|
||||
|
||||
if (fallbackPaintKit == 0)
|
||||
return;
|
||||
|
||||
if (isKnife) return;
|
||||
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gPlayerWeaponsInfo[player.Slot].TryGetValue((ushort)weaponDefIndex, out var value) || value.Paint == 0) return;
|
||||
|
||||
var weaponInfo = value;
|
||||
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
|
||||
weapon.AttributeManager.Item.ItemID = 16384;
|
||||
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
||||
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
|
||||
weapon.FallbackPaintKit = weaponInfo.Paint;
|
||||
weapon.FallbackSeed = weaponInfo.Seed;
|
||||
weapon.FallbackWear = weaponInfo.Wear;
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(
|
||||
weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab",
|
||||
weapon.FallbackPaintKit);
|
||||
|
||||
fallbackPaintKit = weapon.FallbackPaintKit;
|
||||
|
||||
if (fallbackPaintKit == 0)
|
||||
return;
|
||||
|
||||
if (isKnife) return;
|
||||
UpdatePlayerWeaponMeshGroupMask(player, weapon, !newPaints.Contains(fallbackPaintKit));
|
||||
}
|
||||
|
||||
private static void GiveKnifeToPlayer(CCSPlayerController? player)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
|
||||
|
||||
if (PlayerHasKnife(player)) return;
|
||||
|
||||
//string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
|
||||
player.GiveNamedItem(CsItem.Knife);
|
||||
}
|
||||
|
||||
private static bool PlayerHasKnife(CCSPlayerController? player)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled) return false;
|
||||
|
||||
if (player == null || !player.IsValid || !player.PlayerPawn.IsValid) return false;
|
||||
|
||||
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null ||
|
||||
player.PlayerPawn.Value.ItemServices == null)
|
||||
return false;
|
||||
|
||||
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
|
||||
if (weapons == null) return false;
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue;
|
||||
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RefreshWeapons(CCSPlayerController? player)
|
||||
{
|
||||
if (!g_bCommandsAllowed) return;
|
||||
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null ||
|
||||
(LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
|
||||
return;
|
||||
|
||||
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
|
||||
|
||||
if (weapons.Count == 0)
|
||||
return;
|
||||
if (player.Team is CsTeam.None or CsTeam.Spectator)
|
||||
return;
|
||||
|
||||
int playerTeam = player.TeamNum;
|
||||
|
||||
Dictionary<string, List<(int, int)>> weaponsWithAmmo = [];
|
||||
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
if (!weapon.IsValid || weapon.Value == null ||
|
||||
!weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
|
||||
continue;
|
||||
|
||||
var gun = weapon.Value.As<CCSWeaponBaseGun>();
|
||||
|
||||
if (weapon.Value.Entity == null) continue;
|
||||
if (!weapon.Value.OwnerEntity.IsValid) continue;
|
||||
if (gun.Entity == null) continue;
|
||||
if (!gun.IsValid) continue;
|
||||
if (!gun.VisibleinPVS) continue;
|
||||
|
||||
try
|
||||
{
|
||||
var weaponData = weapon.Value.As<CCSWeaponBase>().VData;
|
||||
|
||||
if (weaponData == null) continue;
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
var clip1 = weapon.Value.Clip1;
|
||||
var reservedAmmo = weapon.Value.ReserveAmmo[0];
|
||||
|
||||
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
|
||||
{
|
||||
value = [];
|
||||
weaponsWithAmmo.Add(weaponByDefindex, value);
|
||||
}
|
||||
|
||||
value.Add((clip1, reservedAmmo));
|
||||
|
||||
if (gun.VData == null) return;
|
||||
|
||||
weapon.Value.Remove();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
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();
|
||||
});
|
||||
|
||||
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 ammo in entry.Value)
|
||||
{
|
||||
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
newWeapon.Clip1 = ammo.Item1;
|
||||
newWeapon.ReserveAmmo[0] = ammo.Item2;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private void GivePlayerGloves(CCSPlayerController player)
|
||||
{
|
||||
if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid)
|
||||
return;
|
||||
|
||||
var model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(model))
|
||||
{
|
||||
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
|
||||
pawn.SetModel(model);
|
||||
}
|
||||
|
||||
Instance.AddTimer(0.06f, () =>
|
||||
{
|
||||
var item = pawn.EconGloves;
|
||||
try
|
||||
{
|
||||
if (!player.IsValid)
|
||||
return;
|
||||
|
||||
if (!player.PawnIsAlive)
|
||||
return;
|
||||
|
||||
if (!g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
|
||||
|
||||
var weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
|
||||
|
||||
item.ItemDefinitionIndex = gloveInfo;
|
||||
item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
||||
item.ItemIDHigh = 16384;
|
||||
|
||||
CAttributeListSetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle,
|
||||
"set item texture prefab", weaponInfo.Paint);
|
||||
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;
|
||||
|
||||
SetBodygroup(pawn.Handle, "default_gloves", 1);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private static int GetRandomPaint(int defindex)
|
||||
{
|
||||
if (skinsList.Count == 0)
|
||||
return 0;
|
||||
|
||||
var rnd = new Random();
|
||||
|
||||
// Filter weapons by the provided defindex
|
||||
var filteredWeapons = skinsList.Where(w => w["weapon_defindex"]?.ToString() == defindex.ToString()).ToList();
|
||||
|
||||
if (filteredWeapons.Count == 0)
|
||||
return 0;
|
||||
|
||||
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
|
||||
|
||||
return int.TryParse(randomWeapon["paint"]?.ToString(), out var paintValue) ? paintValue : 0;
|
||||
}
|
||||
|
||||
private static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
|
||||
{
|
||||
var subclassChangeFunc = VirtualFunction.Create<nint, string, int>(
|
||||
GameData.GetSignature("ChangeSubclass")
|
||||
);
|
||||
|
||||
subclassChangeFunc(weapon.Handle, itemD.ToString());
|
||||
}
|
||||
|
||||
private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
|
||||
{
|
||||
if (weapon.CBodyComponent?.SceneNode == null) return;
|
||||
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
|
||||
var value = (ulong)(isLegacy ? 2 : 1);
|
||||
|
||||
if (skeleton.ModelState.MeshGroupMask != value) skeleton.ModelState.MeshGroupMask = value;
|
||||
}
|
||||
|
||||
private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon,
|
||||
bool isLegacy)
|
||||
{
|
||||
UpdateWeaponMeshGroupMask(weapon, isLegacy);
|
||||
|
||||
var viewModel = GetPlayerViewModel(player);
|
||||
if (viewModel == null || viewModel.Weapon.Value == null ||
|
||||
viewModel.Weapon.Value.Index != weapon.Index) return;
|
||||
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
|
||||
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
|
||||
}
|
||||
|
||||
private static void GivePlayerAgent(CCSPlayerController player)
|
||||
{
|
||||
if (!g_playersAgent.TryGetValue(player.Slot, out var value)) return;
|
||||
|
||||
var model = player.TeamNum == 3 ? value.CT : value.T;
|
||||
if (string.IsNullOrEmpty(model)) return;
|
||||
|
||||
if (player.PlayerPawn.Value == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
player.PlayerPawn.Value.SetModel(
|
||||
$"characters/models/{model}.vmdl"
|
||||
);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static void GivePlayerMusicKit(CCSPlayerController player)
|
||||
{
|
||||
if (!g_playersMusic.TryGetValue(player.Slot, out var value)) return;
|
||||
if (player.InventoryServices == null) return;
|
||||
|
||||
player.InventoryServices.MusicID = value;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
|
||||
player.MusicKitID = value;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID");
|
||||
}
|
||||
|
||||
private static void GivePlayerPin(CCSPlayerController player)
|
||||
{
|
||||
if (!g_playersPin.TryGetValue(player.Slot, out var value)) return;
|
||||
if (player.InventoryServices == null) return;
|
||||
|
||||
for (var index = 0; index < player.InventoryServices.Rank.Length; index++)
|
||||
{
|
||||
player.InventoryServices.Rank[index] = index == 5 ? (MedalRank_t)value : MedalRank_t.MEDAL_RANK_NONE;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
|
||||
}
|
||||
}
|
||||
|
||||
private void GiveOnItemPickup(CCSPlayerController player)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null) return;
|
||||
|
||||
var myWeapons = pawn.WeaponServices?.MyWeapons;
|
||||
if (myWeapons == null) return;
|
||||
foreach (var handle in myWeapons)
|
||||
{
|
||||
var weapon = handle.Value;
|
||||
if (weapon != null && weapon.DesignerName.Contains("knife")) GivePlayerWeaponSkin(player, weapon);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerEconItemId(CEconItemView econItemView)
|
||||
{
|
||||
var itemId = _nextItemId++;
|
||||
econItemView.ItemID = itemId;
|
||||
|
||||
econItemView.ItemIDLow = (uint)itemId & 0xFFFFFFFF;
|
||||
econItemView.ItemIDHigh = (uint)itemId >> 32;
|
||||
}
|
||||
|
||||
private static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
|
||||
{
|
||||
var pawn = itemServices.Pawn.Value;
|
||||
if (!pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
|
||||
var player = new CCSPlayerController(pawn.Controller.Value.Handle);
|
||||
return !Utility.IsPlayerValid(player) ? null : player;
|
||||
}
|
||||
|
||||
private static CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
|
||||
{
|
||||
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
|
||||
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
|
||||
var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
|
||||
var references = MemoryMarshal.CreateSpan(ref ptr, 3);
|
||||
var viewModel =
|
||||
(CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
|
||||
return viewModel.Value == null ? null : viewModel.Value;
|
||||
}
|
||||
|
||||
public static T[] GetFixedArray<T>(nint pointer, string @class, string member, int length)
|
||||
where T : CHandle<CBaseViewModel>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,12 @@
|
||||
{
|
||||
public class WeaponInfo
|
||||
{
|
||||
public int Paint { get; set; }
|
||||
public int Seed { get; set; }
|
||||
public float Wear { get; set; }
|
||||
public string Nametag { get; set; } = "";
|
||||
public bool StatTrak { get; set; } = false;
|
||||
public int StatTrakCount { get; set; }
|
||||
public KeyChainInfo? KeyChain { 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; }
|
||||
}
|
||||
public ushort Paint { get; set; }
|
||||
public ushort Seed { get; set; } = 0;
|
||||
public float Wear { get; set; } = 0f;
|
||||
public string? NameTag { get; set; }
|
||||
public ushort Quality { get; set; }
|
||||
public uint StatTrack { get; set; }
|
||||
public bool StatTrackEnabled { get; set; }
|
||||
}
|
||||
}
|
||||
227
WeaponPaints.cs
227
WeaponPaints.cs
@@ -1,22 +1,178 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MySqlConnector;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
namespace WeaponPaints;
|
||||
|
||||
[MinimumApiVersion(276)]
|
||||
[MinimumApiVersion(238)]
|
||||
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
|
||||
{
|
||||
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();
|
||||
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 ModuleName => "WeaponPaints";
|
||||
public override string ModuleVersion => "2.7a";
|
||||
public override string ModuleVersion => "2.5a";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
@@ -25,42 +181,40 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
||||
if (hotReload)
|
||||
{
|
||||
OnMapStart(string.Empty);
|
||||
|
||||
|
||||
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 &&
|
||||
!string.IsNullOrEmpty(player.IpAddress) && player is
|
||||
{ IsBot: false, Connected: PlayerConnectedState.PlayerConnected }))
|
||||
{
|
||||
GPlayerWeaponsInfo.TryRemove(player.Slot, out _);
|
||||
GPlayersKnife.TryRemove(player.Slot, out _);
|
||||
GPlayersGlove.TryRemove(player.Slot, out _);
|
||||
GPlayersAgent.TryRemove(player.Slot, out _);
|
||||
GPlayersPin.TryRemove(player.Slot, out _);
|
||||
g_knifePickupCount[player.Slot] = 0;
|
||||
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
|
||||
g_playersKnife.TryRemove(player.Slot, out _);
|
||||
g_playersGlove.TryRemove(player.Slot, out _);
|
||||
g_playersAgent.TryRemove(player.Slot, out _);
|
||||
|
||||
var playerInfo = new PlayerInfo
|
||||
PlayerInfo? playerInfo = new PlayerInfo
|
||||
{
|
||||
UserId = player.UserId,
|
||||
Slot = player.Slot,
|
||||
Index = (int)player.Index,
|
||||
SteamId = player?.SteamID.ToString(),
|
||||
SteamId = player?.SteamID,
|
||||
Name = player?.PlayerName,
|
||||
IpAddress = player?.IpAddress?.Split(":")[0]
|
||||
};
|
||||
|
||||
_ = 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.LoadGlovesFromFile(ModuleDirectory + $"/data/gloves_{_config.SkinsLanguage}.json", Logger);
|
||||
Utility.LoadAgentsFromFile(ModuleDirectory + $"/data/agents_{_config.SkinsLanguage}.json", Logger);
|
||||
Utility.LoadMusicFromFile(ModuleDirectory + $"/data/music_{_config.SkinsLanguage}.json", Logger);
|
||||
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json", Logger);
|
||||
Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json", Logger);
|
||||
Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json", Logger);
|
||||
Utility.LoadMusicFromFile(ModuleDirectory + "/music.json", Logger);
|
||||
|
||||
if (Config.Additional.KnifeEnabled)
|
||||
SetupKnifeMenu();
|
||||
@@ -79,10 +233,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
||||
|
||||
public void OnConfigParsed(WeaponPaintsConfig config)
|
||||
{
|
||||
Config = config;
|
||||
_config = config;
|
||||
|
||||
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
|
||||
if (config.DatabaseCredentials.DatabaseHost.Length < 1 || config.DatabaseCredentials.DatabaseName.Length < 1 || config.DatabaseCredentials.DatabaseUser.Length < 1)
|
||||
{
|
||||
Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
|
||||
Unload(false);
|
||||
@@ -98,18 +249,21 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
||||
|
||||
var builder = new MySqlConnectionStringBuilder
|
||||
{
|
||||
Server = config.DatabaseHost,
|
||||
UserID = config.DatabaseUser,
|
||||
Password = config.DatabasePassword,
|
||||
Database = config.DatabaseName,
|
||||
Port = (uint)config.DatabasePort,
|
||||
Server = config.DatabaseCredentials.DatabaseHost,
|
||||
UserID = config.DatabaseCredentials.DatabaseUser,
|
||||
Password = config.DatabaseCredentials.DatabasePassword,
|
||||
Database = config.DatabaseCredentials.DatabaseName,
|
||||
Port = (uint)config.DatabaseCredentials.DatabasePort,
|
||||
Pooling = true,
|
||||
MaximumPoolSize = 640,
|
||||
};
|
||||
|
||||
Database = new Database(builder.ConnectionString);
|
||||
_database = new Database(builder.ConnectionString);
|
||||
|
||||
_ = Utility.CheckDatabaseTables();
|
||||
|
||||
Config = config;
|
||||
_config = config;
|
||||
_localizer = Localizer;
|
||||
|
||||
Utility.Config = config;
|
||||
@@ -117,17 +271,8 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
||||
Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger));
|
||||
}
|
||||
|
||||
public override void OnAllPluginsLoaded(bool hotReload)
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
try
|
||||
{
|
||||
MenuApi = MenuCapability.Get();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MenuApi = null;
|
||||
Logger.LogError("Error while loading required plugins");
|
||||
throw;
|
||||
}
|
||||
base.Unload(hotReload);
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<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="MySqlConnector" Version="2.4.0-beta.1" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -22,10 +22,4 @@
|
||||
<ItemGroup>
|
||||
<None Update="gamedata\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="MenuManagerApi">
|
||||
<HintPath>3rd_party\MenuManagerApi.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -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>
|
||||
@@ -1,419 +1,401 @@
|
||||
using Dapper;
|
||||
using MySqlConnector;
|
||||
using System.Collections.Concurrent;
|
||||
using Dapper;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace WeaponPaints;
|
||||
|
||||
namespace WeaponPaints
|
||||
internal class WeaponSynchronization
|
||||
{
|
||||
internal class WeaponSynchronization
|
||||
{
|
||||
private readonly WeaponPaintsConfig _config;
|
||||
private readonly Database _database;
|
||||
private readonly WeaponPaintsConfig _config;
|
||||
private readonly Database _database;
|
||||
|
||||
internal WeaponSynchronization(Database database, WeaponPaintsConfig config)
|
||||
{
|
||||
_database = database;
|
||||
_config = config;
|
||||
}
|
||||
internal WeaponSynchronization(Database database, WeaponPaintsConfig config)
|
||||
{
|
||||
_database = database;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
internal async Task GetPlayerData(PlayerInfo? player)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
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 (_config.Additional.KnifeEnabled)
|
||||
GetKnifeFromDatabase(player, connection);
|
||||
if (_config.Additional.GloveEnabled)
|
||||
GetGloveFromDatabase(player, connection);
|
||||
if (_config.Additional.AgentEnabled)
|
||||
GetAgentFromDatabase(player, connection);
|
||||
if (_config.Additional.MusicEnabled)
|
||||
GetMusicFromDatabase(player, connection);
|
||||
if (_config.Additional.SkinEnabled)
|
||||
GetWeaponPaintsFromDatabase(player, connection);
|
||||
if (_config.Additional.PinsEnabled)
|
||||
GetPinsFromDatabase(player, connection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception or handle it appropriately
|
||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||
return;
|
||||
await GetPlayerData(playerInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetPlayerDatabaseIndex: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
const string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
|
||||
var playerKnife = connection.QueryFirstOrDefault<string>(query, new { steamid = player.SteamId });
|
||||
internal async Task GetPlayerData(PlayerInfo? player)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
|
||||
if (_config.Additional.KnifeEnabled)
|
||||
GetKnifeFromDatabase(player, connection);
|
||||
if (_config.Additional.GloveEnabled)
|
||||
GetGloveFromDatabase(player, connection);
|
||||
if (_config.Additional.AgentEnabled)
|
||||
GetAgentFromDatabase(player, connection);
|
||||
if (_config.Additional.MusicEnabled)
|
||||
GetMusicFromDatabase(player, connection);
|
||||
if (_config.Additional.SkinEnabled)
|
||||
GetWeaponPaintsFromDatabase(player, connection);
|
||||
if (_config.Additional.PinEnabled)
|
||||
GetPinFromDatabase(player, connection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception or handle it appropriately
|
||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(playerKnife))
|
||||
{
|
||||
WeaponPaints.GPlayersKnife[player.Slot] = playerKnife;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||
return;
|
||||
const string query = "SELECT `knife` FROM `wp_users_knives` WHERE `user_id` = @userId";
|
||||
var playerKnife = connection.QueryFirstOrDefault<int>(query,
|
||||
new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
|
||||
|
||||
const string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
|
||||
var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
|
||||
WeaponPaints.g_playersKnife[player.Slot] = (ushort)playerKnife;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (gloveData != null)
|
||||
{
|
||||
WeaponPaints.GPlayersGlove[player.Slot] = gloveData.Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||
return;
|
||||
const string query = "SELECT `weapon_defindex` FROM `wp_users_gloves` WHERE `user_id` = @userId";
|
||||
var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
|
||||
|
||||
const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid";
|
||||
var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId });
|
||||
if (gloveData != null) WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (agentData == default) return;
|
||||
var agentCT = agentData.Item1;
|
||||
var agentT = agentData.Item2;
|
||||
private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
|
||||
{
|
||||
WeaponPaints.GPlayersAgent[player.Slot] = (
|
||||
agentCT,
|
||||
agentT
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_users_agents` WHERE `user_id` = @userId";
|
||||
var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
|
||||
|
||||
private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId))
|
||||
return;
|
||||
if (agentData == default) return;
|
||||
var agentCT = agentData.Item1;
|
||||
var agentT = agentData.Item2;
|
||||
|
||||
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
|
||||
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
|
||||
WeaponPaints.g_playersAgent[player.Slot] = (
|
||||
agentCT,
|
||||
agentT
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
|
||||
var playerSkins = connection.Query<dynamic>(query, new { steamid = player.SteamId });
|
||||
private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
foreach (var row in playerSkins)
|
||||
{
|
||||
int weaponDefIndex = row?.weapon_defindex ?? 0;
|
||||
int weaponPaintId = row?.weapon_paint_id ?? 0;
|
||||
float weaponWear = row?.weapon_wear ?? 0f;
|
||||
int weaponSeed = row?.weapon_seed ?? 0;
|
||||
string weaponNameTag = row?.weapon_nametag ?? "";
|
||||
var weaponInfos = new ConcurrentDictionary<ushort, WeaponInfo>();
|
||||
|
||||
string[]? keyChainParts = row?.weapon_keychain?.ToString().Split(';');
|
||||
|
||||
KeyChainInfo keyChainInfo = new KeyChainInfo();
|
||||
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] });
|
||||
|
||||
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;
|
||||
}
|
||||
foreach (var row in playerSkins)
|
||||
{
|
||||
ushort weaponDefIndex = (ushort)(row.weapon ?? 0);
|
||||
ushort weaponPaintId = (ushort)(row.paint ?? 0);
|
||||
float weaponWear = row.wear ?? 0f;
|
||||
ushort weaponSeed = (ushort)(row.seed ?? 0);
|
||||
string weaponNameTag = row.nametag ?? string.Empty;
|
||||
|
||||
// Create the WeaponInfo object
|
||||
WeaponInfo weaponInfo = new WeaponInfo
|
||||
{
|
||||
Paint = weaponPaintId,
|
||||
Seed = weaponSeed,
|
||||
Wear = weaponWear,
|
||||
Nametag = weaponNameTag,
|
||||
KeyChain = keyChainInfo
|
||||
};
|
||||
var weaponInfo = new WeaponInfo
|
||||
{
|
||||
Paint = weaponPaintId,
|
||||
Seed = weaponSeed,
|
||||
Wear = weaponWear,
|
||||
NameTag = weaponNameTag
|
||||
};
|
||||
|
||||
// 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
|
||||
weaponInfos[weaponDefIndex] = weaponInfo;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(stickerData.ToString())) continue;
|
||||
|
||||
var parts = stickerData.ToString()!.Split(';');
|
||||
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
//"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
|
||||
};
|
||||
private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
weaponInfo.Stickers.Add(stickerInfo);
|
||||
}
|
||||
const string query = "SELECT `music` FROM `wp_users_musics` WHERE `user_id` = @userId";
|
||||
var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot] });
|
||||
|
||||
weaponInfos[weaponDefIndex] = weaponInfo;
|
||||
}
|
||||
if (musicData != null) WeaponPaints.g_playersMusic[player.Slot] = musicData.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
WeaponPaints.GPlayerWeaponsInfo[player.Slot] = weaponInfos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
private void GetPinFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.PinEnabled || string.IsNullOrEmpty(player?.SteamId.ToString()))
|
||||
return;
|
||||
|
||||
private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||
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] });
|
||||
|
||||
const string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid";
|
||||
var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
|
||||
if (pinData != null) WeaponPaints.g_playersPin[player.Slot] = pinData.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetPinFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (musicData != null)
|
||||
{
|
||||
WeaponPaints.GPlayersMusic[player.Slot] = musicData.Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetMusicFromDatabase: {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
|
||||
);
|
||||
|
||||
private void GetPinsFromDatabase(PlayerInfo? player, MySqlConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(player?.SteamId))
|
||||
return;
|
||||
var ids = string.Join(",", userIds);
|
||||
|
||||
const string query = "SELECT `id` FROM `wp_player_pins` WHERE `steamid` = @steamid";
|
||||
var pinData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
|
||||
string query;
|
||||
|
||||
if (pinData != null)
|
||||
{
|
||||
WeaponPaints.GPlayersPin[player.Slot] = pinData.Value;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetPinsFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
|
||||
query = $"DELETE FROM wp_users_gloves WHERE user_id IN ({ids})";
|
||||
await connection.ExecuteAsync(query, transaction: transaction);
|
||||
|
||||
const string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
|
||||
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);
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing knife to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
query = $"DELETE FROM wp_users_pins WHERE user_id IN ({ids})";
|
||||
await connection.ExecuteAsync(query, transaction: transaction);
|
||||
|
||||
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
|
||||
{
|
||||
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId)) return;
|
||||
// Step 3: Delete users from wp_users
|
||||
query = $"DELETE FROM wp_users WHERE id IN ({ids})";
|
||||
await connection.ExecuteAsync(query, transaction: transaction);
|
||||
|
||||
try
|
||||
{
|
||||
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";
|
||||
await connection.ExecuteAsync(query, new { steamid = player.SteamId, weapon_defindex = defindex });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing glove to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
// Commit transaction
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utility.Log($"An error occurred in GetMusicFromDatabase: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task SyncAgentToDatabase(PlayerInfo player)
|
||||
{
|
||||
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return;
|
||||
internal async Task SyncKnifeToDatabase(PlayerInfo player, ushort knife)
|
||||
{
|
||||
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
|
||||
|
||||
const string query = """
|
||||
INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`)
|
||||
VALUES(@steamid, @agent_ct, @agent_t)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`agent_ct` = @agent_ct,
|
||||
`agent_t` = @agent_t
|
||||
""";
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
const string query =
|
||||
"INSERT INTO `wp_users_knives` (`user_id`, `knife`) VALUES(@userId, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
|
||||
|
||||
await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing agents to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
await connection.ExecuteAsync(query, new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], newKnife = knife });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing knife to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
|
||||
{
|
||||
if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
|
||||
return;
|
||||
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
|
||||
{
|
||||
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
const string query =
|
||||
"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)
|
||||
{
|
||||
Utility.Log($"Error syncing glove to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo)
|
||||
{
|
||||
var paintId = weaponInfo.Paint;
|
||||
var wear = weaponInfo.Wear;
|
||||
var seed = weaponInfo.Seed;
|
||||
internal async Task SyncAgentToDatabase(PlayerInfo player)
|
||||
{
|
||||
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) return;
|
||||
|
||||
const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
|
||||
const string query = """
|
||||
INSERT INTO `wp_users_agents` (`user_id`, `agent_ct`, `agent_t`)
|
||||
VALUES(@userId, @agent_ct, @agent_t)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`agent_ct` = @agent_ct,
|
||||
`agent_t` = @agent_t
|
||||
""";
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
|
||||
var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex });
|
||||
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)
|
||||
{
|
||||
Utility.Log($"Error syncing agents to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
string query;
|
||||
object parameters;
|
||||
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
|
||||
{
|
||||
if (string.IsNullOrEmpty(player.SteamId.ToString()) ||
|
||||
!WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
|
||||
return;
|
||||
|
||||
if (existingRecordCount > 0)
|
||||
{
|
||||
query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
|
||||
parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed };
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " +
|
||||
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed)";
|
||||
parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed };
|
||||
}
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
|
||||
await connection.ExecuteAsync(query, parameters);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo)
|
||||
{
|
||||
var paintId = weaponInfo.Paint;
|
||||
var wear = weaponInfo.Wear;
|
||||
var seed = weaponInfo.Seed;
|
||||
|
||||
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
|
||||
{
|
||||
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return;
|
||||
const string queryCheckExistence =
|
||||
"SELECT COUNT(*) FROM `wp_users_skins` WHERE `user_id` = @userId AND `weapon` = @weaponDefIndex";
|
||||
|
||||
try
|
||||
{
|
||||
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";
|
||||
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newMusic = music });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing music kit to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence,
|
||||
new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex });
|
||||
|
||||
internal async Task SyncStatTrakToDatabase(PlayerInfo player, ConcurrentDictionary<int,WeaponInfo> weaponInfos)
|
||||
{
|
||||
if (WeaponPaints.WeaponSync == null || weaponInfos.IsEmpty) return;
|
||||
string query;
|
||||
object parameters;
|
||||
|
||||
var statTrakWeapons = weaponInfos
|
||||
.Where(w => w.Value is { StatTrak: true, StatTrakCount: > 0 })
|
||||
.ToDictionary(w => w.Key, w => w.Value.StatTrakCount);
|
||||
if (existingRecordCount > 0)
|
||||
{
|
||||
query =
|
||||
"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
|
||||
{
|
||||
query =
|
||||
"INSERT INTO `wp_users_skins` (`user_id`, `weapon`, `paint`, `wear`, `seed`) " +
|
||||
"VALUES (@userId, @weaponDefIndex, @paintId, @wear, @seed)";
|
||||
parameters = new { userId = WeaponPaints.g_playersDatabaseIndex[player.Slot], weaponDefIndex, paintId, wear, seed };
|
||||
}
|
||||
|
||||
if (statTrakWeapons.Count == 0) return;
|
||||
await connection.ExecuteAsync(query, parameters);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(player.SteamId))
|
||||
return;
|
||||
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
|
||||
{
|
||||
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId.ToString())) 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
await using var connection = await _database.GetConnectionAsync();
|
||||
const string query =
|
||||
"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)
|
||||
{
|
||||
Utility.Log($"Error syncing music kit to database: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
"ChangeSubclass": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 6C 24 ? 56 48 83 EC ? 48 8B EA 48 8B F1 E8 ? ? ? ? 84 C0 0F 84",
|
||||
"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"
|
||||
"windows": "40 57 48 83 EC 20 48 8B F9 41 B0 01",
|
||||
"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": {
|
||||
@@ -20,4 +20,4 @@
|
||||
"linux": "55 48 89 E5 41 56 49 89 F6 41 55 41 89 D5 41 54 49 89 FC 48 83 EC 08"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* Class DataBase
|
||||
*
|
||||
* This class handles database operations using PDO.
|
||||
*/
|
||||
class DataBase {
|
||||
|
||||
/**
|
||||
* @var PDO The PDO instance for database connection.
|
||||
*/
|
||||
private $PDO;
|
||||
|
||||
/**
|
||||
* Constructor method to initialize the database connection.
|
||||
*/
|
||||
public function __construct() {
|
||||
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>";
|
||||
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->execute($bindings);
|
||||
|
||||
// Fetch the results as associative arrays
|
||||
$result = $STH->fetchAll(PDO::FETCH_ASSOC);
|
||||
$result ??= false;
|
||||
return $result;
|
||||
if ($result === false) {
|
||||
$result = array(); // Set $result to an empty array if no results found
|
||||
}
|
||||
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);
|
||||
return $STH->execute($bindings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
78
website/class/header.php
Normal file
78
website/class/header.php
Normal 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']}");
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,99 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* Class UtilsClass
|
||||
*
|
||||
* Provides utility methods for handling skin and weapon data.
|
||||
*/
|
||||
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 = [];
|
||||
$json = json_decode(file_get_contents(__DIR__ . "/../data/skins.json"), true);
|
||||
$skins = array();
|
||||
$jsonFilePath = __DIR__ . "/../data/skins.json";
|
||||
|
||||
foreach ($json as $skin) {
|
||||
$skins[(int) $skin['weapon_defindex']][(int) $skin['paint']] = [
|
||||
'weapon_name' => $skin['weapon_name'],
|
||||
'paint_name' => $skin['paint_name'],
|
||||
'image_url' => $skin['image'],
|
||||
];
|
||||
if (file_exists($jsonFilePath) && is_readable($jsonFilePath)) {
|
||||
$json = json_decode(file_get_contents($jsonFilePath), true);
|
||||
|
||||
foreach ($json as $skin) {
|
||||
$skins[(int) $skin['weapon_defindex']][(int) $skin['paint']] = array(
|
||||
'weapon_name' => $skin['weapon_name'],
|
||||
'paint_name' => $skin['paint_name'],
|
||||
'image_url' => $skin['image'],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Handle file not found or unreadable error
|
||||
// You can throw an exception or log an error message
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
$weapons = [];
|
||||
$temp = self::skinsFromJson();
|
||||
$weapons = array();
|
||||
$skinsData = self::skinsFromJson();
|
||||
|
||||
foreach ($temp as $key => $value) {
|
||||
if (key_exists($key, $weapons))
|
||||
continue;
|
||||
|
||||
$weapons[$key] = [
|
||||
foreach ($skinsData as $key => $value) {
|
||||
$weapons[$key] = array(
|
||||
'weapon_name' => $value[0]['weapon_name'],
|
||||
'paint_name' => $value[0]['paint_name'],
|
||||
'image_url' => $value[0]['image_url'],
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
return $weapons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve knife types from the weapon data array.
|
||||
*
|
||||
* @return array An associative array containing knife types data.
|
||||
*/
|
||||
public static function getKnifeTypes()
|
||||
{
|
||||
$knifes = [];
|
||||
$temp = self::getWeaponsFromArray();
|
||||
$knifes = array();
|
||||
$weaponsData = self::getWeaponsFromArray();
|
||||
|
||||
foreach ($temp as $key => $weapon) {
|
||||
if (
|
||||
!in_array($key, [
|
||||
500,
|
||||
503,
|
||||
505,
|
||||
506,
|
||||
507,
|
||||
508,
|
||||
509,
|
||||
512,
|
||||
514,
|
||||
515,
|
||||
516,
|
||||
517,
|
||||
518,
|
||||
519,
|
||||
520,
|
||||
521,
|
||||
522,
|
||||
523,
|
||||
525,
|
||||
526
|
||||
])
|
||||
)
|
||||
continue;
|
||||
$allowedKnifeKeys = array(
|
||||
500, 503, 505, 506, 507, 508, 509, 512, 514, 515,
|
||||
516, 517, 518, 519, 520, 521, 522, 523, 525
|
||||
);
|
||||
|
||||
$knifes[$key] = [
|
||||
'weapon_name' => $weapon['weapon_name'],
|
||||
'paint_name' => rtrim(explode("|", $weapon['paint_name'])[0]),
|
||||
'image_url' => $weapon['image_url'],
|
||||
];
|
||||
$knifes[0] = [
|
||||
'weapon_name' => "weapon_knife",
|
||||
'paint_name' => "Default knife",
|
||||
'image_url' => "https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/website/img/skins/weapon_knife.png",
|
||||
];
|
||||
foreach ($weaponsData as $key => $weapon) {
|
||||
if (in_array($key, $allowedKnifeKeys)) {
|
||||
$knifes[$key] = array(
|
||||
'weapon_name' => $weapon['weapon_name'],
|
||||
'paint_name' => rtrim(explode("|", $weapon['paint_name'])[0]),
|
||||
'image_url' => $weapon['image_url'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add default knife
|
||||
$knifes[0] = array(
|
||||
'weapon_name' => "weapon_knife",
|
||||
'paint_name' => "Default knife",
|
||||
'image_url' => "https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/website/img/skins/weapon_knife.png",
|
||||
);
|
||||
|
||||
ksort($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) {
|
||||
$selected[$weapon['weapon_defindex']] = [
|
||||
'weapon_paint_id' => $weapon['weapon_paint_id'],
|
||||
'weapon_seed' => $weapon['weapon_seed'],
|
||||
'weapon_wear' => $weapon['weapon_wear'],
|
||||
];
|
||||
$selected[$weapon['weapon']] = array(
|
||||
'weapon_paint_id' => $weapon['paint'],
|
||||
'weapon_seed' => $weapon['seed'],
|
||||
'weapon_wear' => $weapon['wear'],
|
||||
);
|
||||
}
|
||||
|
||||
return $selected;
|
||||
|
||||
386
website/data/agents.json
Normal file
386
website/data/agents.json
Normal 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
440
website/data/gloves.json
Normal 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"
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
@@ -1 +0,0 @@
|
||||
[{"weapon_defindex":0,"paint":0,"image":"","paint_name":"Gloves | Default"}]
|
||||
367
website/data/music.json
Normal file
367
website/data/music.json
Normal 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
Reference in New Issue
Block a user