Compare commits

...

34 Commits

Author SHA1 Message Date
Nereziel
2abe48f71a 123 2024-03-02 19:15:50 +01:00
Nereziel
219c201fde testref 2024-02-24 22:44:17 +01:00
Nereziel
acf4a766ca Update Commands.cs 2024-02-24 21:15:45 +01:00
Dawid Bepierszcz
ad73e0a85d Merge pull request #171 from daffyyyy/main
Some fixes
2024-02-23 02:58:01 +01:00
Dawid Bepierszcz
25c205e53d Merge branch 'Nereziel:main' into main 2024-02-23 02:56:42 +01:00
Dawid Bepierszcz
1366e141a7 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-23 02:46:00 +01:00
Dawid Bepierszcz
5465b982b7 Some fixes 2024-02-23 02:45:58 +01:00
Dawid Bepierszcz
ead5ae23a3 Merge pull request #170 from daffyyyy/main
1.9b
2024-02-22 22:46:31 +01:00
Dawid Bepierszcz
ff2e7ffd6b Merge branch 'Nereziel:main' into main 2024-02-22 22:43:46 +01:00
Dawid Bepierszcz
c9a1fad496 1.9b 2024-02-22 22:43:25 +01:00
Dawid Bepierszcz
0d4d01800d Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-22 22:41:34 +01:00
Dawid Bepierszcz
19d004c21d 1.9b
- Fixed weapons on retake
- FIxed saving
2024-02-22 22:41:32 +01:00
Dawid Bepierszcz
391efd5cac Merge pull request #169 from daffyyyy/main
1.9a
2024-02-22 21:12:33 +01:00
Dawid Bepierszcz
3cf9a67ee2 Merge branch 'Nereziel:main' into main 2024-02-22 21:10:26 +01:00
Dawid Bepierszcz
ddb4fb7cba Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-22 21:09:00 +01:00
Dawid Bepierszcz
e75d48bd0d 1.9a
- Removed GlobalShare
- More stability
2024-02-22 21:07:52 +01:00
Dawid Bepierszcz
959123344f Merge pull request #165 from daffyyyy/main
1.8d
2024-02-21 12:06:08 +01:00
Dawid Bepierszcz
14b0b8153f Merge branch 'Nereziel:main' into main 2024-02-21 12:04:41 +01:00
Dawid Bepierszcz
fa48245b34 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-21 12:03:52 +01:00
Dawid Bepierszcz
5d5e0f2bd1 1.8d
- Small changes
- Fixed gloves command
2024-02-21 12:03:48 +01:00
Dawid Bepierszcz
726e67865c Merge pull request #163 from daffyyyy/main
1.8c
2024-02-20 12:54:31 +01:00
Dawid Bepierszcz
868e6c8746 Merge branch 'Nereziel:main' into main 2024-02-20 12:52:33 +01:00
Dawid Bepierszcz
a1285bef26 Merge branch 'main' of https://github.com/daffyyyy/cs2-WeaponPaints 2024-02-20 12:51:15 +01:00
Dawid Bepierszcz
b1920f312c 1.8c
- Better gloves operations
- Changed gloves table
2024-02-20 12:51:14 +01:00
Dawid Bepierszcz
5e9850bece Merge pull request #162 from daffyyyy/main
1.8b
2024-02-20 01:57:01 +01:00
Dawid Bepierszcz
e1802fd0f0 Merge branch 'Nereziel:main' into main 2024-02-20 01:55:45 +01:00
Dawid Bepierszcz
267de3c4de 1.8b
- Fixed gloves changing?
2024-02-20 01:54:54 +01:00
Dawid Bepierszcz
9f24fbf3ef test 2024-02-20 01:51:25 +01:00
Dawid Bepierszcz
9c23545173 test 2024-02-20 01:48:41 +01:00
Dawid Bepierszcz
40d1088ee6 test 2024-02-20 01:46:41 +01:00
Dawid Bepierszcz
e7f546ed58 test 2024-02-20 01:43:27 +01:00
Dawid Bepierszcz
beab940ebb test 2024-02-20 01:38:22 +01:00
Dawid Bepierszcz
7dc78e7706 test 2024-02-20 01:30:09 +01:00
Dawid Bepierszcz
02208095f0 test 2024-02-20 01:28:25 +01:00
18 changed files with 909 additions and 809 deletions

View File

@@ -63,11 +63,7 @@ jobs:
- name: Copy gloves.json - name: Copy gloves.json
run: cp website/data/gloves.json ${{ env.OUTPUT_PATH }}/gloves.json run: cp website/data/gloves.json ${{ env.OUTPUT_PATH }}/gloves.json
- name: Zip - name: Zip
uses: thedoctor0/zip-release@0.7.5 run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
with:
type: 'zip'
filename: '${{ env.PROJECT_NAME }}.zip'
path: ${{ env.OUTPUT_PATH }}
- name: Clean files Website - name: Clean files Website
run: | run: |
rm -rf website/img/ rm -rf website/img/

View File

@@ -1,6 +1,8 @@
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Menu;
using Newtonsoft.Json.Linq;
using System.Text;
namespace WeaponPaints namespace WeaponPaints
{ {
@@ -12,40 +14,52 @@ namespace WeaponPaints
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return; if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return;
PlayerInfo playerInfo = new (
int playerIndex = (int)player!.Index; (int)player.Index,
player.Slot,
PlayerInfo playerInfo = new PlayerInfo player.UserId,
{ player.SteamID.ToString(),
UserId = player.UserId, player.PlayerName,
Index = (int)player.Index, player.IpAddress?.Split(":")[0]
SteamId = player?.SteamID.ToString(), );
Name = player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0]
};
if (player == null || !player.IsValid || player.UserId == null || player.IsBot) return;
try try
{ {
if (!commandsCooldown.TryGetValue((int)player.UserId, out DateTime cooldownEndTime) || if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
DateTime.UtcNow >= (commandsCooldown.TryGetValue((int)player.UserId, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
commandsCooldown[(int)player.UserId] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds); commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
if (weaponSync != null) if (weaponSync != null)
Task.Run(async () => await weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
if (Config.Additional.GloveEnabled && weaponSync != null)
Task.Run(async () => await weaponSync.GetGloveFromDatabase(playerInfo));
if (Config.Additional.KnifeEnabled)
{ {
if (weaponSync != null) var weaponTasks = new List<Task>();
Task.Run(async () => await weaponSync.GetKnifeFromDatabase(playerInfo));
weaponTasks.Add(Task.Run(async () =>
{
await weaponSync.GetWeaponPaintsFromDatabase(playerInfo);
}));
if (Config.Additional.GloveEnabled)
{
weaponTasks.Add(Task.Run(async () =>
{
await weaponSync.GetGloveFromDatabase(playerInfo);
}));
}
if (Config.Additional.KnifeEnabled)
{
weaponTasks.Add(Task.Run(async () =>
{
await weaponSync.GetKnifeFromDatabase(playerInfo);
}));
}
Task.WaitAll(weaponTasks.ToArray());
RefreshGloves(player);
RefreshWeapons(player); RefreshWeapons(player);
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"])) if (!string.IsNullOrEmpty(Localizer["wp_command_refresh_done"]))
{ {
player!.Print(Localizer["wp_command_refresh_done"]); player!.Print(Localizer["wp_command_refresh_done"]);
@@ -96,7 +110,7 @@ namespace WeaponPaints
}); });
AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) => AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) =>
{ {
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return; if (!Utility.IsPlayerValid(player)) return;
OnCommandRefresh(player, info); OnCommandRefresh(player, info);
}); });
if (Config.Additional.CommandKillEnabled) if (Config.Additional.CommandKillEnabled)
@@ -110,301 +124,372 @@ namespace WeaponPaints
} }
} }
private void SetupKnifeMenu() private void SetupKnifeMenu()
{ {
if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return; if (!Config.Additional.KnifeEnabled || !g_bCommandsAllowed) return;
var knivesOnly = weaponList var knivesOnly = GetKnivesOnly();
.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")) var giveItemMenu = new ChatMenu(Localizer["wp_knife_menu_title"]);
.ToDictionary(pair => pair.Key, pair => pair.Value);
var giveItemMenu = new ChatMenu(Localizer["wp_knife_menu_title"]); AddMenuOptions(giveItemMenu, knivesOnly);
var handleGive = (CCSPlayerController player, ChatMenuOption option) => AddCommandToOpenKnifeMenu(giveItemMenu);
{ }
if (!Utility.IsPlayerValid(player)) return;
var knifeName = option.Text; private Dictionary<string, string> GetKnivesOnly()
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key; {
if (!string.IsNullOrEmpty(knifeKey)) return weaponList
{ .Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet"))
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"])) .ToDictionary(pair => pair.Key, pair => pair.Value);
{ }
player!.Print(Localizer["wp_knife_menu_select", knifeName]);
}
if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled) private void AddMenuOptions(ChatMenu giveItemMenu, Dictionary<string, string> knivesOnly)
{ {
player!.Print(Localizer["wp_knife_menu_kill"]); foreach (var knifePair in knivesOnly)
} {
giveItemMenu.AddMenuOption(knifePair.Value, (player, option) => HandleGiveOption(player, option, knivesOnly));
}
}
PlayerInfo playerInfo = new PlayerInfo private void HandleGiveOption(CCSPlayerController player, ChatMenuOption option, Dictionary<string, string> knivesOnly)
{ {
UserId = player.UserId, if (!Utility.IsPlayerValid(player)) return;
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
g_playersKnife[(int)player!.Index] = knifeKey; var knifeName = option.Text;
var knifeKey = knivesOnly.FirstOrDefault(x => x.Value == knifeName).Key;
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE) if (!string.IsNullOrEmpty(knifeKey))
AddTimer(0.15f, () => RefreshWeapons(player), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); {
PrintMessages(player, knifeName);
SetPlayerKnife(player, knifeKey);
SyncKnifeToDatabase(player, knifeKey);
}
}
_ = weaponSync?.SyncKnifeToDatabase(playerInfo, knifeKey) ?? Task.CompletedTask; private void PrintMessages(CCSPlayerController player, string knifeName)
} {
}; if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_select"]))
foreach (var knifePair in knivesOnly) {
{ player!.Print(Localizer["wp_knife_menu_select", knifeName]);
giveItemMenu.AddMenuOption(knifePair.Value, handleGive); }
}
AddCommand($"css_{Config.Additional.CommandKnife}", "Knife Menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
if (player == null || player.UserId == null) return; if (!string.IsNullOrEmpty(Localizer["wp_knife_menu_kill"]) && Config.Additional.CommandKillEnabled)
{
player!.Print(Localizer["wp_knife_menu_kill"]);
}
}
if (!commandsCooldown.TryGetValue((int)player.UserId, out DateTime cooldownEndTime) || private void SetPlayerKnife(CCSPlayerController player, string knifeKey)
DateTime.UtcNow >= (commandsCooldown.TryGetValue((int)player.UserId, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) {
{ g_playersKnife[player.Slot] = knifeKey;
commandsCooldown[(int)player.UserId] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
giveItemMenu.PostSelectAction = PostSelectAction.Close;
MenuManager.OpenChatMenu(player, giveItemMenu);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player!.Print(Localizer["wp_command_cooldown"]);
}
});
}
private void SetupSkinsMenu() if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
{ RefreshWeapons(player);
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 private void SyncKnifeToDatabase(CCSPlayerController player, string knifeKey)
var handleWeaponSelection = (CCSPlayerController? player, ChatMenuOption option) => {
{ if (weaponSync != null)
if (!Utility.IsPlayerValid(player)) return; Task.Run(async () => await weaponSync.SyncKnifeToDatabase(GetPlayerInfo(player), knifeKey));
}
int playerIndex = (int)player!.Index; private PlayerInfo GetPlayerInfo(CCSPlayerController player)
string selectedWeapon = option.Text; {
if (classNamesByWeapon.TryGetValue(selectedWeapon, out string? selectedWeaponClassname)) return new PlayerInfo
{ {
if (selectedWeaponClassname == null) return; UserId = player.UserId,
var skinsForSelectedWeapon = skinsList?.Where(skin => Slot = player.Slot,
skin != null && Index = (int)player.Index,
skin.TryGetValue("weapon_name", out var weaponName) && SteamId = player.SteamID.ToString(),
weaponName?.ToString() == selectedWeaponClassname Name = player.PlayerName,
)?.ToList(); IpAddress = player.IpAddress?.Split(":")[0]
};
}
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]); private void AddCommandToOpenKnifeMenu(ChatMenu giveItemMenu)
skinSubMenu.PostSelectAction = PostSelectAction.Close; {
AddCommand($"css_{Config.Additional.CommandKnife}", "Knife Menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
// Function to handle skin selection for the chosen weapon if (player == null || player.UserId == null) return;
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
{
if (!Utility.IsPlayerValid(p)) return;
playerIndex = (int)p.Index; if (IsCommandAllowed(player))
{
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
giveItemMenu.PostSelectAction = PostSelectAction.Close;
MenuManager.OpenChatMenu(player, giveItemMenu);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player!.Print(Localizer["wp_command_cooldown"]);
}
});
}
string steamId = p.SteamID.ToString(); private bool IsCommandAllowed(CCSPlayerController player)
var firstSkin = skinsList?.FirstOrDefault(skin => {
{ if (!commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime))
if (skin != null && skin.TryGetValue("weapon_name", out var weaponName)) {
{ return true;
return weaponName?.ToString() == selectedWeaponClassname; }
} return DateTime.UtcNow >= cooldownEndTime;
return false; }
});
string selectedSkin = opt.Text; private void SetupSkinsMenu()
string selectedPaintID = selectedSkin.Split('(')[1].Trim(')').Trim(); {
var classNamesByWeapon = weaponList.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
var weaponSelectionMenu = new ChatMenu(Localizer["wp_skin_menu_weapon_title"]);
if (firstSkin != null && // Add weapon options to the weapon selection menu
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) && foreach (var weaponClass in weaponList.Keys)
weaponDefIndexObj != null && {
int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) && string weaponName = weaponList[weaponClass];
int.TryParse(selectedPaintID, out var paintID)) weaponSelectionMenu.AddMenuOption(weaponName, (player, option) => HandleWeaponSelection(player, option, classNamesByWeapon));
{ }
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]); // Command to open the weapon selection menu for players
AddCommand($"css_{Config.Additional.CommandSkinSelection}", "Skins selection menu", (player, info) => OpenWeaponSelectionMenu(player, weaponSelectionMenu));
}
if (!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex)) private void HandleWeaponSelection(CCSPlayerController? player, ChatMenuOption option, Dictionary<string, string> classNamesByWeapon)
{ {
gPlayerWeaponsInfo[playerIndex][weaponDefIndex] = new WeaponInfo(); if (!Utility.IsPlayerValid(player)) return;
}
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Paint = paintID; string selectedWeapon = option.Text;
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Wear = 0.01f; if (classNamesByWeapon.TryGetValue(selectedWeapon, out string? selectedWeaponClassname))
gPlayerWeaponsInfo[playerIndex][weaponDefIndex].Seed = 0; {
if (selectedWeaponClassname == null) return;
var skinsForSelectedWeapon = skinsList?.Where(skin =>
skin != null &&
skin.TryGetValue("weapon_name", out var weaponName) &&
weaponName?.ToString() == selectedWeaponClassname
)?.ToList();
PlayerInfo playerInfo = new PlayerInfo var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
{ skinSubMenu.PostSelectAction = PostSelectAction.Close;
UserId = p.UserId,
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) // Add skin options to the submenu for the selected weapon
AddTimer(0.15f, () => RefreshWeapons(p), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); if (skinsForSelectedWeapon != null)
{
foreach (var skin in skinsForSelectedWeapon.Where(s => s != null))
{
if (skin.TryGetValue("paint_name", out var paintNameObj) && skin.TryGetValue("paint", out var paintObj))
{
var paintName = paintNameObj?.ToString();
var paint = paintObj?.ToString();
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint))
{
var optionText = new StringBuilder(paintName).Append(" (").Append(paint).Append(")").ToString();
skinSubMenu.AddMenuOption(optionText, (p, opt) => HandleSkinSelection(p, opt, selectedWeaponClassname));
}
}
}
}
if (player != null && Utility.IsPlayerValid(player))
MenuManager.OpenChatMenu(player, skinSubMenu);
}
}
if (!Config.GlobalShare) private void HandleSkinSelection(CCSPlayerController p, ChatMenuOption opt, string selectedWeaponClassname)
{ {
if (weaponSync != null) if (!Utility.IsPlayerValid(p)) return;
Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
}
}
};
// Add skin options to the submenu for the selected weapon string steamId = p.SteamID.ToString();
if (skinsForSelectedWeapon != null) var firstSkin = skinsList?.Find(skin =>
{ {
foreach (var skin in skinsForSelectedWeapon.Where(s => s != null)) if (skin != null && skin.TryGetValue("weapon_name", out var weaponName))
{ {
if (skin.TryGetValue("paint_name", out var paintNameObj) && skin.TryGetValue("paint", out var paintObj)) return weaponName?.ToString() == selectedWeaponClassname;
{ }
var paintName = paintNameObj?.ToString(); return false;
var paint = paintObj?.ToString(); });
if (!string.IsNullOrEmpty(paintName) && !string.IsNullOrEmpty(paint)) string selectedSkin = opt.Text;
{ string selectedPaintID = selectedSkin.Split('(')[1].Trim(')').Trim();
skinSubMenu.AddMenuOption($"{paintName} ({paint})", handleSkinSelection);
}
}
}
}
// Open the submenu for skin selection of the chosen weapon if (firstSkin != null &&
MenuManager.OpenChatMenu(player, skinSubMenu); firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) &&
} weaponDefIndexObj != null &&
}; int.TryParse(weaponDefIndexObj.ToString(), out var weaponDefIndex) &&
int.TryParse(selectedPaintID, out var paintID))
{
HandleSkinImage(p, weaponDefIndex, paintID);
p.Print(Localizer["wp_skin_menu_select", selectedSkin]);
UpdatePlayerWeaponInfo(p, weaponDefIndex, paintID);
}
}
// Add weapon options to the weapon selection menu private void HandleSkinImage(CCSPlayerController p, int weaponDefIndex, int paintID)
foreach (var weaponClass in weaponList.Keys) {
{ if (Config.Additional.ShowSkinImage && skinsList != null)
string weaponName = weaponList[weaponClass]; {
weaponSelectionMenu.AddMenuOption(weaponName, handleWeaponSelection); var foundSkin = skinsList.FirstOrDefault(skin =>
} ((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
// Command to open the weapon selection menu for players ((int?)skin?["paint"] ?? 0) == paintID &&
AddCommand($"css_{Config.Additional.CommandSkinSelection}", "Skins selection menu", (player, info) => skin?["image"] != null
{ );
if (!Utility.IsPlayerValid(player)) return; string image = foundSkin?["image"]?.ToString() ?? "";
PlayerWeaponImage[p.Slot] = image;
AddTimer(2.0f, () => PlayerWeaponImage.Remove(p.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
}
if (player == null || player.UserId == null) return; private void UpdatePlayerWeaponInfo(CCSPlayerController p, int weaponDefIndex, int paintID)
{
if (!gPlayerWeaponsInfo[p.Slot].TryGetValue(weaponDefIndex, out WeaponInfo? value))
{
value = new WeaponInfo();
gPlayerWeaponsInfo[p.Slot][weaponDefIndex] = value;
}
if (!commandsCooldown.TryGetValue((int)player.UserId, out DateTime cooldownEndTime) || value.Paint = paintID;
DateTime.UtcNow >= (commandsCooldown.TryGetValue((int)player.UserId, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) value.Wear = 0.00f;
{ value.Seed = 0;
commandsCooldown[(int)player.UserId] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, weaponSelectionMenu);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player!.Print(Localizer["wp_command_cooldown"]);
}
});
}
private void SetupGlovesMenu() if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE)
{ {
var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]); RefreshWeapons(p);
}
}
var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) => private void OpenWeaponSelectionMenu(CCSPlayerController? player, ChatMenu weaponSelectionMenu)
{ {
if (!Utility.IsPlayerValid(player)) return; if (!Utility.IsPlayerValid(player)) return;
uint playerIndex = player!.Index; if (player == null || player.UserId == null) return;
string selectedPaintName = option.Text;
var selectedGlove = glovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName); if (player != null && !commandsCooldown.TryGetValue(player.Slot, out DateTime cooldownEndTime) ||
if (selectedGlove != null) player != null && DateTime.UtcNow >= (commandsCooldown.TryGetValue(player.Slot, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow))
{ {
if ( commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
selectedGlove != null && MenuManager.OpenChatMenu(player, weaponSelectionMenu);
selectedGlove.ContainsKey("weapon_defindex") && return;
selectedGlove.ContainsKey("paint") && }
int.TryParse(selectedGlove["weapon_defindex"]?.ToString(), out int weaponDefindex) && if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
int.TryParse(selectedGlove["paint"]?.ToString(), out int paint) {
) player!.Print(Localizer["wp_command_cooldown"]);
{ }
if (Config.Additional.ShowSkinImage) }
{ private void SetupGlovesMenu()
string image = selectedGlove["image"]?.ToString() ?? ""; {
PlayerWeaponImage[player.Slot] = image; var glovesSelectionMenu = new ChatMenu(Localizer["wp_glove_menu_title"]);
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); glovesSelectionMenu.PostSelectAction = PostSelectAction.Close;
}
PlayerInfo playerInfo = new PlayerInfo var handleGloveSelection = (CCSPlayerController? player, ChatMenuOption option) =>
{ {
UserId = player.UserId, if (!Utility.IsPlayerValid(player) || player is null) return;
Index = (int)player.Index,
SteamId = player.SteamID.ToString(),
Name = player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0]
};
if (paint != 0) string selectedPaintName = option.Text;
g_playersGlove[playerIndex] = ((ushort)weaponDefindex, paint); var selectedGlove = glovesList.FirstOrDefault(g => g.ContainsKey("paint_name") && g["paint_name"]?.ToString() == selectedPaintName);
else if (selectedGlove != null)
g_playersGlove.TryRemove(playerIndex, out _); {
HandleSelectedGlove(player, selectedGlove, selectedPaintName);
}
};
if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"])) AddGloveOptionsToMenu(glovesSelectionMenu, handleGloveSelection);
{ AddCommandToOpenGloveSelectionMenu(glovesSelectionMenu);
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]); }
}
void HandleSelectedGlove(CCSPlayerController? player, JObject selectedGlove, string selectedPaintName)
{
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);
}
PlayerInfo playerInfo = new(
(int)player.Index,
player.Slot,
player.UserId,
player.SteamID.ToString(),
player.PlayerName,
player.IpAddress?.Split(":")[0]
);
_ = weaponSync?.SyncGloveToDatabase(playerInfo, (ushort)weaponDefindex, paint) ?? Task.CompletedTask; if (paint != 0)
} {
}; g_playersGlove[player.Slot] = (ushort)weaponDefindex;
};
// Add weapon options to the weapon selection menu if (!gPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefindex, out _))
foreach (var gloveObject in glovesList) {
{ WeaponInfo weaponInfo = new();
string paintName = gloveObject["paint_name"]?.ToString() ?? ""; weaponInfo.Paint = paint;
gPlayerWeaponsInfo[player.Slot][weaponDefindex] = weaponInfo;
}
}
else
{
g_playersGlove.TryRemove(player.Slot, out _);
}
if (paintName.Length > 0) if (!string.IsNullOrEmpty(Localizer["wp_glove_menu_select"]))
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection); {
} player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
}
// Command to open the weapon selection menu for players if (weaponSync != null)
AddCommand($"css_{Config.Additional.CommandGlove}", "Gloves selection menu", (player, info) => {
{ Task.Run(async () =>
if (!Utility.IsPlayerValid(player)) return; {
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
if (player == null || player.UserId == null) return; if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out var weaponInfo))
{
weaponInfo = new WeaponInfo();
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = weaponInfo;
}
if (!commandsCooldown.TryGetValue((int)player.UserId, out DateTime cooldownEndTime) || weaponInfo.Paint = paint;
DateTime.UtcNow >= (commandsCooldown.TryGetValue((int)player.UserId, out cooldownEndTime) ? cooldownEndTime : DateTime.UtcNow)) weaponInfo.Wear = 0.00f;
{ weaponInfo.Seed = 0;
commandsCooldown[(int)player.UserId] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
glovesSelectionMenu.PostSelectAction = PostSelectAction.Close; });
MenuManager.OpenChatMenu(player, glovesSelectionMenu); }
return; RefreshGloves(player);
} }
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"])) }
{
player!.Print(Localizer["wp_command_cooldown"]); private void AddGloveOptionsToMenu(ChatMenu glovesSelectionMenu, Action<CCSPlayerController?, ChatMenuOption> handleGloveSelection)
} {
}); foreach (var gloveObject in glovesList)
} {
string paintName = gloveObject["paint_name"]?.ToString() ?? "";
if (paintName.Length > 0)
glovesSelectionMenu.AddMenuOption(paintName, handleGloveSelection);
}
}
private void AddCommandToOpenGloveSelectionMenu(ChatMenu glovesSelectionMenu)
{
AddCommand($"css_{Config.Additional.CommandGlove}", "Gloves selection menu", (player, info) =>
{
if (!Utility.IsPlayerValid(player) || !g_bCommandsAllowed) return;
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))
{
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
MenuManager.OpenChatMenu(player, glovesSelectionMenu);
return;
}
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
{
player!.Print(Localizer["wp_command_cooldown"]);
}
});
}
} }
} }

View File

@@ -73,9 +73,6 @@ namespace WeaponPaints
[JsonPropertyName("DatabaseName")] [JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; } = ""; public string DatabaseName { get; set; } = "";
[JsonPropertyName("GlobalShare")]
public bool GlobalShare { get; set; } = false;
[JsonPropertyName("CmdRefreshCooldownSeconds")] [JsonPropertyName("CmdRefreshCooldownSeconds")]
public int CmdRefreshCooldownSeconds { get; set; } = 60; public int CmdRefreshCooldownSeconds { get; set; } = 60;

View File

@@ -11,18 +11,11 @@ namespace WeaponPaints
_dbConnectionString = dbConnectionString; _dbConnectionString = dbConnectionString;
} }
public async Task<MySqlConnection> GetConnectionAsync() public async Task<MySqlConnection> GetConnectionAsync()
{ {
try var connection = new MySqlConnection(_dbConnectionString);
{ await connection.OpenAsync();
var connection = new MySqlConnection(_dbConnectionString); return connection;
await connection.OpenAsync(); }
return connection;
}
catch (Exception)
{
throw;
}
}
} }
} }

192
Events.cs
View File

@@ -1,56 +1,95 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
namespace WeaponPaints namespace WeaponPaints
{ {
public partial class WeaponPaints public partial class WeaponPaints
{ {
private void OnClientPutInServer(int playerSlot) [GameEventHandler]
public HookResult OnClientFullConnect(EventPlayerConnectFull @event, GameEventInfo info)
{ {
CCSPlayerController? player = Utilities.GetPlayerFromSlot(playerSlot); 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 || player.IsHLTV || player.SteamID.ToString().Length != 17 ||
weaponSync == null) return; weaponSync == null || _database == null) return HookResult.Continue;
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new(
{ (int)player.Index,
UserId = player.UserId, player.Slot,
Index = (int)player.Index, player.UserId,
SteamId = player.SteamID.ToString(), player.SteamID.ToString(),
Name = player.PlayerName, player.PlayerName,
IpAddress = player.IpAddress?.Split(":")[0] player.IpAddress?.Split(":")[0]
}; );
Task.Run(async () => try
{ {
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
await weaponSync.GetWeaponPaintsFromDatabase(playerInfo); {
Task.Run(() => weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
await weaponSync.GetKnifeFromDatabase(playerInfo); {
Task.Run(() => weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled) if (Config.Additional.GloveEnabled)
await weaponSync.GetGloveFromDatabase(playerInfo); {
}); Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo));
} }
}
private void OnClientDisconnect(int playerSlot) catch (Exception ex)
{
CCSPlayerController player = Utilities.GetPlayerFromSlot(playerSlot);
if (player is null || !player.IsValid || !player.UserId.HasValue || player.IsBot || player.IsHLTV || player.SteamID.ToString().Length != 17) return;
if (Config.Additional.KnifeEnabled)
g_playersKnife.TryRemove((int)player.Index, out _);
if (Config.Additional.GloveEnabled)
g_playersGlove.TryRemove(player.Index, out _);
if (Config.Additional.SkinEnabled && gPlayerWeaponsInfo.TryGetValue((int)player.Index, out var innerDictionary))
{ {
innerDictionary.Clear(); Console.WriteLine($"An error occurred: {ex.Message}");
gPlayerWeaponsInfo.TryRemove((int)player.Index, out _);
} }
commandsCooldown.Remove((int)player.UserId); return HookResult.Continue;
}
[GameEventHandler]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
{
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(
(int)player.Index,
player.Slot,
player.UserId,
player.SteamID.ToString(),
player.PlayerName,
player.IpAddress?.Split(":")[0]
);
if (weaponSync != null)
{
// Run weapon sync tasks asynchronously
Task.Run(async () =>
{
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
});
// Remove player data
if (Config.Additional.SkinEnabled)
{
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
}
if (Config.Additional.KnifeEnabled)
{
g_playersKnife.TryRemove(player.Slot, out _);
}
if (Config.Additional.GloveEnabled)
{
g_playersGlove.TryRemove(player.Slot, out _);
}
}
// Remove player's command cooldown
commandsCooldown.Remove(player.Slot);
return HookResult.Continue;
} }
private void OnEntityCreated(CEntityInstance entity) private void OnEntityCreated(CEntityInstance entity)
@@ -75,8 +114,7 @@ namespace WeaponPaints
if (weapon.OwnerEntity.Value == null) return; if (weapon.OwnerEntity.Value == null) return;
if (weapon.OwnerEntity.Index <= 0) return; if (weapon.OwnerEntity.Index <= 0) return;
int weaponOwner = (int)weapon.OwnerEntity.Index; int weaponOwner = (int)weapon.OwnerEntity.Index;
CBasePlayerPawn? pawn = Utilities.GetEntityFromIndex<CCSPlayerPawn>((int)weaponOwner); CBasePlayerPawn? pawn = Utilities.GetEntityFromIndex<CCSPlayerPawn>(weaponOwner);
//var pawn = new CBasePlayerPawn(NativeAPI.GetEntityFromIndex(weaponOwner));
if (!pawn.IsValid) return; if (!pawn.IsValid) return;
var playerIndex = (int)pawn.Controller.Index; var playerIndex = (int)pawn.Controller.Index;
@@ -91,11 +129,14 @@ namespace WeaponPaints
public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay) public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay)
{ {
if (!Config.Additional.GiveKnifeAfterRemove)
return HookResult.Continue;
CCSPlayerController? player = Utilities.GetEntityFromIndex<CCSPlayerPawn>((int)activator.Index).OriginalController.Value; CCSPlayerController? player = Utilities.GetEntityFromIndex<CCSPlayerPawn>((int)activator.Index).OriginalController.Value;
if (player == null || player.IsBot || player.IsHLTV || if (player == null || player.IsBot || player.IsHLTV ||
player.SteamID.ToString().Length != 17 || !g_knifePickupCount.TryGetValue((int)player.Index, out var pickupCount) || player.SteamID.ToString().Length != 17 || !g_knifePickupCount.TryGetValue(player.Slot, out var pickupCount) ||
!g_playersKnife.ContainsKey((int)player.Index)) !g_playersKnife.ContainsKey(player.Slot))
{ {
return HookResult.Continue; return HookResult.Continue;
} }
@@ -112,18 +153,12 @@ namespace WeaponPaints
return HookResult.Continue; return HookResult.Continue;
} }
if (g_playersKnife[(int)player.Index] != "weapon_knife") if (g_playersKnife[player.Slot] != "weapon_knife")
{ {
pickupCount++; pickupCount++;
g_knifePickupCount[(int)player.Index] = pickupCount; g_knifePickupCount[player.Slot] = pickupCount;
if (Config.Additional.GiveKnifeAfterRemove) AddTimer(0.2f, () => RefreshWeapons(player));
{
AddTimer(0.10f, () =>
{
RefreshWeapons(player);
});
}
} }
return HookResult.Continue; return HookResult.Continue;
@@ -134,7 +169,7 @@ namespace WeaponPaints
if (!Config.Additional.KnifeEnabled && !Config.Additional.SkinEnabled && !Config.Additional.GloveEnabled) return; if (!Config.Additional.KnifeEnabled && !Config.Additional.SkinEnabled && !Config.Additional.GloveEnabled) return;
if (_database != null) if (_database != null)
weaponSync = new WeaponSynchronization(_database, Config, GlobalShareApi, GlobalShareServerId); weaponSync = new WeaponSynchronization(_database, Config);
// TODO // TODO
// needed for now // needed for now
@@ -143,9 +178,6 @@ namespace WeaponPaints
NativeAPI.IssueServerCommand("mp_t_default_melee \"\""); NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\""); NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0"); NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0");
if (Config.GlobalShare)
GlobalShareConnect();
}); });
} }
@@ -156,26 +188,15 @@ namespace WeaponPaints
if (player is null || !player.IsValid || !Config.Additional.KnifeEnabled && !Config.Additional.GloveEnabled) if (player is null || !player.IsValid || !Config.Additional.KnifeEnabled && !Config.Additional.GloveEnabled)
return HookResult.Continue; return HookResult.Continue;
if (g_playersGlove.TryGetValue(player.Index, out var gloveInfo) && gloveInfo.Paint != 0) g_knifePickupCount[player.Slot] = 0;
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player);
Server.NextFrame(() =>
{ {
player.PlayerPawn!.Value!.EconGloves.ItemDefinitionIndex = gloveInfo.Definition; RefreshGloves(player);
player.PlayerPawn!.Value!.EconGloves.ItemIDLow = 16384 & 0xFFFFFFFF; });
player.PlayerPawn!.Value!.EconGloves.ItemIDHigh = 16384 >> 32;
player.PlayerPawn!.Value!.EconGloves.EntityQuality = 3;
player.PlayerPawn!.Value!.EconGloves.EntityLevel = 1;
Server.NextFrame(() =>
{
player.PlayerPawn!.Value!.EconGloves.Initialized = true;
SetPlayerBody(player, "default_gloves", 1);
SetOrAddAttributeValueByName(player.PlayerPawn!.Value!.EconGloves.NetworkedDynamicAttributes, "set item texture prefab", gloveInfo.Paint);
Utilities.SetStateChanged(player.PlayerPawn.Value, "CCSPlayerPawn", "m_EconGloves");
});
}
g_knifePickupCount[(int)player.Index] = 0;
GiveKnifeToPlayer(player);
return HookResult.Continue; return HookResult.Continue;
} }
@@ -183,6 +204,7 @@ namespace WeaponPaints
private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info)
{ {
g_bCommandsAllowed = false; g_bCommandsAllowed = false;
return HookResult.Continue; return HookResult.Continue;
} }
@@ -196,17 +218,17 @@ namespace WeaponPaints
return HookResult.Continue; return HookResult.Continue;
} }
private void OnTick() private void OnTick()
{ {
foreach (var player in Utilities.GetPlayers()) foreach (var player in Utilities.GetPlayers().Where(p =>
p is not null && p.IsValid &&
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && p.SteamID.ToString().Length == 17
&& !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected && p.Team != CounterStrikeSharp.API.Modules.Utils.CsTeam.None
)
)
{ {
try try
{ {
if (player is null || !player.IsValid || !player.PawnIsAlive || player.SteamID.ToString().Length != 17
|| player.IsBot || player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected)
continue;
if (Config.Additional.ShowSkinImage && PlayerWeaponImage.ContainsKey(player.Slot) && !string.IsNullOrEmpty(PlayerWeaponImage[player.Slot])) if (Config.Additional.ShowSkinImage && PlayerWeaponImage.ContainsKey(player.Slot) && !string.IsNullOrEmpty(PlayerWeaponImage[player.Slot]))
{ {
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", PlayerWeaponImage[player.Slot])); player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", PlayerWeaponImage[player.Slot]));
@@ -238,20 +260,28 @@ namespace WeaponPaints
if (skeleton == null) if (skeleton == null)
continue; continue;
bool skeletonChange = false;
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 }; int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
if (newPaints.Contains(weapon.FallbackPaintKit)) if (newPaints.Contains(weapon.FallbackPaintKit))
{ {
skeleton.ModelState.MeshGroupMask = 1; if (skeleton.ModelState.MeshGroupMask != 1)
{
skeleton.ModelState.MeshGroupMask = 1;
skeletonChange = true;
}
} }
else else
{ {
if (skeleton.ModelState.MeshGroupMask != 2) if (skeleton.ModelState.MeshGroupMask != 2)
{ {
skeleton.ModelState.MeshGroupMask = 2; skeleton.ModelState.MeshGroupMask = 2;
skeletonChange = true;
} }
} }
Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent"); if (skeletonChange)
Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent");
} }
catch (Exception) catch (Exception)
{ {
@@ -261,9 +291,9 @@ namespace WeaponPaints
private void RegisterListeners() private void RegisterListeners()
{ {
RegisterListener<Listeners.OnEntityCreated>(OnEntityCreated); RegisterListener<Listeners.OnEntitySpawned>(OnEntityCreated);
RegisterListener<Listeners.OnClientPutInServer>(OnClientPutInServer); //RegisterListener<Listeners.OnClientPutInServer>(OnClientPutInServer);
RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect); //RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect);
RegisterListener<Listeners.OnMapStart>(OnMapStart); RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterListener<Listeners.OnTick>(OnTick); RegisterListener<Listeners.OnTick>(OnTick);

View File

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

View File

@@ -1,11 +1,24 @@
namespace WeaponPaints namespace WeaponPaints
{ {
public class PlayerInfo public class PlayerInfo
{ {
public int Index { get; set; } public int Index { get; set; }
public int? UserId { get; set; } public int Slot { get; set; }
public string? SteamId { get; set; } public int? UserId { get; set; }
public string? Name { get; set; } public string? SteamId { get; set; }
public string? IpAddress { get; set; } public string? Name { get; set; }
} public string? IpAddress { get; set; }
public PlayerInfo() { }
public PlayerInfo(int index, int slot, int? userId, string? steamId, string? name, string? ipAddress)
{
Index = index;
Slot = slot;
UserId = userId;
SteamId = steamId;
Name = name;
IpAddress = ipAddress;
}
}
} }

View File

@@ -10,7 +10,7 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
## Features ## Features
- Changes only paint, seed and wear on weapons and knives - Changes only paint, seed and wear on weapons and knives
- MySQL based or global website, so you dont need MySQL/Website - MySQL based
- Data syncs on player connect - Data syncs on player connect
- Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)*** - Added command **`!wp`** to refresh skins ***(with cooldown in seconds can be configured)***
- Added command **`!ws`** to show website - Added command **`!ws`** to show website
@@ -18,13 +18,11 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
- Knife change is now limited to have these cvars empty **`mp_t_default_melee ""`** and **`mp_ct_default_melee ""`** - Knife change is now limited to have these cvars empty **`mp_t_default_melee ""`** and **`mp_ct_default_melee ""`**
- Translations support, submit a PR if you want to share your translation - Translations support, submit a PR if you want to share your translation
**GlobalShare** - global website accessible at [weaponpaints.fun](https://weaponpaints.fun/)
## CS2 Server ## CS2 Server
- Have working CounterStrikeSharp (**with RUNTIME!**) - Have working CounterStrikeSharp (**with RUNTIME!**)
- Download from Release and copy plugin to plugins - Download from Release and copy plugin to plugins
- Run server with plugin, **it will generate config if installed correctly!** - Run server with plugin, **it will generate config if installed correctly!**
- Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** set **`GlobalShare`** to **`true`** for global, or include database credentials - Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`** - In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
## Plugin Configuration ## Plugin Configuration
@@ -32,12 +30,11 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
<summary>Click to expand</summary> <summary>Click to expand</summary>
<code><pre>{ <code><pre>{
"Version": 4, // Don't touch "Version": 4, // Don't touch
"DatabaseHost": "", // MySQL host (required if GlobalShare = false) "DatabaseHost": "", // MySQL host
"DatabasePort": 3306, // MySQL port (required if GlobalShare = false) "DatabasePort": 3306, // MySQL port
"DatabaseUser": "", // MySQL username (required if GlobalShare = false) "DatabaseUser": "", // MySQL username
"DatabasePassword": "", // MySQL user password (required if GlobalShare = false) "DatabasePassword": "", // MySQL user password
"DatabaseName": "", // MySQL database name (required if GlobalShare = false) "DatabaseName": "", // MySQL database name
"GlobalShare": false, // Enable or disable GlobalShare, plugin can work without mysql credentials but with shared website at weaponpaints.fun
"CmdRefreshCooldownSeconds": 60, // Cooldown time in refreshing skins (!wp command) "CmdRefreshCooldownSeconds": 60, // Cooldown time in refreshing skins (!wp command)
"Prefix": "[WeaponPaints]", // Prefix every chat message "Prefix": "[WeaponPaints]", // Prefix every chat message
"Website": "example.com/skins", // Website used in WebsiteMessageCommand (!ws command) "Website": "example.com/skins", // Website used in WebsiteMessageCommand (!ws command)
@@ -74,7 +71,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
</details> </details>
## Web install ## Web install
Disregard if the config is **`GlobalShare = true`**
- Requires PHP >= 7.4 ***(Tested on php ver **`8.2.3`** and nginx webserver)*** - Requires PHP >= 7.4 ***(Tested on php ver **`8.2.3`** and nginx webserver)***
- **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website. - **Before using website, make sure the plugin is correctly loaded in cs2 server!** Mysql tables are created by plugin not by website.
- Copy website to web server ***(Folder `img` not needed)*** - Copy website to web server ***(Folder `img` not needed)***

View File

@@ -10,15 +10,16 @@ public class SchemaString<TSchemaClass> : NativeObject where TSchemaClass : Nati
internal SchemaString(TSchemaClass instance, string member) : base(Schema.GetSchemaValue<nint>(instance.Handle, typeof(TSchemaClass).Name!, member)) internal SchemaString(TSchemaClass instance, string member) : base(Schema.GetSchemaValue<nint>(instance.Handle, typeof(TSchemaClass).Name!, member))
{ } { }
internal unsafe void Set(string str) internal unsafe void Set(string str)
{ {
var bytes = Encoding.UTF8.GetBytes(str); var bytes = Encoding.UTF8.GetBytes(str);
var handle = Handle.ToInt64();
for (var i = 0; i < bytes.Length; i++) for (var i = 0; i < bytes.Length; i++)
{ {
Unsafe.Write((void*)(Handle.ToInt64() + i), bytes[i]); Unsafe.Write((void*)(handle + i), bytes[i]);
} }
Unsafe.Write((void*)(Handle.ToInt64() + bytes.Length), 0); Unsafe.Write((void*)(handle + bytes.Length), 0);
} }
} }

View File

@@ -43,27 +43,33 @@ namespace WeaponPaints
{ {
string[] createTableQueries = new[] string[] createTableQueries = new[]
{ {
@"CREATE TABLE IF NOT EXISTS `wp_player_skins` ( @"CREATE TABLE IF NOT EXISTS `wp_player_skins` (
`steamid` varchar(64) NOT NULL, `steamid` varchar(64) NOT NULL,
`weapon_defindex` int(6) NOT NULL, `weapon_defindex` int(6) NOT NULL,
`weapon_paint_id` int(6) NOT NULL, `weapon_paint_id` int(6) NOT NULL,
`weapon_wear` float NOT NULL DEFAULT 0.000001, `weapon_wear` float NOT NULL DEFAULT 0.000001,
`weapon_seed` int(16) NOT NULL DEFAULT 0 `weapon_seed` int(16) NOT NULL DEFAULT 0
) ENGINE=InnoDB", ) ENGINE=InnoDB",
@"CREATE TABLE IF NOT EXISTS `wp_player_knife` ( @"CREATE TABLE IF NOT EXISTS `wp_player_knife` (
`steamid` varchar(64) NOT NULL, `steamid` varchar(64) NOT NULL,
`knife` varchar(64) NOT NULL, `knife` varchar(64) NOT NULL,
UNIQUE (`steamid`) UNIQUE (`steamid`)
) ENGINE = InnoDB", ) ENGINE = InnoDB",
@"CREATE TABLE IF NOT EXISTS `wp_player_gloves` ( @"CREATE TABLE IF NOT EXISTS `wp_player_gloves` (
`steamid` varchar(64) NOT NULL, `steamid` varchar(64) NOT NULL,
`weapon_defindex` int(11) NOT NULL, `weapon_defindex` int(11) NOT NULL,
`paint` int(11) NOT NULL, UNIQUE (`steamid`)
UNIQUE (`steamid`) ) ENGINE=InnoDB"
) ENGINE=InnoDB" };
}; /*string[] createTableQueries = new[]
{
foreach (var query in createTableQueries) @"CREATE TABLE IF NOT EXISTS `wp_players` (`steamid` BIGINT UNSIGNED NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
@"CREATE TABLE IF NOT EXISTS `wp_players_skins` (`steamid` BIGINT UNSIGNED NOT NULL, `team` SMALLINT UNSIGNED NOT NULL, `weapon` SMALLINT UNSIGNED NOT NULL, `paint` SMALLINT UNSIGNED NOT NULL, `wear` FLOAT NOT NULL DEFAULT 0.00001, `seed` SMALLINT UNSIGNED NOT NULL DEFAULT 0, `nametag` VARCHAR(20) DEFAULT NULL, `stattrack` INT UNSIGNED NOT NULL DEFAULT 0, `stattrack_enabled` SMALLINT NOT NULL DEFAULT 0, PRIMARY KEY (`steamid`,`weapon`,`team`), FOREIGN KEY (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
@"CREATE TABLE IF NOT EXISTS `wp_players_knife` (`steamid` BIGINT UNSIGNED NOT NULL, `knife_t` SMALLINT UNSIGNED NOT NULL, `knife_ct` SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (`steamid`), FOREIGN KEY (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
@"CREATE TABLE IF NOT EXISTS `wp_players_music` (`steamid` BIGINT UNSIGNED NOT NULL, `music` SMALLINT UNSIGNED DEFAULT NULL, PRIMARY KEY (`steamid`), FOREIGN KEY (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;",
@"CREATE TABLE IF NOT EXISTS `wp_players_gloves` (`steamid` BIGINT UNSIGNED NOT NULL, `glove_t` SMALLINT UNSIGNED NOT NULL, `glove_ct` SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (`steamid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"
};*/
foreach (var query in createTableQueries)
{ {
await connection.ExecuteAsync(query, transaction: transaction); await connection.ExecuteAsync(query, transaction: transaction);
} }
@@ -86,8 +92,8 @@ namespace WeaponPaints
{ {
if (player is null) return false; if (player is null) return false;
return (player is not null && player.IsValid && !player.IsBot && !player.IsHLTV return (player is not null && player.IsValid && !player.IsBot && !player.IsHLTV && player.UserId.HasValue
&& WeaponPaints.weaponSync != null && player.Connected == PlayerConnectedState.PlayerConnected); && WeaponPaints.weaponSync != null && player.Connected == PlayerConnectedState.PlayerConnected && player.SteamID.ToString().Length == 17);
} }
internal static void LoadSkinsFromFile(string filePath) internal static void LoadSkinsFromFile(string filePath)

View File

@@ -1 +1 @@
1.8a 1.9b

View File

@@ -1,6 +1,7 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -12,12 +13,9 @@ namespace WeaponPaints
internal static void ChangeWeaponAttributes(CBasePlayerWeapon? weapon, CCSPlayerController? player, bool isKnife = false) internal static void ChangeWeaponAttributes(CBasePlayerWeapon? weapon, CCSPlayerController? player, bool isKnife = false)
{ {
if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return; if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return;
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out _)) return;
int playerIndex = (int)player.Index; if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
if (!gPlayerWeaponsInfo.ContainsKey(playerIndex)) return;
if (isKnife && !g_playersKnife.ContainsKey(playerIndex) || isKnife && g_playersKnife[playerIndex] == "weapon_knife") return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex; int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
@@ -29,7 +27,7 @@ namespace WeaponPaints
int fallbackPaintKit = weapon.FallbackPaintKit; int fallbackPaintKit = weapon.FallbackPaintKit;
if (_config.Additional.GiveRandomSkin && if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex)) !gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
{ {
// Random skins // Random skins
weapon.AttributeManager.Item.ItemID = 16384; weapon.AttributeManager.Item.ItemID = 16384;
@@ -86,8 +84,8 @@ namespace WeaponPaints
return; return;
} }
if (!gPlayerWeaponsInfo[playerIndex].ContainsKey(weaponDefIndex)) return; if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) return;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[playerIndex][weaponDefIndex]; 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]}"); //Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
weapon.AttributeManager.Item.ItemID = 16384; weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF; weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
@@ -143,38 +141,41 @@ namespace WeaponPaints
{ {
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return; if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
string knifeToGive; WeaponPaints.Instance.AddTimer(1.0f, () =>
if (g_playersKnife.TryGetValue((int)player.Index, out var knife))
{ {
knifeToGive = knife; string knifeToGive;
} if (g_playersKnife.TryGetValue(player.Slot, out var knife))
else if (_config.Additional.GiveRandomKnife)
{
var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList();
if (knifeTypes.Count == 0)
{ {
Utility.Log("No valid knife types found."); knifeToGive = knife;
return; }
else if (_config.Additional.GiveRandomKnife)
{
var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList();
if (knifeTypes.Count == 0)
{
Utility.Log("No valid knife types found.");
return;
}
Random random = new();
int index = random.Next(knifeTypes.Count);
knifeToGive = knifeTypes[index].Key;
}
else
{
knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
} }
Random random = new(); player.GiveNamedItem(knifeToGive);
int index = random.Next(knifeTypes.Count); });
knifeToGive = knifeTypes[index].Key;
}
else
{
knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
}
player.GiveNamedItem(knifeToGive);
} }
internal static bool PlayerHasKnife(CCSPlayerController? player) internal static bool PlayerHasKnife(CCSPlayerController? player)
{ {
if (!_config.Additional.KnifeEnabled) return false; if (!_config.Additional.KnifeEnabled) return false;
if (player == null || !player.IsValid || player.PlayerPawn == null || !player.PlayerPawn.IsValid || !player.PawnIsAlive) if (player == null || !player.IsValid || player.PlayerPawn == null || !player.PlayerPawn.IsValid)
{ {
return false; return false;
} }
@@ -201,125 +202,130 @@ namespace WeaponPaints
{ {
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) if (player == null || !player.IsValid || player.PlayerPawn?.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE)
return; return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
return; return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons == null || weapons.Count == 0) if (weapons == null || weapons.Count == 0)
return; return;
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator)
return;
if (weapons != null && weapons.Count > 0) //Dictionary<string, (int, int)> weaponsWithAmmo = new Dictionary<string, (int, int)>();
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>();
// Iterate through each weapon
foreach (var weapon in weapons)
{ {
//Dictionary<string, (int, int)> weaponsWithAmmo = new Dictionary<string, (int, int)>(); if (weapon == null || !weapon.IsValid || weapon.Value == null ||
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>(); !weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
bool bomb = false; continue;
bool defuser = player.PawnHasDefuser;
bool healthshot = false;
// Iterate through each weapon CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>();
foreach (var weapon in weapons)
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
{ {
if (weapon == null || !weapon.IsValid || weapon.Value == null || string? weaponByDefindex = null;
!weapon.Value.IsValid || !weapon.Value.DesignerName.Contains("weapon_"))
continue;
try 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)
{ {
string? weaponByDefindex = null; if (!WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex, out weaponByDefindex))
continue;
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData; int clip1 = weapon.Value.Clip1;
int reservedAmmo = weapon.Value.ReserveAmmo[0];
if (weaponData != null) if (!weaponsWithAmmo.ContainsKey(weaponByDefindex))
{ {
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_C4) weaponsWithAmmo.Add(weaponByDefindex, new List<(int, int)>());
bomb = true;
if (weaponData.Name.Equals("weapon_healtshot"))
healthshot = true;
if (weaponData.GearSlot == gear_slot_t.GEAR_SLOT_GRENADES || weaponData.GearSlot == gear_slot_t.GEAR_SLOT_UTILITY || weaponData.GearSlot == gear_slot_t.GEAR_SLOT_BOOSTS)
{
int clip1 = weapon.Value.Clip1;
int reservedAmmo = weapon.Value.ReserveAmmo[0];
weaponsWithAmmo.Add(weapon.Value.DesignerName, new List<(int, int)>() { (clip1, reservedAmmo) });
}
} }
if (!weapon.Value.DesignerName.Contains("knife") && WeaponDefindex.TryGetValue(weapon.Value.AttributeManager.Item.ItemDefinitionIndex, out weaponByDefindex) && weaponByDefindex != null) weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
{
int clip1 = weapon.Value.Clip1;
int reservedAmmo = weapon.Value.ReserveAmmo[0];
if (!weaponsWithAmmo.ContainsKey(weaponByDefindex))
{
weaponsWithAmmo.Add(weaponByDefindex, new List<(int, int)>());
}
weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
}
} }
catch (Exception ex)
//player.RemoveItemByDesignerName(weapon.Value.DesignerName, false);
}
catch (Exception ex)
{
Logger.LogWarning(ex.Message);
continue;
}
}
for (int i = 1; i <= 3; i++)
{
player.ExecuteClientCommand($"slot {i}");
player.ExecuteClientCommand($"slot {i}");
AddTimer(0.1f, () =>
{
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value;
CCSWeaponBaseGun? gun = weapon?.As<CCSWeaponBaseGun>();
if (gun == null || gun.VData == null) return;
if (gun?.VData?.GearSlot == gear_slot_t.GEAR_SLOT_C4 || gun?.VData?.GearSlot == gear_slot_t.GEAR_SLOT_GRENADES) return;
player.DropActiveWeapon();
AddTimer(0.22f, () =>
{ {
Logger.LogWarning(ex.Message); if (gun != null && gun.IsValid && gun.State == CSWeaponState_t.WEAPON_NOT_CARRIED)
continue; {
weapon?.Remove();
}
});
});
}
AddTimer(1.2f, () =>
{
GiveKnifeToPlayer(player);
foreach (var entry in weaponsWithAmmo)
{
foreach (var ammo in entry.Value)
{
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
Server.NextFrame(() =>
{
try
{
if (newWeapon != null)
{
newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2;
}
}
catch (Exception ex)
{
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
}
});
} }
} }
}, TimerFlags.STOP_ON_MAPCHANGE);
player.RemoveWeapons();
AddTimer(0.35f, () =>
{
GiveKnifeToPlayer(player);
if (bomb)
player.GiveNamedItem("weapon_c4");
if (defuser)
{
var itemServ = player.PlayerPawn?.Value?.ItemServices;
if (itemServ != null)
{
var items = new CCSPlayer_ItemServices(itemServ.Handle);
items.HasDefuser = true;
}
}
if (healthshot)
player.GiveNamedItem("weapon_healtshot");
foreach (var entry in weaponsWithAmmo)
{
foreach (var ammo in entry.Value)
{
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
Server.NextFrame(() =>
{
try
{
if (newWeapon != null)
{
newWeapon.Clip1 = ammo.Item1;
newWeapon.ReserveAmmo[0] = ammo.Item2;
}
}
catch (Exception ex)
{
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
}
});
}
}
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
} }
internal void RefreshKnife(CCSPlayerController? player) internal void RefreshKnife(CCSPlayerController? player)
{ {
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE) if (player == null || !player.IsValid || player.PlayerPawn?.Value == null)
return; return;
if (player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null) if (player.PlayerPawn.Value.WeaponServices == null)
return; return;
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
@@ -335,8 +341,10 @@ namespace WeaponPaints
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{ {
RefreshWeapons(player); player.ExecuteClientCommand("slot 3");
break;
weapon.Value.Remove();
GiveKnifeToPlayer(player);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -348,6 +356,57 @@ namespace WeaponPaints
} }
} }
private static void RefreshGloves(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)
return;
string model = pawn.CBodyComponent?.SceneNode?.GetSkeletonInstance()?.ModelState.ModelName ?? string.Empty;
if (!string.IsNullOrEmpty(model))
{
pawn.SetModel("characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl");
pawn.SetModel(model);
}
Instance.AddTimer(0.06f, () =>
{
try
{
if (player == null || !player.IsValid)
return;
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
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;
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][gloveInfo];
CEconItemView item = pawn.EconGloves;
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);
item.Initialized = true;
CBaseModelEntity_SetBodygroup.Invoke(pawn, "default_gloves", 1);
}
}
catch (Exception) { }
}, TimerFlags.STOP_ON_MAPCHANGE);
}
private static int GetRandomPaint(int defindex) private static int GetRandomPaint(int defindex)
{ {
if (skinsList == null || skinsList.Count == 0) if (skinsList == null || skinsList.Count == 0)
@@ -375,18 +434,6 @@ namespace WeaponPaints
return new CSkeletonInstance(GetSkeletonInstance(node.Handle)); return new CSkeletonInstance(GetSkeletonInstance(node.Handle));
} }
public void SetOrAddAttributeValueByName(CAttributeList attr, string name, float f)
{
var SetAttr = VirtualFunction.Create<IntPtr, string, float, int>("\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78");
SetAttr(attr.Handle, name, f);
}
public void SetPlayerBody(CCSPlayerController player, string model, int i)
{
var SetBody = VirtualFunction.Create<IntPtr, string, int, int>("\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08");
SetBody(player.PlayerPawn.Value!.Handle, model, i);
}
private static unsafe CHandle<CBaseViewModel>[]? GetPlayerViewModels(CCSPlayerController player) private static unsafe CHandle<CBaseViewModel>[]? GetPlayerViewModels(CCSPlayerController player)
{ {
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null; if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;

View File

@@ -1,9 +1,18 @@
namespace WeaponPaints namespace WeaponPaints
{ {
public class WeaponInfo public class WeaponInfo
{ {
public int Paint { get; set; } public int Paint { get; set; }
public int Seed { get; set; } public int Seed { get; set; }
public float Wear { get; set; } public float Wear { get; set; }
}
public WeaponInfo() : this(0, 0, 0f) { }
public WeaponInfo(int paint, int seed, float wear)
{
Paint = paint;
Seed = seed;
Wear = wear;
}
}
} }

View File

@@ -1,7 +1,7 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Cvars; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MySqlConnector; using MySqlConnector;
@@ -10,10 +10,12 @@ using System.Collections.Concurrent;
namespace WeaponPaints; namespace WeaponPaints;
[MinimumApiVersion(167)] [MinimumApiVersion(168)]
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig> public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{ {
internal static readonly Dictionary<string, string> weaponList = new() internal static WeaponPaints Instance { get; private set; } = new();
internal static readonly int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
internal static readonly Dictionary<string, string> weaponList = new()
{ {
{"weapon_deagle", "Desert Eagle"}, {"weapon_deagle", "Desert Eagle"},
{"weapon_elite", "Dual Berettas"}, {"weapon_elite", "Dual Berettas"},
@@ -77,19 +79,20 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
internal static IStringLocalizer? _localizer; internal static IStringLocalizer? _localizer;
internal static Dictionary<int, int> g_knifePickupCount = new Dictionary<int, int>(); 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, string> g_playersKnife = new ConcurrentDictionary<int, string>();
internal static ConcurrentDictionary<uint, (ushort Definition, int Paint)> g_playersGlove = new ConcurrentDictionary<uint, (ushort Definition, int Paint)>(); internal static ConcurrentDictionary<int, ushort> g_playersGlove = new ConcurrentDictionary<int, ushort>();
internal static ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>>(); 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> skinsList = new List<JObject>();
internal static List<JObject> glovesList = new List<JObject>(); internal static List<JObject> glovesList = new List<JObject>();
internal static WeaponSynchronization? weaponSync; internal static WeaponSynchronization? weaponSync;
internal bool g_bCommandsAllowed = true; public static bool g_bCommandsAllowed = true;
internal Dictionary<int, string> PlayerWeaponImage = new(); internal Dictionary<int, string> PlayerWeaponImage = new();
internal Uri GlobalShareApi = new("https://weaponpaints.fun/api.php");
internal int GlobalShareServerId = 0;
internal static Dictionary<int, DateTime> commandsCooldown = new Dictionary<int, DateTime>(); internal static Dictionary<int, DateTime> commandsCooldown = new Dictionary<int, DateTime>();
internal static Database? _database; 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"));
public static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string> public static Dictionary<int, string> WeaponDefindex { get; } = new Dictionary<int, string>
{ {
{ 1, "weapon_deagle" }, { 1, "weapon_deagle" },
@@ -148,12 +151,12 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ 525, "weapon_knife_skeleton" }, { 525, "weapon_knife_skeleton" },
{ 526, "weapon_knife_kukri" } { 526, "weapon_knife_kukri" }
}; };
public static MemoryFunctionVoid<IntPtr, string, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr> GiveNamedItem2 = new(@"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x83\xEC\x18\x48\x89\x7D\xC8\x48\x85\xF6\x74");
public WeaponPaintsConfig Config { get; set; } = new(); public WeaponPaintsConfig Config { get; set; } = new();
public override string ModuleAuthor => "Nereziel & daffyy"; public override string ModuleAuthor => "Nereziel & daffyy";
public override string ModuleDescription => "Skin, gloves and knife selector, standalone and web-based"; public override string ModuleDescription => "Skin, gloves and knife selector, standalone and web-based";
public override string ModuleName => "WeaponPaints"; public override string ModuleName => "WeaponPaints";
public override string ModuleVersion => "1.8a"; public override string ModuleVersion => "1.9b";
public static WeaponPaintsConfig GetWeaponPaintsConfig() public static WeaponPaintsConfig GetWeaponPaintsConfig()
{ {
@@ -162,6 +165,8 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
Instance = this;
if (hotReload) if (hotReload)
{ {
OnMapStart(string.Empty); OnMapStart(string.Empty);
@@ -172,25 +177,30 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected) player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected)
continue; continue;
g_knifePickupCount[(int)player.Index] = 0; g_knifePickupCount[(int)player.Slot] = 0;
gPlayerWeaponsInfo.TryRemove((int)player.Index, out _); gPlayerWeaponsInfo.TryRemove((int)player.Slot, out _);
g_playersKnife.TryRemove((int)player.Index, out _); g_playersKnife.TryRemove((int)player.Slot, out _);
PlayerInfo playerInfo = new PlayerInfo PlayerInfo playerInfo = new PlayerInfo(
{ (int)player.Slot,
UserId = player.UserId, player.Slot,
Index = (int)player.Index, player.UserId,
SteamId = player?.SteamID.ToString(), player?.SteamID.ToString(),
Name = player?.PlayerName, player?.PlayerName,
IpAddress = player?.IpAddress?.Split(":")[0] player?.IpAddress?.Split(":")[0]);
};
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
_ = weaponSync.GetWeaponPaintsFromDatabase(playerInfo); {
Task.Run(() => weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
}
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
_ = weaponSync.GetKnifeFromDatabase(playerInfo); {
Task.Run(() => weaponSync.GetKnifeFromDatabase(playerInfo));
}
if (Config.Additional.GloveEnabled) if (Config.Additional.GloveEnabled)
_ = weaponSync.GetGloveFromDatabase(playerInfo); {
Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo));
}
} }
} }
@@ -207,32 +217,37 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
RegisterListeners(); RegisterListeners();
RegisterCommands(); RegisterCommands();
} }
public static void PlayerGiveNamedItem(CCSPlayerController player, string item)
{
if (!player.PlayerPawn.IsValid) return;
if (player.PlayerPawn.Value == null) return;
if (!player.PlayerPawn.Value.IsValid) return;
if (player.PlayerPawn.Value.ItemServices == null) return;
public void OnConfigParsed(WeaponPaintsConfig config) GiveNamedItem2.Invoke(player.PlayerPawn.Value.ItemServices.Handle, item, 0, 0, 0, 0, 0, 0);
}
public void OnConfigParsed(WeaponPaintsConfig config)
{ {
if (!config.GlobalShare) if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1)
{ {
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 config!");
throw new Exception("[WeaponPaints] You need to setup Database credentials in config!");
}
var builder = new MySqlConnectionStringBuilder
{
Server = config.DatabaseHost,
UserID = config.DatabaseUser,
Password = config.DatabasePassword,
Database = config.DatabaseName,
Port = (uint)config.DatabasePort,
Pooling = true
};
_database = new(builder.ConnectionString);
_ = Utility.CheckDatabaseTables();
} }
var builder = new MySqlConnectionStringBuilder
{
Server = config.DatabaseHost,
UserID = config.DatabaseUser,
Password = config.DatabasePassword,
Database = config.DatabaseName,
Port = (uint)config.DatabasePort,
Pooling = true
};
_database = new(builder.ConnectionString);
_ = Utility.CheckDatabaseTables();
Config = config; Config = config;
_config = config; _config = config;
_localizer = Localizer; _localizer = Localizer;
@@ -246,41 +261,4 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ {
base.Unload(hotReload); base.Unload(hotReload);
} }
private void GlobalShareConnect()
{
if (!Config.GlobalShare) return;
var values = new Dictionary<string, string>
{
{ "server_address", $"{ConVar.Find("ip")!.StringValue}:{ConVar.Find("hostport")!.GetPrimitiveValue<int>().ToString()}" },
{ "server_hostname", ConVar.Find("hostname")!.StringValue }
};
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = GlobalShareApi;
var formContent = new FormUrlEncodedContent(values);
Task<HttpResponseMessage> responseTask = httpClient.PostAsync("", formContent);
responseTask.Wait();
HttpResponseMessage response = responseTask.Result;
if (response.IsSuccessStatusCode)
{
Task<string> responseBodyTask = response.Content.ReadAsStringAsync();
responseBodyTask.Wait();
string responseBody = responseBodyTask.Result;
GlobalShareServerId = int.Parse(responseBody);
}
else
{
Logger.LogError("Unable to retrieve serverid from GlobalShare!");
throw new Exception("[WeaponPaints] Unable to retrieve serverid from GlobalShare!");
}
}
Logger.LogInformation("GlobalShare ONLINE!");
Console.WriteLine("[WeaponPaints] GlobalShare ONLINE");
}
} }

View File

@@ -9,7 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.168" /> <PackageReference Include="CounterStrikeSharp.API" Version="1.0.172" />
<PackageReference Include="Dapper" Version="2.1.28" /> <PackageReference Include="Dapper" Version="2.1.28" />
<PackageReference Include="MySqlConnector" Version="2.3.5" /> <PackageReference Include="MySqlConnector" Version="2.3.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

View File

@@ -1,5 +1,4 @@
using Dapper; using Dapper;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent; using System.Collections.Concurrent;
namespace WeaponPaints namespace WeaponPaints
@@ -8,68 +7,25 @@ namespace WeaponPaints
{ {
private readonly WeaponPaintsConfig _config; private readonly WeaponPaintsConfig _config;
private readonly Database _database; private readonly Database _database;
private readonly Uri _globalShareApi;
private readonly int _globalShareServerId;
internal WeaponSynchronization(Database database, WeaponPaintsConfig config, Uri globalShareApi, int globalShareServerId) internal WeaponSynchronization(Database database, WeaponPaintsConfig config)
{ {
_database = database; _database = database;
_config = config; _config = config;
_globalShareApi = globalShareApi;
_globalShareServerId = globalShareServerId;
} }
internal async Task GetKnifeFromDatabase(PlayerInfo player) internal async Task GetKnifeFromDatabase(PlayerInfo player)
{ {
if (!_config.Additional.KnifeEnabled) return; if (!_config.Additional.KnifeEnabled) return;
if (player.SteamId == null || player.Index == 0) return;
try try
{ {
if (_config.GlobalShare)
{
var values = new Dictionary<string, string>
{
{ "server_id", _globalShareServerId.ToString() },
{ "steamid", player.SteamId },
{ "knife", "1" }
};
UriBuilder builder = new UriBuilder(_globalShareApi);
builder.Query = string.Join("&", values.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = _globalShareApi;
var formContent = new FormUrlEncodedContent(values);
HttpResponseMessage response = await httpClient.GetAsync(builder.Uri);
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(result))
{
WeaponPaints.g_playersKnife[player.Index] = result;
}
else
{
return;
}
}
else
{
return;
}
}
return;
}
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid"; string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
string? playerKnife = await connection.QueryFirstOrDefaultAsync<string>(query, new { steamid = player.SteamId }); string? playerKnife = await connection.QueryFirstOrDefaultAsync<string>(query, new { steamid = player.SteamId });
if (!string.IsNullOrEmpty(playerKnife)) if (!string.IsNullOrEmpty(playerKnife))
{ {
WeaponPaints.g_playersKnife[player.Index] = playerKnife; WeaponPaints.g_playersKnife[player.Slot] = playerKnife;
} }
} }
catch (Exception e) catch (Exception e)
@@ -82,116 +38,75 @@ namespace WeaponPaints
internal async Task GetGloveFromDatabase(PlayerInfo player) internal async Task GetGloveFromDatabase(PlayerInfo player)
{ {
if (!_config.Additional.GloveEnabled) return; if (!_config.Additional.GloveEnabled) return;
try try
{ {
// Ensure proper disposal of resources using "using" statement
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "SELECT `weapon_defindex`, `paint` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
var gloveData = await connection.QueryFirstOrDefaultAsync<(ushort Definition, int Paint)>(query, new { steamid = player.SteamId });
if (gloveData != default) // Construct the SQL query with specific columns for better performance
string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
// Execute the query and retrieve glove data
ushort? gloveData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
// Check if glove data is retrieved successfully
if (gloveData != null)
{ {
WeaponPaints.g_playersGlove[(uint)player.Index] = gloveData; // Update g_playersGlove dictionary with glove data
WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
} }
} }
catch (Exception e) catch (Exception e)
{ {
Utility.Log(e.Message); // Log any exceptions occurred during database operation
return; Utility.Log("An error occurred while fetching glove data: " + e.Message);
} }
} }
internal async Task GetWeaponPaintsFromDatabase(PlayerInfo player) internal async Task GetWeaponPaintsFromDatabase(PlayerInfo player)
{ {
if (!_config.Additional.SkinEnabled) return; if (!_config.Additional.SkinEnabled || player == null || player.SteamId == null) return;
if (!WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Index, out _))
{
WeaponPaints.gPlayerWeaponsInfo[player.Index] = new ConcurrentDictionary<int, WeaponInfo>();
}
try try
{ {
if (_config.GlobalShare)
{
var values = new Dictionary<string, string>
{
{ "server_id", _globalShareServerId.ToString() },
{ "steamid", player.SteamId },
{ "skins", "1" }
};
UriBuilder builder = new UriBuilder(_globalShareApi);
builder.Query = string.Join("&", values.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = _globalShareApi;
var formContent = new FormUrlEncodedContent(values);
HttpResponseMessage response = await httpClient.GetAsync(builder.Uri);
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
JArray jsonArray = JArray.Parse(responseBody);
if (jsonArray != null && jsonArray.Count > 0)
{
foreach (var weapon in jsonArray)
{
int? weaponDefIndex = weapon["weapon_defindex"]?.Value<int>();
int? weaponPaintId = weapon["weapon_paint_id"]?.Value<int>();
float? weaponWear = weapon["weapon_wear"]?.Value<float>();
int? weaponSeed = weapon["weapon_seed"]?.Value<int>();
if (weaponDefIndex != null && weaponPaintId != null && weaponWear != null && weaponSeed != null)
{
WeaponInfo weaponInfo = new WeaponInfo
{
Paint = weaponPaintId.Value,
Seed = weaponSeed.Value,
Wear = weaponWear.Value
};
WeaponPaints.gPlayerWeaponsInfo[player.Index][weaponDefIndex.Value] = weaponInfo;
}
}
}
return;
}
else
{
return;
}
}
}
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid"; string query = "SELECT `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed` FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = await connection.QueryAsync<dynamic>(query, new { steamid = player.SteamId });
var playerSkins = await connection.QueryAsync<dynamic>(query, new { steamid = player.SteamId });
if (playerSkins == null) return;
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
foreach (var row in playerSkins) foreach (var row in playerSkins)
{ {
int? weaponDefIndex = row.weapon_defindex; int weaponDefIndex = row?.weapon_defindex ?? 0;
int? weaponPaintId = row.weapon_paint_id; int weaponPaintId = row?.weapon_paint_id ?? 0;
float? weaponWear = row.weapon_wear; float weaponWear = row?.weapon_wear ?? 0f;
int? weaponSeed = row.weapon_seed; int weaponSeed = row?.weapon_seed ?? 0;
WeaponInfo weaponInfo = new WeaponInfo WeaponInfo weaponInfo = new WeaponInfo
{ {
Paint = weaponPaintId.HasValue ? weaponPaintId.Value : 0, Paint = weaponPaintId,
Seed = weaponSeed.HasValue ? weaponSeed.Value : 0, Seed = weaponSeed,
Wear = weaponWear.HasValue ? weaponWear.Value : 0f Wear = weaponWear
}; };
WeaponPaints.gPlayerWeaponsInfo[player.Index][weaponDefIndex.GetValueOrDefault()] = weaponInfo; weaponInfos[weaponDefIndex] = weaponInfo;
} }
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
} }
catch (Exception e) catch (Exception e)
{ {
Utility.Log(e.Message); Utility.Log($"Database error occurred: {e.Message}");
return;
} }
} }
internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife) internal async Task SyncKnifeToDatabase(PlayerInfo player, string knife)
{ {
if (!_config.Additional.KnifeEnabled) return; if (!_config.Additional.KnifeEnabled || player == null || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife)) return;
try try
{ {
@@ -201,53 +116,65 @@ namespace WeaponPaints
} }
catch (Exception e) catch (Exception e)
{ {
Utility.Log(e.Message); Utility.Log($"Error syncing knife to database: {e.Message}");
} }
} }
internal async Task SyncGloveToDatabase(PlayerInfo player, ushort defindex, int paint)
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
{ {
if (!_config.Additional.GloveEnabled) return; if (!_config.Additional.GloveEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
try try
{ {
await using var connection = await _database.GetConnectionAsync(); await using var connection = await _database.GetConnectionAsync();
string query = "INSERT INTO `wp_player_gloves` (`steamid`, `weapon_defindex`, `paint`) VALUES(@steamid, @weapon_defindex, @paint) ON DUPLICATE KEY UPDATE `weapon_defindex` = @weapon_defindex, `paint` = @paint"; 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, paint }); await connection.ExecuteAsync(query, new { steamid = player.SteamId, weapon_defindex = defindex });
} }
catch (Exception e) catch (Exception e)
{ {
Utility.Log(e.Message); Utility.Log($"Error syncing glove to database: {e.Message}");
} }
} }
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player) internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
{ {
if (player == null || player.Index <= 0 || player.SteamId == null) return; if (player == null || string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
await using var connection = await _database.GetConnectionAsync();
if (!WeaponPaints.gPlayerWeaponsInfo.ContainsKey(player.Index))
return; return;
foreach (var weaponInfoPair in WeaponPaints.gPlayerWeaponsInfo[player.Index]) try
{ {
int weaponDefIndex = weaponInfoPair.Key; await using var connection = await _database.GetConnectionAsync();
WeaponInfo weaponInfo = weaponInfoPair.Value;
int paintId = weaponInfo.Paint; foreach (var weaponInfoPair in weaponsInfo)
float wear = weaponInfo.Wear; {
int seed = weaponInfo.Seed; int weaponDefIndex = weaponInfoPair.Key;
WeaponInfo weaponInfo = weaponInfoPair.Value;
string updateSql = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, " + int paintId = weaponInfo.Paint;
"`weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + float wear = weaponInfo.Wear;
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed) " + int seed = weaponInfo.Seed;
"ON DUPLICATE KEY UPDATE `weapon_paint_id` = @paintId, " +
"`weapon_wear` = @wear, `weapon_seed` = @seed";
var updateParams = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed }; string query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " +
await connection.ExecuteAsync(updateSql, updateParams); "VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed) " +
"ON DUPLICATE KEY UPDATE `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed";
var parameters = new DynamicParameters();
parameters.Add("@steamid", player.SteamId);
parameters.Add("@weaponDefIndex", weaponDefIndex);
parameters.Add("@paintId", paintId);
parameters.Add("@wear", wear);
parameters.Add("@seed", seed);
await connection.ExecuteAsync(query, parameters);
}
}
catch (Exception e)
{
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
} }
} }
} }
} }

16
gamedata/gloves.json Normal file
View File

@@ -0,0 +1,16 @@
{
"CAttributeList_SetOrAddAttributeValueByName": {
"signatures": {
"library": "server",
"windows": "\\x40\\x53\\x41\\x56\\x41\\x57\\x48\\x81\\xEC\\x90\\x00\\x00\\x00\\x0F\\x29\\x74\\x24\\x70",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xFE\\x41\\x55\\x41\\x54\\x49\\x89\\xF4\\x53\\x48\\x83\\xEC\\x78"
}
},
"CBaseModelEntity_SetBodygroup": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x08\\x48\\x89\\x74\\x24\\x10\\x57\\x48\\x83\\xEC\\x20\\x41\\x8B\\xF8\\x48\\x8B\\xF2\\x48\\x8B\\xD9\\xE8\\x2A\\x2A\\x2A\\x2A",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xD5\\x41\\x54\\x49\\x89\\xFC\\x48\\x83\\xEC\\x08"
}
}
}

View File

@@ -7,7 +7,7 @@
"wp_command_cooldown": "{lightred}Nie możesz teraz odświeżyć skórek broni", "wp_command_cooldown": "{lightred}Nie możesz teraz odświeżyć skórek broni",
"wp_command_refresh_done": "{lime}Odświeżanie skórek broni", "wp_command_refresh_done": "{lime}Odświeżanie skórek broni",
"wp_knife_menu_select": "Wybrałeś {lime}{0}{default} jako swój nóż", "wp_knife_menu_select": "Wybrałeś {lime}{0}{default} jako swój nóż",
"wp_knife_menu_kill": "", "wp_knife_menu_kill": "{lime}Wybrane skiny będą ustawione dopiero po ponownym wejściu na serwer lub wpisaniu komendy {orange}!kill",
"wp_knife_menu_title": "Menu Noży", "wp_knife_menu_title": "Menu Noży",
"wp_glove_menu_select": "Wybrałeś {lime}{0}{default} jako swoje rękawiczki", "wp_glove_menu_select": "Wybrałeś {lime}{0}{default} jako swoje rękawiczki",
"wp_glove_menu_title": "Menu Rękawiczek", "wp_glove_menu_title": "Menu Rękawiczek",