- New knife method
- Minor commands changes
- Remove OnTick event
- Changed save place
- New skins saving method
- New gamedata file

**IMPORTANT UPDATE**
This commit is contained in:
Dawid Bepierszcz
2024-03-04 21:47:54 +01:00
parent 85d4e11f26
commit 8cf175d336
11 changed files with 353 additions and 271 deletions

View File

@@ -217,7 +217,6 @@ 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) =>
@@ -234,8 +233,9 @@ namespace WeaponPaints
return false; return false;
}); });
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) &&
@@ -263,21 +263,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}");
}
} }
} }
}; };

View File

@@ -5,9 +5,6 @@ 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;
@@ -56,7 +53,7 @@ namespace WeaponPaints
public class WeaponPaintsConfig : BasePluginConfig public class WeaponPaintsConfig : BasePluginConfig
{ {
public override int Version { get; set; } = 4; public override int Version { get; set; } = 5;
[JsonPropertyName("DatabaseHost")] [JsonPropertyName("DatabaseHost")]
public string DatabaseHost { get; set; } = ""; public string DatabaseHost { get; set; } = "";

300
Events.cs
View File

@@ -1,6 +1,8 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
namespace WeaponPaints namespace WeaponPaints
{ {
@@ -73,110 +75,156 @@ namespace WeaponPaints
IpAddress = player.IpAddress?.Split(":")[0] IpAddress = player.IpAddress?.Split(":")[0]
}; };
if (weaponSync != null) if (Config.Additional.SkinEnabled)
{ {
Task.Run(async () => gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
{ }
try if (Config.Additional.KnifeEnabled)
{ {
await weaponSync.SyncWeaponPaintsToDatabase(playerInfo); g_playersKnife.TryRemove(player.Slot, out _);
} }
catch (Exception ex) if (Config.Additional.GloveEnabled)
{ {
Utility.Log($"Error syncing weapon paints: {ex.Message}"); g_playersGlove.TryRemove(player.Slot, out _);
}
if (Config.Additional.SkinEnabled)
{
gPlayerWeaponsInfo.TryRemove(player.Slot, out _);
}
if (Config.Additional.KnifeEnabled)
{
g_playersKnife.TryRemove(player.Slot, out _);
}
if (Config.Additional.GloveEnabled)
{
g_playersGlove.TryRemove(player.Slot, out _);
}
});
} }
// Remove player's command cooldown
commandsCooldown.Remove(player.Slot); 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;
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.PlayerPawn == null || !player.PlayerPawn.IsValid || !player.PawnIsAlive ||
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;
var foundSkin = skinsList.FirstOrDefault(skin =>
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
((int?)skin?["paint"] ?? 0) == fallbackPaintKit &&
skin?["paint_name"] != null
);
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 (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;
var foundSkin1 = skinsList.FirstOrDefault(skin =>
((int?)skin?["weapon_defindex"] ?? 0) == weaponDefIndex &&
((int?)skin?["paint"] ?? 0) == fallbackPaintKit &&
skin?["paint_name"] != null
);
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{ {
return HookResult.Continue; 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;
}
}
} }
if (g_playersKnife[player.Slot] != "weapon_knife") var viewModels1 = GetPlayerViewModels(player);
{ if (viewModels1 == null || viewModels1.Length == 0)
pickupCount++; return;
g_knifePickupCount[player.Slot] = pickupCount;
AddTimer(0.2f, () => RefreshWeapons(player)); var viewModel1 = viewModels1[0];
} if (viewModel1 == null || viewModel1.Value == null || viewModel1.Value.Weapon == null || viewModel1.Value.Weapon.Value == null)
return;
return HookResult.Continue; Utilities.SetStateChanged(viewModel1.Value, "CBaseEntity", "m_CBodyComponent");
} }
private void OnMapStart(string mapName) private void OnMapStart(string mapName)
@@ -186,14 +234,18 @@ namespace WeaponPaints
if (_database != null) if (_database != null)
weaponSync = new WeaponSynchronization(_database, Config); weaponSync = new WeaponSynchronization(_database, Config);
// TODO
// needed for now // needed for now
/*
AddTimer(2.0f, () => AddTimer(2.0f, () =>
{ {
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");
}); });
*/
} }
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
@@ -210,8 +262,8 @@ namespace WeaponPaints
g_knifePickupCount[player.Slot] = 0; g_knifePickupCount[player.Slot] = 0;
if (!PlayerHasKnife(player)) //if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player); //GiveKnifeToPlayer(player);
Server.NextFrame(() => Server.NextFrame(() =>
{ {
@@ -230,101 +282,41 @@ 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;
} }
private void OnTick() public HookResult OnGiveNamedItemPost(DynamicHook hook)
{ {
foreach (var player in Utilities.GetPlayers().Where(p => var itemServices = hook.GetParam<CCSPlayer_ItemServices>(0);
p is not null && p.IsValid && p.PlayerPawn != null && p.PlayerPawn.IsValid && var weapon = hook.GetReturn<CBasePlayerWeapon>(0);
(LifeState_t)p.LifeState == LifeState_t.LIFE_ALIVE && p.SteamID.ToString().Length == 17 if (!weapon.DesignerName.Contains("weapon"))
&& !p.IsBot && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected return HookResult.Continue;
)
)
{
try
{
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) var player = GetPlayerFromItemServices(itemServices);
continue; if (player != null)
GivePlayerWeaponSkin(player, weapon);
var viewModels = GetPlayerViewModels(player); return HookResult.Continue;
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)
{
}
}
} }
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);
//RegisterEventHandler<EventItemPickup>(OnItemPickup); VirtualFunctions.GiveNamedItemFunc.Hook(OnGiveNamedItemPost, HookMode.Post);
HookEntityOutput("weapon_knife", "OnPlayerPickup", OnPickup); //HookEntityOutput("weapon_knife", "OnPlayerPickup", OnPickup);
} }
} }
} }

View File

@@ -15,7 +15,6 @@ Unfinished, unoptimized and not fully functional ugly demo weapon paints plugin
- 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 ""`**
- 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 +51,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

View File

@@ -1 +1 @@
1.9c 2.0a

View File

@@ -18,14 +18,22 @@ namespace WeaponPaints
if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return; if (isKnife && !g_playersKnife.ContainsKey(player.Slot) || isKnife && g_playersKnife[player.Slot] == "weapon_knife") return;
int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
if (isKnife) if (isKnife)
{ {
var newDefIndex = WeaponDefindex.FirstOrDefault(x => x.Value == g_playersKnife[player.Slot]);
if (newDefIndex.Key == 0) return;
if (weapon.AttributeManager.Item.ItemDefinitionIndex != newDefIndex.Key)
{
SubclassChange(weapon, (ushort)newDefIndex.Key);
}
weapon.AttributeManager.Item.ItemDefinitionIndex = (ushort)newDefIndex.Key;
weapon.AttributeManager.Item.EntityQuality = 3; weapon.AttributeManager.Item.EntityQuality = 3;
} }
int fallbackPaintKit = weapon.FallbackPaintKit; int weaponDefIndex = weapon.AttributeManager.Item.ItemDefinitionIndex;
int fallbackPaintKit = 0;
if (_config.Additional.GiveRandomSkin && if (_config.Additional.GiveRandomSkin &&
!gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex)) !gPlayerWeaponsInfo[player.Slot].ContainsKey(weaponDefIndex))
@@ -37,6 +45,7 @@ namespace WeaponPaints
weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex); weapon.FallbackPaintKit = GetRandomPaint(weaponDefIndex);
weapon.FallbackSeed = 0; weapon.FallbackSeed = 0;
weapon.FallbackWear = 0.000001f; weapon.FallbackWear = 0.000001f;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit; fallbackPaintKit = weapon.FallbackPaintKit;
@@ -48,11 +57,11 @@ namespace WeaponPaints
((int?)skin?["paint"] ?? 0) == fallbackPaintKit && ((int?)skin?["paint"] ?? 0) == fallbackPaintKit &&
skin?["paint_name"] != null skin?["paint_name"] != null
); );
/*
string skinName = foundSkin?["paint_name"]?.ToString() ?? ""; string skinName = foundSkin?["paint_name"]?.ToString() ?? "";
if (!string.IsNullOrEmpty(skinName)) if (!string.IsNullOrEmpty(skinName))
new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName); new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName);
*/
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{ {
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
@@ -94,6 +103,7 @@ namespace WeaponPaints
weapon.FallbackPaintKit = weaponInfo.Paint; weapon.FallbackPaintKit = weaponInfo.Paint;
weapon.FallbackSeed = weaponInfo.Seed; weapon.FallbackSeed = weaponInfo.Seed;
weapon.FallbackWear = weaponInfo.Wear; weapon.FallbackWear = weaponInfo.Wear;
CAttributeList_SetOrAddAttributeValueByName.Invoke(weapon.AttributeManager.Item.NetworkedDynamicAttributes.Handle, "set item texture prefab", weapon.FallbackPaintKit);
fallbackPaintKit = weapon.FallbackPaintKit; fallbackPaintKit = weapon.FallbackPaintKit;
@@ -106,10 +116,11 @@ namespace WeaponPaints
skin?["paint_name"] != null skin?["paint_name"] != null
); );
/*
var skinName1 = foundSkin1?["paint_name"]?.ToString() ?? ""; var skinName1 = foundSkin1?["paint_name"]?.ToString() ?? "";
if (!string.IsNullOrEmpty(skinName1)) if (!string.IsNullOrEmpty(skinName1))
new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName1); new SchemaString<CEconItemView>(weapon.AttributeManager.Item, "m_szCustomName").Set(skinName1);
*/
if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null) if (!isKnife && weapon.CBodyComponent != null && weapon.CBodyComponent.SceneNode != null)
{ {
var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode); var skeleton = GetSkeletonInstance(weapon.CBodyComponent.SceneNode);
@@ -142,36 +153,33 @@ namespace WeaponPaints
{ {
if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return; if (!_config.Additional.KnifeEnabled || player == null || !player.IsValid) return;
Instance.AddTimer(1.0f, () => if (PlayerHasKnife(player)) return;
string knifeToGive;
if (g_playersKnife.TryGetValue(player.Slot, out var knife))
{ {
if (PlayerHasKnife(player)) return; knifeToGive = knife;
}
else if (_config.Additional.GiveRandomKnife)
{
var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList();
string knifeToGive; if (knifeTypes.Count == 0)
if (g_playersKnife.TryGetValue(player.Slot, out var knife))
{ {
knifeToGive = knife; Utility.Log("No valid knife types found.");
} return;
else if (_config.Additional.GiveRandomKnife)
{
var knifeTypes = weaponList.Where(pair => pair.Key.StartsWith("weapon_knife") || pair.Key.StartsWith("weapon_bayonet")).ToList();
if (knifeTypes.Count == 0)
{
Utility.Log("No valid knife types found.");
return;
}
Random random = new();
int index = random.Next(knifeTypes.Count);
knifeToGive = knifeTypes[index].Key;
}
else
{
knifeToGive = (CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife";
} }
player.GiveNamedItem(knifeToGive); 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)
@@ -203,6 +211,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)
@@ -215,6 +224,8 @@ namespace WeaponPaints
if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator) if (player.Team == CsTeam.None || player.Team == CsTeam.Spectator)
return; return;
int playerTeam = player.TeamNum;
//Dictionary<string, (int, int)> weaponsWithAmmo = new Dictionary<string, (int, int)>(); //Dictionary<string, (int, int)> weaponsWithAmmo = new Dictionary<string, (int, int)>();
Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>(); Dictionary<string, List<(int, int)>> weaponsWithAmmo = new Dictionary<string, List<(int, int)>>();
@@ -257,6 +268,10 @@ namespace WeaponPaints
} }
weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo)); weaponsWithAmmo[weaponByDefindex].Add((clip1, reservedAmmo));
if (gun == null || gun.VData == null) return;
weapon.Value.Remove();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -266,45 +281,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.2f, () => 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>();
if (weapon is null || !weapon.IsValid) return; AddTimer(0.3f, () =>
CCSWeaponBaseGun gun = weapon.As<CCSWeaponBaseGun>();
if (gun == null || gun.VData == null) return;
if (gun.VData.GearSlot == gear_slot_t.GEAR_SLOT_C4 || gun.VData.GearSlot == gear_slot_t.GEAR_SLOT_GRENADES) return;
player.DropActiveWeapon();
AddTimer(0.25f, () =>
{ {
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
{ {
@@ -319,13 +344,16 @@ namespace WeaponPaints
Logger.LogWarning("Error setting weapon properties: " + ex.Message); Logger.LogWarning("Error setting weapon properties: " + ex.Message);
} }
}); });
} }
} }
}, TimerFlags.STOP_ON_MAPCHANGE);
}, TimerFlags.STOP_ON_MAPCHANGE);
} }
/*
internal void RefreshKnife(CCSPlayerController? player) internal void RefreshKnife(CCSPlayerController? player)
{ {
return;
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null) if (player == null || !player.IsValid || player.PlayerPawn?.Value == null)
return; return;
@@ -335,30 +363,45 @@ namespace WeaponPaints
var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons;
if (weapons != null && weapons.Count > 0) if (weapons != null && weapons.Count > 0)
{ {
try
{
player.ExecuteClientCommand("slot 3");
player.ExecuteClientCommand("slot 3");
var weapon = player.PlayerPawn.Value.WeaponServices.ActiveWeapon;
if (weapon is null || !weapon.IsValid || weapon.Value == null) return;
CCSWeaponBaseVData? weaponData = weapon.Value.As<CCSWeaponBase>().VData;
if (weapon.Value.DesignerName.Contains("knife") || weaponData?.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE)
{
AddTimer(0.2f, () =>
{
player.ExecuteClientCommand("slot 3");
player.DropActiveWeapon();
AddTimer(0.6f, () =>
{
if (weapon.IsValid)
weapon.Value.Remove();
GiveKnifeToPlayer(player);
});
});
}
}
catch (Exception ex)
{
Logger.LogWarning($"Cannot remove knife: {ex.Message}");
}
return;
foreach (var weapon in weapons) foreach (var weapon in weapons)
{ {
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid && weapon.Index > 0) 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)
{
Logger.LogWarning($"Cannot remove knife: {ex.Message}");
}
} }
} }
} }
} }
*/
private static void RefreshGloves(CCSPlayerController player) private static void RefreshGloves(CCSPlayerController player)
{ {
@@ -432,6 +475,24 @@ namespace WeaponPaints
return 0; return 0;
} }
public static void SubclassChange(CBasePlayerWeapon weapon, ushort itemD)
{
var SubclassChangeFunc = VirtualFunction.Create<nint, string, int>(
GameData.GetSignature("ChangeSubclass")
);
SubclassChangeFunc(weapon.Handle, itemD.ToString());
}
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 CSkeletonInstance GetSkeletonInstance(CGameSceneNode node) private static CSkeletonInstance GetSkeletonInstance(CGameSceneNode node)
{ {
Func<nint, nint> GetSkeletonInstance = VirtualFunction.Create<nint, nint>(node.Handle, 8); Func<nint, nint> GetSkeletonInstance = VirtualFunction.Create<nint, nint>(node.Handle, 8);
@@ -448,7 +509,7 @@ namespace WeaponPaints
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++)

View File

@@ -10,7 +10,7 @@ using System.Collections.Concurrent;
namespace WeaponPaints; namespace WeaponPaints;
[MinimumApiVersion(168)] [MinimumApiVersion(178)]
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();
@@ -156,7 +156,7 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig
public override string ModuleAuthor => "Nereziel & daffyy"; public override string ModuleAuthor => "Nereziel & daffyy";
public override string ModuleDescription => "Skin, gloves and knife selector, standalone and web-based"; public override string ModuleDescription => "Skin, gloves and knife selector, standalone and web-based";
public override string ModuleName => "WeaponPaints"; public override string ModuleName => "WeaponPaints";
public override string ModuleVersion => "1.9c"; public override string ModuleVersion => "2.0a";
public static WeaponPaintsConfig GetWeaponPaintsConfig() public static WeaponPaintsConfig GetWeaponPaintsConfig()
{ {

View File

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

View File

@@ -149,11 +149,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);
} }
} }

View File

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

View File

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