Compare commits

..

27 Commits

Author SHA1 Message Date
Nereziel
683f9f2a1c fix deagle thingy 2024-10-05 00:02:17 +02:00
Nereziel
a70e2f771e Update README.md 2024-10-04 13:16:14 +02:00
Nereziel
f4e6a4338d Update README.md 2024-10-04 13:15:26 +02:00
Nereziel
edd3733940 updated new skins and added optional languages
to use another lang just rename it to skins.json
2024-10-04 10:36:37 +02:00
Nereziel
492b8a7976 Merge pull request #303 from stefanx111/fix-armory-update
fix gamedata
2024-10-04 01:10:31 +02:00
Dawid Bepierszcz
6db3d00893 Update weaponpaints.json 2024-10-04 00:02:40 +02:00
StefanX
fc79381e1e fix gamedata 2024-10-04 00:34:59 +03: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
108 changed files with 659 additions and 12771 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,7 +27,7 @@ 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);
@@ -34,30 +35,8 @@ namespace WeaponPaints
if (weaponSync != null)
{
_ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
/*
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));
}
*/
RefreshGloves(player);
GivePlayerGloves(player);
RefreshWeapons(player);
}
@@ -107,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()
@@ -141,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);
@@ -152,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)
{
@@ -193,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;
@@ -210,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
@@ -218,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
@@ -338,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);
@@ -354,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
@@ -453,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);
@@ -473,7 +437,7 @@ 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 &&
@@ -482,7 +446,6 @@ namespace WeaponPaints
if (selectedAgent == null) return;
if (
selectedAgent != null &&
selectedAgent.ContainsKey("model")
)
{
@@ -498,7 +461,7 @@ namespace WeaponPaints
if (Config.Additional.ShowSkinImage)
{
string image = selectedAgent["image"]?.ToString() ?? "";
var image = selectedAgent["image"]?.ToString() ?? "";
PlayerWeaponImage[player.Slot] = image;
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
}
@@ -539,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;
}
@@ -561,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);
@@ -580,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
{
@@ -672,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
@@ -687,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();
}
}

159
Events.cs
View File

@@ -15,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
@@ -54,7 +54,7 @@ namespace WeaponPaints
}
*/
}
catch (Exception)
catch
{
}
@@ -64,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)
{
@@ -104,100 +93,10 @@ namespace WeaponPaints
return HookResult.Continue;
}
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
{
if (!Config.Additional.SkinEnabled) return;
if (!gPlayerWeaponsInfo.TryGetValue(player.Slot, out System.Collections.Concurrent.ConcurrentDictionary<int, WeaponInfo>? _value)) return;
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
{
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
weapon.AttributeManager.Item.EntityQuality = 3;
}
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0;
if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
{
// Random skins
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
weapon.FallbackSeed = 0;
weapon.FallbackWear = 0.000001f;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
return;
}
if (!gPlayerWeaponsInfo[player.Slot].TryGetValue(weaponDefIndex, out WeaponInfo? value) || value.Paint == 0) return;
WeaponInfo weaponInfo = value;
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
weapon.AttributeManager.Item.ItemID = 16384;
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
weapon.FallbackPaintKit = weaponInfo.Paint;
weapon.FallbackSeed = weaponInfo.Seed;
weapon.FallbackWear = weaponInfo.Wear;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit;
if (fallbackPaintKit == 0)
return;
if (!isKnife)
{
if (newPaints.Contains(fallbackPaintKit))
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
}
else
{
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
}
}
}
private void OnMapStart(string mapName)
{
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);
@@ -207,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;
@@ -219,11 +118,7 @@ namespace WeaponPaints
GivePlayerMusicKit(player);
GivePlayerAgent(player);
Server.NextFrame(() =>
{
RefreshGloves(player);
});
GivePlayerGloves(player);
return HookResult.Continue;
}
@@ -237,17 +132,10 @@ 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)
{
try
@@ -266,7 +154,6 @@ namespace WeaponPaints
return HookResult.Continue;
}
public void OnEntityCreated(CEntityInstance entity)
{
var designerName = entity.DesignerName;
@@ -276,7 +163,7 @@ namespace WeaponPaints
Server.NextFrame(() =>
{
var weapon = new CBasePlayerWeapon(entity.Handle);
if (weapon == null || !weapon.IsValid) return;
if (!weapon.IsValid) return;
try
{
@@ -289,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);
@@ -301,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);
}
@@ -318,18 +205,32 @@ namespace WeaponPaints
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 (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()
{
@@ -343,7 +244,7 @@ namespace WeaponPaints
if (Config.Additional.ShowSkinImage)
RegisterListener<Listeners.OnTick>(OnTick);
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (!IsWindows)
VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
}
}

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

@@ -25,6 +25,7 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
- Run server with plugin, **it will generate config if installed correctly!**
- Edit `addons/counterstrikesharp/configs/`**`plugins/WeaponPaints/WeaponPaints.json`** include database credentials
- In `addons/counterstrikesharp/configs/`**`core.json`** set **FollowCS2ServerGuidelines** to **`false`**
- Copy from plugins folder gamedata file **`weaponpaints.json`** to folder **`addons/counterstrikesharp/gamedata/`**
## Plugin Configuration
<details>
@@ -71,7 +72,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

@@ -25,34 +25,42 @@ namespace WeaponPaints
{
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_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)
@@ -78,16 +86,16 @@ 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, 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)
{
@@ -99,9 +107,9 @@ namespace WeaponPaints
{
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)
{
@@ -113,9 +121,9 @@ namespace WeaponPaints
{
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)
{
@@ -127,9 +135,9 @@ namespace WeaponPaints
{
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)
{
@@ -156,26 +164,26 @@ namespace WeaponPaints
try
{
HttpResponseMessage response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
var response = await client.GetAsync("https://raw.githubusercontent.com/Nereziel/cs2-WeaponPaints/main/VERSION").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var remoteVersion = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
remoteVersion = remoteVersion.Trim();
int comparisonResult = string.Compare(version, remoteVersion);
var comparisonResult = string.CompareOrdinal(version, remoteVersion);
if (comparisonResult < 0)
switch (comparisonResult)
{
logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints");
}
else if (comparisonResult > 0)
{
logger.LogInformation("Probably dev version detected");
}
else
{
logger.LogInformation("Plugin is up to date");
case < 0:
logger.LogWarning("Plugin is outdated! Check https://github.com/Nereziel/cs2-WeaponPaints");
break;
case > 0:
logger.LogInformation("Probably dev version detected");
break;
default:
logger.LogInformation("Plugin is up to date");
break;
}
}
else

View File

@@ -1 +1 @@
2.4d
2.5a

View File

@@ -11,7 +11,88 @@ 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 = { 106, 112, 113, 114, 115, 117, 118, 120, 121, 123, 126, 127, 128, 129, 130, 131, 133, 134, 137, 138, 139, 140, 142, 144, 145, 146, 152, 160, 161, 163, 173, 239, 292, 324, 331, 412, 461, 513, 766, 768, 770, 773, 774, 830, 831, 832, 834, 874, 875, 877, 878, 882, 883, 901, 912, 936, 937, 938, 939, 940, 1054, 1062, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1177, 1178, 1179, 1180 };
if (isKnife)
{
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == 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;
@@ -21,11 +102,11 @@ namespace WeaponPaints
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,9 +137,9 @@ 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;
@@ -69,37 +148,33 @@ namespace WeaponPaints
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.TryGetValue(weaponByDefindex, out List<(int, int)>? value))
if (!weaponsWithAmmo.TryGetValue(weaponByDefindex, out var value))
{
value = [];
weaponsWithAmmo.Add(weaponByDefindex, value);
@@ -107,7 +182,7 @@ namespace WeaponPaints
value.Add((clip1, reservedAmmo));
if (gun == null || gun.VData == null) return;
if (gun.VData == null) return;
weapon.Value.Remove();
}
@@ -121,16 +196,16 @@ namespace WeaponPaints
try
{
player.ExecuteClientCommandFromServer("slot 3");
player.ExecuteClientCommandFromServer("slot 3");
player.ExecuteClientCommand("slot 3");
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, () =>
{
@@ -144,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();
});
@@ -171,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)
{
@@ -187,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");
@@ -204,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);
@@ -240,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();
@@ -253,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)
@@ -321,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(215)]
[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,9 +76,9 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
{ "weapon_knife_kukri", "Kukri Knife" }
};
internal static WeaponPaintsConfig _config = new();
private static WeaponPaintsConfig _config = new();
internal static IStringLocalizer? _localizer;
internal static Dictionary<int, int> g_knifePickupCount = new();
private static Dictionary<int, int> g_knifePickupCount = new();
internal static ConcurrentDictionary<int, string> g_playersKnife = new();
internal static ConcurrentDictionary<int, ushort> g_playersGlove = new();
internal static ConcurrentDictionary<int, ushort> g_playersMusic = new();
@@ -88,16 +89,20 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
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();
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.4d";
public static WeaponPaintsConfig GetWeaponPaintsConfig()
{
return _config;
}
public override string ModuleVersion => "2.5a";
public override void Load(bool hotReload)
{
@@ -175,22 +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)
break;
if (player is null || !player.IsValid || player.SteamID.ToString().Length != 17 || string.IsNullOrEmpty(player.IpAddress) || player.IsBot ||
player.IsHLTV || player.Connected != PlayerConnectedState.PlayerConnected)
continue;
g_knifePickupCount[player.Slot] = 0;
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,
@@ -200,30 +201,10 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
IpAddress = player?.IpAddress?.Split(":")[0]
};
_ = Task.Run(async () => await weaponSync.GetPlayerData(playerInfo));
/*
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);
});
}
}
@@ -251,11 +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!");
Logger.LogError("You need to setup Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!");
Unload(false);
//throw new Exception("[WeaponPaints] You need to setup Database credentials in config!");
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,
@@ -265,10 +253,9 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
Port = (uint)config.DatabasePort,
Pooling = true,
MaximumPoolSize = 640,
ConnectionReset = false
};
_database = new(builder.ConnectionString);
_database = new Database(builder.ConnectionString);
_ = Utility.CheckDatabaseTables();

View File

@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.215" />
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.233" />
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.3.7" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

View File

@@ -15,12 +15,12 @@ namespace WeaponPaints
_config = config;
}
internal async Task GetPlayerData(PlayerInfo player)
internal async Task GetPlayerData(PlayerInfo? player)
{
try
{
await using MySqlConnection connection = await _database.GetConnectionAsync();
await using var connection = await _database.GetConnectionAsync();
if (_config.Additional.KnifeEnabled)
GetKnifeFromDatabase(player, connection);
if (_config.Additional.GloveEnabled)
@@ -39,15 +39,15 @@ namespace WeaponPaints
}
}
internal void GetKnifeFromDatabase(PlayerInfo player, MySqlConnection connection)
private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
string query = "SELECT `knife` FROM `wp_player_knife` WHERE `steamid` = @steamid";
string? playerKnife = connection.QueryFirstOrDefault<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))
{
@@ -60,15 +60,15 @@ namespace WeaponPaints
}
}
internal void GetGloveFromDatabase(PlayerInfo player, MySqlConnection connection)
private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
ushort? gloveData = connection.QueryFirstOrDefault<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)
{
@@ -81,28 +81,26 @@ namespace WeaponPaints
}
}
internal void GetAgentFromDatabase(PlayerInfo player, MySqlConnection connection)
private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId))
return;
string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @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)
{
string agentCT = agentData.Item1;
string agentT = agentData.Item2;
if (agentData == default) return;
var agentCT = agentData.Item1;
var agentT = agentData.Item2;
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
WeaponPaints.g_playersAgent[player.Slot] = (
agentCT,
agentT
);
}
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
{
WeaponPaints.g_playersAgent[player.Slot] = (
agentCT,
agentT
);
}
}
catch (Exception ex)
@@ -111,7 +109,7 @@ namespace WeaponPaints
}
}
internal void GetWeaponPaintsFromDatabase(PlayerInfo player, MySqlConnection connection)
private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection)
{
try
{
@@ -120,15 +118,9 @@ namespace WeaponPaints
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid";
var playerSkins = connection.Query<dynamic>(query, new { steamid = player.SteamId });
if (playerSkins == null)
{
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
return;
}
foreach (var row in playerSkins)
{
int weaponDefIndex = row?.weapon_defindex ?? 0;
@@ -154,15 +146,15 @@ namespace WeaponPaints
}
}
internal void GetMusicFromDatabase(PlayerInfo player, MySqlConnection connection)
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;
string query = "SELECT `music_id` FROM `wp_player_music` WHERE `steamid` = @steamid";
ushort? musicData = connection.QueryFirstOrDefault<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)
{
@@ -179,12 +171,13 @@ 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)
@@ -195,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)
@@ -211,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 });
}
@@ -233,25 +227,22 @@ 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;
@@ -259,13 +250,13 @@ namespace WeaponPaints
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);
@@ -279,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"
},
{

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

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