Compare commits

...

40 Commits

Author SHA1 Message Date
Dawid Bepierszcz
6db3d00893 Update weaponpaints.json 2024-10-04 00:02:40 +02:00
Nereziel
7b12d29227 Merge pull request #299 from originalaidn/main
fixing latest skins size & editing every weapon, knife and glove defa…
2024-10-01 21:48:38 +02:00
AiDN™
abff60a1db fixing latest skins size & editing every weapon, knife and glove default images 2024-09-16 23:11:26 +02:00
Nereziel
edb848b4f9 Merge pull request #298 from originalaidn/main
adding missing skins & missing agent #282
2024-09-11 21:55:17 +02:00
AiDN™
694cc548c8 adding missing skins & missing agent #282 2024-09-11 21:34:57 +02:00
Nereziel
201f723a3c Update README.md 2024-06-21 22:38:18 +02:00
Dawid Bepierszcz
d6384f4ecf Merge pull request #270 from stefanx111/fix-sig
fix wildcard
2024-06-01 12:47:09 +02:00
StefanX
85fc0bd4bc fix wildcard 2024-06-01 13:44:33 +03:00
Dawid Bepierszcz
5c7df833cc Merge pull request #269 from stefanx111/fix-win
win sig mistake
2024-05-31 12:15:23 +02:00
StefanX
5640919b09 win sig mistake 2024-05-31 03:18:17 +03:00
Dawid Bepierszcz
0550ef68f4 Merge pull request #267 from stefanx111/sig-workground
sig workground
2024-05-31 01:08:58 +02:00
Dawid Bepierszcz
c0d42a3d9c Merge branch 'main' into sig-workground 2024-05-31 01:06:58 +02:00
StefanX
5636b401ea sig workground 2024-05-31 00:20:48 +03:00
Dawid Bepierszcz
06cfda21f2 Fix for gameupdate - linux only 2024-05-30 00:38:16 +02:00
Dawid Bepierszcz
771a832ae8 Update weaponpaints.json 2024-05-25 20:58:48 +02:00
Dawid Bepierszcz
323c74b49c Merge pull request #261 from daffyyyy/main
2.5a
2024-05-25 15:32:04 +02:00
Dawid Bepierszcz
ee1dffa06b Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-05-25 15:30:49 +02:00
Dawid Bepierszcz
d90055ad89 2.5a
- Minor changes
- New gloves applied only on spawn (probably new cs2 update issue)
2024-05-25 15:30:47 +02:00
Dawid Bepierszcz
48854c4eaf Merge pull request #253 from daffyyyy/main
2.4e
2024-04-28 02:20:36 +02:00
Dawid Bepierszcz
c06f7ae3be Merge branch 'Nereziel:main' into main 2024-04-28 02:18:14 +02:00
Dawid Bepierszcz
29461e9de2 2.4e
- Minor changes
2024-04-28 02:17:24 +02:00
Dawid Bepierszcz
74ec584d9a Merge pull request #241 from daffyyyy/main
2.4d
2024-04-26 10:07:05 +02:00
Dawid Bepierszcz
ec0d4f4d5a 2.4d
- Updated for latest css
2024-04-26 10:02:32 +02:00
Dawid Bepierszcz
a8ba645292 Merge branch 'Nereziel:main' into main 2024-04-14 22:10:17 +02:00
Dawid Bepierszcz
e04dd312e8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-14 22:09:55 +02:00
Dawid Bepierszcz
702dea9450 2.4c
- Disable hooking giveitemfunc on windows (counterstrikesharp issue) (fix)
2024-04-14 22:09:53 +02:00
Dawid Bepierszcz
c594cd534e Merge pull request #237 from daffyyyy/main
2.4b
2024-04-08 21:31:43 +02:00
Dawid Bepierszcz
5aaf0e6f62 Merge branch 'Nereziel:main' into main 2024-04-08 21:30:46 +02:00
Dawid Bepierszcz
942e776688 2.4b
- Nothing big ;P
2024-04-08 21:30:22 +02:00
Dawid Bepierszcz
36046fee2d Merge pull request #231 from daffyyyy/main
2.4a
2024-04-03 01:35:07 +02:00
Dawid Bepierszcz
d6de0ce6c8 Merge branch 'Nereziel:main' into main 2024-04-03 01:33:52 +02:00
Dawid Bepierszcz
d2c19d8af8 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-04-03 01:32:27 +02:00
Dawid Bepierszcz
0f6d334621 2.4a
- .NET8
- Mysql queries optimization
- CounterStrikeSharp updated
2024-04-03 01:32:24 +02:00
Dawid Bepierszcz
f99c9b2767 Merge pull request #226 from daffyyyy/main
2.3c
2024-03-27 23:20:43 +01:00
Dawid Bepierszcz
6a2d28c303 Merge branch 'Nereziel:main' into main 2024-03-27 23:19:42 +01:00
Dawid Bepierszcz
27a2ae5be9 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-03-27 23:19:26 +01:00
Dawid Bepierszcz
0af9177f07 2.3c
- Small change for mysql performance
2024-03-27 23:19:24 +01:00
Dawid Bepierszcz
cfb49e1498 Merge pull request #222 from daffyyyy/main
2.3b
2024-03-21 01:13:14 +01:00
Dawid Bepierszcz
bbdb4b82ce Merge branch 'Nereziel:main' into main 2024-03-21 01:12:08 +01:00
Dawid Bepierszcz
bfb7defcaa 2.3b
- Fixed agent team bug
- Minor changes
2024-03-21 01:09:45 +01:00
82 changed files with 790 additions and 838 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,4 +1,5 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Menu;
using Newtonsoft.Json.Linq;
@@ -14,7 +15,7 @@ namespace WeaponPaints
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,
@@ -26,35 +27,16 @@ namespace WeaponPaints
try
{
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out var cooldownEndTime) ||
player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
if (weaponSync != null)
{
if (Config.Additional.SkinEnabled)
{
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled)
{
_ = Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled)
{
_ = Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
}
if (Config.Additional.AgentEnabled)
{
_ = Task.Run(async () => await weaponSync.GetAgentFromDatabase(playerInfo));
}
if (Config.Additional.MusicEnabled)
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
_ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
RefreshGloves(player);
GivePlayerGloves(player);
RefreshWeapons(player);
}
@@ -104,11 +86,11 @@ namespace WeaponPaints
player!.Print(Localizer["wp_info_music"]);
}
if (Config.Additional.KnifeEnabled)
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
{
player!.Print(Localizer["wp_info_knife"]);
}
if (!Config.Additional.KnifeEnabled) return;
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
{
player!.Print(Localizer["wp_info_knife"]);
}
}
private void RegisterCommands()
@@ -138,7 +120,7 @@ namespace WeaponPaints
{
if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return;
var knivesOnly = weaponList
var knivesOnly = WeaponList
.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet"))
.ToDictionary(pair => pair.Key, pair => pair.Value);
@@ -149,36 +131,34 @@ namespace WeaponPaints
var knifeName = option.Text;
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key;
if (!string.IsNullOrEmpty(knifeKey))
if (string.IsNullOrEmpty(knifeKey)) return;
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"]))
{
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"]))
{
player!.Print(Localizer["wp_knife_menu_select", knifeName]);
}
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled)
{
player!.Print(Localizer["wp_knife_menu_kill"]);
}
PlayerInfo 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_playersKnife[player.Slot] = knifeKey;
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
RefreshWeapons(player);
if (weaponSync != null)
_ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, knifeKey));
player!.Print(Localizer["wp_knife_menu_select", knifeName]);
}
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled)
{
player!.Print(Localizer["wp_knife_menu_kill"]);
}
PlayerInfo 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_playersKnife[player.Slot] = knifeKey;
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
RefreshWeapons(player);
if (weaponSync != null)
_ = Task.Run(async () => await weaponSync.SyncKnifeToDatabase(playerInfo, knifeKey));
};
foreach (var knifePair in knivesOnly)
{
@@ -190,8 +170,8 @@ namespace WeaponPaints
if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && 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);
giveItemMenu.PostSelectAction = PostSelectAction.Close;
@@ -207,7 +187,7 @@ namespace WeaponPaints
private void SetupSkinsMenu()
{
var classNamesByWeapon = weaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var classNamesByWeapon = WeaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = new ChatMenu(Localizer["wp_skin_menu_weapon_title"]);
// Function to handle skin selection for a specific weapon
@@ -215,117 +195,110 @@ namespace WeaponPaints
{
if (!Utility.IsPlayerValid(player)) return;
string selectedWeapon = option.Text;
if (classNamesByWeapon.TryGetValue(selectedWeapon, out string? selectedWeaponClassname))
{
if (selectedWeaponClassname == null) return;
var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin != null &&
var selectedWeapon = option.Text;
if (!classNamesByWeapon.TryGetValue(selectedWeapon, out var selectedWeaponClassname)) return;
var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin.TryGetValue("weapon_name", out var weaponName) &&
weaponName?.ToString() == selectedWeaponClassname
)?.ToList();
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
// Function to handle skin selection for the chosen weapon
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
// Function to handle skin selection for the chosen weapon
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
{
if (!Utility.IsPlayerValid(p)) return;
var steamId = p.SteamID.ToString();
var firstSkin = skinsList?.FirstOrDefault(skin =>
{
if (!Utility.IsPlayerValid(p)) return;
string steamId = p.SteamID.ToString();
var firstSkin = skinsList?.FirstOrDefault(skin =>
if (skin.TryGetValue("weapon_name", out var weaponName))
{
if (skin != null && skin.TryGetValue("weapon_name", out var weaponName))
{
return weaponName?.ToString() == selectedWeaponClassname;
}
return false;
});
string selectedSkin = opt.Text;
string selectedPaintID = selectedSkin.Substring(selectedSkin.LastIndexOf('(') + 1).Trim(')');
if (firstSkin != null &&
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) &&
weaponDefIndexObj != null &&
int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) &&
int.TryParse(selectedPaintID, out var paintID))
{
if (Config.Additional.ShowSkinImage && skinsList != null)
{
var foundSkin = skinsList.FirstOrDefault(skin =>
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
((int?)skin?["paint"] ?? 0) == paintID &&
skin?["image"] != null
);
string image = foundSkin?["image"]?.ToString() ?? "";
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].ContainsKey(weaponDefIndex))
{
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = new WeaponInfo();
}
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Paint = paintID;
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.01f;
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Seed = 0;
PlayerInfo playerInfo = new PlayerInfo
{
UserId = p.UserId,
Slot = p.Slot,
Index = (int)p.Index,
SteamId = p.SteamID.ToString(),
Name = p.PlayerName,
IpAddress = p.IpAddress?.Split(":")[0]
};
if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && weaponSync != null)
{
RefreshWeapons(player);
try
{
_ = Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
}
catch (Exception ex)
{
Utility.Log($"Error syncing weapon paints: {ex.Message}");
}
}
return weaponName?.ToString() == selectedWeaponClassname;
}
};
return false;
});
// Add skin options to the submenu for the selected weapon
if (skinsForSelectedWeapon != null)
var selectedSkin = opt.Text;
var selectedPaintId = selectedSkin[(selectedSkin.LastIndexOf('(') + 1)..].Trim(')');
if (firstSkin == null ||
!firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) ||
!int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) ||
!int.TryParse(selectedPaintId, out var paintId)) return;
{
foreach (var skin in skinsForSelectedWeapon.Where(s => s != null))
if (Config.Additional.ShowSkinImage && skinsList != null)
{
if (skin.TryGetValue("paint_name", out var paintNameObj) && skin.TryGetValue("paint", out var paintObj))
{
var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString();
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);
}
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{
skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
}
}
p.Print(Localizer["wp_skin_menu_select", selectedSkin]);
if (!gPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out var value))
{
value = new WeaponInfo();
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
}
value.Paint = paintId;
value.Wear = 0.01f;
value.Seed = 0;
PlayerInfo playerInfo = new PlayerInfo
{
UserId = p.UserId,
Slot = p.Slot,
Index = (int)p.Index,
SteamId = p.SteamID.ToString(),
Name = p.PlayerName,
IpAddress = p.IpAddress?.Split(":")[0]
};
if (!g_bCommandsAllowed || (LifeState_t)p.LifeState != LifeState_t.LIFE_ALIVE ||
weaponSync == null) return;
RefreshWeapons(player);
try
{
_ = Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
}
catch (Exception ex)
{
Utility.Log($"Error syncing weapon paints: {ex.Message}");
}
}
};
// Add skin options to the submenu for the selected weapon
if (skinsForSelectedWeapon != null)
{
foreach (var skin in skinsForSelectedWeapon)
{
if (!skin.TryGetValue("paint_name", out var paintNameObj) ||
!skin.TryGetValue("paint", out var paintObj)) continue;
var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString();
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{
skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
}
}
if (player != null && Utility.IsPlayerValid(player))
MenuManager.OpenChatMenu(player, skinSubMenu);
}
if (player != null && Utility.IsPlayerValid(player))
MenuManager.OpenChatMenu(player, skinSubMenu);
};
// Add weapon options to the weapon selection menu
foreach (var weaponClass in weaponList.Keys)
foreach (var weaponName in WeaponList.Keys.Select(weaponClass => WeaponList[weaponClass]))
{
string weaponName = weaponList[weaponClass];
weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection);
}
// Command to open the weapon selection menu for players
@@ -335,8 +308,8 @@ namespace WeaponPaints
if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && 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);
MenuManager.OpenChatMenu(player, weaponSelectionMenu);
@@ -351,96 +324,90 @@ namespace WeaponPaints
private void SetupGlovesMenu()
{
var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]);
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"])
{
PostSelectAction = PostSelectAction.Close
};
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text;
var selectedPaintName = option.Text;
var selectedGlove = glovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName);
if (selectedGlove != null)
var image = selectedGlove?["image"]?.ToString() ?? "";
if (selectedGlove == null ||
!selectedGlove.ContainsKey("weapon_defindex") ||
!selectedGlove.ContainsKey("paint") ||
!int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out var weaponDefindex) ||
!int.TryParse(selectedGlove["paint"]?.ToString(), out var paint)) return;
if (Config.Additional.ShowSkinImage)
{
if (
selectedGlove != null &&
selectedGlove.ContainsKey("weapon_defindex") &&
selectedGlove.ContainsKey("paint") &&
int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out int weaponDefindex) &&
int.TryParse(selectedGlove["paint"]?.ToString(), out int paint)
)
{
if (Config.Additional.ShowSkinImage)
{
string image = selectedGlove["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);
}
PlayerInfo 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]
};
if (paint != 0)
{
g_playersGlove[player.Slot] = (ushort)weaponDefindex;
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex))
{
WeaponInfo weaponInfo = new();
weaponInfo.Paint = paint;
gPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo;
}
}
else
{
g_playersGlove.TryRemove(player.Slot, out _);
}
if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"]))
{
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
}
if (weaponSync != null)
{
_ = Task.Run(async () =>
{
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out WeaponInfo? value))
{
value = new WeaponInfo();
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value;
}
value.Paint = paint;
value.Wear = 0.00f;
value.Seed = 0;
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
});
}
RefreshGloves(player);
}
PlayerInfo 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]
};
if (paint != 0)
{
g_playersGlove[player.Slot] = (ushort)weaponDefindex;
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefindex))
{
WeaponInfo weaponInfo = new()
{
Paint = paint
};
gPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo;
}
}
else
{
g_playersGlove.TryRemove(player.Slot, out _);
}
if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"]))
{
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
}
if (weaponSync == null) return;
_ = Task.Run(async () =>
{
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out var value))
{
value = new WeaponInfo();
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value;
}
value.Paint = paint;
value.Wear = 0.00f;
value.Seed = 0;
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
});
AddTimer(0.1f, () => GivePlayerGloves(player));
AddTimer(0.15f, () => GivePlayerGloves(player));
};
// Add weapon options to the weapon selection menu
foreach (var gloveObject in glovesList)
foreach (var paintName in glovesList.Select(gloveObject => gloveObject["paint_name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{
string paintName = gloveObject["paint_name"]?.ToString() ?? "";
if (paintName.Length > 0)
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection);
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection);
}
// Command to open the weapon selection menu for players
@@ -450,8 +417,8 @@ namespace WeaponPaints
if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && 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);
MenuManager.OpenChatMenu(player, glovesSelectionMenu);
@@ -470,61 +437,62 @@ namespace WeaponPaints
{
if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text;
var selectedPaintName = option.Text;
var selectedAgent = agentsList.FirstOrDefault(g =>
g.ContainsKey("agent_name") &&
g["agent_name"] != null && g["agent_name"]!.ToString() == selectedPaintName &&
g["team"] != null && (int)(g["team"]!) == player.TeamNum);
var selectedAgent = agentsList.FirstOrDefault(g => g.ContainsKey("agent_name") && g["agent_name"]?.ToString() == selectedPaintName);
if (selectedAgent != null)
if (selectedAgent == null) return;
if (
selectedAgent.ContainsKey("model")
)
{
if (
selectedAgent != null &&
selectedAgent.ContainsKey("model")
)
PlayerInfo playerInfo = new PlayerInfo
{
PlayerInfo 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]
};
if (Config.Additional.ShowSkinImage)
{
string image = selectedAgent["image"]?.ToString() ?? "";
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]);
}
if (player.TeamNum == 3)
{
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
{
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)
{
_ = Task.Run(async () =>
{
await weaponSync.SyncAgentToDatabase(playerInfo);
});
}
UserId = player.UserId,
Slot = player.Slot,
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
}
if (Config.Additional.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);
}
if (!string.IsNullOrEmpty(Localizer["wp_agent_menu_select"]))
{
player!.Print(Localizer["wp_agent_menu_select", selectedPaintName]);
}
if (player.TeamNum == 3)
{
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
{
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)
{
_ = Task.Run(async () =>
{
await weaponSync.SyncAgentToDatabase(playerInfo);
});
}
};
};
// Command to open the weapon selection menu for players
@@ -534,15 +502,17 @@ namespace WeaponPaints
if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && 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 = new ChatMenu(Localizer["wp_agent_menu_title"]);
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
var agentsSelectionMenu = new ChatMenu(Localizer["wp_agent_menu_title"])
{
PostSelectAction = PostSelectAction.Close
};
var filteredAgents = agentsList.Where(agentObject =>
{
if (agentObject["team"]?.Value<int>() is int teamNum)
if (agentObject["team"]?.Value<int>() is { } teamNum)
{
return teamNum == player.TeamNum;
}
@@ -556,7 +526,7 @@ namespace WeaponPaints
foreach (var agentObject in filteredAgents)
{
string paintName = agentObject["agent_name"]?.ToString() ?? "";
var paintName = agentObject["agent_name"]?.ToString() ?? "";
if (paintName.Length > 0)
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
@@ -575,66 +545,63 @@ namespace WeaponPaints
private void SetupMusicMenu()
{
var musicSelectionMenu = new ChatMenu(Localizer["wp_music_menu_title"]);
musicSelectionMenu.PostSelectAction = PostSelectAction.Close;
var musicSelectionMenu = new ChatMenu(Localizer["wp_music_menu_title"])
{
PostSelectAction = PostSelectAction.Close
};
var handleMusicSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{
if (!Utility.IsPlayerValid(player) || player is null) return;
string selectedPaintName = option.Text;
var selectedPaintName = option.Text;
var selectedMusic = musicList.FirstOrDefault(g => g.ContainsKey("name") && g["name"]?.ToString() == selectedPaintName);
if (selectedMusic != null)
{
if (
selectedMusic != null &&
selectedMusic.ContainsKey("id") &&
selectedMusic.ContainsKey("name") &&
int.TryParse(selectedMusic["id"]?.ToString(), out int paint)
)
if (!selectedMusic.ContainsKey("id") ||
!selectedMusic.ContainsKey("name") ||
!int.TryParse(selectedMusic["id"]?.ToString(), out var paint)) return;
var image = selectedMusic["image"]?.ToString() ?? "";
if (Config.Additional.ShowSkinImage)
{
if (Config.Additional.ShowSkinImage)
{
string image = selectedMusic["image"]?.ToString() ?? "";
PlayerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
PlayerInfo 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]
};
if (paint != 0)
{
g_playersMusic[player.Slot] = (ushort)paint;
}
else
{
g_playersMusic[player.Slot] = 0;
}
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{
player!.Print(Localizer["wp_music_menu_select", selectedPaintName]);
}
if (weaponSync != null)
{
_ = Task.Run(async () =>
{
await weaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
});
}
//RefreshGloves(player);
PlayerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
PlayerInfo 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]
};
if (paint != 0)
{
g_playersMusic[player.Slot] = (ushort)paint;
}
else
{
g_playersMusic[player.Slot] = 0;
}
if (!string.IsNullOrEmpty(Localizer["wp_music_menu_select"]))
{
player!.Print(Localizer["wp_music_menu_select", selectedPaintName]);
}
if (weaponSync != null)
{
_ = Task.Run(async () =>
{
await weaponSync.SyncMusicToDatabase(playerInfo, (ushort)paint);
});
}
//RefreshGloves(player);
}
else
{
@@ -667,12 +634,9 @@ namespace WeaponPaints
musicSelectionMenu.AddMenuOption(Localizer["None"], handleMusicSelection);
// Add weapon options to the weapon selection menu
foreach (var musicObject in musicList)
foreach (var paintName in musicList.Select(musicObject => musicObject["name"]?.ToString() ?? "").Where(paintName => paintName.Length > 0))
{
string paintName = musicObject["name"]?.ToString() ?? "";
if (paintName.Length > 0)
musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection);
musicSelectionMenu.AddMenuOption(paintName, handleMusicSelection);
}
// Command to open the weapon selection menu for players
@@ -682,8 +646,8 @@ namespace WeaponPaints
if (player == null || player.UserId == null) return;
if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
player != null && 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);
MenuManager.OpenChatMenu(player, musicSelectionMenu);

View File

@@ -89,6 +89,6 @@ namespace WeaponPaints
public string Website { get; set; } = "example.com/skins";
[JsonPropertyName("Additional")]
public Additional Additional { get; set; } = new Additional();
public Additional Additional { get; set; } = new();
}
}

View File

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

193
Events.cs
View File

@@ -2,6 +2,9 @@
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
{
@@ -12,7 +15,7 @@ namespace WeaponPaints
{
CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot || player.IsHLTV || player.SteamID.ToString().Length != 17 ||
if (player is null || !player.IsValid || player.IsBot ||
weaponSync == null || _database == null) return HookResult.Continue;
PlayerInfo playerInfo = new PlayerInfo
@@ -27,6 +30,8 @@ namespace WeaponPaints
try
{
_ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
/*
if (Config.Additional.SkinEnabled)
{
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
@@ -47,8 +52,9 @@ namespace WeaponPaints
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
*/
}
catch (Exception)
catch
{
}
@@ -58,20 +64,9 @@ namespace WeaponPaints
[GameEventHandler]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
{
CCSPlayerController player = @event.Userid;
CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || player.IsBot ||
player.IsHLTV || player.SteamID.ToString().Length != 17) return HookResult.Continue;
PlayerInfo 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]
};
if (player is null || !player.IsValid || player.IsBot) return HookResult.Continue;
if (Config.Additional.SkinEnabled)
{
@@ -98,101 +93,10 @@ namespace WeaponPaints
return HookResult.Continue;
}
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (!Config.Additional.SkinEnabled) return;
if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return;
if (!gPlayerWeaponsInfo.ContainsKey(player.Slot)) return;
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
{
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
weapon.AttributeManager.Item.EntityQuality = 3;
}
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0;
if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
{
// Random skins
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
weapon.FallbackSeed = 0;
weapon.FallbackWear = 0.000001f;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
return;
}
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex) || gPlayerWeaponsInfo[player.Slot][weaponDefIndex].Paint == 0) return;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][weaponDefIndex];
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.FallbackPaintKit = weaponInfo.Paint;
weapon.FallbackSeed = weaponInfo.Seed;
weapon.FallbackWear = weaponInfo.Wear;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
}
private void OnMapStart(string mapName)
{
if (!Config.Additional.KnifeEnabled && !Config.Additional.SkinEnabled && !Config.Additional.GloveEnabled) return;
if (Config.Additional is { KnifeEnabled: false, SkinEnabled: false, GloveEnabled: false }) return;
if (_database != null)
weaponSync = new WeaponSynchronization(_database, Config);
@@ -202,7 +106,7 @@ namespace WeaponPaints
{
CCSPlayerController? player = @event.Userid;
if (player is null || !player.IsValid || !Config.Additional.KnifeEnabled && !Config.Additional.GloveEnabled)
if (player is null || !player.IsValid || Config.Additional is { KnifeEnabled: false, GloveEnabled: false })
return HookResult.Continue;
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
@@ -214,10 +118,7 @@ namespace WeaponPaints
GivePlayerMusicKit(player);
GivePlayerAgent(player);
Server.NextFrame(() =>
{
RefreshGloves(player);
});
GivePlayerGloves(player);
return HookResult.Continue;
}
@@ -231,31 +132,27 @@ namespace WeaponPaints
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
{
/*
NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0");
*/
g_bCommandsAllowed = true;
return HookResult.Continue;
}
/*
public HookResult OnGiveNamedItemPost(DynamicHook hook)
{
var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
var weapon = hook.GetReturn<CBasePlayerWeapon>(0);
if (!weapon.DesignerName.Contains("weapon"))
return HookResult.Continue;
try
{
var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
var weapon = hook.GetReturn<CBasePlayerWeapon>();
if (!weapon.DesignerName.Contains("weapon"))
return HookResult.Continue;
var player = GetPlayerFromItemServices(itemServices);
if (player != null)
GivePlayerWeaponSkin(player, weapon);
var player = GetPlayerFromItemServices(itemServices);
if (player != null)
GivePlayerWeaponSkin(player, weapon);
}
catch { }
return HookResult.Continue;
}
*/
public void OnEntityCreated(CEntityInstance entity)
{
@@ -266,7 +163,7 @@ namespace WeaponPaints
Server.NextFrame(() =>
{
var weapon = new CBasePlayerWeapon(entity.Handle);
if (weapon == null || !weapon.IsValid || weapon.OwnerEntity.Value == null) return;
if (!weapon.IsValid) return;
try
{
@@ -279,7 +176,7 @@ namespace WeaponPaints
if (_steamid != null && _steamid.IsValid())
{
player = Utilities.GetPlayers().Where(p => p is not null && p.IsValid && p.SteamID == _steamid.SteamId64).FirstOrDefault();
player = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == _steamid.SteamId64);
if (player == null)
player = Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow);
@@ -291,7 +188,7 @@ namespace WeaponPaints
}
if (string.IsNullOrEmpty(player?.PlayerName)) return;
if (player is null || !Utility.IsPlayerValid(player)) return;
if (!Utility.IsPlayerValid(player)) return;
GivePlayerWeaponSkin(player, weapon);
}
@@ -305,30 +202,50 @@ namespace WeaponPaints
private void OnTick()
{
if (!Config.Additional.ShowSkinImage) return;
foreach (var player in Utilities.GetPlayers().Where(p =>
p is not null && p.IsValid && p.PlayerPawn != null && p.PlayerPawn.IsValid &&
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && p.SteamID.ToString().Length == 17
&& !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected
p is { IsValid: true, PlayerPawn.IsValid: true } &&
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE
&& !p.IsBot && p is { Connected: PlayerConnectedState.PlayerConnected }
)
)
{
if (Config.Additional.ShowSkinImage && PlayerWeaponImage.TryGetValue(player.Slot, out string? value) && !string.IsNullOrEmpty(value))
if (PlayerWeaponImage.TryGetValue(player.Slot, out var value) && !string.IsNullOrEmpty(value))
{
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", value));
}
}
}
[GameEventHandler]
public HookResult OnItemPickup(EventItemPickup @event, GameEventInfo _)
{
if (!IsWindows) return HookResult.Continue;
var player = @event.Userid;
if (player != null && player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, PawnIsAlive: true, PlayerPawn.IsValid: true })
{
GiveOnItemPickup(player);
}
return HookResult.Continue;
}
private void RegisterListeners()
{
RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre);
RegisterEventHandler<EventRoundStart>(OnRoundStart);
RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated);
RegisterListener<Listeners.OnTick>(OnTick);
//VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
if (Config.Additional.ShowSkinImage)
RegisterListener<Listeners.OnTick>(OnTick);
if (!IsWindows)
VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
}
}
}

View File

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

View File

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

View File

@@ -71,7 +71,7 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
</details>
## Web install
- Requires PHP >= 7.4 ***(Tested on php ver **`8.2.3`** and nginx webserver)***
- Requires PHP >= 7.4 with curl and pdo_mysql ***(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)

View File

@@ -1,11 +1,9 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using CounterStrikeSharp.API.Core.Translations;
using Dapper;
using Microsoft.Extensions.Logging;
using MySqlConnector;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Reflection;
namespace WeaponPaints
{
@@ -13,22 +11,6 @@ namespace WeaponPaints
{
internal static WeaponPaintsConfig? Config { get; set; }
internal static string BuildDatabaseConnectionString()
{
if (Config == null) return string.Empty;
var builder = new MySqlConnectionStringBuilder
{
Server = Config.DatabaseHost,
UserID = Config.DatabaseUser,
Password = Config.DatabasePassword,
Database = Config.DatabaseName,
Port = (uint)Config.DatabasePort,
Pooling = true
};
return builder.ConnectionString;
}
internal static async Task CheckDatabaseTables()
{
if (WeaponPaints._database is null) return;
@@ -41,37 +23,45 @@ namespace WeaponPaints
try
{
string[] createTableQueries = new[]
{
@"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
) ENGINE=InnoDB",
@"CREATE TABLE IF NOT EXISTS `wp_player_knife` (
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
) 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_gloves` (
`steamid` varchar(18) NOT NULL,
`weapon_defindex` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_agents` (
`steamid` varchar(18) NOT NULL,
`agent_ct` varchar(64) DEFAULT NULL,
`agent_t` varchar(64) DEFAULT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
"""
CREATE TABLE IF NOT EXISTS `wp_player_music` (
`steamid` varchar(64) NOT NULL,
`music_id` int(11) NOT NULL,
UNIQUE (`steamid`)
) ENGINE=InnoDB
""",
];
foreach (var query in createTableQueries)
{
@@ -96,62 +86,62 @@ namespace WeaponPaints
{
if (player is null || WeaponPaints.weaponSync is null) return false;
return (player.IsValid && !player.IsBot && !player.IsHLTV && player.UserId.HasValue);
return player is { IsValid: true, IsBot: false, IsHLTV: false, UserId: not null };
}
internal static void LoadSkinsFromFile(string filePath)
internal static void LoadSkinsFromFile(string filePath, ILogger logger)
{
var json = File.ReadAllText(filePath);
try
{
string json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.skinsList = deserializedSkins ?? new List<JObject>();
WeaponPaints.skinsList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
throw;
logger?.LogError("Not found \"skins.json\" file");
}
}
internal static void LoadGlovesFromFile(string filePath)
internal static void LoadGlovesFromFile(string filePath, ILogger logger)
{
try
{
string json = File.ReadAllText(filePath);
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.glovesList = deserializedSkins ?? new List<JObject>();
WeaponPaints.glovesList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
throw;
logger?.LogError("Not found \"gloves.json\" file");
}
}
internal static void LoadAgentsFromFile(string filePath)
internal static void LoadAgentsFromFile(string filePath, ILogger logger)
{
try
{
string json = File.ReadAllText(filePath);
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.agentsList = deserializedSkins ?? new List<JObject>();
WeaponPaints.agentsList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
throw;
logger?.LogError("Not found \"agents.json\" file");
}
}
internal static void LoadMusicFromFile(string filePath)
internal static void LoadMusicFromFile(string filePath, ILogger logger)
{
try
{
string json = File.ReadAllText(filePath);
var json = File.ReadAllText(filePath);
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
WeaponPaints.musicList = deserializedSkins ?? new List<JObject>();
WeaponPaints.musicList = deserializedSkins ?? [];
}
catch (FileNotFoundException)
{
throw;
logger?.LogError("Not found \"music.json\" file");
}
}
@@ -165,69 +155,50 @@ namespace WeaponPaints
internal static string ReplaceTags(string message)
{
if (message.Contains('{'))
{
string modifiedValue = message;
if (Config != null)
{
modifiedValue = modifiedValue.Replace("{WEBSITE}", Config.Website);
}
foreach (FieldInfo field in typeof(ChatColors).GetFields())
{
string pattern = $"{{{field.Name}}}";
if (message.Contains(pattern, StringComparison.OrdinalIgnoreCase))
{
modifiedValue = modifiedValue.Replace(pattern, field.GetValue(null)!.ToString(), StringComparison.OrdinalIgnoreCase);
}
}
return modifiedValue;
}
return message;
return message.ReplaceColorTags();
}
internal static async Task CheckVersion(string version, ILogger logger)
{
using (HttpClient client = new HttpClient())
using HttpClient client = new();
try
{
try
var response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
HttpResponseMessage response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
var remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
remoteVersion = remoteVersion.Trim();
if (response.IsSuccessStatusCode)
var comparisonResult = string.CompareOrdinal(version, remoteVersion);
switch (comparisonResult)
{
string remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
remoteVersion = remoteVersion.Trim();
int comparisonResult = string.Compare(version, remoteVersion);
if (comparisonResult < 0)
{
case < 0:
logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints");
}
else if (comparisonResult > 0)
{
break;
case > 0:
logger.LogInformation("Probably dev version detected");
}
else
{
break;
default:
logger.LogInformation("Plugin is up to date");
}
}
else
{
logger.LogWarning("Failed to check version");
break;
}
}
catch (HttpRequestException ex)
else
{
logger.LogError(ex, "Failed to connect to the version server.");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while checking version.");
logger.LogWarning("Failed to check version");
}
}
catch (HttpRequestException ex)
{
logger.LogError(ex, "Failed to connect to the version server.");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while checking version.");
}
}
internal static void ShowAd(string moduleVersion)

View File

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

View File

@@ -11,21 +11,102 @@ namespace WeaponPaints
{
public partial class WeaponPaints
{
internal static void GiveKnifeToPlayer(CCSPlayerController? player)
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (!Config.Additional.SkinEnabled) return;
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
{
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
weapon.AttributeManager.Item.EntityQuality = 3;
}
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.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";
//string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
player.GiveNamedItem(CsItem.Knife);
}
internal static bool PlayerHasKnife(CCSPlayerController? player)
private static bool PlayerHasKnife(CCSPlayerController? player)
{
if (!_config.Additional.KnifeEnabled) return false;
if (player == null || !player.IsValid || player.PlayerPawn == null || !player.PlayerPawn.IsValid)
if (player == null || !player.IsValid || !player.PlayerPawn.IsValid)
{
return false;
}
@@ -37,18 +118,16 @@ namespace WeaponPaints
if (weapons == null) return false;
foreach (var weapon in weapons)
{
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid)
if (!weapon.IsValid || weapon.Value == null || !weapon.Value.IsValid) continue;
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
if (weapon.Value.DesignerName.Contains("knife") || weapon.Value.DesignerName.Contains("bayonet"))
{
return true;
}
return true;
}
}
return false;
}
internal void RefreshWeapons(CCSPlayerController? player)
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)
@@ -58,55 +137,52 @@ namespace WeaponPaints
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons == null || weapons.Count == 0)
if (weapons.Count == 0)
return;
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator)
if (player.Team is CsTeam.None or CsTeam.Spectator)
return;
int playerTeam = player.TeamNum;
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>();
Dictionary<string, List<(int, int)>> weaponsWithAmmo = [];
foreach (var weapon in weapons)
{
if (weapon == null || !weapon.IsValid || weapon.Value == null ||
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 == null) continue;
if (!weapon.Value.OwnerEntity.IsValid) continue;
if (gun == null) continue;
if (gun.Entity == null) continue;
if (!gun.IsValid) continue;
if (!gun.VisibleinPVS) continue;
try
{
string? weaponByDefindex = null;
CCSWeaponBaseVData? 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 weaponByDefindex))
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.ContainsKey(weaponByDefindex))
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
{
weaponsWithAmmo.Add(weaponByDefindex, new List<(int, int)>());
value = [];
weaponsWithAmmo.Add(weaponByDefindex, value);
}
weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
value.Add((clip1, reservedAmmo));
if (gun == null || gun.VData == null) return;
if (gun.VData == null) return;
weapon.Value.Remove();
}
@@ -124,12 +200,12 @@ namespace WeaponPaints
player.ExecuteClientCommand("slot 3");
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon;
if (weapon is null || !weapon.IsValid || weapon.Value == null) return;
if (!weapon.IsValid || weapon.Value == null) return;
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>();
CCSWeaponBaseGun gun;
AddTimer(0.3f, () =>
{
@@ -143,7 +219,7 @@ namespace WeaponPaints
{
if (player.TeamNum != playerTeam) return;
if (gun == null || !gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return;
if (!gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return;
gun.Remove();
});
@@ -170,11 +246,8 @@ namespace WeaponPaints
{
try
{
if (newWeapon != null)
{
newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2;
}
newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2;
}
catch (Exception ex)
{
@@ -186,15 +259,15 @@ namespace WeaponPaints
}, TimerFlags.STOP_ON_MAPCHANGE);
}
private static void RefreshGloves(CCSPlayerController player)
private void GivePlayerGloves(CCSPlayerController player)
{
if (!Utility.IsPlayerValid(player) || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) return;
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
if (pawn == null || !pawn.IsValid)
return;
string model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
var model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
if (!string.IsNullOrEmpty(model))
{
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
@@ -203,35 +276,30 @@ namespace WeaponPaints
Instance.AddTimer(0.06f, () =>
{
CEconItemView item = pawn.EconGloves;
try
{
if (player == null || !player.IsValid)
if (!player.IsValid)
return;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
if (!player.PawnIsAlive)
return;
if (g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) && gloveInfo != 0)
{
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
return;
if (!g_playersGlove.TryGetValue(player.Slot, out var gloveInfo) || gloveInfo == 0) return;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
CEconItemView item = pawn.EconGloves;
item.ItemDefinitionIndex = gloveInfo;
item.ItemIDLow = 16384 & 0xFFFFFFFF;
item.ItemIDHigh = 16384;
item.ItemDefinitionIndex = gloveInfo;
item.ItemIDLow = 16384 & 0xFFFFFFFF;
item.ItemIDHigh = 16384;
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weaponInfo.Paint);
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture seed", weaponInfo.Seed);
CAttributeList_SetOrAddAttributeValueByName.Invoke(item.NetworkedDynamicAttributes.Handle, "set item texture wear", weaponInfo.Wear);
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;
item.Initialized = true;
CBaseModelEntity_SetBodygroup.Invoke(pawn, "default_gloves", 1);
}
SetBodygroup(pawn.Handle, "default_gloves", 1);
}
catch (Exception) { }
}, TimerFlags.STOP_ON_MAPCHANGE);
@@ -239,7 +307,7 @@ namespace WeaponPaints
private static int GetRandomPaint(int defindex)
{
if (skinsList == null || skinsList.Count == 0)
if (skinsList.Count == 0)
return 0;
Random rnd = new Random();
@@ -252,55 +320,46 @@ namespace WeaponPaints
var randomWeapon = filteredWeapons[rnd.Next(filteredWeapons.Count)];
if (int.TryParse(randomWeapon["paint"]?.ToString(), out int paintValue))
return paintValue;
return 0;
return int.TryParse(randomWeapon["paint"]?.ToString(), out var paintValue) ? paintValue : 0;
}
public static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
private static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
{
var SubclassChangeFunc = VirtualFunction.Create<nint, string, int>(
var subclassChangeFunc = VirtualFunction.Create<nint, string, int>(
GameData.GetSignature("ChangeSubclass")
);
SubclassChangeFunc(weapon.Handle, itemD.ToString());
subclassChangeFunc(weapon.Handle, itemD.ToString());
}
public static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
private static void UpdateWeaponMeshGroupMask(CBaseEntity weapon, bool isLegacy = false)
{
if (weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{
var skeleton = weapon.CBodyComponent.SceneNode.GetSkeletonInstance();
if (skeleton != null)
{
var value = (ulong)(isLegacy ? 2 : 1);
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;
}
}
if (skeleton.ModelState.MeshGroupMask != value)
{
skeleton.ModelState.MeshGroupMask = value;
}
}
public static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy)
private static void UpdatePlayerWeaponMeshGroupMask(CCSPlayerController player, CBasePlayerWeapon weapon, bool isLegacy)
{
UpdateWeaponMeshGroupMask(weapon, isLegacy);
var viewModel = GetPlayerViewModel(player);
if (viewModel != null && viewModel.Weapon.Value != null && viewModel.Weapon.Value.Index == weapon.Index)
{
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
}
if (viewModel == null || viewModel.Weapon.Value == null ||
viewModel.Weapon.Value.Index != weapon.Index) return;
UpdateWeaponMeshGroupMask(viewModel, isLegacy);
Utilities.SetStateChanged(viewModel, "CBaseEntity", "m_CBodyComponent");
}
public static void GivePlayerAgent(CCSPlayerController player)
private static void GivePlayerAgent(CCSPlayerController player)
{
if (!g_playersAgent.ContainsKey(player.Slot)) return;
if (!g_playersAgent.TryGetValue(player.Slot, out var value)) return;
string? model = player.TeamNum == 3 ? g_playersAgent[player.Slot].CT : g_playersAgent[player.Slot].T;
var model = player.TeamNum == 3 ? value.CT : value.T;
if (string.IsNullOrEmpty(model)) return;
if (player.PlayerPawn.Value == null)
@@ -320,43 +379,68 @@ namespace WeaponPaints
}
}
public static void GivePlayerMusicKit(CCSPlayerController player)
private static void GivePlayerMusicKit(CCSPlayerController player)
{
if (!g_playersMusic.ContainsKey(player.Slot)) return;
if (!g_playersMusic.TryGetValue(player.Slot, out var value)) return;
if (player.InventoryServices == null) return;
player.InventoryServices.MusicID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInventoryServices");
player.MusicKitID = value;
Utilities.SetStateChanged(player, "CCSPlayerController", "m_iMusicKitID");
}
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;
Console.WriteLine(g_playersMusic[player.Slot]);
player.InventoryServices.MusicID = g_playersMusic[player.Slot];
econItemView.ItemIDLow = (uint)itemId & 0xFFFFFFFF;
econItemView.ItemIDHigh = (uint)itemId >> 32;
}
public static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
private static CCSPlayerController? GetPlayerFromItemServices(CCSPlayer_ItemServices itemServices)
{
var pawn = itemServices.Pawn.Value;
if (pawn == null || !pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
if (!pawn.IsValid || !pawn.Controller.IsValid || pawn.Controller.Value == null) return null;
var player = new CCSPlayerController(pawn.Controller.Value.Handle);
if (!Utility.IsPlayerValid(player)) return null;
return player;
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);
nint ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
var ptr = viewModelServices.Handle + Schema.GetSchemaOffset("CCSPlayer_ViewModelServices", "m_hViewModel");
var references = MemoryMarshal.CreateSpan(ref ptr, 3);
var viewModel = (CHandle<CBaseViewModel>)Activator.CreateInstance(typeof(CHandle<CBaseViewModel>), references[0])!;
if (viewModel == null || viewModel.Value == null) return null;
return viewModel.Value;
return viewModel.Value == null ? null : viewModel.Value;
}
public static unsafe T[] GetFixedArray<T>(nint pointer, string @class, string member, int length) where T : CHandle<CBaseViewModel>
{
nint ptr = pointer + Schema.GetSchemaOffset(@class, member);
Span<nint> references = MemoryMarshal.CreateSpan(ref ptr, length);
T[] values = new T[length];
var ptr = pointer + Schema.GetSchemaOffset(@class, member);
var references = MemoryMarshal.CreateSpan(ref ptr, length);
var values = new T[length];
for (int i = 0; i < length; i++)
for (var i = 0; i < length; i++)
{
values[i] = (T)Activator.CreateInstance(typeof(T), references[i])!;
}

View File

@@ -7,15 +7,16 @@ using Microsoft.Extensions.Logging;
using MySqlConnector;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
namespace WeaponPaints;
[MinimumApiVersion(191)]
[MinimumApiVersion(230)]
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{
internal static WeaponPaints Instance { get; private set; } = new();
internal static readonly Dictionary<string, string> weaponList = new()
private static readonly Dictionary<string, string> WeaponList = new()
{
{"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"},
@@ -75,29 +76,33 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ "weapon_knife_kukri", "Kukri Knife" }
};
internal static WeaponPaintsConfig _config = new WeaponPaintsConfig();
private static WeaponPaintsConfig _config = new();
internal static IStringLocalizer? _localizer;
internal static Dictionary<int, int> g_knifePickupCount = new Dictionary<int, int>();
internal static ConcurrentDictionary<int, string> g_playersKnife = new ConcurrentDictionary<int, string>();
internal static ConcurrentDictionary<int, ushort> g_playersGlove = new ConcurrentDictionary<int, ushort>();
internal static ConcurrentDictionary<int, ushort> g_playersMusic = new ConcurrentDictionary<int, ushort>();
internal static ConcurrentDictionary<int, (string? CT, string? T)> g_playersAgent = new ConcurrentDictionary<int, (string?, string?)>();
internal static ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>>();
internal static List<JObject> skinsList = new List<JObject>();
internal static List<JObject> glovesList = new List<JObject>();
internal static List<JObject> agentsList = new List<JObject>();
internal static List<JObject> musicList = new List<JObject>();
private static Dictionary<int, int> g_knifePickupCount = new();
internal static ConcurrentDictionary<int, string> g_playersKnife = new();
internal static ConcurrentDictionary<int, ushort> g_playersGlove = new();
internal static ConcurrentDictionary<int, ushort> g_playersMusic = new();
internal static ConcurrentDictionary<int, (string? CT, string? T)> g_playersAgent = new();
internal static ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new();
internal static List<JObject> skinsList = new();
internal static List<JObject> glovesList = new();
internal static List<JObject> agentsList = new();
internal static List<JObject> musicList = new();
internal static WeaponSynchronization? weaponSync;
public static bool g_bCommandsAllowed = true;
internal Dictionary<int, string> PlayerWeaponImage = new();
private static bool g_bCommandsAllowed = true;
private Dictionary<int, string> PlayerWeaponImage = new();
internal static Dictionary<int, DateTime> commandsCooldown = new Dictionary<int, DateTime>();
private static Dictionary<int, DateTime> commandsCooldown = new();
internal static Database? _database;
internal static MemoryFunctionVoid<nint, string, float> CAttributeList_SetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
internal static MemoryFunctionVoid<CBaseModelEntity, string, UInt64> CBaseModelEntity_SetBodygroup = new(GameData.GetSignature("CBaseModelEntity_SetBodygroup"));
private static readonly MemoryFunctionVoid<nint, string, float> CAttributeListSetOrAddAttributeValueByName = new(GameData.GetSignature("CAttributeList_SetOrAddAttributeValueByName"));
public static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string>
private static readonly MemoryFunctionWithReturn<nint, string, int, int> SetBodygroupFunc = new(
GameData.GetSignature("CBaseModelEntity_SetBodygroup"));
private static readonly Func<nint, string, int, int> SetBodygroup = SetBodygroupFunc.Invoke;
private static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string>
{
{ 1, "weapon_deagle" },
{ 2, "weapon_elite" },
@@ -156,16 +161,15 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ 526, "weapon_knife_kukri" }
};
private const ulong MinimumCustomItemId = 65578;
private ulong _nextItemId = MinimumCustomItemId;
public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public WeaponPaintsConfig Config { get; set; } = new();
public 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.3a";
public static WeaponPaintsConfig GetWeaponPaintsConfig()
{
return _config;
}
public override string ModuleVersion => "2.5a";
public override void Load(bool hotReload)
{
@@ -175,19 +179,19 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{
OnMapStart(string.Empty);
foreach (var player in Utilities.GetPlayers())
foreach (var player in Enumerable
.OfType<CCSPlayerController>(Utilities.GetPlayers().TakeWhile(player => weaponSync != null))
.Where(player => player.IsValid &&
!string.IsNullOrEmpty(player.IpAddress) && player is
{ IsBot: false, Connected: PlayerConnectedState.PlayerConnected }))
{
if (weaponSync == null || player is null || !player.IsValid || player.SteamID.ToString().Length != 17 || player.IsBot ||
player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected)
continue;
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 _);
PlayerInfo playerInfo = new PlayerInfo
PlayerInfo? playerInfo = new PlayerInfo
{
UserId = player.UserId,
Slot = player.Slot,
@@ -197,33 +201,17 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
IpAddress = player?.IpAddress?.Split(":")[0]
};
if (Config.Additional.SkinEnabled)
_ = Task.Run(async () =>
{
_ = Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled)
{
_ = Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled)
{
_ = Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
}
if (Config.Additional.AgentEnabled)
{
_ = Task.Run(async () => await weaponSync.GetAgentFromDatabase(playerInfo));
}
if (Config.Additional.MusicEnabled)
{
_ = Task.Run(async () => await weaponSync.GetMusicFromDatabase(playerInfo));
}
if (weaponSync != null) await weaponSync.GetPlayerData(playerInfo);
});
}
}
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json");
Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json");
Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json");
Utility.LoadMusicFromFile(ModuleDirectory + "/music.json");
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();
@@ -244,10 +232,18 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{
if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{
Logger.LogError("You need to setup Database credentials in config!");
throw new Exception("[WeaponPaints] You need to setup Database credentials in config!");
Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
Unload(false);
return;
}
if (!File.Exists(Path.GetDirectoryName(Path.GetDirectoryName(ModuleDirectory)) + "/gamedata/weaponpaints.json"))
{
Logger.LogError("You need to upload \"weaponpaints.json\" to \"gamedata directory\"!");
Unload(false);
return;
}
var builder = new MySqlConnectionStringBuilder
{
Server = config.DatabaseHost,
@@ -255,10 +251,11 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
Password = config.DatabasePassword,
Database = config.DatabaseName,
Port = (uint)config.DatabasePort,
Pooling = true
Pooling = true,
MaximumPoolSize = 640,
};
_database = new(builder.ConnectionString);
_database = new Database(builder.ConnectionString);
_ = Utility.CheckDatabaseTables();

View File

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

View File

@@ -1,4 +1,5 @@
using Dapper;
using MySqlConnector;
using System.Collections.Concurrent;
namespace WeaponPaints
@@ -14,16 +15,39 @@ namespace WeaponPaints
_config = config;
}
internal async Task GetKnifeFromDatabase(PlayerInfo player)
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);
}
catch (Exception ex)
{
// Log the exception or handle it appropriately
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
string? playerKnife = await connection.QueryFirstOrDefaultAsync<string>(query, new { steamid = player.SteamId });
const string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
var playerKnife = connection.QueryFirstOrDefault<string>(query, new { steamid = player.SteamId });
if (!string.IsNullOrEmpty(playerKnife))
{
@@ -36,16 +60,15 @@ namespace WeaponPaints
}
}
internal async Task GetGloveFromDatabase(PlayerInfo player)
private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
ushort? gloveData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
const string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
var gloveData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
if (gloveData != null)
{
@@ -58,38 +81,35 @@ namespace WeaponPaints
}
}
internal async Task GetAgentFromDatabase(PlayerInfo player)
private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid";
var agentData = await connection.QueryFirstOrDefaultAsync<(string, string)>(query, new { steamid = player.SteamId });
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 (agentData != default)
if (agentData == default) return;
var agentCT = agentData.Item1;
var agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
string agentCT = agentData.Item1;
string agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
WeaponPaints.g_playersAgent[player.Slot] = (
agentCT,
agentT
);
}
WeaponPaints.g_playersAgent[player.Slot] = (
agentCT,
agentT
);
}
}
catch (Exception ex)
{
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
Utility.Log($"An error occurred in GetAgentFromDatabase: {ex.Message}");
}
}
internal async Task GetWeaponPaintsFromDatabase(PlayerInfo player)
private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
@@ -98,15 +118,8 @@ namespace WeaponPaints
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = await connection.QueryAsync<dynamic>(query, new { steamid = player.SteamId });
if (playerSkins == null)
{
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
return;
}
const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = connection.Query<dynamic>(query, new { steamid = player.SteamId });
foreach (var row in playerSkins)
{
@@ -133,16 +146,15 @@ namespace WeaponPaints
}
}
internal async Task GetMusicFromDatabase(PlayerInfo player)
private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId))
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid";
ushort? musicData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
const string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid";
var musicData = connection.QueryFirstOrDefault<ushort?>(query, new { steamid = player.SteamId });
if (musicData != null)
{
@@ -155,14 +167,17 @@ namespace WeaponPaints
}
}
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife)
{
if (!_config.Additional.KnifeEnabled || player == null || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
const string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
try
{
await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_knife` (`steamid`, `knife`) VALUES(@steamid, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife";
await connection.ExecuteAsync(query, new { steamid = player.SteamId, newKnife = knife });
}
catch (Exception e)
@@ -173,12 +188,12 @@ namespace WeaponPaints
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
{
if (!_config.Additional.GloveEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId)) return;
try
{
await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_gloves` (`steamid`, `weapon_defindex`) VALUES(@steamid, @weapon_defindex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex";
const string query = "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)
@@ -189,17 +204,18 @@ namespace WeaponPaints
internal async Task SyncAgentToDatabase(PlayerInfo player)
{
if (!_config.Additional.AgentEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) 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();
string query = @"
INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`)
VALUES(@steamid, @agent_ct, @agent_t)
ON DUPLICATE KEY UPDATE
`agent_ct` = @agent_ct,
`agent_t` = @agent_t";
await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.g_playersAgent[player.Slot].CT, agent_t = WeaponPaints.g_playersAgent[player.Slot].T });
}
@@ -211,38 +227,36 @@ namespace WeaponPaints
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
{
if (player == null || string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
if (string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
return;
try
{
await using var connection = await _database.GetConnectionAsync();
foreach (var weaponInfoPair in weaponsInfo)
foreach (var (weaponDefIndex, weaponInfo) in weaponsInfo)
{
int weaponDefIndex = weaponInfoPair.Key;
WeaponInfo weaponInfo = weaponInfoPair.Value;
var paintId = weaponInfo.Paint;
var wear = weaponInfo.Wear;
var seed = weaponInfo.Seed;
int paintId = weaponInfo.Paint;
float wear = weaponInfo.Wear;
int seed = weaponInfo.Seed;
const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
int existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex });
var existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex });
string query;
object parameters;
if (existingRecordCount > 0)
{
query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed };
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, paintId, wear, seed };
parameters = new { steamid = player.SteamId, weaponDefIndex = weaponDefIndex, paintId, wear, seed };
}
await connection.ExecuteAsync(query, parameters);
@@ -256,12 +270,12 @@ namespace WeaponPaints
internal async Task SyncMusicToDatabase(PlayerInfo player, ushort music)
{
if (!_config.Additional.MusicEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return;
try
{
await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_music` (`steamid`, `music_id`) VALUES(@steamid, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic";
const string query = "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)

View File

@@ -2,22 +2,22 @@
"ChangeSubclass": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x20\\x48\\x8B\\xDA\\x48\\x8B\\xF9\\xE8\\x2A\\x2A\\x2A\\x2A\\x84\\xC0\\x74\\x2A\\x41\\xB0\\x01",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x49\\x89\\xF5\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x81\\xEC\\xA8\\x00\\x00\\x00"
"windows": "40 57 48 83 EC 20 48 8B F9 41 B0 01",
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 F5 41 54 49 89 FC 53 48 81 EC A8 00 00 00"
}
},
"CAttributeList_SetOrAddAttributeValueByName": {
"signatures": {
"library": "server",
"windows": "\\x40\\x53\\x41\\x56\\x41\\x57\\x48\\x81\\xEC\\x90\\x00\\x00\\x00\\x0F\\x29\\x74\\x24\\x70",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78"
"windows": "40 53 41 56 41 57 48 81 EC 90 00 00 00 0F 29 74 24 70",
"linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 49 89 F4 53 48 83 EC 78"
}
},
"CBaseModelEntity_SetBodygroup": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x08\\x48\\x89\\x74\\x24\\x10\\x57\\x48\\x83\\xEC\\x20\\x41\\x8B\\xF8\\x48\\x8B\\xF2\\x48\\x8B\\xD9\\xE8\\x2A\\x2A\\x2A\\x2A",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08"
"windows": "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 41 8B F8 48 8B F2 48 8B D9 E8 ? ? ? ?",
"linux": "55 48 89 E5 41 56 49 89 F6 41 55 41 89 D5 41 54 49 89 FC 48 83 EC 08"
}
}
}
}

View File

@@ -119,6 +119,12 @@
"model": "tm_professional/tm_professional_varf4",
"agent_name": "Sir Bloody Loudmouth Darryl | The Professionals"
},
{
"team": 2,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4613.png",
"model": "tm_professional/tm_professional_varf5",
"agent_name": "Bloody Darryl The Strapped | The Professionals"
},
{
"team": 3,
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4749.png",

View File

@@ -2,7 +2,7 @@
{
"weapon_defindex": 0,
"paint": "0",
"image": "",
"image": "https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/website/img/skins/default_gloves.png",
"paint_name": "Gloves | Default"
},
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 31 KiB