Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f86cddd13 | ||
|
|
24801e814b | ||
|
|
77def8a305 | ||
|
|
651fae4d23 | ||
|
|
692c22f7d1 | ||
|
|
cf07106641 | ||
|
|
44177f18fe | ||
|
|
88274d78d8 | ||
|
|
5cef723674 | ||
|
|
5f83645867 | ||
|
|
89005fdd4b | ||
|
|
4f432cddf5 | ||
|
|
ee1259846d | ||
|
|
485dd1e9dd | ||
|
|
666de9e2d2 | ||
|
|
77409269d0 | ||
|
|
09d9de2a2a | ||
|
|
362084c503 | ||
|
|
8cf175d336 | ||
|
|
84adfa8085 | ||
|
|
286d97d125 | ||
|
|
4d3db5b34f | ||
|
|
85d4e11f26 | ||
|
|
34b086a140 |
14
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: nereziel # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
polar: # Replace with a single Polar username
|
||||||
|
custom: ['https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
2
.github/workflows/build.yml
vendored
@@ -62,6 +62,8 @@ jobs:
|
|||||||
run: cp website/data/skins.json ${{ env.OUTPUT_PATH }}/skins.json
|
run: cp website/data/skins.json ${{ env.OUTPUT_PATH }}/skins.json
|
||||||
- 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: Copy agents.json
|
||||||
|
run: cp website/data/agents.json ${{ env.OUTPUT_PATH }}/agents.json
|
||||||
- name: Zip
|
- name: Zip
|
||||||
run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
|
run: zip -r "${{ env.PROJECT_NAME }}.zip" "${{ env.OUTPUT_PATH }}" gamedata/
|
||||||
- name: Clean files Website
|
- name: Clean files Website
|
||||||
|
|||||||
151
Commands.cs
@@ -1,6 +1,7 @@
|
|||||||
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;
|
||||||
|
|
||||||
namespace WeaponPaints
|
namespace WeaponPaints
|
||||||
{
|
{
|
||||||
@@ -95,6 +96,12 @@ namespace WeaponPaints
|
|||||||
player!.Print(Localizer["wp_info_glove"]);
|
player!.Print(Localizer["wp_info_glove"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Config.Additional.AgentEnabled)
|
||||||
|
if (!string.IsNullOrEmpty(Localizer["wp_info_agent"]))
|
||||||
|
{
|
||||||
|
player!.Print(Localizer["wp_info_agent"]);
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.Additional.KnifeEnabled)
|
if (Config.Additional.KnifeEnabled)
|
||||||
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
|
if (!string.IsNullOrEmpty(Localizer["wp_info_knife"]))
|
||||||
{
|
{
|
||||||
@@ -164,7 +171,6 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
g_playersKnife[player.Slot] = knifeKey;
|
g_playersKnife[player.Slot] = knifeKey;
|
||||||
|
|
||||||
|
|
||||||
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
|
if (g_bCommandsAllowed && (LifeState_t)player.LifeState == LifeState_t.LIFE_ALIVE)
|
||||||
RefreshWeapons(player);
|
RefreshWeapons(player);
|
||||||
|
|
||||||
@@ -218,14 +224,12 @@ namespace WeaponPaints
|
|||||||
)?.ToList();
|
)?.ToList();
|
||||||
|
|
||||||
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
|
var skinSubMenu = new ChatMenu(Localizer["wp_skin_menu_skin_title", selectedWeapon]);
|
||||||
skinSubMenu.PostSelectAction = PostSelectAction.Close;
|
|
||||||
|
|
||||||
// Function to handle skin selection for the chosen weapon
|
// Function to handle skin selection for the chosen weapon
|
||||||
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
|
var handleSkinSelection = (CCSPlayerController p, ChatMenuOption opt) =>
|
||||||
{
|
{
|
||||||
if (!Utility.IsPlayerValid(p)) return;
|
if (!Utility.IsPlayerValid(p)) return;
|
||||||
|
|
||||||
|
|
||||||
string steamId = p.SteamID.ToString();
|
string steamId = p.SteamID.ToString();
|
||||||
var firstSkin = skinsList?.FirstOrDefault(skin =>
|
var firstSkin = skinsList?.FirstOrDefault(skin =>
|
||||||
{
|
{
|
||||||
@@ -237,7 +241,7 @@ namespace WeaponPaints
|
|||||||
});
|
});
|
||||||
|
|
||||||
string selectedSkin = opt.Text;
|
string selectedSkin = opt.Text;
|
||||||
string selectedPaintID = selectedSkin.Split('(')[1].Trim(')').Trim();
|
string selectedPaintID = selectedSkin.Substring(selectedSkin.LastIndexOf('(') + 1).Trim(')');
|
||||||
|
|
||||||
if (firstSkin != null &&
|
if (firstSkin != null &&
|
||||||
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) &&
|
firstSkin.TryGetValue("weapon_defindex", out var weaponDefIndexObj) &&
|
||||||
@@ -265,21 +269,31 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
|
|
||||||
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Paint = paintID;
|
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Paint = paintID;
|
||||||
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.00f;
|
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Wear = 0.01f;
|
||||||
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Seed = 0;
|
gPlayerWeaponsInfo[p.Slot][weaponDefIndex].Seed = 0;
|
||||||
|
|
||||||
PlayerInfo playerInfo = new PlayerInfo
|
PlayerInfo playerInfo = new PlayerInfo
|
||||||
{
|
{
|
||||||
UserId = p.UserId,
|
UserId = p.UserId,
|
||||||
|
Slot = p.Slot,
|
||||||
Index = (int)p.Index,
|
Index = (int)p.Index,
|
||||||
SteamId = p.SteamID.ToString(),
|
SteamId = p.SteamID.ToString(),
|
||||||
Name = p.PlayerName,
|
Name = p.PlayerName,
|
||||||
IpAddress = p.IpAddress?.Split(":")[0]
|
IpAddress = p.IpAddress?.Split(":")[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE)
|
if (g_bCommandsAllowed && (LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && weaponSync != null)
|
||||||
{
|
{
|
||||||
RefreshWeapons(player);
|
RefreshWeapons(player);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utility.Log($"Error syncing weapon paints: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -393,24 +407,26 @@ namespace WeaponPaints
|
|||||||
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
|
player!.Print(Localizer["wp_glove_menu_select", selectedPaintName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (weaponSync != null)
|
if (weaponSync != null)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
|
await weaponSync.SyncGloveToDatabase(playerInfo, weaponDefindex);
|
||||||
|
|
||||||
if (!gPlayerWeaponsInfo[playerInfo.Slot].ContainsKey(weaponDefindex))
|
if (!gPlayerWeaponsInfo[playerInfo.Slot].TryGetValue(weaponDefindex, out WeaponInfo? value))
|
||||||
{
|
{
|
||||||
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = new WeaponInfo();
|
value = new WeaponInfo();
|
||||||
|
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex].Paint = paint;
|
value.Paint = paint;
|
||||||
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex].Wear = 0.00f;
|
value.Wear = 0.00f;
|
||||||
gPlayerWeaponsInfo[playerInfo.Slot][weaponDefindex].Seed = 0;
|
value.Seed = 0;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task.Run(async () => await weaponSync.SyncWeaponPaintsToDatabase(playerInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshGloves(player);
|
RefreshGloves(player);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -445,5 +461,114 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetupAgentsMenu()
|
||||||
|
{
|
||||||
|
var handleAgentSelection = (CCSPlayerController? player, ChatMenuOption option) =>
|
||||||
|
{
|
||||||
|
if (!Utility.IsPlayerValid(player) || player is null) return;
|
||||||
|
|
||||||
|
string selectedPaintName = option.Text;
|
||||||
|
|
||||||
|
var selectedAgent = agentsList.FirstOrDefault(g => g.ContainsKey("agent_name") && g["agent_name"]?.ToString() == selectedPaintName);
|
||||||
|
if (selectedAgent != null)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
selectedAgent != null &&
|
||||||
|
selectedAgent.ContainsKey("model")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PlayerInfo playerInfo = new PlayerInfo
|
||||||
|
{
|
||||||
|
UserId = player.UserId,
|
||||||
|
Slot = player.Slot,
|
||||||
|
Index = (int)player.Index,
|
||||||
|
SteamId = player.SteamID.ToString(),
|
||||||
|
Name = player.PlayerName,
|
||||||
|
IpAddress = player.IpAddress?.Split(":")[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Config.Additional.ShowSkinImage)
|
||||||
|
{
|
||||||
|
string image = selectedAgent["image"]?.ToString() ?? "";
|
||||||
|
PlayerWeaponImage[player.Slot] = image;
|
||||||
|
AddTimer(2.0f, () => PlayerWeaponImage.Remove(player.Slot), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Localizer["wp_agent_menu_select"]))
|
||||||
|
{
|
||||||
|
player!.Print(Localizer["wp_agent_menu_select", selectedPaintName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.TeamNum == 3)
|
||||||
|
{
|
||||||
|
g_playersAgent.AddOrUpdate(player.Slot,
|
||||||
|
key => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), null),
|
||||||
|
(key, oldValue) => (selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString(), oldValue.T));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_playersAgent.AddOrUpdate(player.Slot,
|
||||||
|
key => (null, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString()),
|
||||||
|
(key, oldValue) => (oldValue.CT, selectedAgent["model"]!.ToString().Equals("null") ? null : selectedAgent["model"]!.ToString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weaponSync != null)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await weaponSync.SyncAgentToDatabase(playerInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Command to open the weapon selection menu for players
|
||||||
|
AddCommand($"css_{Config.Additional.CommandAgent}", "Agents 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))
|
||||||
|
{
|
||||||
|
var agentsSelectionMenu = new ChatMenu(Localizer["wp_agent_menu_title"]);
|
||||||
|
agentsSelectionMenu.PostSelectAction = PostSelectAction.Close;
|
||||||
|
|
||||||
|
var filteredAgents = agentsList.Where(agentObject =>
|
||||||
|
{
|
||||||
|
if (agentObject["team"]?.Value<int>() is int teamNum)
|
||||||
|
{
|
||||||
|
return teamNum == player.TeamNum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add weapon options to the weapon selection menu
|
||||||
|
|
||||||
|
foreach (var agentObject in filteredAgents)
|
||||||
|
{
|
||||||
|
string paintName = agentObject["agent_name"]?.ToString() ?? "";
|
||||||
|
|
||||||
|
if (paintName.Length > 0)
|
||||||
|
agentsSelectionMenu.AddMenuOption(paintName, handleAgentSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
commandsCooldown[player.Slot] = DateTime.UtcNow.AddSeconds(Config.CmdRefreshCooldownSeconds);
|
||||||
|
MenuManager.OpenChatMenu(player, agentsSelectionMenu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(Localizer["wp_command_cooldown"]))
|
||||||
|
{
|
||||||
|
player!.Print(Localizer["wp_command_cooldown"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
14
Config.cs
@@ -5,15 +5,15 @@ namespace WeaponPaints
|
|||||||
{
|
{
|
||||||
public class Additional
|
public class Additional
|
||||||
{
|
{
|
||||||
[JsonPropertyName("SkinVisibilityFix")]
|
|
||||||
public bool SkinVisibilityFix { get; set; } = true;
|
|
||||||
|
|
||||||
[JsonPropertyName("KnifeEnabled")]
|
[JsonPropertyName("KnifeEnabled")]
|
||||||
public bool KnifeEnabled { get; set; } = true;
|
public bool KnifeEnabled { get; set; } = true;
|
||||||
|
|
||||||
[JsonPropertyName("GloveEnabled")]
|
[JsonPropertyName("GloveEnabled")]
|
||||||
public bool GloveEnabled { get; set; } = true;
|
public bool GloveEnabled { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonPropertyName("AgentEnabled")]
|
||||||
|
public bool AgentEnabled { get; set; } = true;
|
||||||
|
|
||||||
[JsonPropertyName("SkinEnabled")]
|
[JsonPropertyName("SkinEnabled")]
|
||||||
public bool SkinEnabled { get; set; } = true;
|
public bool SkinEnabled { get; set; } = true;
|
||||||
|
|
||||||
@@ -29,6 +29,9 @@ namespace WeaponPaints
|
|||||||
[JsonPropertyName("CommandGlove")]
|
[JsonPropertyName("CommandGlove")]
|
||||||
public string CommandGlove { get; set; } = "gloves";
|
public string CommandGlove { get; set; } = "gloves";
|
||||||
|
|
||||||
|
[JsonPropertyName("CommandAgent")]
|
||||||
|
public string CommandAgent { get; set; } = "agents";
|
||||||
|
|
||||||
[JsonPropertyName("CommandSkin")]
|
[JsonPropertyName("CommandSkin")]
|
||||||
public string CommandSkin { get; set; } = "ws";
|
public string CommandSkin { get; set; } = "ws";
|
||||||
|
|
||||||
@@ -47,16 +50,13 @@ namespace WeaponPaints
|
|||||||
[JsonPropertyName("GiveRandomSkin")]
|
[JsonPropertyName("GiveRandomSkin")]
|
||||||
public bool GiveRandomSkin { get; set; } = false;
|
public bool GiveRandomSkin { get; set; } = false;
|
||||||
|
|
||||||
[JsonPropertyName("GiveKnifeAfterRemove")]
|
|
||||||
public bool GiveKnifeAfterRemove { get; set; } = false;
|
|
||||||
|
|
||||||
[JsonPropertyName("ShowSkinImage")]
|
[JsonPropertyName("ShowSkinImage")]
|
||||||
public bool ShowSkinImage { get; set; } = true;
|
public bool ShowSkinImage { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WeaponPaintsConfig : BasePluginConfig
|
public class WeaponPaintsConfig : BasePluginConfig
|
||||||
{
|
{
|
||||||
public override int Version { get; set; } = 4;
|
public override int Version { get; set; } = 6;
|
||||||
|
|
||||||
[JsonPropertyName("DatabaseHost")]
|
[JsonPropertyName("DatabaseHost")]
|
||||||
public string DatabaseHost { get; set; } = "";
|
public string DatabaseHost { get; set; } = "";
|
||||||
|
|||||||
316
Events.cs
@@ -26,22 +26,34 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
List<Task> tasks = new List<Task>();
|
||||||
|
|
||||||
if (Config.Additional.SkinEnabled)
|
if (Config.Additional.SkinEnabled)
|
||||||
{
|
{
|
||||||
Task.Run(() => weaponSync.GetWeaponPaintsFromDatabase(playerInfo));
|
tasks.Add(Task.Run(() => weaponSync.GetWeaponPaintsFromDatabase(playerInfo)));
|
||||||
}
|
}
|
||||||
if (Config.Additional.KnifeEnabled)
|
if (Config.Additional.KnifeEnabled)
|
||||||
{
|
{
|
||||||
Task.Run(() => weaponSync.GetKnifeFromDatabase(playerInfo));
|
tasks.Add(Task.Run(() => weaponSync.GetKnifeFromDatabase(playerInfo)));
|
||||||
}
|
}
|
||||||
if (Config.Additional.GloveEnabled)
|
if (Config.Additional.GloveEnabled)
|
||||||
{
|
{
|
||||||
Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo));
|
tasks.Add(Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo)));
|
||||||
}
|
}
|
||||||
|
if (Config.Additional.AgentEnabled)
|
||||||
|
{
|
||||||
|
tasks.Add(Task.Run(() => weaponSync.GetAgentFromDatabase(playerInfo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (AggregateException ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
// Handle the exception
|
||||||
|
foreach (var innerException in ex.InnerExceptions)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"An error occurred for player {player}: {innerException.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
@@ -65,105 +77,118 @@ namespace WeaponPaints
|
|||||||
IpAddress = player.IpAddress?.Split(":")[0]
|
IpAddress = player.IpAddress?.Split(":")[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (weaponSync != null)
|
if (Config.Additional.SkinEnabled)
|
||||||
{
|
{
|
||||||
// Run weapon sync tasks asynchronously
|
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
|
||||||
Task.Run(async () =>
|
}
|
||||||
{
|
if (Config.Additional.KnifeEnabled)
|
||||||
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo);
|
{
|
||||||
});
|
g_playersKnife.TryRemove(player.Slot, out _);
|
||||||
|
}
|
||||||
// Remove player data
|
if (Config.Additional.GloveEnabled)
|
||||||
if (Config.Additional.SkinEnabled)
|
{
|
||||||
{
|
g_playersGlove.TryRemove(player.Slot, out _);
|
||||||
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
|
}
|
||||||
}
|
if (Config.Additional.AgentEnabled)
|
||||||
if (Config.Additional.KnifeEnabled)
|
{
|
||||||
{
|
g_playersAgent.TryRemove(player.Slot, out _);
|
||||||
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);
|
commandsCooldown.Remove(player.Slot);
|
||||||
|
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEntityCreated(CEntityInstance entity)
|
private void GivePlayerWeaponSkin(CCSPlayerController player, CBasePlayerWeapon weapon)
|
||||||
{
|
{
|
||||||
if (!Config.Additional.SkinEnabled) return;
|
if (!Config.Additional.SkinEnabled) return;
|
||||||
if (entity == null || !entity.IsValid || string.IsNullOrEmpty(entity.DesignerName)) return;
|
|
||||||
string designerName = entity.DesignerName;
|
|
||||||
if (!weaponList.ContainsKey(designerName)) return;
|
|
||||||
bool isKnife = false;
|
|
||||||
var weapon = new CBasePlayerWeapon(entity.Handle);
|
|
||||||
|
|
||||||
if (designerName.Contains("knife") || designerName.Contains("bayonet"))
|
if (player is null || weapon is null || !weapon.IsValid || !Utility.IsPlayerValid(player)) return;
|
||||||
{
|
|
||||||
isKnife = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.NextFrame(() =>
|
if (!gPlayerWeaponsInfo.ContainsKey(player.Slot)) return;
|
||||||
|
|
||||||
|
bool isKnife = weapon.DesignerName.Contains("knife") || weapon.DesignerName.Contains("bayonet");
|
||||||
|
|
||||||
|
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
|
||||||
|
|
||||||
|
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
|
||||||
|
|
||||||
|
if (isKnife)
|
||||||
{
|
{
|
||||||
try
|
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
|
||||||
|
if (newDefIndex.Key == 0) return;
|
||||||
|
|
||||||
|
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
|
||||||
{
|
{
|
||||||
if (!weapon.IsValid) return;
|
SubclassChange(weapon, (ushort)newDefIndex.Key);
|
||||||
if (weapon.OwnerEntity.Value == null) return;
|
|
||||||
if (weapon.OwnerEntity.Index <= 0) return;
|
|
||||||
int weaponOwner = (int)weapon.OwnerEntity.Index;
|
|
||||||
CBasePlayerPawn? pawn = Utilities.GetEntityFromIndex<CCSPlayerPawn>(weaponOwner);
|
|
||||||
if (!pawn.IsValid) return;
|
|
||||||
|
|
||||||
var playerIndex = (int)pawn.Controller.Index;
|
|
||||||
var player = Utilities.GetPlayerFromIndex(playerIndex);
|
|
||||||
if (!Utility.IsPlayerValid(player)) return;
|
|
||||||
|
|
||||||
ChangeWeaponAttributes(weapon, player, isKnife);
|
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay)
|
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
|
||||||
{
|
weapon.AttributeManager.Item.EntityQuality = 3;
|
||||||
if (!Config.Additional.GiveKnifeAfterRemove)
|
|
||||||
return HookResult.Continue;
|
|
||||||
|
|
||||||
CCSPlayerController? player = Utilities.GetEntityFromIndex<CCSPlayerPawn>((int)activator.Index).OriginalController.Value;
|
|
||||||
|
|
||||||
if (player == null || player.IsBot || player.IsHLTV ||
|
|
||||||
player.SteamID.ToString().Length != 17 || !g_knifePickupCount.TryGetValue(player.Slot, out var pickupCount) ||
|
|
||||||
!g_playersKnife.ContainsKey(player.Slot))
|
|
||||||
{
|
|
||||||
return HookResult.Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CBasePlayerWeapon weapon = new(caller.Handle);
|
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
|
||||||
|
int fallbackPaintKit = 0;
|
||||||
|
|
||||||
if (weapon.AttributeManager.Item.ItemDefinitionIndex != 42 && weapon.AttributeManager.Item.ItemDefinitionIndex != 59)
|
if (_config.Additional.GiveRandomSkin &&
|
||||||
|
!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
|
||||||
{
|
{
|
||||||
return HookResult.Continue;
|
// 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 (pickupCount >= 2)
|
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) return;
|
||||||
|
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][weaponDefIndex];
|
||||||
|
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
|
||||||
|
weapon.AttributeManager.Item.ItemID = 16384;
|
||||||
|
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
||||||
|
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
|
||||||
|
weapon.FallbackPaintKit = weaponInfo.Paint;
|
||||||
|
weapon.FallbackSeed = weaponInfo.Seed;
|
||||||
|
weapon.FallbackWear = weaponInfo.Wear;
|
||||||
|
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
|
||||||
|
|
||||||
|
fallbackPaintKit = weapon.FallbackPaintKit;
|
||||||
|
|
||||||
|
if (fallbackPaintKit == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isKnife)
|
||||||
{
|
{
|
||||||
return HookResult.Continue;
|
if (newPaints.Contains(fallbackPaintKit))
|
||||||
|
{
|
||||||
|
UpdatePlayerWeaponMeshGroupMask(player, weapon, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdatePlayerWeaponMeshGroupMask(player, weapon, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_playersKnife[player.Slot] != "weapon_knife")
|
|
||||||
{
|
|
||||||
pickupCount++;
|
|
||||||
g_knifePickupCount[player.Slot] = pickupCount;
|
|
||||||
|
|
||||||
AddTimer(0.2f, () => RefreshWeapons(player));
|
|
||||||
}
|
|
||||||
|
|
||||||
return HookResult.Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapStart(string mapName)
|
private void OnMapStart(string mapName)
|
||||||
@@ -172,15 +197,6 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
if (_database != null)
|
if (_database != null)
|
||||||
weaponSync = new WeaponSynchronization(_database, Config);
|
weaponSync = new WeaponSynchronization(_database, Config);
|
||||||
|
|
||||||
// TODO
|
|
||||||
// needed for now
|
|
||||||
AddTimer(2.0f, () =>
|
|
||||||
{
|
|
||||||
NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
|
|
||||||
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
|
|
||||||
NativeAPI.IssueServerCommand("mp_equipment_reset_rounds 0");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
|
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
|
||||||
@@ -190,11 +206,14 @@ 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;
|
||||||
|
|
||||||
|
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
|
||||||
|
|
||||||
|
if (pawn == null || !pawn.IsValid)
|
||||||
|
return HookResult.Continue;
|
||||||
|
|
||||||
g_knifePickupCount[player.Slot] = 0;
|
g_knifePickupCount[player.Slot] = 0;
|
||||||
|
|
||||||
if (!PlayerHasKnife(player))
|
GivePlayerAgent(player);
|
||||||
GiveKnifeToPlayer(player);
|
|
||||||
|
|
||||||
Server.NextFrame(() =>
|
Server.NextFrame(() =>
|
||||||
{
|
{
|
||||||
RefreshGloves(player);
|
RefreshGloves(player);
|
||||||
@@ -212,100 +231,77 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
|
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
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");
|
||||||
|
*/
|
||||||
g_bCommandsAllowed = true;
|
g_bCommandsAllowed = true;
|
||||||
|
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public HookResult OnGiveNamedItemPost(DynamicHook hook)
|
||||||
|
{
|
||||||
|
var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
|
||||||
|
var weapon = hook.GetReturn<CBasePlayerWeapon>(0);
|
||||||
|
if (!weapon.DesignerName.Contains("weapon"))
|
||||||
|
return HookResult.Continue;
|
||||||
|
|
||||||
|
var player = GetPlayerFromItemServices(itemServices);
|
||||||
|
if (player != null)
|
||||||
|
GivePlayerWeaponSkin(player, weapon);
|
||||||
|
|
||||||
|
return HookResult.Continue;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void OnEntitySpawned(CEntityInstance entity)
|
||||||
|
{
|
||||||
|
var designerName = entity.DesignerName;
|
||||||
|
|
||||||
|
if (designerName.Contains("weapon"))
|
||||||
|
{
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
var weapon = new CBasePlayerWeapon(entity.Handle);
|
||||||
|
if (weapon == null || !weapon.IsValid || weapon.OwnerEntity.Value == null) return;
|
||||||
|
|
||||||
|
CCSPlayerController? player = Utilities.GetPlayerFromIndex((int)weapon.OwnerEntity.Value.Index);
|
||||||
|
if (player == null || !player.IsValid || !Utility.IsPlayerValid(player)) return;
|
||||||
|
|
||||||
|
GivePlayerWeaponSkin(player, weapon);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnTick()
|
private void OnTick()
|
||||||
{
|
{
|
||||||
foreach (var player in Utilities.GetPlayers().Where(p =>
|
foreach (var player in Utilities.GetPlayers().Where(p =>
|
||||||
p is not null && p.IsValid &&
|
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
|
(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
|
&& !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
try
|
if (Config.Additional.ShowSkinImage && PlayerWeaponImage.TryGetValue(player.Slot, out string? value) && !string.IsNullOrEmpty(value))
|
||||||
{
|
|
||||||
if (Config.Additional.ShowSkinImage && PlayerWeaponImage.ContainsKey(player.Slot) && !string.IsNullOrEmpty(PlayerWeaponImage[player.Slot]))
|
|
||||||
{
|
|
||||||
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", PlayerWeaponImage[player.Slot]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.PlayerPawn?.IsValid != true || player.PlayerPawn?.Value?.IsValid != true)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var viewModels = GetPlayerViewModels(player);
|
|
||||||
if (viewModels == null || viewModels.Length == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var viewModel = viewModels[0];
|
|
||||||
if (viewModel == null || viewModel.Value == null || viewModel.Value.Weapon == null || viewModel.Value.Weapon.Value == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var weapon = viewModel.Value.Weapon.Value;
|
|
||||||
if (weapon == null || !weapon.IsValid || weapon.FallbackPaintKit == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (viewModel.Value.VMName.Contains("knife"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var sceneNode = viewModel.Value.CBodyComponent?.SceneNode;
|
|
||||||
if (sceneNode == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var skeleton = GetSkeletonInstance(sceneNode);
|
|
||||||
if (skeleton == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool skeletonChange = false;
|
|
||||||
|
|
||||||
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
|
|
||||||
if (newPaints.Contains(weapon.FallbackPaintKit))
|
|
||||||
{
|
|
||||||
if (skeleton.ModelState.MeshGroupMask != 1)
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 1;
|
|
||||||
skeletonChange = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (skeleton.ModelState.MeshGroupMask != 2)
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 2;
|
|
||||||
skeletonChange = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skeletonChange)
|
|
||||||
Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent");
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
{
|
||||||
|
player.PrintToCenterHtml("<img src='{PATH}'</img>".Replace("{PATH}", value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterListeners()
|
private void RegisterListeners()
|
||||||
{
|
{
|
||||||
RegisterListener<Listeners.OnEntitySpawned>(OnEntityCreated);
|
|
||||||
//RegisterListener<Listeners.OnClientPutInServer>(OnClientPutInServer);
|
|
||||||
//RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect);
|
|
||||||
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||||
RegisterListener<Listeners.OnTick>(OnTick);
|
|
||||||
|
|
||||||
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
|
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
|
||||||
RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre);
|
RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre);
|
||||||
RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
|
RegisterEventHandler<EventRoundEnd>(OnRoundEnd);
|
||||||
|
RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawned);
|
||||||
//RegisterEventHandler<EventItemPickup>(OnItemPickup);
|
RegisterListener<Listeners.OnTick>(OnTick);
|
||||||
|
//VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
|
||||||
HookEntityOutput("weapon_knife", "OnPlayerPickup", OnPickup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
README.md
@@ -9,13 +9,14 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
[](https://ko-fi.com/E1E2G0P2O) or [](https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE)
|
[](https://ko-fi.com/E1E2G0P2O) or [](https://steamcommunity.com/tradeoffer/new/?partner=41515647&token=gW2W-nXE)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Changes only paint, seed and wear on weapons and knives
|
- Changes only paint, seed and wear on weapons, knives, gloves and agents
|
||||||
- MySQL based
|
- 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
|
||||||
- Added command **`!knife`** to show menu with knives
|
- Added command **`!knife`** to show menu with knives
|
||||||
- Knife change is now limited to have these cvars empty **`mp_t_default_melee ""`** and **`mp_ct_default_melee ""`**
|
- Added command **`!gloves`** to show menu with gloves
|
||||||
|
- Added command **`!agents`** to show menu with agents
|
||||||
- Translations support, submit a PR if you want to share your translation
|
- Translations support, submit a PR if you want to share your translation
|
||||||
|
|
||||||
## CS2 Server
|
## CS2 Server
|
||||||
@@ -52,7 +53,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
"SkinMenuTitle": "Select skin for {WEAPON}" // Menu title (!skins menu, after weapon select)
|
"SkinMenuTitle": "Select skin for {WEAPON}" // Menu title (!skins menu, after weapon select)
|
||||||
},
|
},
|
||||||
"Additional": {
|
"Additional": {
|
||||||
"SkinVisibilityFix": true, // Enable or disable fix for skin visibility
|
|
||||||
"KnifeEnabled": true, // Enable or disable knife feature
|
"KnifeEnabled": true, // Enable or disable knife feature
|
||||||
"SkinEnabled": true, // Enable or disable skin feature
|
"SkinEnabled": true, // Enable or disable skin feature
|
||||||
"CommandWpEnabled": true, // Enable or disable refreshing command
|
"CommandWpEnabled": true, // Enable or disable refreshing command
|
||||||
@@ -83,11 +83,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
|
|||||||
- Steam login/logout
|
- Steam login/logout
|
||||||
- Change knife, paint, seed and wear
|
- Change knife, paint, seed and wear
|
||||||
|
|
||||||
## Known issues
|
|
||||||
- Issue on Windows servers, no knives are given.
|
|
||||||
- You can't change knife if it's equpied in cs2 inventory
|
|
||||||
- Can cause incompatibility with plugins/maps which manipulates weapons and knives
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
<details>
|
<details>
|
||||||
**Skins are not changing:**
|
**Skins are not changing:**
|
||||||
@@ -96,11 +91,6 @@ Set FollowCSGOGuidelines to false in cssharp’s core.jcon config
|
|||||||
**Database error table does not exists:**
|
**Database error table does not exists:**
|
||||||
Plugin is not loaded or configured with mysql credentials. Tables are auto-created by plugin.
|
Plugin is not loaded or configured with mysql credentials. Tables are auto-created by plugin.
|
||||||
|
|
||||||
**Knives are disappearing:**
|
|
||||||
Set in config GiveKnifeAfterRemove to true
|
|
||||||
|
|
||||||
**Knives are not changing for players:**
|
|
||||||
You can't change knife if you have your own equipped
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Use this plugin at your own risk! Using this may lead to GSLT ban or something else Valve come with. [Valve Server guidelines](https://blog.counter-strike.net/index.php/server_guidelines/)
|
### Use this plugin at your own risk! Using this may lead to GSLT ban or something else Valve come with. [Valve Server guidelines](https://blog.counter-strike.net/index.php/server_guidelines/)
|
||||||
|
|||||||
47
Utility.cs
@@ -44,21 +44,27 @@ 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(18) 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(18) 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(18) NOT NULL,
|
||||||
`weapon_defindex` int(11) NOT NULL,
|
`weapon_defindex` int(11) NOT NULL,
|
||||||
UNIQUE (`steamid`)
|
UNIQUE (`steamid`)
|
||||||
|
) ENGINE=InnoDB",
|
||||||
|
@"CREATE TABLE `wp_player_agents` (
|
||||||
|
`steamid` varchar(18) NOT NULL,
|
||||||
|
`agent_ct` varchar(64) DEFAULT NULL,
|
||||||
|
`agent_t` varchar(64) DEFAULT NULL,
|
||||||
|
UNIQUE KEY `steamid` (`steamid`)
|
||||||
) ENGINE=InnoDB"
|
) ENGINE=InnoDB"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,6 +123,20 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void LoadAgentsFromFile(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(filePath);
|
||||||
|
var deserializedSkins = JsonConvert.DeserializeObject<List<JObject>>(json);
|
||||||
|
WeaponPaints.agentsList = deserializedSkins ?? new List<JObject>();
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static void Log(string message)
|
internal static void Log(string message)
|
||||||
{
|
{
|
||||||
Console.BackgroundColor = ConsoleColor.DarkGray;
|
Console.BackgroundColor = ConsoleColor.DarkGray;
|
||||||
@@ -206,26 +226,5 @@ namespace WeaponPaints
|
|||||||
Console.WriteLine(" >> GitHub: https://github.com/Nereziel/cs2-WeaponPaints");
|
Console.WriteLine(" >> GitHub: https://github.com/Nereziel/cs2-WeaponPaints");
|
||||||
Console.WriteLine(" ");
|
Console.WriteLine(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*(
|
|
||||||
internal static void TestDatabaseConnection()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var connection = new MySqlConnection(BuildDatabaseConnectionString());
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
if (connection.State != System.Data.ConnectionState.Open)
|
|
||||||
{
|
|
||||||
throw new Exception("[WeaponPaints] Unable connect to database!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new Exception("[WeaponPaints] Unknown mysql exception! " + ex.Message);
|
|
||||||
}
|
|
||||||
CheckDatabaseTables();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
355
WeaponAction.cs
@@ -1,5 +1,6 @@
|
|||||||
using CounterStrikeSharp.API;
|
using CounterStrikeSharp.API;
|
||||||
using CounterStrikeSharp.API.Core;
|
using CounterStrikeSharp.API.Core;
|
||||||
|
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||||
using CounterStrikeSharp.API.Modules.Memory;
|
using CounterStrikeSharp.API.Modules.Memory;
|
||||||
using CounterStrikeSharp.API.Modules.Timers;
|
using CounterStrikeSharp.API.Modules.Timers;
|
||||||
using CounterStrikeSharp.API.Modules.Utils;
|
using CounterStrikeSharp.API.Modules.Utils;
|
||||||
@@ -10,166 +11,14 @@ namespace WeaponPaints
|
|||||||
{
|
{
|
||||||
public partial class WeaponPaints
|
public partial class WeaponPaints
|
||||||
{
|
{
|
||||||
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 (!gPlayerWeaponsInfo.ContainsKey(player.Slot)) return;
|
|
||||||
|
|
||||||
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
|
|
||||||
|
|
||||||
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
|
|
||||||
|
|
||||||
if (isKnife)
|
|
||||||
{
|
|
||||||
weapon.AttributeManager.Item.EntityQuality = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fallbackPaintKit = weapon.FallbackPaintKit;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
fallbackPaintKit = weapon.FallbackPaintKit;
|
|
||||||
|
|
||||||
if (fallbackPaintKit == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var foundSkin = skinsList.FirstOrDefault(skin =>
|
|
||||||
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
|
|
||||||
((int?)skin?["paint"] ?? 0) == fallbackPaintKit &&
|
|
||||||
skin?["paint_name"] != null
|
|
||||||
);
|
|
||||||
|
|
||||||
string skinName = foundSkin?["paint_name"]?.ToString() ?? "";
|
|
||||||
if (!string.IsNullOrEmpty(skinName))
|
|
||||||
new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName);
|
|
||||||
|
|
||||||
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
|
|
||||||
{
|
|
||||||
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
|
|
||||||
|
|
||||||
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
|
|
||||||
|
|
||||||
if (newPaints.Contains(fallbackPaintKit))
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (skeleton.ModelState.MeshGroupMask != 2)
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewModels = GetPlayerViewModels(player);
|
|
||||||
if (viewModels == null || viewModels.Length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var viewModel = viewModels[0];
|
|
||||||
if (viewModel == null || viewModel.Value == null || viewModel.Value.Weapon == null || viewModel.Value.Weapon.Value == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Utilities.SetStateChanged(viewModel.Value, "CBaseEntity", "m_CBodyComponent");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) return;
|
|
||||||
WeaponInfo weaponInfo = gPlayerWeaponsInfo[player.Slot][weaponDefIndex];
|
|
||||||
//Log($"Apply on {weapon.DesignerName}({weapon.AttributeManager.Item.ItemDefinitionIndex}) paint {gPlayerWeaponPaints[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} seed {gPlayerWeaponSeed[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]} wear {gPlayerWeaponWear[steamId.SteamId64][weapon.AttributeManager.Item.ItemDefinitionIndex]}");
|
|
||||||
weapon.AttributeManager.Item.ItemID = 16384;
|
|
||||||
weapon.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
|
|
||||||
weapon.AttributeManager.Item.ItemIDHigh = weapon.AttributeManager.Item.ItemIDLow >> 32;
|
|
||||||
weapon.FallbackPaintKit = weaponInfo.Paint;
|
|
||||||
weapon.FallbackSeed = weaponInfo.Seed;
|
|
||||||
weapon.FallbackWear = weaponInfo.Wear;
|
|
||||||
|
|
||||||
fallbackPaintKit = weapon.FallbackPaintKit;
|
|
||||||
|
|
||||||
if (fallbackPaintKit == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var foundSkin1 = skinsList.FirstOrDefault(skin =>
|
|
||||||
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
|
|
||||||
((int?)skin?["paint"] ?? 0) == fallbackPaintKit &&
|
|
||||||
skin?["paint_name"] != null
|
|
||||||
);
|
|
||||||
|
|
||||||
var skinName1 = foundSkin1?["paint_name"]?.ToString() ?? "";
|
|
||||||
if (!string.IsNullOrEmpty(skinName1))
|
|
||||||
new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName1);
|
|
||||||
|
|
||||||
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
|
|
||||||
{
|
|
||||||
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
|
|
||||||
int[] newPaints = { 1171, 1170, 1169, 1164, 1162, 1161, 1159, 1175, 1174, 1167, 1165, 1168, 1163, 1160, 1166, 1173 };
|
|
||||||
if (newPaints.Contains(fallbackPaintKit))
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (skeleton.ModelState.MeshGroupMask != 2)
|
|
||||||
{
|
|
||||||
skeleton.ModelState.MeshGroupMask = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewModels1 = GetPlayerViewModels(player);
|
|
||||||
if (viewModels1 == null || viewModels1.Length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var viewModel1 = viewModels1[0];
|
|
||||||
if (viewModel1 == null || viewModel1.Value == null || viewModel1.Value.Weapon == null || viewModel1.Value.Weapon.Value == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Utilities.SetStateChanged(viewModel1.Value, "CBaseEntity", "m_CBodyComponent");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void GiveKnifeToPlayer(CCSPlayerController? player)
|
internal static void GiveKnifeToPlayer(CCSPlayerController? player)
|
||||||
{
|
{
|
||||||
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
|
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
|
||||||
|
|
||||||
WeaponPaints.Instance.AddTimer(1.0f, () =>
|
if (PlayerHasKnife(player)) return;
|
||||||
{
|
|
||||||
string knifeToGive;
|
|
||||||
if (g_playersKnife.TryGetValue(player.Slot, out var knife))
|
|
||||||
{
|
|
||||||
knifeToGive = 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)
|
string knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
|
||||||
{
|
player.GiveNamedItem(CsItem.Knife);
|
||||||
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";
|
|
||||||
}
|
|
||||||
|
|
||||||
player.GiveNamedItem(knifeToGive);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool PlayerHasKnife(CCSPlayerController? player)
|
internal static bool PlayerHasKnife(CCSPlayerController? player)
|
||||||
@@ -181,7 +30,7 @@ namespace WeaponPaints
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.PlayerPawn?.Value == null || player.PlayerPawn?.Value.WeaponServices == null || player.PlayerPawn?.Value.ItemServices == null)
|
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null || player.PlayerPawn.Value.ItemServices == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
|
var weapons = player.PlayerPawn.Value.WeaponServices?.MyWeapons;
|
||||||
@@ -201,6 +50,7 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
internal void RefreshWeapons(CCSPlayerController? player)
|
internal 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)
|
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)
|
||||||
@@ -213,10 +63,10 @@ namespace WeaponPaints
|
|||||||
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator)
|
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Dictionary<string, (int, int)> weaponsWithAmmo = new Dictionary<string, (int, int)>();
|
int playerTeam = player.TeamNum;
|
||||||
|
|
||||||
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>();
|
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>();
|
||||||
|
|
||||||
// Iterate through each weapon
|
|
||||||
foreach (var weapon in weapons)
|
foreach (var weapon in weapons)
|
||||||
{
|
{
|
||||||
if (weapon == null || !weapon.IsValid || weapon.Value == null ||
|
if (weapon == null || !weapon.IsValid || weapon.Value == null ||
|
||||||
@@ -255,9 +105,11 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
|
|
||||||
weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
|
weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
|
||||||
}
|
|
||||||
|
|
||||||
//player.RemoveItemByDesignerName(weapon.Value.DesignerName, false);
|
if (gun == null || gun.VData == null) return;
|
||||||
|
|
||||||
|
weapon.Value.Remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -266,42 +118,55 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 3; i++)
|
try
|
||||||
{
|
{
|
||||||
player.ExecuteClientCommand($"slot {i}");
|
player.ExecuteClientCommand("slot 3");
|
||||||
player.ExecuteClientCommand($"slot {i}");
|
player.ExecuteClientCommand("slot 3");
|
||||||
|
|
||||||
AddTimer(0.1f, () =>
|
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon;
|
||||||
|
if (weapon is null || !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)
|
||||||
{
|
{
|
||||||
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value;
|
CCSWeaponBaseGun gun = weapon.Value.As<CCSWeaponBaseGun>();
|
||||||
CCSWeaponBaseGun? gun = weapon?.As<CCSWeaponBaseGun>();
|
|
||||||
|
|
||||||
if (gun == null || gun.VData == null) return;
|
AddTimer(0.3f, () =>
|
||||||
|
|
||||||
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, () =>
|
|
||||||
{
|
{
|
||||||
if (gun != null && gun.IsValid && gun.State == CSWeaponState_t.WEAPON_NOT_CARRIED)
|
if (player.TeamNum != playerTeam) return;
|
||||||
|
|
||||||
|
player.ExecuteClientCommand("slot 3");
|
||||||
|
gun = weapon.Value.As<CCSWeaponBaseGun>();
|
||||||
|
player.DropActiveWeapon();
|
||||||
|
|
||||||
|
AddTimer(0.7f, () =>
|
||||||
{
|
{
|
||||||
weapon?.Remove();
|
if (player.TeamNum != playerTeam) return;
|
||||||
}
|
|
||||||
|
if (gun == null || !gun.IsValid || gun.State != CSWeaponState_t.WEAPON_NOT_CARRIED) return;
|
||||||
|
|
||||||
|
gun.Remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
GiveKnifeToPlayer(player);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning($"Cannot remove knife: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
AddTimer(1.2f, () =>
|
AddTimer(0.6f, () =>
|
||||||
{
|
|
||||||
GiveKnifeToPlayer(player);
|
|
||||||
|
|
||||||
foreach (var entry in weaponsWithAmmo)
|
|
||||||
{
|
|
||||||
foreach (var ammo in entry.Value)
|
|
||||||
{
|
{
|
||||||
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
|
if (!g_bCommandsAllowed) return;
|
||||||
Server.NextFrame(() =>
|
|
||||||
|
foreach (var entry in weaponsWithAmmo)
|
||||||
|
{
|
||||||
|
foreach (var ammo in entry.Value)
|
||||||
|
{
|
||||||
|
var newWeapon = new CBasePlayerWeapon(player.GiveNamedItem(entry.Key));
|
||||||
|
Server.NextFrame(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -316,45 +181,9 @@ namespace WeaponPaints
|
|||||||
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
|
Logger.LogWarning("Error setting weapon properties: " + ex.Message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
}, TimerFlags.STOP_ON_MAPCHANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RefreshKnife(CCSPlayerController? player)
|
|
||||||
{
|
|
||||||
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (player.PlayerPawn.Value.WeaponServices == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
|
|
||||||
if (weapons != null && weapons.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var weapon in weapons)
|
|
||||||
{
|
|
||||||
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid && weapon.Index > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
|
|
||||||
|
|
||||||
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
|
|
||||||
{
|
|
||||||
player.ExecuteClientCommand("slot 3");
|
|
||||||
|
|
||||||
weapon.Value.Remove();
|
|
||||||
GiveKnifeToPlayer(player);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}, TimerFlags.STOP_ON_MAPCHANGE);
|
||||||
{
|
|
||||||
Logger.LogWarning($"Cannot remove knife: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RefreshGloves(CCSPlayerController player)
|
private static void RefreshGloves(CCSPlayerController player)
|
||||||
@@ -429,23 +258,89 @@ namespace WeaponPaints
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CSkeletonInstance GetSkeletonInstance(CGameSceneNode node)
|
public static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
|
||||||
{
|
{
|
||||||
Func<nint, nint> GetSkeletonInstance = VirtualFunction.Create<nint, nint>(node.Handle, 8);
|
var SubclassChangeFunc = VirtualFunction.Create<nint, string, int>(
|
||||||
return new CSkeletonInstance(GetSkeletonInstance(node.Handle));
|
GameData.GetSignature("ChangeSubclass")
|
||||||
|
);
|
||||||
|
|
||||||
|
SubclassChangeFunc(weapon.Handle, itemD.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe CHandle<CBaseViewModel>[]? GetPlayerViewModels(CCSPlayerController player)
|
public 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 (skeleton.ModelState.MeshGroupMask != value)
|
||||||
|
{
|
||||||
|
skeleton.ModelState.MeshGroupMask = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GivePlayerAgent(CCSPlayerController player)
|
||||||
|
{
|
||||||
|
if (!g_playersAgent.ContainsKey(player.Slot)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
string? model = player.TeamNum == 3 ? g_playersAgent[player.Slot].CT : g_playersAgent[player.Slot].T;
|
||||||
|
if (string.IsNullOrEmpty(model)) return;
|
||||||
|
|
||||||
|
player.PlayerPawn.Value!.SetModel(
|
||||||
|
$"characters/models/{model}.vmdl"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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;
|
||||||
|
var player = new CCSPlayerController(pawn.Controller.Value.Handle);
|
||||||
|
if (!Utility.IsPlayerValid(player)) return null;
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe CBaseViewModel? GetPlayerViewModel(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
|
if (player.PlayerPawn.Value == null || player.PlayerPawn.Value.ViewModelServices == null) return null;
|
||||||
CCSPlayer_ViewModelServices viewModelServices = new CCSPlayer_ViewModelServices(player.PlayerPawn.Value.ViewModelServices!.Handle);
|
CCSPlayer_ViewModelServices viewModelServices = new(player.PlayerPawn.Value.ViewModelServices!.Handle);
|
||||||
return GetFixedArray<CHandle<CBaseViewModel>>(viewModelServices.Handle, "CCSPlayer_ViewModelServices", "m_hViewModel", 3);
|
nint 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe T[] GetFixedArray<T>(nint pointer, string @class, string member, int length) where T : CHandle<CBaseViewModel>
|
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);
|
nint ptr = pointer + Schema.GetSchemaOffset(@class, member);
|
||||||
Span<nint> references = MemoryMarshal.CreateSpan<nint>(ref ptr, length);
|
Span<nint> references = MemoryMarshal.CreateSpan(ref ptr, length);
|
||||||
T[] values = new T[length];
|
T[] values = new T[length];
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ using System.Collections.Concurrent;
|
|||||||
|
|
||||||
namespace WeaponPaints;
|
namespace WeaponPaints;
|
||||||
|
|
||||||
[MinimumApiVersion(168)]
|
[MinimumApiVersion(191)]
|
||||||
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
|
public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
|
||||||
{
|
{
|
||||||
internal static WeaponPaints Instance { get; private set; } = new();
|
internal static WeaponPaints Instance { get; private set; } = new();
|
||||||
|
|
||||||
internal static readonly Dictionary<string, string> weaponList = new()
|
internal static readonly Dictionary<string, string> weaponList = new()
|
||||||
{
|
{
|
||||||
{"weapon_deagle", "Desert Eagle"},
|
{"weapon_deagle", "Desert Eagle"},
|
||||||
@@ -79,9 +80,11 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
|||||||
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<int, ushort> g_playersGlove = new ConcurrentDictionary<int, ushort>();
|
internal static ConcurrentDictionary<int, ushort> g_playersGlove = new ConcurrentDictionary<int, ushort>();
|
||||||
|
internal static ConcurrentDictionary<int, (string? CT, string? T)> g_playersAgent = new ConcurrentDictionary<int, (string?, string?)>();
|
||||||
internal static ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>> gPlayerWeaponsInfo = new ConcurrentDictionary<int, ConcurrentDictionary<int, WeaponInfo>>();
|
internal static 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 List<JObject> agentsList = new List<JObject>();
|
||||||
internal static WeaponSynchronization? weaponSync;
|
internal static WeaponSynchronization? weaponSync;
|
||||||
public static bool g_bCommandsAllowed = true;
|
public static bool g_bCommandsAllowed = true;
|
||||||
internal Dictionary<int, string> PlayerWeaponImage = new();
|
internal Dictionary<int, string> PlayerWeaponImage = new();
|
||||||
@@ -153,9 +156,9 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
|||||||
|
|
||||||
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, agents and knife selector, standalone and web-based";
|
||||||
public override string ModuleName => "WeaponPaints";
|
public override string ModuleName => "WeaponPaints";
|
||||||
public override string ModuleVersion => "1.9b";
|
public override string ModuleVersion => "2.2c";
|
||||||
|
|
||||||
public static WeaponPaintsConfig GetWeaponPaintsConfig()
|
public static WeaponPaintsConfig GetWeaponPaintsConfig()
|
||||||
{
|
{
|
||||||
@@ -176,15 +179,15 @@ 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.Slot] = 0;
|
g_knifePickupCount[player.Slot] = 0;
|
||||||
gPlayerWeaponsInfo.TryRemove((int)player.Slot, out _);
|
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
|
||||||
g_playersKnife.TryRemove((int)player.Slot, out _);
|
g_playersKnife.TryRemove(player.Slot, out _);
|
||||||
|
|
||||||
PlayerInfo playerInfo = new PlayerInfo
|
PlayerInfo playerInfo = new PlayerInfo
|
||||||
{
|
{
|
||||||
UserId = player.UserId,
|
UserId = player.UserId,
|
||||||
Slot = player.Slot,
|
Slot = player.Slot,
|
||||||
Index = (int)player.Slot,
|
Index = (int)player.Index,
|
||||||
SteamId = player?.SteamID.ToString(),
|
SteamId = player?.SteamID.ToString(),
|
||||||
Name = player?.PlayerName,
|
Name = player?.PlayerName,
|
||||||
IpAddress = player?.IpAddress?.Split(":")[0]
|
IpAddress = player?.IpAddress?.Split(":")[0]
|
||||||
@@ -202,11 +205,16 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
|||||||
{
|
{
|
||||||
Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo));
|
Task.Run(() => weaponSync.GetGloveFromDatabase(playerInfo));
|
||||||
}
|
}
|
||||||
|
if (Config.Additional.AgentEnabled)
|
||||||
|
{
|
||||||
|
Task.Run(() => weaponSync.GetAgentFromDatabase(playerInfo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json");
|
Utility.LoadSkinsFromFile(ModuleDirectory + "/skins.json");
|
||||||
Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json");
|
Utility.LoadGlovesFromFile(ModuleDirectory + "/gloves.json");
|
||||||
|
Utility.LoadAgentsFromFile(ModuleDirectory + "/agents.json");
|
||||||
|
|
||||||
if (Config.Additional.KnifeEnabled)
|
if (Config.Additional.KnifeEnabled)
|
||||||
SetupKnifeMenu();
|
SetupKnifeMenu();
|
||||||
@@ -214,6 +222,8 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
|
|||||||
SetupSkinsMenu();
|
SetupSkinsMenu();
|
||||||
if (Config.Additional.GloveEnabled)
|
if (Config.Additional.GloveEnabled)
|
||||||
SetupGlovesMenu();
|
SetupGlovesMenu();
|
||||||
|
if (Config.Additional.AgentEnabled)
|
||||||
|
SetupAgentsMenu();
|
||||||
|
|
||||||
RegisterListeners();
|
RegisterListeners();
|
||||||
RegisterCommands();
|
RegisterCommands();
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.168" />
|
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.193" />
|
||||||
<PackageReference Include="Dapper" Version="2.1.28" />
|
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||||
<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" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -18,4 +18,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
|
<None Update="lang\**\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="gamedata\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ namespace WeaponPaints
|
|||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task GetKnifeFromDatabase(PlayerInfo player)
|
public async Task GetKnifeFromDatabase(PlayerInfo player)
|
||||||
{
|
{
|
||||||
if (!_config.Additional.KnifeEnabled) return;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||||
|
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 });
|
||||||
@@ -28,53 +30,78 @@ namespace WeaponPaints
|
|||||||
WeaponPaints.g_playersKnife[player.Slot] = playerKnife;
|
WeaponPaints.g_playersKnife[player.Slot] = playerKnife;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utility.Log(e.Message);
|
Utility.Log($"An error occurred in GetKnifeFromDatabase: {ex.Message}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task GetGloveFromDatabase(PlayerInfo player)
|
public async Task GetGloveFromDatabase(PlayerInfo player)
|
||||||
{
|
{
|
||||||
if (!_config.Additional.GloveEnabled) return;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Ensure proper disposal of resources using "using" statement
|
if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||||
|
return;
|
||||||
|
|
||||||
await using var connection = await _database.GetConnectionAsync();
|
await using var connection = await _database.GetConnectionAsync();
|
||||||
|
|
||||||
// Construct the SQL query with specific columns for better performance
|
|
||||||
string query = "SELECT `weapon_defindex` FROM `wp_player_gloves` WHERE `steamid` = @steamid";
|
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 });
|
ushort? gloveData = await connection.QueryFirstOrDefaultAsync<ushort?>(query, new { steamid = player.SteamId });
|
||||||
|
|
||||||
// Check if glove data is retrieved successfully
|
|
||||||
if (gloveData != null)
|
if (gloveData != null)
|
||||||
{
|
{
|
||||||
// Update g_playersGlove dictionary with glove data
|
|
||||||
WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
|
WeaponPaints.g_playersGlove[player.Slot] = gloveData.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Log any exceptions occurred during database operation
|
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
|
||||||
Utility.Log("An error occurred while fetching glove data: " + e.Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task GetWeaponPaintsFromDatabase(PlayerInfo player)
|
public async Task GetAgentFromDatabase(PlayerInfo player)
|
||||||
{
|
{
|
||||||
if (!_config.Additional.SkinEnabled || player == null || player.SteamId == null) return;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await using var connection = await _database.GetConnectionAsync();
|
||||||
|
string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid";
|
||||||
|
var agentData = await connection.QueryFirstOrDefaultAsync<(string, string)>(query, new { steamid = player.SteamId });
|
||||||
|
|
||||||
|
if (agentData != default)
|
||||||
|
{
|
||||||
|
string agentCT = agentData.Item1;
|
||||||
|
string agentT = agentData.Item2;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(agentCT) || !string.IsNullOrEmpty(agentT))
|
||||||
|
{
|
||||||
|
WeaponPaints.g_playersAgent[player.Slot] = (
|
||||||
|
agentCT,
|
||||||
|
agentT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Utility.Log($"An error occurred in GetGloveFromDatabase: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GetWeaponPaintsFromDatabase(PlayerInfo player)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_config.Additional.SkinEnabled || player == null || string.IsNullOrEmpty(player.SteamId))
|
||||||
|
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 * 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;
|
if (playerSkins == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
|
var weaponInfos = new ConcurrentDictionary<int, WeaponInfo>();
|
||||||
|
|
||||||
@@ -97,9 +124,9 @@ namespace WeaponPaints
|
|||||||
|
|
||||||
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
|
WeaponPaints.gPlayerWeaponsInfo[player.Slot] = weaponInfos;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utility.Log($"Database error occurred: {e.Message}");
|
Utility.Log($"An error occurred in GetWeaponPaintsFromDatabase: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +146,6 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
|
internal async Task SyncGloveToDatabase(PlayerInfo player, int defindex)
|
||||||
{
|
{
|
||||||
if (!_config.Additional.GloveEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
|
if (!_config.Additional.GloveEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
|
||||||
@@ -136,6 +162,28 @@ namespace WeaponPaints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task SyncAgentToDatabase(PlayerInfo player)
|
||||||
|
{
|
||||||
|
if (!_config.Additional.AgentEnabled || player == null || string.IsNullOrEmpty(player.SteamId)) return;
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Utility.Log($"Error syncing agents to database: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
|
internal async Task SyncWeaponPaintsToDatabase(PlayerInfo player)
|
||||||
{
|
{
|
||||||
if (player == null || string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
|
if (player == null || string.IsNullOrEmpty(player.SteamId) || !WeaponPaints.gPlayerWeaponsInfo.TryGetValue(player.Slot, out var weaponsInfo))
|
||||||
@@ -154,11 +202,24 @@ namespace WeaponPaints
|
|||||||
float wear = weaponInfo.Wear;
|
float wear = weaponInfo.Wear;
|
||||||
int seed = weaponInfo.Seed;
|
int seed = weaponInfo.Seed;
|
||||||
|
|
||||||
string query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " +
|
string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
|
||||||
"VALUES (@steamid, @weaponDefIndex, @paintId, @wear, @seed) " +
|
|
||||||
"ON DUPLICATE KEY UPDATE `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed";
|
int existingRecordCount = await connection.ExecuteScalarAsync<int>(queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex });
|
||||||
|
|
||||||
|
string query;
|
||||||
|
object parameters;
|
||||||
|
if (existingRecordCount > 0)
|
||||||
|
{
|
||||||
|
query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex";
|
||||||
|
parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed };
|
||||||
|
}
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
var parameters = new { steamid = player.SteamId, weaponDefIndex, paintId, wear, seed };
|
|
||||||
await connection.ExecuteAsync(query, parameters);
|
await connection.ExecuteAsync(query, parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +228,5 @@ namespace WeaponPaints
|
|||||||
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
|
Utility.Log($"Error syncing weapon paints to database: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
},
|
||||||
"CAttributeList_SetOrAddAttributeValueByName": {
|
"CAttributeList_SetOrAddAttributeValueByName": {
|
||||||
"signatures": {
|
"signatures": {
|
||||||
"library": "server",
|
"library": "server",
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Type {lime}!wp{default} to synchronize chosen skins",
|
"wp_info_refresh": "Type {lime}!wp{default} to synchronize chosen skins",
|
||||||
"wp_info_knife": "Type {lime}!knife{default} to open knife menu",
|
"wp_info_knife": "Type {lime}!knife{default} to open knife menu",
|
||||||
"wp_info_glove": "Type {lime}!gloves{default} to open gloves menu",
|
"wp_info_glove": "Type {lime}!gloves{default} to open gloves menu",
|
||||||
|
"wp_info_agent": "Type {lime}!agents{default} to open agents menu",
|
||||||
"wp_command_cooldown": "{lightred}You can't refresh weapon paints right now",
|
"wp_command_cooldown": "{lightred}You can't refresh weapon paints right now",
|
||||||
"wp_command_refresh_done": "{lime}Refreshing weapon paints",
|
"wp_command_refresh_done": "{lime}Refreshing weapon paints",
|
||||||
"wp_knife_menu_select": "You have chosen {lime}{0}{default} as your knife",
|
"wp_knife_menu_select": "You have chosen {lime}{0}{default} as your knife",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Knife Menu",
|
"wp_knife_menu_title": "Knife Menu",
|
||||||
"wp_glove_menu_select": "You have chosen {lime}{0}{default} as your glove",
|
"wp_glove_menu_select": "You have chosen {lime}{0}{default} as your glove",
|
||||||
"wp_glove_menu_title": "Gloves Menu",
|
"wp_glove_menu_title": "Gloves Menu",
|
||||||
|
"wp_agent_menu_select": "You have chosen {lime}{0}{default} as your agent",
|
||||||
|
"wp_agent_menu_title": "Agents Menu",
|
||||||
"wp_skin_menu_weapon_title": "Weapon Menu",
|
"wp_skin_menu_weapon_title": "Weapon Menu",
|
||||||
"wp_skin_menu_skin_title": "Select skin for {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Select skin for {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "You have chosen {lime}{0}{default} as your skin"
|
"wp_skin_menu_select": "You have chosen {lime}{0}{default} as your skin",
|
||||||
|
|
||||||
|
"None": "None"
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Ievadiet {lime}!wp{default}, lai sinhronizētu izvēlētās ādas",
|
"wp_info_refresh": "Ievadiet {lime}!wp{default}, lai sinhronizētu izvēlētās ādas",
|
||||||
"wp_info_knife": "Ievadiet {lime}!knife{default}, lai atvērtu nazis izvēlni",
|
"wp_info_knife": "Ievadiet {lime}!knife{default}, lai atvērtu nazis izvēlni",
|
||||||
"wp_info_glove": "Ievadiet {lime}!gloves{default}, lai atvērtu cimdi izvēlni",
|
"wp_info_glove": "Ievadiet {lime}!gloves{default}, lai atvērtu cimdi izvēlni",
|
||||||
|
"wp_info_agent": "Ierakstiet {lime}!agents{default}, lai atvērtu aģentu izvēlni",
|
||||||
"wp_command_cooldown": "{lightred}Šobrīd jūs nevarat atjaunot ieroču ādas",
|
"wp_command_cooldown": "{lightred}Šobrīd jūs nevarat atjaunot ieroču ādas",
|
||||||
"wp_command_refresh_done": "{lime}Atjauno ieroču ādas",
|
"wp_command_refresh_done": "{lime}Atjauno ieroču ādas",
|
||||||
"wp_knife_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu nazi",
|
"wp_knife_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu nazi",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Nazis Izvēlne",
|
"wp_knife_menu_title": "Nazis Izvēlne",
|
||||||
"wp_glove_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savus cimdus",
|
"wp_glove_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savus cimdus",
|
||||||
"wp_glove_menu_title": "Cimdu Izvēlne",
|
"wp_glove_menu_title": "Cimdu Izvēlne",
|
||||||
|
"wp_agent_menu_select": "Jūs esat izvēlējušies {lime}{0}{default} kā savu aģentu",
|
||||||
|
"wp_agent_menu_title": "Aģentu izvēlnes",
|
||||||
"wp_skin_menu_weapon_title": "Ieroču Izvēlne",
|
"wp_skin_menu_weapon_title": "Ieroču Izvēlne",
|
||||||
"wp_skin_menu_skin_title": "Izvēlieties ādu {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Izvēlieties ādu {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu ādu"
|
"wp_skin_menu_select": "Jūs esat izvēlējies {lime}{0}{default} kā savu ādu",
|
||||||
}
|
|
||||||
|
"None": "Nav"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Wpisz {lime}!wp{default}, aby zsynchronizować wybrane skórki",
|
"wp_info_refresh": "Wpisz {lime}!wp{default}, aby zsynchronizować wybrane skórki",
|
||||||
"wp_info_knife": "Wpisz {lime}!knife{default}, aby otworzyć menu noży",
|
"wp_info_knife": "Wpisz {lime}!knife{default}, aby otworzyć menu noży",
|
||||||
"wp_info_glove": "Wpisz {lime}!gloves{default}, aby otworzyć menu rękawiczek",
|
"wp_info_glove": "Wpisz {lime}!gloves{default}, aby otworzyć menu rękawiczek",
|
||||||
|
"wp_info_agent": "Wpisz {lime}!agents{default}, aby otworzyć menu agentów",
|
||||||
"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óż",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"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",
|
||||||
|
"wp_agent_menu_select": "Wybrałeś {lime}{0}{default} jako swojego agenta",
|
||||||
|
"wp_agent_menu_title": "Menu agentów",
|
||||||
"wp_skin_menu_weapon_title": "Menu Broni",
|
"wp_skin_menu_weapon_title": "Menu Broni",
|
||||||
"wp_skin_menu_skin_title": "Wybierz skórkę dla {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Wybierz skórkę dla {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Wybrałeś {lime}{0}{default} jako swoją skórkę"
|
"wp_skin_menu_select": "Wybrałeś {lime}{0}{default} jako swoją skórkę",
|
||||||
}
|
|
||||||
|
"None": "Brak"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins selecionadas",
|
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins selecionadas",
|
||||||
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
|
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
|
||||||
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
|
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
|
||||||
|
"wp_info_agent": "Digite {lime}!agents{default} para abrir o menu de agentes",
|
||||||
"wp_command_cooldown": "{lightred}Você não pode atualizar as skins de arma agora",
|
"wp_command_cooldown": "{lightred}Você não pode atualizar as skins de arma agora",
|
||||||
"wp_command_refresh_done": "{lime}Atualizando as skins de arma",
|
"wp_command_refresh_done": "{lime}Atualizando as skins de arma",
|
||||||
"wp_knife_menu_select": "Você escolheu {lime}{0}{default} como sua faca",
|
"wp_knife_menu_select": "Você escolheu {lime}{0}{default} como sua faca",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Menu de Facas",
|
"wp_knife_menu_title": "Menu de Facas",
|
||||||
"wp_glove_menu_select": "Você escolheu {lime}{0}{default} como suas luvas",
|
"wp_glove_menu_select": "Você escolheu {lime}{0}{default} como suas luvas",
|
||||||
"wp_glove_menu_title": "Menu de Luvas",
|
"wp_glove_menu_title": "Menu de Luvas",
|
||||||
|
"wp_agent_menu_select": "Você escolheu {lime}{0}{default} como seu agente",
|
||||||
|
"wp_agent_menu_title": "Menu de Agentes",
|
||||||
"wp_skin_menu_weapon_title": "Menu de Armas",
|
"wp_skin_menu_weapon_title": "Menu de Armas",
|
||||||
"wp_skin_menu_skin_title": "Selecione uma skin para {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Selecione uma skin para {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Você escolheu {lime}{0}{default} como sua skin"
|
"wp_skin_menu_select": "Você escolheu {lime}{0}{default} como sua skin",
|
||||||
}
|
|
||||||
|
"None": "Nenhum"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins selecionadas",
|
"wp_info_refresh": "Digite {lime}!wp{default} para sincronizar as skins selecionadas",
|
||||||
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
|
"wp_info_knife": "Digite {lime}!knife{default} para abrir o menu de facas",
|
||||||
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
|
"wp_info_glove": "Digite {lime}!gloves{default} para abrir o menu de luvas",
|
||||||
|
"wp_info_agent": "Digite {lime}!agents{default} para abrir o menu de agentes",
|
||||||
"wp_command_cooldown": "{lightred}Você não pode atualizar as skins de arma agora",
|
"wp_command_cooldown": "{lightred}Você não pode atualizar as skins de arma agora",
|
||||||
"wp_command_refresh_done": "{lime}Atualizando as skins de arma",
|
"wp_command_refresh_done": "{lime}Atualizando as skins de arma",
|
||||||
"wp_knife_menu_select": "Você escolheu {lime}{0}{default} como sua faca",
|
"wp_knife_menu_select": "Você escolheu {lime}{0}{default} como sua faca",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Menu de Facas",
|
"wp_knife_menu_title": "Menu de Facas",
|
||||||
"wp_glove_menu_select": "Você escolheu {lime}{0}{default} como suas luvas",
|
"wp_glove_menu_select": "Você escolheu {lime}{0}{default} como suas luvas",
|
||||||
"wp_glove_menu_title": "Menu de Luvas",
|
"wp_glove_menu_title": "Menu de Luvas",
|
||||||
|
"wp_agent_menu_select": "Escolheste {lime}{0}{default} como teu agente",
|
||||||
|
"wp_agent_menu_title": "Menu de Agentes",
|
||||||
"wp_skin_menu_weapon_title": "Menu de Armas",
|
"wp_skin_menu_weapon_title": "Menu de Armas",
|
||||||
"wp_skin_menu_skin_title": "Selecione uma skin para {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Selecione uma skin para {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Você escolheu {lime}{0}{default} como sua skin"
|
"wp_skin_menu_select": "Você escolheu {lime}{0}{default} como sua skin",
|
||||||
}
|
|
||||||
|
"None": "Nenhum"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Введите {lime}!wp{default}, чтобы синхронизировать выбранные скины",
|
"wp_info_refresh": "Введите {lime}!wp{default}, чтобы синхронизировать выбранные скины",
|
||||||
"wp_info_knife": "Введите {lime}!knife{default}, чтобы открыть меню ножей",
|
"wp_info_knife": "Введите {lime}!knife{default}, чтобы открыть меню ножей",
|
||||||
"wp_info_glove": "Введите {lime}!gloves{default}, чтобы открыть меню перчаток",
|
"wp_info_glove": "Введите {lime}!gloves{default}, чтобы открыть меню перчаток",
|
||||||
|
"wp_info_agent": "Введите {lime}!agents{default}, чтобы открыть меню агентов",
|
||||||
"wp_command_cooldown": "{lightred}Вы не можете обновить скины оружия сейчас",
|
"wp_command_cooldown": "{lightred}Вы не можете обновить скины оружия сейчас",
|
||||||
"wp_command_refresh_done": "{lime}Обновление скинов оружия",
|
"wp_command_refresh_done": "{lime}Обновление скинов оружия",
|
||||||
"wp_knife_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего ножа",
|
"wp_knife_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего ножа",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Меню Ножей",
|
"wp_knife_menu_title": "Меню Ножей",
|
||||||
"wp_glove_menu_select": "Вы выбрали {lime}{0}{default} в качестве ваших перчаток",
|
"wp_glove_menu_select": "Вы выбрали {lime}{0}{default} в качестве ваших перчаток",
|
||||||
"wp_glove_menu_title": "Меню Перчаток",
|
"wp_glove_menu_title": "Меню Перчаток",
|
||||||
|
"wp_agent_menu_select": "Вы выбрали {lime}{0}{default} в качестве своего агента",
|
||||||
|
"wp_agent_menu_title": "Меню агентов",
|
||||||
"wp_skin_menu_weapon_title": "Меню Оружия",
|
"wp_skin_menu_weapon_title": "Меню Оружия",
|
||||||
"wp_skin_menu_skin_title": "Выберите скин для {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Выберите скин для {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего скина"
|
"wp_skin_menu_select": "Вы выбрали {lime}{0}{default} в качестве вашего скина",
|
||||||
|
|
||||||
|
"None": "Нет"
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Senkronize edilen skinleri görmek için {lime}!wp{default} yazın",
|
"wp_info_refresh": "Senkronize edilen skinleri görmek için {lime}!wp{default} yazın",
|
||||||
"wp_info_knife": "Bıçak menüsünü açmak için {lime}!knife{default} yazın",
|
"wp_info_knife": "Bıçak menüsünü açmak için {lime}!knife{default} yazın",
|
||||||
"wp_info_glove": "Eldiven menüsünü açmak için {lime}!gloves{default} yazın",
|
"wp_info_glove": "Eldiven menüsünü açmak için {lime}!gloves{default} yazın",
|
||||||
|
"wp_info_agent": "Ajanlar menüsünü açmak için {lime}!agents{default} yazın",
|
||||||
"wp_command_cooldown": "{lightred}Şu anda silah skinlerini yenileyemezsiniz",
|
"wp_command_cooldown": "{lightred}Şu anda silah skinlerini yenileyemezsiniz",
|
||||||
"wp_command_refresh_done": "{lime}Silah skinleri yenileniyor",
|
"wp_command_refresh_done": "{lime}Silah skinleri yenileniyor",
|
||||||
"wp_knife_menu_select": "{lime}{0}{default} olarak bıçağınızı seçtiniz",
|
"wp_knife_menu_select": "{lime}{0}{default} olarak bıçağınızı seçtiniz",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Bıçak Menüsü",
|
"wp_knife_menu_title": "Bıçak Menüsü",
|
||||||
"wp_glove_menu_select": "{lime}{0}{default} olarak eldiveninizi seçtiniz",
|
"wp_glove_menu_select": "{lime}{0}{default} olarak eldiveninizi seçtiniz",
|
||||||
"wp_glove_menu_title": "Eldiven Menüsü",
|
"wp_glove_menu_title": "Eldiven Menüsü",
|
||||||
|
"wp_agent_menu_select": "Ajanınız olarak {lime}{0}{default} seçtiniz",
|
||||||
|
"wp_agent_menu_title": "Ajan Menüsü",
|
||||||
"wp_skin_menu_weapon_title": "Silah Menüsü",
|
"wp_skin_menu_weapon_title": "Silah Menüsü",
|
||||||
"wp_skin_menu_skin_title": "{lime}{0}{default} için bir skin seçin",
|
"wp_skin_menu_skin_title": "{lime}{0}{default} için bir skin seçin",
|
||||||
"wp_skin_menu_select": "{lime}{0}{default} olarak bir skin seçtiniz"
|
"wp_skin_menu_select": "{lime}{0}{default} olarak bir skin seçtiniz",
|
||||||
}
|
|
||||||
|
"None": "Hiçbiri"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "Введіть {lime}!wp{default}, щоб синхронізувати обрані шкури",
|
"wp_info_refresh": "Введіть {lime}!wp{default}, щоб синхронізувати обрані шкури",
|
||||||
"wp_info_knife": "Введіть {lime}!knife{default}, щоб відкрити меню ножів",
|
"wp_info_knife": "Введіть {lime}!knife{default}, щоб відкрити меню ножів",
|
||||||
"wp_info_glove": "Введіть {lime}!gloves{default}, щоб відкрити меню рукавичок",
|
"wp_info_glove": "Введіть {lime}!gloves{default}, щоб відкрити меню рукавичок",
|
||||||
|
"wp_info_agent": "Введіть {lime}!агенти{default}, щоб відкрити меню агентів",
|
||||||
"wp_command_cooldown": "{lightred}Наразі ви не можете оновлювати шкіри зброї",
|
"wp_command_cooldown": "{lightred}Наразі ви не можете оновлювати шкіри зброї",
|
||||||
"wp_command_refresh_done": "{lime}Оновлення шкірок зброї",
|
"wp_command_refresh_done": "{lime}Оновлення шкірок зброї",
|
||||||
"wp_knife_menu_select": "Ви вибрали {lime}{0}{default} як ваш ніж",
|
"wp_knife_menu_select": "Ви вибрали {lime}{0}{default} як ваш ніж",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "Меню Ножів",
|
"wp_knife_menu_title": "Меню Ножів",
|
||||||
"wp_glove_menu_select": "Ви вибрали {lime}{0}{default} як ваші рукавички",
|
"wp_glove_menu_select": "Ви вибрали {lime}{0}{default} як ваші рукавички",
|
||||||
"wp_glove_menu_title": "Меню Рукавичок",
|
"wp_glove_menu_title": "Меню Рукавичок",
|
||||||
|
"wp_agent_menu_select": "Ви обрали {lime}{0}{default} як вашого агента",
|
||||||
|
"wp_agent_menu_title": "Меню агентів",
|
||||||
"wp_skin_menu_weapon_title": "Меню Зброї",
|
"wp_skin_menu_weapon_title": "Меню Зброї",
|
||||||
"wp_skin_menu_skin_title": "Виберіть шкіру для {lime}{0}{default}",
|
"wp_skin_menu_skin_title": "Виберіть шкіру для {lime}{0}{default}",
|
||||||
"wp_skin_menu_select": "Ви вибрали {lime}{0}{default} як вашу шкіру"
|
"wp_skin_menu_select": "Ви вибрали {lime}{0}{default} як вашу шкіру",
|
||||||
|
|
||||||
|
"None": "Немає"
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
"wp_info_refresh": "输入 {lime}!wp{default} 同步已选择的皮肤",
|
"wp_info_refresh": "输入 {lime}!wp{default} 同步已选择的皮肤",
|
||||||
"wp_info_knife": "输入 {lime}!knife{default} 打开刀具菜单",
|
"wp_info_knife": "输入 {lime}!knife{default} 打开刀具菜单",
|
||||||
"wp_info_glove": "输入 {lime}!gloves{default} 打开手套菜单",
|
"wp_info_glove": "输入 {lime}!gloves{default} 打开手套菜单",
|
||||||
|
"wp_info_agent": "键入 {lime}!agents{default} 打开代理菜单",
|
||||||
"wp_command_cooldown": "{lightred}您现在无法刷新武器皮肤",
|
"wp_command_cooldown": "{lightred}您现在无法刷新武器皮肤",
|
||||||
"wp_command_refresh_done": "{lime}刷新武器皮肤",
|
"wp_command_refresh_done": "{lime}刷新武器皮肤",
|
||||||
"wp_knife_menu_select": "您已选择 {lime}{0}{default} 作为您的刀具",
|
"wp_knife_menu_select": "您已选择 {lime}{0}{default} 作为您的刀具",
|
||||||
@@ -11,7 +12,11 @@
|
|||||||
"wp_knife_menu_title": "刀具菜单",
|
"wp_knife_menu_title": "刀具菜单",
|
||||||
"wp_glove_menu_select": "您已选择 {lime}{0}{default} 作为您的手套",
|
"wp_glove_menu_select": "您已选择 {lime}{0}{default} 作为您的手套",
|
||||||
"wp_glove_menu_title": "手套菜单",
|
"wp_glove_menu_title": "手套菜单",
|
||||||
|
"wp_agent_menu_select": "您选择了{lime}{0}{default}作为您的代理",
|
||||||
|
"wp_agent_menu_title": "代理菜单",
|
||||||
"wp_skin_menu_weapon_title": "武器菜单",
|
"wp_skin_menu_weapon_title": "武器菜单",
|
||||||
"wp_skin_menu_skin_title": "为 {lime}{0}{default} 选择皮肤",
|
"wp_skin_menu_skin_title": "为 {lime}{0}{default} 选择皮肤",
|
||||||
"wp_skin_menu_select": "您已选择 {lime}{0}{default} 作为您的皮肤"
|
"wp_skin_menu_select": "您已选择 {lime}{0}{default} 作为您的皮肤",
|
||||||
}
|
|
||||||
|
"None": "无"
|
||||||
|
}
|
||||||
386
website/data/agents.json
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "",
|
||||||
|
"model": "null",
|
||||||
|
"agent_name": "Agent | Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "",
|
||||||
|
"model": "null",
|
||||||
|
"agent_name": "Agent | Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4619.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantj",
|
||||||
|
"agent_name": "'Blueberries' Buckshot | NSWC SEAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4680.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantl",
|
||||||
|
"agent_name": "'Two Times' McCoy | TACP Cavalry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4711.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_variante",
|
||||||
|
"agent_name": "Cmdr. Mae 'Dead Cold' Jamison | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4712.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_variantf",
|
||||||
|
"agent_name": "1st Lieutenant Farlow | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4713.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_variantg",
|
||||||
|
"agent_name": "John 'Van Healen' Kask | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4714.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_varianth",
|
||||||
|
"agent_name": "Bio-Haz Specialist | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4715.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_varianti",
|
||||||
|
"agent_name": "Sergeant Bombson | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4716.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_variantj",
|
||||||
|
"agent_name": "Chem-Haz Specialist | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4718.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_variantk",
|
||||||
|
"agent_name": "Rezan the Redshirt | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4726.png",
|
||||||
|
"model": "tm_professional/tm_professional_varf",
|
||||||
|
"agent_name": "Sir Bloody Miami Darryl | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4727.png",
|
||||||
|
"model": "tm_professional/tm_professional_varg",
|
||||||
|
"agent_name": "Safecracker Voltzmann | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4728.png",
|
||||||
|
"model": "tm_professional/tm_professional_varh",
|
||||||
|
"agent_name": "Little Kev | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4730.png",
|
||||||
|
"model": "tm_professional/tm_professional_varj",
|
||||||
|
"agent_name": "Getaway Sally | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4732.png",
|
||||||
|
"model": "tm_professional/tm_professional_vari",
|
||||||
|
"agent_name": "Number K | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4733.png",
|
||||||
|
"model": "tm_professional/tm_professional_varf1",
|
||||||
|
"agent_name": "Sir Bloody Silent Darryl | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4734.png",
|
||||||
|
"model": "tm_professional/tm_professional_varf2",
|
||||||
|
"agent_name": "Sir Bloody Skullhead Darryl | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4735.png",
|
||||||
|
"model": "tm_professional/tm_professional_varf3",
|
||||||
|
"agent_name": "Sir Bloody Darryl Royale | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4736.png",
|
||||||
|
"model": "tm_professional/tm_professional_varf4",
|
||||||
|
"agent_name": "Sir Bloody Loudmouth Darryl | The Professionals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4749.png",
|
||||||
|
"model": "ctm_gendarmerie/ctm_gendarmerie_varianta",
|
||||||
|
"agent_name": "Sous-Lieutenant Medic | Gendarmerie Nationale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4750.png",
|
||||||
|
"model": "ctm_gendarmerie/ctm_gendarmerie_variantb",
|
||||||
|
"agent_name": "Chem-Haz Capitaine | Gendarmerie Nationale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4751.png",
|
||||||
|
"model": "ctm_gendarmerie/ctm_gendarmerie_variantc",
|
||||||
|
"agent_name": "Chef d'Escadron Rouchard | Gendarmerie Nationale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4752.png",
|
||||||
|
"model": "ctm_gendarmerie/ctm_gendarmerie_variantd",
|
||||||
|
"agent_name": "Aspirant | Gendarmerie Nationale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4753.png",
|
||||||
|
"model": "ctm_gendarmerie/ctm_gendarmerie_variante",
|
||||||
|
"agent_name": "Officer Jacques Beltram | Gendarmerie Nationale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4756.png",
|
||||||
|
"model": "ctm_swat/ctm_swat_variantk",
|
||||||
|
"agent_name": "Lieutenant 'Tree Hugger' Farlow | SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4757.png",
|
||||||
|
"model": "ctm_diver/ctm_diver_varianta",
|
||||||
|
"agent_name": "Cmdr. Davida 'Goggles' Fernandez | SEAL Frogman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4771.png",
|
||||||
|
"model": "ctm_diver/ctm_diver_variantb",
|
||||||
|
"agent_name": "Cmdr. Frank 'Wet Sox' Baroud | SEAL Frogman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4772.png",
|
||||||
|
"model": "ctm_diver/ctm_diver_variantc",
|
||||||
|
"agent_name": "Lieutenant Rex Krikey | SEAL Frogman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4773.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_varianta",
|
||||||
|
"agent_name": "Elite Trapper Solman | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4774.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantb",
|
||||||
|
"agent_name": "Crasswater The Forgotten | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4775.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantc",
|
||||||
|
"agent_name": "Arno The Overgrown | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4776.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantd",
|
||||||
|
"agent_name": "Col. Mangos Dabisi | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4777.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variante",
|
||||||
|
"agent_name": "Vypa Sista of the Revolution | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4778.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantf",
|
||||||
|
"agent_name": "Trapper Aggressor | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4780.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantb2",
|
||||||
|
"agent_name": "'Medium Rare' Crasswater | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-4781.png",
|
||||||
|
"model": "tm_jungle_raider/tm_jungle_raider_variantf2",
|
||||||
|
"agent_name": "Trapper | Guerrilla Warfare"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5105.png",
|
||||||
|
"model": "tm_leet/tm_leet_variantg",
|
||||||
|
"agent_name": "Ground Rebel | Elite Crew"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5106.png",
|
||||||
|
"model": "tm_leet/tm_leet_varianth",
|
||||||
|
"agent_name": "Osiris | Elite Crew"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5107.png",
|
||||||
|
"model": "tm_leet/tm_leet_varianti",
|
||||||
|
"agent_name": "Prof. Shahmat | Elite Crew"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5108.png",
|
||||||
|
"model": "tm_leet/tm_leet_variantf",
|
||||||
|
"agent_name": "The Elite Mr. Muhlik | Elite Crew"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5109.png",
|
||||||
|
"model": "tm_leet/tm_leet_variantj",
|
||||||
|
"agent_name": "Jungle Rebel | Elite Crew"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5205.png",
|
||||||
|
"model": "tm_phoenix/tm_phoenix_varianth",
|
||||||
|
"agent_name": "Soldier | Phoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5206.png",
|
||||||
|
"model": "tm_phoenix/tm_phoenix_variantf",
|
||||||
|
"agent_name": "Enforcer | Phoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5207.png",
|
||||||
|
"model": "tm_phoenix/tm_phoenix_variantg",
|
||||||
|
"agent_name": "Slingshot | Phoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5208.png",
|
||||||
|
"model": "tm_phoenix/tm_phoenix_varianti",
|
||||||
|
"agent_name": "Street Soldier | Phoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5305.png",
|
||||||
|
"model": "ctm_fbi/ctm_fbi_variantf",
|
||||||
|
"agent_name": "Operator | FBI SWAT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5306.png",
|
||||||
|
"model": "ctm_fbi/ctm_fbi_variantg",
|
||||||
|
"agent_name": "Markus Delrow | FBI HRT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5307.png",
|
||||||
|
"model": "ctm_fbi/ctm_fbi_varianth",
|
||||||
|
"agent_name": "Michael Syfers | FBI Sniper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5308.png",
|
||||||
|
"model": "ctm_fbi/ctm_fbi_variantb",
|
||||||
|
"agent_name": "Special Agent Ava | FBI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5400.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantk",
|
||||||
|
"agent_name": "3rd Commando Company | KSK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5401.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variante",
|
||||||
|
"agent_name": "Seal Team 6 Soldier | NSWC SEAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5402.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantg",
|
||||||
|
"agent_name": "Buckshot | NSWC SEAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5403.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantm",
|
||||||
|
"agent_name": "'Two Times' McCoy | USAF TACP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5404.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_varianti",
|
||||||
|
"agent_name": "Lt. Commander Ricksaw | NSWC SEAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5405.png",
|
||||||
|
"model": "ctm_st6/ctm_st6_variantn",
|
||||||
|
"agent_name": "Primeiro Tenente | Brazilian 1st Battalion"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5500.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_variantf",
|
||||||
|
"agent_name": "Dragomir | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5501.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_varianti",
|
||||||
|
"agent_name": "Maximus | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5502.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_variantg",
|
||||||
|
"agent_name": "Rezan The Ready | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5503.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_variantj",
|
||||||
|
"agent_name": "Blackwolf | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5504.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_varianth",
|
||||||
|
"agent_name": "'The Doctor' Romanov | Sabre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 2,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5505.png",
|
||||||
|
"model": "tm_balkan/tm_balkan_variantl",
|
||||||
|
"agent_name": "Dragomir | Sabre Footsoldier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5601.png",
|
||||||
|
"model": "ctm_sas/ctm_sas_variantf",
|
||||||
|
"agent_name": "B Squadron Officer | SAS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"team": 3,
|
||||||
|
"image": "https://raw.githubusercontent.com/daffyyyy/cs2-WeaponPaints/main/website/img/skins/agent-5602.png",
|
||||||
|
"model": "ctm_sas/ctm_sas_variantg",
|
||||||
|
"agent_name": "D Squadron Officer | NZSAS"
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
website/img/skins/agent-4613.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
website/img/skins/agent-4619.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
website/img/skins/agent-4680.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
website/img/skins/agent-4711.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
website/img/skins/agent-4712.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
website/img/skins/agent-4713.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
website/img/skins/agent-4714.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
website/img/skins/agent-4715.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
BIN
website/img/skins/agent-4716.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
website/img/skins/agent-4718.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
website/img/skins/agent-4726.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
website/img/skins/agent-4727.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
website/img/skins/agent-4728.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
website/img/skins/agent-4730.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
website/img/skins/agent-4732.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/img/skins/agent-4733.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
website/img/skins/agent-4734.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
website/img/skins/agent-4735.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/img/skins/agent-4736.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
website/img/skins/agent-4749.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
website/img/skins/agent-4750.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
website/img/skins/agent-4751.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
website/img/skins/agent-4752.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
website/img/skins/agent-4753.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
website/img/skins/agent-4756.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
website/img/skins/agent-4757.png
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
website/img/skins/agent-4771.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
website/img/skins/agent-4772.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
website/img/skins/agent-4773.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
website/img/skins/agent-4774.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
website/img/skins/agent-4775.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/img/skins/agent-4776.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
website/img/skins/agent-4777.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
website/img/skins/agent-4778.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
website/img/skins/agent-4780.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
website/img/skins/agent-4781.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
website/img/skins/agent-5105.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
website/img/skins/agent-5106.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
website/img/skins/agent-5107.png
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
website/img/skins/agent-5108.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
website/img/skins/agent-5109.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
website/img/skins/agent-5205.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
website/img/skins/agent-5206.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
website/img/skins/agent-5207.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
website/img/skins/agent-5208.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
website/img/skins/agent-5305.png
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
website/img/skins/agent-5306.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
website/img/skins/agent-5307.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/img/skins/agent-5308.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
website/img/skins/agent-5400.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
website/img/skins/agent-5401.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
website/img/skins/agent-5402.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
website/img/skins/agent-5403.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
website/img/skins/agent-5404.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
website/img/skins/agent-5405.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
website/img/skins/agent-5500.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
website/img/skins/agent-5501.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
website/img/skins/agent-5502.png
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
website/img/skins/agent-5503.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
website/img/skins/agent-5504.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
website/img/skins/agent-5505.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
website/img/skins/agent-5601.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
website/img/skins/agent-5602.png
Normal file
|
After Width: | Height: | Size: 152 KiB |