Compare commits

...

5 Commits

Author SHA1 Message Date
Nereziel
e53ee27b39 Merge pull request #44 from daffyyyy/fix-knives_finally
Finally fixed knife problem?
2023-11-18 19:26:37 +01:00
Dawid Bepierszcz
75112b02fe Update WeaponPaints.cs 2023-11-18 19:21:28 +01:00
Nereziel
8e92635231 sync paints on plugin reload 2023-11-18 15:20:26 +01:00
Nereziel
6923295cb6 Update build.yml 2023-11-18 15:14:40 +01:00
Nereziel
e5f98077f3 Update build.yml 2023-11-18 15:12:57 +01:00
2 changed files with 144 additions and 126 deletions

View File

@@ -28,6 +28,21 @@ jobs:
run: dotnet restore run: dotnet restore
- name: Build - name: Build
run: dotnet build ${{ env.PROJECT_PATH }} -c WeaponPaints -o ${{ env.OUTPUT_PATH }} run: dotnet build ${{ env.PROJECT_PATH }} -c WeaponPaints -o ${{ env.OUTPUT_PATH }}
publish:
permissions: write-all
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build ${{ env.PROJECT_PATH }} -c WeaponPaints -o ${{ env.OUTPUT_PATH }}
- name: Clean files - name: Clean files
run: | run: |
rm -f \ rm -f \
@@ -57,4 +72,4 @@ jobs:
name: "Build ${{ env.BUILD_NUMBER }}" name: "Build ${{ env.BUILD_NUMBER }}"
tag: "build-${{ env.BUILD_NUMBER }}" tag: "build-${{ env.BUILD_NUMBER }}"
body: | body: |
Place the plugin in game/csgo/addons/counterstrikesharp/plugins/WeaponPaints Place the plugin in game/csgo/addons/counterstrikesharp/plugins/WeaponPaints

View File

@@ -11,47 +11,39 @@ using MySqlConnector;
using Dapper; using Dapper;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.Reflection; using System.Reflection;
using CounterStrikeSharp.API.Modules.Cvars;
namespace WeaponPaints; namespace WeaponPaints;
[MinimumApiVersion(54)] [MinimumApiVersion(55)]
public class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig> public class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{ {
public override string ModuleName => "WeaponPaints"; public override string ModuleName => "WeaponPaints";
public override string ModuleDescription => "Connector for web-based player chosen wepaon paints, and standalone for knife."; public override string ModuleDescription => "Connector for web-based player chosen wepaon paints, and standalone for knife.";
public override string ModuleAuthor => "Nereziel"; public override string ModuleAuthor => "Nereziel";
public override string ModuleVersion => "0.9"; public override string ModuleVersion => "0.9";
public WeaponPaintsConfig Config { get; set; } = new(); public WeaponPaintsConfig Config { get; set; } = new();
private string DatabaseConnectionString = string.Empty; private string DatabaseConnectionString = string.Empty;
private DateTime[] commandCooldown = new DateTime[Server.MaxPlayers];
public bool IsMatchZy = false;
private DateTime[] commandCooldown = new DateTime[Server.MaxPlayers];
private Dictionary<ulong, Dictionary<nint, int>> gPlayerWeaponPaints = new(); private Dictionary<ulong, Dictionary<nint, int>> gPlayerWeaponPaints = new();
private Dictionary<ulong, Dictionary<nint, int>> gPlayerWeaponSeed = new(); private Dictionary<ulong, Dictionary<nint, int>> gPlayerWeaponSeed = new();
private Dictionary<ulong, Dictionary<nint, float>> gPlayerWeaponWear = new(); private Dictionary<ulong, Dictionary<nint, float>> gPlayerWeaponWear = new();
private Dictionary<int, string> g_playersKnife = new(); private Dictionary<int, string> g_playersKnife = new();
private static readonly Dictionary<string, string> knifeTypes = new() private static readonly Dictionary<string, string> knifeTypes = new()
{ {
{ "m9", "weapon_knife_m9_bayonet" }, { "m9", "weapon_knife_m9_bayonet" }, { "karambit", "weapon_knife_karambit" },
{ "karambit", "weapon_knife_karambit" }, { "bayonet", "weapon_bayonet" }, { "bowie", "weapon_knife_survival_bowie" },
{ "bayonet", "weapon_bayonet" }, { "butterfly", "weapon_knife_butterfly" }, { "falchion", "weapon_knife_falchion" },
{ "bowie", "weapon_knife_survival_bowie" }, { "flip", "weapon_knife_flip" }, { "gut", "weapon_knife_gut" },
{ "butterfly", "weapon_knife_butterfly" }, { "tactical", "weapon_knife_tactical" }, { "shadow", "weapon_knife_push" },
{ "falchion", "weapon_knife_falchion" }, { "navaja", "weapon_knife_gypsy_jackknife" }, { "stiletto", "weapon_knife_stiletto" },
{ "flip", "weapon_knife_flip" }, { "talon", "weapon_knife_widowmaker" }, { "ursus", "weapon_knife_ursus" },
{ "gut", "weapon_knife_gut" }, { "css", "weapon_knife_css" }, { "paracord", "weapon_knife_cord" },
{ "tactical", "weapon_knife_tactical" }, { "survival", "weapon_knife_canis" }, { "nomad", "weapon_knife_outdoor" },
{ "shadow", "weapon_knife_push" }, { "skeleton", "weapon_knife_skeleton" }, { "default", "weapon_knife" }
{ "navaja", "weapon_knife_gypsy_jackknife" },
{ "stiletto", "weapon_knife_stiletto" },
{ "talon", "weapon_knife_widowmaker" },
{ "ursus", "weapon_knife_ursus" },
{ "css", "weapon_knife_css" },
{ "paracord", "weapon_knife_cord" },
{ "survival", "weapon_knife_canis" },
{ "nomad", "weapon_knife_outdoor" },
{ "skeleton", "weapon_knife_skeleton" },
{ "default", "weapon_knife" }
}; };
private static readonly List<string> weaponList = new() private static readonly List<string> weaponList = new()
{ {
@@ -67,18 +59,33 @@ public class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
}; };
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
base.Load(hotReload); SetGlobalExceptionHandler();
BuildDatabaseConnectionString(); BuildDatabaseConnectionString();
TestDatabaseConnection(); TestDatabaseConnection();
SetGlobalExceptionHandler();
//MySql = new MySqlDb(Config.DatabaseHost, Config.DatabaseUser, Config.DatabasePassword, Config.DatabaseName!, Config.DatabasePort);
RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawned); RegisterListener<Listeners.OnEntitySpawned>(OnEntitySpawned);
RegisterListener<Listeners.OnClientPutInServer>(OnClientPutInServer); RegisterListener<Listeners.OnClientPutInServer>(OnClientPutInServer);
RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect); RegisterListener<Listeners.OnClientDisconnect>(OnClientDisconnect);
RegisterListener<Listeners.OnMapStart>(OnMapStart); RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn); RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn);
//RegisterEventHandler<EventRoundPrestart>(OnRoundPreStart); RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre);
if (Config.Additional.KnifeEnabled) RegisterEventHandler<EventItemPickup>(OnItemPickup, HookMode.Pre);
if (hotReload)
{
OnMapStart(string.Empty);
Task.Run(async () =>
{
for (int i = 1; i <= Server.MaxPlayers; i++)
{
if (Config.Additional.KnifeEnabled)
await GetKnifeFromDatabase(i);
if (Config.Additional.SkinEnabled)
await GetWeaponPaintsFromDatabase(i);
}
});
}
if (Config.Additional.KnifeEnabled)
SetupMenus(); SetupMenus();
RegisterCommands(); RegisterCommands();
@@ -123,7 +130,6 @@ public class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{ {
throw new Exception("Unknown mysql exception! " + ex.Message); throw new Exception("Unknown mysql exception! " + ex.Message);
} }
CheckDatabaseTables(); CheckDatabaseTables();
} }
@@ -131,25 +137,25 @@ public class WeaponPaints : BasePlugin, IPluginConfig<WeaponPaintsConfig>
{ {
try try
{ {
using var connection = new MySqlConnection(DatabaseConnectionString); using var connection = new MySqlConnection(DatabaseConnectionString);
await connection.OpenAsync(); await connection.OpenAsync();
using var transaction = await connection.BeginTransactionAsync(); using var transaction = await connection.BeginTransactionAsync();
try try
{ {
string createTable1 = "CREATE TABLE IF NOT EXISTS `wp_player_skins` (`steamid` varchar(64) NOT NULL, `weapon_defindex` int(6) NOT NULL, `weapon_paint_id` int(6) NOT NULL, `weapon_wear` float NOT NULL DEFAULT 0.0001, `weapon_seed` int(16) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci"; string createTable1 = "CREATE TABLE IF NOT EXISTS `wp_player_skins` (`steamid` varchar(64) NOT NULL, `weapon_defindex` int(6) NOT NULL, `weapon_paint_id` int(6) NOT NULL, `weapon_wear` float NOT NULL DEFAULT 0.0001, `weapon_seed` int(16) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci";
string createTable2 = "CREATE TABLE IF NOT EXISTS `wp_player_knife` (`steamid` varchar(64) NOT NULL, `knife` varchar(64) NOT NULL, UNIQUE (`steamid`)) ENGINE = InnoDB"; string createTable2 = "CREATE TABLE IF NOT EXISTS `wp_player_knife` (`steamid` varchar(64) NOT NULL, `knife` varchar(64) NOT NULL, UNIQUE (`steamid`)) ENGINE = InnoDB";
await connection.ExecuteAsync(createTable1, transaction: transaction); await connection.ExecuteAsync(createTable1, transaction: transaction);
await connection.ExecuteAsync(createTable2, transaction: transaction); await connection.ExecuteAsync(createTable2, transaction: transaction);
await transaction.CommitAsync(); await transaction.CommitAsync();
} }
catch (Exception) catch (Exception)
{ {
await transaction.RollbackAsync(); await transaction.RollbackAsync();
throw new Exception("Unable to create tables!"); throw new Exception("Unable to create tables!");
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -182,7 +188,7 @@ public override void Unload(bool hotReload)
{ {
AppDomain.CurrentDomain.FirstChanceException -= this.GlobalExceptionHandler; AppDomain.CurrentDomain.FirstChanceException -= this.GlobalExceptionHandler;
} }
public void RegisterCommands() private void RegisterCommands()
{ {
AddCommand($"css_{Config.Additional.CommandSkin}", "Skins info", (player, info) => { if (player == null) return; OnCommandWS(player, info); }); AddCommand($"css_{Config.Additional.CommandSkin}", "Skins info", (player, info) => { if (player == null) return; OnCommandWS(player, info); });
AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) => { if (player == null) return; OnCommandRefresh(player, info); }); AddCommand($"css_{Config.Additional.CommandRefresh}", "Skins refresh", (player, info) => { if (player == null) return; OnCommandRefresh(player, info); });
@@ -195,16 +201,27 @@ public override void Unload(bool hotReload)
}); });
} }
} }
private void OnMapStart(string mapName) private void IncompatibilityCheck()
{
// MatchZy
if (Directory.Exists(Path.GetDirectoryName(ModuleDirectory) + "/MatchZy"))
{
Console.WriteLine("[WeaponPaints] Incompatibility found: MatchZy");
IsMatchZy = true;
}
}
private void OnMapStart(string mapName)
{ {
if (!Config.Additional.KnifeEnabled) return; if (!Config.Additional.KnifeEnabled) return;
// TODO // TODO
// needed for now // needed for now
base.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 \"\"");
}); IncompatibilityCheck();
} });
}
private void OnClientPutInServer(int playerSlot) private void OnClientPutInServer(int playerSlot)
{ {
@@ -214,18 +231,18 @@ public override void Unload(bool hotReload)
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
await GetKnifeFromDatabase(playerIndex); await GetKnifeFromDatabase(playerIndex);
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
await GetWeaponPaintsFromDatabase(playerIndex); await GetWeaponPaintsFromDatabase(playerIndex);
}); });
} }
private void OnClientDisconnect(int playerSlot) private void OnClientDisconnect(int playerSlot)
{ {
CCSPlayerController player = Utilities.GetPlayerFromSlot(playerSlot); CCSPlayerController player = Utilities.GetPlayerFromSlot(playerSlot);
if (!player.IsValid || player.IsBot) return; if (!player.IsValid || player.IsBot) return;
// TODO: Clean up after player
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
g_playersKnife.Remove(playerSlot+1); g_playersKnife.Remove((int)player.EntityIndex!.Value.Value);
if (Config.Additional.SkinEnabled) if (Config.Additional.SkinEnabled)
gPlayerWeaponPaints.Remove(new SteamID(player.SteamID).SteamId64); gPlayerWeaponPaints.Remove(new SteamID(player.SteamID).SteamId64);
} }
private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) private HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info)
@@ -237,19 +254,38 @@ public override void Unload(bool hotReload)
} }
if (Config.Additional.KnifeEnabled) { if (Config.Additional.KnifeEnabled) {
GiveKnifeToPlayer(player); GiveKnifeToPlayer(player);
}
AddTimer(0.1f, () => RefreshPlayerKnife(player));
}
if (Config.Additional.SkinVisibilityFix)
{
// Check the best slot and set it. Weird solution but works xD
}
return HookResult.Continue; return HookResult.Continue;
} }
private void OnEntitySpawned(CEntityInstance entity) private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
{
if (!IsMatchZy) return HookResult.Continue;
NativeAPI.IssueServerCommand("mp_t_default_melee \"\"");
NativeAPI.IssueServerCommand("mp_ct_default_melee \"\"");
return HookResult.Continue;
}
private HookResult OnItemPickup(EventItemPickup @event, GameEventInfo info)
{
if (@event.Defindex == 42 || @event.Defindex == 59)
{
CCSPlayerController player = @event.Userid;
if (player.IsValid && !player.IsBot && @event.Item == "knife")
{
if (g_playersKnife.ContainsKey((int)player.EntityIndex!.Value.Value)
&&
g_playersKnife[(int)player.EntityIndex!.Value.Value] != "weapon_knife")
RefreshPlayerKnife(player, true);
}
}
return HookResult.Continue;
}
private void OnEntitySpawned(CEntityInstance entity)
{ {
if (!Config.Additional.SkinEnabled) return; if (!Config.Additional.SkinEnabled) return;
var designerName = entity.DesignerName; var designerName = entity.DesignerName;
@@ -297,11 +333,12 @@ public override void Unload(bool hotReload)
} catch(Exception) {} } catch(Exception) {}
}); });
} }
public void GiveKnifeToPlayer(CCSPlayerController player) public void GiveKnifeToPlayer(CCSPlayerController? player)
{ {
if (!Config.Additional.KnifeEnabled) return; if (!Config.Additional.KnifeEnabled) return;
if (player == null || !player.IsValid) return;
if (g_playersKnife.TryGetValue((int)player.EntityIndex!.Value.Value, out var knife)) if (g_playersKnife.TryGetValue((int)player.EntityIndex!.Value.Value, out var knife))
{ {
player.GiveNamedItem(knife); player.GiveNamedItem(knife);
} }
@@ -319,9 +356,10 @@ public override void Unload(bool hotReload)
} }
} }
} }
public void RemoveKnifeFromPlayer(CCSPlayerController player) public void RemoveKnifeFromPlayer(CCSPlayerController? player)
{ {
var weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons; if (player == null || !player.IsValid || !player.PawnIsAlive) return;
var weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons;
foreach (var weapon in weapons) foreach (var weapon in weapons)
{ {
if (weapon.IsValid && weapon.Value.IsValid) if (weapon.IsValid && weapon.Value.IsValid)
@@ -335,69 +373,30 @@ public override void Unload(bool hotReload)
} }
} }
} }
public void RefreshPlayerKnife(CCSPlayerController player) public void RefreshPlayerKnife(CCSPlayerController? player, bool remove = false)
{ {
if (!player.IsValid || !player.PawnIsAlive) return; if (player == null || !player.IsValid || !player.PawnIsAlive) return;
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player);
AddTimer(0.2f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot3")); if (remove == true)
AddTimer(0.32f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot2")); RemoveKnifeFromPlayer(player);
AddTimer(0.42f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot1"));
AddTimer(0.1f, () => {
if (!PlayerHasKnife(player))
GiveKnifeToPlayer(player);
});
if (Config.Additional.SkinVisibilityFix)
{
AddTimer(0.2f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot3"));
AddTimer(0.32f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot2"));
AddTimer(0.42f, () => NativeAPI.IssueClientCommand((int)player.EntityIndex!.Value.Value - 1, "slot1"));
}
} }
// Unused method, only for testing public bool PlayerHasKnife(CCSPlayerController? player)
// public void RefreshPlayerKnife(CCSPlayerController player)
// {
// if (!Config.Additional.KnifeEnabled) return;
// // if (!g_playersKnife.ContainsKey((int)player.EntityIndex!.Value.Value)) return;
// // if (!PlayerHasKnife(player))
// // player.GiveNamedItem((CsTeam)player.TeamNum == CsTeam.Terrorist ? "weapon_knife_t" : "weapon_knife");
// var weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons;
// foreach (var weapon in weapons)
// {
// if (weapon.IsValid && weapon.Value.IsValid)
// {
// //if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59)
// if (weapon.Value.DesignerName.Contains("knife"))
// {
// weapon.Value.Remove();
// break;
// }
// }
// }
// weapons = player.PlayerPawn.Value.WeaponServices!.MyWeapons;
// foreach (var weapon in weapons)
// {
// if (weapon.IsValid && weapon.Value.IsValid)
// {
// //if (weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 42 || weapon.Value.AttributeManager.Item.ItemDefinitionIndex == 59)
// if (weapon.Value.DesignerName.Contains("knife"))
// {
// var temp = weapon.Value;
// var steamId = new SteamID(player.SteamID);
// if (!gPlayerWeaponPaints.ContainsKey(steamId.SteamId64)) return;
// if (!gPlayerWeaponPaints[steamId.SteamId64].ContainsKey(temp.AttributeManager.Item.ItemDefinitionIndex)) return;
// //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]}");
// temp.AttributeManager.Item.ItemID = 16384;
// temp.AttributeManager.Item.ItemIDLow = 16384 & 0xFFFFFFFF;
// temp.AttributeManager.Item.ItemIDHigh = temp.AttributeManager.Item.ItemIDLow >> 32;
// temp.FallbackPaintKit = gPlayerWeaponPaints[steamId.SteamId64][temp.AttributeManager.Item.ItemDefinitionIndex];
// temp.FallbackSeed = gPlayerWeaponSeed[steamId.SteamId64][temp.AttributeManager.Item.ItemDefinitionIndex];
// temp.FallbackWear = gPlayerWeaponWear[steamId.SteamId64][temp.AttributeManager.Item.ItemDefinitionIndex];
// break;
// }
// }
// }
// }
public bool PlayerHasKnife(CCSPlayerController player)
{ {
if (!Config.Additional.KnifeEnabled) return false; if (!Config.Additional.KnifeEnabled) return false;
if (!player.IsValid || !player.PawnIsAlive) if (player == null || !player.IsValid || !player.PawnIsAlive)
{ {
return false; return false;
} }
@@ -457,7 +456,11 @@ public override void Unload(bool hotReload)
commandCooldown[playerIndex] = DateTime.UtcNow; commandCooldown[playerIndex] = DateTime.UtcNow;
Task.Run(async () => await GetWeaponPaintsFromDatabase(playerIndex)); Task.Run(async () => await GetWeaponPaintsFromDatabase(playerIndex));
if (Config.Additional.KnifeEnabled) if (Config.Additional.KnifeEnabled)
Task.Run(async () => await GetKnifeFromDatabase(playerIndex)); {
Task.Run(async () => await GetKnifeFromDatabase(playerIndex));
RemoveKnifeFromPlayer(player);
AddTimer(0.3f, () => GiveKnifeToPlayer(player));
}
if (!string.IsNullOrEmpty(Config.Messages.SuccessRefreshCommand)) { if (!string.IsNullOrEmpty(Config.Messages.SuccessRefreshCommand)) {
temp = $"{Config.Prefix} {Config.Messages.SuccessRefreshCommand}"; temp = $"{Config.Prefix} {Config.Messages.SuccessRefreshCommand}";
player.PrintToChat(ReplaceTags(temp)); player.PrintToChat(ReplaceTags(temp));