From 76bcb5bb858c75c56ce74c93293a9c81c5a2e725 Mon Sep 17 00:00:00 2001 From: Eduardo Leonardo Rosa da Silva Date: Mon, 20 Oct 2025 12:55:20 -0300 Subject: [PATCH 1/2] feat: Add SQLite database support with MySQL compatibility --- Config.cs | 6 ++ Database.cs | 25 ++--- IDatabaseConnection.cs | 14 +++ MySQLConnection.cs | 68 ++++++++++++ SQLiteConnection.cs | 68 ++++++++++++ Utility.cs | 227 ++++++++++++++++++++++++++------------- WeaponPaints.cs | 69 +++++++++--- WeaponPaints.csproj | 1 + WeaponPaints.json | 37 +++++++ WeaponSynchronization.cs | 164 +++++++++++++++------------- 10 files changed, 503 insertions(+), 176 deletions(-) create mode 100644 IDatabaseConnection.cs create mode 100644 MySQLConnection.cs create mode 100644 SQLiteConnection.cs create mode 100644 WeaponPaints.json diff --git a/Config.cs b/Config.cs index a23198eb..610da276 100644 --- a/Config.cs +++ b/Config.cs @@ -91,6 +91,12 @@ namespace WeaponPaints [JsonPropertyName("DatabaseName")] public string DatabaseName { get; set; } = ""; + [JsonPropertyName("DatabaseType")] + public string DatabaseType { get; set; } = "mysql"; + + [JsonPropertyName("DatabasePath")] + public string DatabasePath { get; set; } = "weaponpaints.db"; + [JsonPropertyName("CmdRefreshCooldownSeconds")] public int CmdRefreshCooldownSeconds { get; set; } = 3; diff --git a/Database.cs b/Database.cs index 08d69d54..21dbe970 100644 --- a/Database.cs +++ b/Database.cs @@ -1,23 +1,20 @@ using Microsoft.Extensions.Logging; -using MySqlConnector; namespace WeaponPaints { - public class Database(string dbConnectionString) + public class Database { - public async Task GetConnectionAsync() + private readonly IDatabaseConnection _connection; + + public Database(IDatabaseConnection connection) { - try - { - var connection = new MySqlConnection(dbConnectionString); - await connection.OpenAsync(); - return connection; - } - catch (Exception ex) - { - WeaponPaints.Instance.Logger.LogError($"Unable to connect to database: {ex.Message}"); - throw; - } + _connection = connection; + } + + public async Task GetConnectionAsync() + { + await _connection.OpenAsync(); + return _connection; } } } \ No newline at end of file diff --git a/IDatabaseConnection.cs b/IDatabaseConnection.cs new file mode 100644 index 00000000..12e08dcc --- /dev/null +++ b/IDatabaseConnection.cs @@ -0,0 +1,14 @@ +using System.Data; + +namespace WeaponPaints +{ + public interface IDatabaseConnection : IAsyncDisposable, IDisposable + { + Task OpenAsync(); + Task CloseAsync(); + Task BeginTransactionAsync(); + Task CommitTransactionAsync(IDbTransaction transaction); + Task RollbackTransactionAsync(IDbTransaction transaction); + IDbConnection GetConnection(); + } +} diff --git a/MySQLConnection.cs b/MySQLConnection.cs new file mode 100644 index 00000000..057752b0 --- /dev/null +++ b/MySQLConnection.cs @@ -0,0 +1,68 @@ +using Microsoft.Extensions.Logging; +using MySqlConnector; +using System.Data; + +namespace WeaponPaints +{ + public class MySQLConnection : IDatabaseConnection + { + private readonly MySqlConnection _connection; + private readonly ILogger _logger; + + public MySQLConnection(string connectionString, ILogger logger) + { + _connection = new MySqlConnection(connectionString); + _logger = logger; + } + + public async Task OpenAsync() + { + try + { + await _connection.OpenAsync(); + } + catch (Exception ex) + { + _logger.LogError($"Unable to connect to MySQL database: {ex.Message}"); + throw; + } + } + + public async Task CloseAsync() + { + await _connection.CloseAsync(); + } + + public async Task BeginTransactionAsync() + { + return await _connection.BeginTransactionAsync(); + } + + public Task CommitTransactionAsync(IDbTransaction transaction) + { + transaction.Commit(); + return Task.CompletedTask; + } + + public Task RollbackTransactionAsync(IDbTransaction transaction) + { + transaction.Rollback(); + return Task.CompletedTask; + } + + public IDbConnection GetConnection() + { + return _connection; + } + + public void Dispose() + { + _connection?.Dispose(); + } + + public async ValueTask DisposeAsync() + { + await _connection.DisposeAsync(); + } + } +} diff --git a/SQLiteConnection.cs b/SQLiteConnection.cs new file mode 100644 index 00000000..d67a99ae --- /dev/null +++ b/SQLiteConnection.cs @@ -0,0 +1,68 @@ +using Microsoft.Data.Sqlite; +using Microsoft.Extensions.Logging; +using System.Data; + +namespace WeaponPaints +{ + public class SQLiteConnection : IDatabaseConnection + { + private readonly Microsoft.Data.Sqlite.SqliteConnection _connection; + private readonly ILogger _logger; + + public SQLiteConnection(string connectionString, ILogger logger) + { + _connection = new Microsoft.Data.Sqlite.SqliteConnection(connectionString); + _logger = logger; + } + + public async Task OpenAsync() + { + try + { + await _connection.OpenAsync(); + } + catch (Exception ex) + { + _logger.LogError($"Unable to connect to SQLite database: {ex.Message}"); + throw; + } + } + + public async Task CloseAsync() + { + await _connection.CloseAsync(); + } + + public async Task BeginTransactionAsync() + { + return await _connection.BeginTransactionAsync(); + } + + public Task CommitTransactionAsync(IDbTransaction transaction) + { + transaction.Commit(); + return Task.CompletedTask; + } + + public Task RollbackTransactionAsync(IDbTransaction transaction) + { + transaction.Rollback(); + return Task.CompletedTask; + } + + public IDbConnection GetConnection() + { + return _connection; + } + + public void Dispose() + { + _connection?.Dispose(); + } + + public async ValueTask DisposeAsync() + { + await _connection.DisposeAsync(); + } + } +} diff --git a/Utility.cs b/Utility.cs index d80e8b21..91e5a889 100644 --- a/Utility.cs +++ b/Utility.cs @@ -20,89 +20,166 @@ namespace WeaponPaints try { await using var connection = await WeaponPaints.Database.GetConnectionAsync(); - await using var transaction = await connection.BeginTransactionAsync(); + string[] createTableQueries = GetCreateTableQueries(); + + // Log para debug + WeaponPaints.Instance.Logger.LogInformation($"[WeaponPaints] Creating {createTableQueries.Length} tables for {Config?.DatabaseType} database"); - try + foreach (var query in createTableQueries) { - string[] createTableQueries = - [ - @" - CREATE TABLE IF NOT EXISTS `wp_player_skins` ( - `steamid` varchar(18) NOT NULL, - `weapon_team` int(1) NOT NULL, - `weapon_defindex` int(6) NOT NULL, - `weapon_paint_id` int(6) NOT NULL, - `weapon_wear` float NOT NULL DEFAULT 0.000001, - `weapon_seed` int(16) NOT NULL DEFAULT 0, - `weapon_nametag` VARCHAR(128) DEFAULT NULL, - `weapon_stattrak` tinyint(1) NOT NULL DEFAULT 0, - `weapon_stattrak_count` int(10) NOT NULL DEFAULT 0, - `weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', - `weapon_keychain` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed', - UNIQUE (`steamid`, `weapon_team`, `weapon_defindex`) -- Add unique constraint here - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", - - @" - CREATE TABLE IF NOT EXISTS `wp_player_knife` ( - `steamid` varchar(18) NOT NULL, - `weapon_team` int(1) NOT NULL, - `knife` varchar(64) NOT NULL, - UNIQUE (`steamid`, `weapon_team`) -- Unique constraint - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", - - @" - CREATE TABLE IF NOT EXISTS `wp_player_gloves` ( - `steamid` varchar(18) NOT NULL, - `weapon_team` int(1) NOT NULL, - `weapon_defindex` int(11) NOT NULL, - UNIQUE (`steamid`, `weapon_team`) -- Unique constraint - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", - - @" - CREATE TABLE IF NOT EXISTS `wp_player_agents` ( - `steamid` varchar(18) NOT NULL, - `agent_ct` varchar(64) DEFAULT NULL, - `agent_t` varchar(64) DEFAULT NULL, - UNIQUE (`steamid`) -- Unique constraint - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", - - @" - CREATE TABLE IF NOT EXISTS `wp_player_music` ( - `steamid` varchar(64) NOT NULL, - `weapon_team` int(1) NOT NULL, - `music_id` int(11) NOT NULL, - UNIQUE (`steamid`, `weapon_team`) -- Unique constraint - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", - - @" - CREATE TABLE IF NOT EXISTS `wp_player_pins` ( - `steamid` varchar(64) NOT NULL, - `weapon_team` int(1) NOT NULL, - `id` int(11) NOT NULL, - UNIQUE (`steamid`, `weapon_team`) -- Unique constraint - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" - ]; - - foreach (var query in createTableQueries) + try { - await connection.ExecuteAsync(query, transaction: transaction); + await connection.GetConnection().ExecuteAsync(query); + WeaponPaints.Instance.Logger.LogInformation($"[WeaponPaints] Table created successfully"); } + catch (Exception ex) + { + WeaponPaints.Instance.Logger.LogError($"[WeaponPaints] Error creating table: {ex.Message}"); + WeaponPaints.Instance.Logger.LogError($"[WeaponPaints] Query: {query}"); + throw; + } + } - await transaction.CommitAsync(); - } - catch (Exception) - { - await transaction.RollbackAsync(); - throw new Exception("[WeaponPaints] Unable to create tables!"); - } + WeaponPaints.Instance.Logger.LogInformation("[WeaponPaints] All database tables created successfully"); } catch (Exception ex) { - throw new Exception("[WeaponPaints] Unknown MySQL exception! " + ex.Message); + WeaponPaints.Instance.Logger.LogError($"[WeaponPaints] Database exception: {ex.Message}"); + throw new Exception("[WeaponPaints] Unknown database exception! " + ex.Message); + } + } + + private static string[] GetCreateTableQueries() + { + if (Config?.DatabaseType?.ToLower() == "sqlite") + { + return new string[] + { + @" + CREATE TABLE IF NOT EXISTS wp_player_skins ( + steamid TEXT NOT NULL, + weapon_team INTEGER NOT NULL, + weapon_defindex INTEGER NOT NULL, + weapon_paint_id INTEGER NOT NULL, + weapon_wear REAL NOT NULL DEFAULT 0.000001, + weapon_seed INTEGER NOT NULL DEFAULT 0, + weapon_nametag TEXT DEFAULT NULL, + weapon_stattrak INTEGER NOT NULL DEFAULT 0, + weapon_stattrak_count INTEGER NOT NULL DEFAULT 0, + weapon_sticker_0 TEXT NOT NULL DEFAULT '0;0;0;0;0;0;0', + weapon_sticker_1 TEXT NOT NULL DEFAULT '0;0;0;0;0;0;0', + weapon_sticker_2 TEXT NOT NULL DEFAULT '0;0;0;0;0;0;0', + weapon_sticker_3 TEXT NOT NULL DEFAULT '0;0;0;0;0;0;0', + weapon_sticker_4 TEXT NOT NULL DEFAULT '0;0;0;0;0;0;0', + weapon_keychain TEXT NOT NULL DEFAULT '0;0;0;0;0', + UNIQUE (steamid, weapon_team, weapon_defindex) + )", + + @" + CREATE TABLE IF NOT EXISTS wp_player_knife ( + steamid TEXT NOT NULL, + weapon_team INTEGER NOT NULL, + knife TEXT NOT NULL, + UNIQUE (steamid, weapon_team) + )", + + @" + CREATE TABLE IF NOT EXISTS wp_player_gloves ( + steamid TEXT NOT NULL, + weapon_team INTEGER NOT NULL, + weapon_defindex INTEGER NOT NULL, + UNIQUE (steamid, weapon_team) + )", + + @" + CREATE TABLE IF NOT EXISTS wp_player_agents ( + steamid TEXT NOT NULL, + agent_ct TEXT DEFAULT NULL, + agent_t TEXT DEFAULT NULL, + UNIQUE (steamid) + )", + + @" + CREATE TABLE IF NOT EXISTS wp_player_music ( + steamid TEXT NOT NULL, + weapon_team INTEGER NOT NULL, + music_id INTEGER NOT NULL, + UNIQUE (steamid, weapon_team) + )", + + @" + CREATE TABLE IF NOT EXISTS wp_player_pins ( + steamid TEXT NOT NULL, + weapon_team INTEGER NOT NULL, + id INTEGER NOT NULL, + UNIQUE (steamid, weapon_team) + )" + }; + } + else // MySQL + { + return new string[] + { + @" + CREATE TABLE IF NOT EXISTS `wp_player_skins` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `weapon_defindex` int(6) NOT NULL, + `weapon_paint_id` int(6) NOT NULL, + `weapon_wear` float NOT NULL DEFAULT 0.000001, + `weapon_seed` int(16) NOT NULL DEFAULT 0, + `weapon_nametag` VARCHAR(128) DEFAULT NULL, + `weapon_stattrak` tinyint(1) NOT NULL DEFAULT 0, + `weapon_stattrak_count` int(10) NOT NULL DEFAULT 0, + `weapon_sticker_0` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_1` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_2` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_3` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_sticker_4` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0;0;0' COMMENT 'id;schema;x;y;wear;scale;rotation', + `weapon_keychain` VARCHAR(128) NOT NULL DEFAULT '0;0;0;0;0' COMMENT 'id;x;y;z;seed', + UNIQUE (`steamid`, `weapon_team`, `weapon_defindex`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_knife` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `knife` varchar(64) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_gloves` ( + `steamid` varchar(18) NOT NULL, + `weapon_team` int(1) NOT NULL, + `weapon_defindex` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_agents` ( + `steamid` varchar(18) NOT NULL, + `agent_ct` varchar(64) DEFAULT NULL, + `agent_t` varchar(64) DEFAULT NULL, + UNIQUE (`steamid`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_music` ( + `steamid` varchar(64) NOT NULL, + `weapon_team` int(1) NOT NULL, + `music_id` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + + @" + CREATE TABLE IF NOT EXISTS `wp_player_pins` ( + `steamid` varchar(64) NOT NULL, + `weapon_team` int(1) NOT NULL, + `id` int(11) NOT NULL, + UNIQUE (`steamid`, `weapon_team`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" + }; } } diff --git a/WeaponPaints.cs b/WeaponPaints.cs index 0f96ac68..ec180710 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -80,9 +80,28 @@ public partial class WeaponPaints : BasePlugin, IPluginConfig await Utility.CheckDatabaseTables()); + _localizer = Localizer; Utility.ShowAd(ModuleVersion); Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger)); } diff --git a/WeaponPaints.csproj b/WeaponPaints.csproj index af12d7fa..b84754ac 100644 --- a/WeaponPaints.csproj +++ b/WeaponPaints.csproj @@ -12,6 +12,7 @@ + diff --git a/WeaponPaints.json b/WeaponPaints.json new file mode 100644 index 00000000..a66a6ada --- /dev/null +++ b/WeaponPaints.json @@ -0,0 +1,37 @@ +{ + "ConfigVersion": 10, + "SkinsLanguage": "pt-BR", + "DatabaseType": "sqlite", + "DatabasePath": "weaponpaints.db", + "DatabaseHost": "", + "DatabasePort": 3306, + "DatabaseUser": "", + "DatabasePassword": "", + "DatabaseName": "", + "CmdRefreshCooldownSeconds": 3, + "Website": "example.com/skins", + "Additional": { + "KnifeEnabled": true, + "GloveEnabled": true, + "MusicEnabled": true, + "AgentEnabled": true, + "SkinEnabled": true, + "PinsEnabled": true, + "CommandWpEnabled": true, + "CommandKillEnabled": true, + "CommandKnife": ["knife"], + "CommandMusic": ["music"], + "CommandPin": ["pin", "pins", "coin", "coins"], + "CommandGlove": ["gloves"], + "CommandAgent": ["agents"], + "CommandStattrak": ["stattrak", "st"], + "CommandSkin": ["ws"], + "CommandSkinSelection": ["skins"], + "CommandRefresh": ["wp"], + "CommandKill": ["kill"], + "GiveRandomKnife": false, + "GiveRandomSkin": false, + "ShowSkinImage": true + }, + "MenuType": "selectable" +} diff --git a/WeaponSynchronization.cs b/WeaponSynchronization.cs index bc944188..09678361 100644 --- a/WeaponSynchronization.cs +++ b/WeaponSynchronization.cs @@ -1,8 +1,8 @@ using Dapper; -using MySqlConnector; using System.Collections.Concurrent; using CounterStrikeSharp.API.Modules.Utils; using System.Globalization; +using System.Data; namespace WeaponPaints; @@ -24,17 +24,17 @@ internal class WeaponSynchronization await using var connection = await _database.GetConnectionAsync(); if (_config.Additional.KnifeEnabled) - GetKnifeFromDatabase(player, connection); + GetKnifeFromDatabase(player, connection.GetConnection()); if (_config.Additional.GloveEnabled) - GetGloveFromDatabase(player, connection); + GetGloveFromDatabase(player, connection.GetConnection()); if (_config.Additional.AgentEnabled) - GetAgentFromDatabase(player, connection); + GetAgentFromDatabase(player, connection.GetConnection()); if (_config.Additional.MusicEnabled) - GetMusicFromDatabase(player, connection); + GetMusicFromDatabase(player, connection.GetConnection()); if (_config.Additional.SkinEnabled) - GetWeaponPaintsFromDatabase(player, connection); + GetWeaponPaintsFromDatabase(player, connection.GetConnection()); if (_config.Additional.PinsEnabled) - GetPinsFromDatabase(player, connection); + GetPinsFromDatabase(player, connection.GetConnection()); } catch (Exception ex) { @@ -43,14 +43,16 @@ internal class WeaponSynchronization } } - private void GetKnifeFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetKnifeFromDatabase(PlayerInfo? player, IDbConnection connection) { try { if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player?.SteamId)) return; - const string query = "SELECT `knife`, `weapon_team` FROM `wp_player_knife` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT knife, weapon_team FROM wp_player_knife WHERE steamid = @steamid ORDER BY weapon_team ASC" + : "SELECT `knife`, `weapon_team` FROM `wp_player_knife` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player foreach (var row in rows) @@ -59,14 +61,14 @@ internal class WeaponSynchronization if (string.IsNullOrEmpty(row.knife)) continue; // Determine the weapon team based on the query result - CsTeam weaponTeam = (int)row.weapon_team switch + CsTeam weaponTeam = Convert.ToInt32(row.weapon_team) switch { 2 => CsTeam.Terrorist, 3 => CsTeam.CounterTerrorist, _ => CsTeam.None, }; - // Get or create entries for the player’s slot + // Get or create entries for the player's slot var playerKnives = WeaponPaints.GPlayersKnife.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); if (weaponTeam == CsTeam.None) @@ -88,14 +90,16 @@ internal class WeaponSynchronization } } - private void GetGloveFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetGloveFromDatabase(PlayerInfo? player, IDbConnection connection) { try { if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player?.SteamId)) return; - const string query = "SELECT `weapon_defindex`, `weapon_team` FROM `wp_player_gloves` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT weapon_defindex, weapon_team FROM wp_player_gloves WHERE steamid = @steamid ORDER BY weapon_team ASC" + : "SELECT `weapon_defindex`, `weapon_team` FROM `wp_player_gloves` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player foreach (var row in rows) @@ -104,7 +108,7 @@ internal class WeaponSynchronization if (row.weapon_defindex == null) continue; // Determine the weapon team based on the query result var playerGloves = WeaponPaints.GPlayersGlove.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); - CsTeam weaponTeam = (int)row.weapon_team switch + CsTeam weaponTeam = Convert.ToInt32(row.weapon_team) switch { 2 => CsTeam.Terrorist, 3 => CsTeam.CounterTerrorist, @@ -116,13 +120,13 @@ internal class WeaponSynchronization if (weaponTeam == CsTeam.None) { // Assign glove ID to both teams if weaponTeam is None - playerGloves[CsTeam.Terrorist] = (ushort)row.weapon_defindex; - playerGloves[CsTeam.CounterTerrorist] = (ushort)row.weapon_defindex; + playerGloves[CsTeam.Terrorist] = Convert.ToUInt16(row.weapon_defindex); + playerGloves[CsTeam.CounterTerrorist] = Convert.ToUInt16(row.weapon_defindex); } else { // Assign glove ID to the specific team - playerGloves[weaponTeam] = (ushort)row.weapon_defindex; + playerGloves[weaponTeam] = Convert.ToUInt16(row.weapon_defindex); } } } @@ -132,14 +136,16 @@ internal class WeaponSynchronization } } - private void GetAgentFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetAgentFromDatabase(PlayerInfo? player, IDbConnection connection) { try { if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player?.SteamId)) return; - const string query = "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT agent_ct, agent_t FROM wp_player_agents WHERE steamid = @steamid" + : "SELECT `agent_ct`, `agent_t` FROM `wp_player_agents` WHERE `steamid` = @steamid"; var agentData = connection.QueryFirstOrDefault<(string, string)>(query, new { steamid = player.SteamId }); if (agentData == default) return; @@ -160,7 +166,7 @@ internal class WeaponSynchronization } } - private void GetWeaponPaintsFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetWeaponPaintsFromDatabase(PlayerInfo? player, IDbConnection connection) { try { @@ -172,20 +178,22 @@ internal class WeaponSynchronization // var weaponInfos = new ConcurrentDictionary(); - const string query = "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT * FROM wp_player_skins WHERE steamid = @steamid ORDER BY weapon_team ASC" + : "SELECT * FROM `wp_player_skins` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; var playerSkins = connection.Query(query, new { steamid = player.SteamId }); foreach (var row in playerSkins) { - int weaponDefIndex = row.weapon_defindex ?? 0; - int weaponPaintId = row.weapon_paint_id ?? 0; - float weaponWear = row.weapon_wear ?? 0f; - int weaponSeed = row.weapon_seed ?? 0; - string weaponNameTag = row.weapon_nametag ?? ""; - bool weaponStatTrak = row.weapon_stattrak ?? false; - int weaponStatTrakCount = row.weapon_stattrak_count ?? 0; + int weaponDefIndex = Convert.ToInt32(row.weapon_defindex ?? 0); + int weaponPaintId = Convert.ToInt32(row.weapon_paint_id ?? 0); + float weaponWear = Convert.ToSingle(row.weapon_wear ?? 0f); + int weaponSeed = Convert.ToInt32(row.weapon_seed ?? 0); + string weaponNameTag = row.weapon_nametag?.ToString() ?? ""; + bool weaponStatTrak = Convert.ToBoolean(row.weapon_stattrak ?? false); + int weaponStatTrakCount = Convert.ToInt32(row.weapon_stattrak_count ?? 0); - CsTeam weaponTeam = row.weapon_team switch + CsTeam weaponTeam = Convert.ToInt32(row.weapon_team) switch { 2 => CsTeam.Terrorist, 3 => CsTeam.CounterTerrorist, @@ -295,14 +303,16 @@ internal class WeaponSynchronization } } - private void GetMusicFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetMusicFromDatabase(PlayerInfo? player, IDbConnection connection) { try { if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player?.SteamId)) return; - const string query = "SELECT `music_id`, `weapon_team` FROM `wp_player_music` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT music_id, weapon_team FROM wp_player_music WHERE steamid = @steamid ORDER BY weapon_team ASC" + : "SELECT `music_id`, `weapon_team` FROM `wp_player_music` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player foreach (var row in rows) @@ -311,26 +321,26 @@ internal class WeaponSynchronization if (row.music_id == null) continue; // Determine the weapon team based on the query result - CsTeam weaponTeam = (int)row.weapon_team switch + CsTeam weaponTeam = Convert.ToInt32(row.weapon_team) switch { 2 => CsTeam.Terrorist, 3 => CsTeam.CounterTerrorist, _ => CsTeam.None, }; - // Get or create entries for the player’s slot + // Get or create entries for the player's slot var playerMusic = WeaponPaints.GPlayersMusic.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); if (weaponTeam == CsTeam.None) { // Assign music ID to both teams if weaponTeam is None - playerMusic[CsTeam.Terrorist] = (ushort)row.music_id; - playerMusic[CsTeam.CounterTerrorist] = (ushort)row.music_id; + playerMusic[CsTeam.Terrorist] = Convert.ToUInt16(row.music_id); + playerMusic[CsTeam.CounterTerrorist] = Convert.ToUInt16(row.music_id); } else { // Assign music ID to the specific team - playerMusic[weaponTeam] = (ushort)row.music_id; + playerMusic[weaponTeam] = Convert.ToUInt16(row.music_id); } } } @@ -340,14 +350,16 @@ internal class WeaponSynchronization } } - private void GetPinsFromDatabase(PlayerInfo? player, MySqlConnection connection) + private void GetPinsFromDatabase(PlayerInfo? player, IDbConnection connection) { try { if (string.IsNullOrEmpty(player?.SteamId)) return; - const string query = "SELECT `id`, `weapon_team` FROM `wp_player_pins` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT id, weapon_team FROM wp_player_pins WHERE steamid = @steamid ORDER BY weapon_team ASC" + : "SELECT `id`, `weapon_team` FROM `wp_player_pins` WHERE `steamid` = @steamid ORDER BY `weapon_team` ASC"; var rows = connection.Query(query, new { steamid = player.SteamId }); // Retrieve all records for the player foreach (var row in rows) @@ -356,26 +368,26 @@ internal class WeaponSynchronization if (row.id == null) continue; // Determine the weapon team based on the query result - CsTeam weaponTeam = (int)row.weapon_team switch + CsTeam weaponTeam = Convert.ToInt32(row.weapon_team) switch { 2 => CsTeam.Terrorist, 3 => CsTeam.CounterTerrorist, _ => CsTeam.None, }; - // Get or create entries for the player’s slot + // Get or create entries for the player's slot var playerPins = WeaponPaints.GPlayersPin.GetOrAdd(player.Slot, _ => new ConcurrentDictionary()); if (weaponTeam == CsTeam.None) { // Assign pin ID to both teams if weaponTeam is None - playerPins[CsTeam.Terrorist] = (ushort)row.id; - playerPins[CsTeam.CounterTerrorist] = (ushort)row.id; + playerPins[CsTeam.Terrorist] = Convert.ToUInt16(row.id); + playerPins[CsTeam.CounterTerrorist] = Convert.ToUInt16(row.id); } else { // Assign pin ID to the specific team - playerPins[weaponTeam] = (ushort)row.id; + playerPins[weaponTeam] = Convert.ToUInt16(row.id); } } } @@ -389,7 +401,9 @@ internal class WeaponSynchronization { if (!_config.Additional.KnifeEnabled || string.IsNullOrEmpty(player.SteamId) || string.IsNullOrEmpty(knife) || teams.Length == 0) return; - const string query = "INSERT INTO `wp_player_knife` (`steamid`, `weapon_team`, `knife`) VALUES(@steamid, @team, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT OR REPLACE INTO wp_player_knife (steamid, weapon_team, knife) VALUES(@steamid, @team, @newKnife)" + : "INSERT INTO `wp_player_knife` (`steamid`, `weapon_team`, `knife`) VALUES(@steamid, @team, @newKnife) ON DUPLICATE KEY UPDATE `knife` = @newKnife"; try { @@ -398,7 +412,7 @@ internal class WeaponSynchronization // Loop through each team and insert/update accordingly foreach (var team in teams) { - await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newKnife = knife }); + await connection.GetConnection().ExecuteAsync(query, new { steamid = player.SteamId, team, newKnife = knife }); } } catch (Exception e) @@ -413,8 +427,9 @@ internal class WeaponSynchronization if (!_config.Additional.GloveEnabled || string.IsNullOrEmpty(player.SteamId) || teams.Length == 0) return; - const string query = @" - INSERT INTO `wp_player_gloves` (`steamid`, `weapon_team`, `weapon_defindex`) + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT OR REPLACE INTO wp_player_gloves (steamid, weapon_team, weapon_defindex) VALUES(@steamid, @team, @gloveDefIndex)" + : @"INSERT INTO `wp_player_gloves` (`steamid`, `weapon_team`, `weapon_defindex`) VALUES(@steamid, @team, @gloveDefIndex) ON DUPLICATE KEY UPDATE `weapon_defindex` = @gloveDefIndex"; @@ -427,7 +442,7 @@ internal class WeaponSynchronization foreach (var team in teams) { // Execute the SQL command for each team - await connection.ExecuteAsync(query, new { + await connection.GetConnection().ExecuteAsync(query, new { steamid = player.SteamId, team = (int)team, // Cast the CsTeam enum to int for insertion gloveDefIndex @@ -445,18 +460,14 @@ internal class WeaponSynchronization { if (!_config.Additional.AgentEnabled || string.IsNullOrEmpty(player.SteamId)) return; - const string query = """ - INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`) - VALUES(@steamid, @agent_ct, @agent_t) - ON DUPLICATE KEY UPDATE - `agent_ct` = @agent_ct, - `agent_t` = @agent_t - """; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT OR REPLACE INTO wp_player_agents (steamid, agent_ct, agent_t) VALUES(@steamid, @agent_ct, @agent_t)" + : "INSERT INTO `wp_player_agents` (`steamid`, `agent_ct`, `agent_t`) VALUES(@steamid, @agent_ct, @agent_t) ON DUPLICATE KEY UPDATE `agent_ct` = @agent_ct, `agent_t` = @agent_t"; try { await using var connection = await _database.GetConnectionAsync(); - await connection.ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T }); + await connection.GetConnection().ExecuteAsync(query, new { steamid = player.SteamId, agent_ct = WeaponPaints.GPlayersAgent[player.Slot].CT, agent_t = WeaponPaints.GPlayersAgent[player.Slot].T }); } catch (Exception e) { @@ -483,9 +494,11 @@ internal class WeaponSynchronization var seed = weaponInfo.Seed; // Prepare the queries to check and update/insert weapon skin data - const string queryCheckExistence = "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; + string queryCheckExistence = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "SELECT COUNT(*) FROM wp_player_skins WHERE steamid = @steamid AND weapon_defindex = @weaponDefIndex AND weapon_team = @weaponTeam" + : "SELECT COUNT(*) FROM `wp_player_skins` WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; - var existingRecordCount = await connection.ExecuteScalarAsync( + var existingRecordCount = await connection.GetConnection().ExecuteScalarAsync( queryCheckExistence, new { steamid = player.SteamId, weaponDefIndex, weaponTeam = teamId } ); @@ -496,19 +509,21 @@ internal class WeaponSynchronization if (existingRecordCount > 0) { // Update existing record - query = "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed " + - "WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; + query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "UPDATE wp_player_skins SET weapon_paint_id = @paintId, weapon_wear = @wear, weapon_seed = @seed WHERE steamid = @steamid AND weapon_defindex = @weaponDefIndex AND weapon_team = @weaponTeam" + : "UPDATE `wp_player_skins` SET `weapon_paint_id` = @paintId, `weapon_wear` = @wear, `weapon_seed` = @seed WHERE `steamid` = @steamid AND `weapon_defindex` = @weaponDefIndex AND `weapon_team` = @weaponTeam"; parameters = new { steamid = player.SteamId, weaponDefIndex, weaponTeam = (int)teamId, paintId, wear, seed }; } else { // Insert new record - query = "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_team`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) " + - "VALUES (@steamid, @weaponDefIndex, @weaponTeam, @paintId, @wear, @seed)"; + query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT INTO wp_player_skins (steamid, weapon_defindex, weapon_team, weapon_paint_id, weapon_wear, weapon_seed) VALUES (@steamid, @weaponDefIndex, @weaponTeam, @paintId, @wear, @seed)" + : "INSERT INTO `wp_player_skins` (`steamid`, `weapon_defindex`, `weapon_team`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`) VALUES (@steamid, @weaponDefIndex, @weaponTeam, @paintId, @wear, @seed)"; parameters = new { steamid = player.SteamId, weaponDefIndex, weaponTeam = (int)teamId, paintId, wear, seed }; } - await connection.ExecuteAsync(query, parameters); + await connection.GetConnection().ExecuteAsync(query, parameters); } } } @@ -522,7 +537,9 @@ internal class WeaponSynchronization { if (!_config.Additional.MusicEnabled || string.IsNullOrEmpty(player.SteamId)) return; - const string query = "INSERT INTO `wp_player_music` (`steamid`, `weapon_team`, `music_id`) VALUES(@steamid, @team, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT OR REPLACE INTO wp_player_music (steamid, weapon_team, music_id) VALUES(@steamid, @team, @newMusic)" + : "INSERT INTO `wp_player_music` (`steamid`, `weapon_team`, `music_id`) VALUES(@steamid, @team, @newMusic) ON DUPLICATE KEY UPDATE `music_id` = @newMusic"; try { @@ -531,7 +548,7 @@ internal class WeaponSynchronization // Loop through each team and insert/update accordingly foreach (var team in teams) { - await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newMusic = music }); + await connection.GetConnection().ExecuteAsync(query, new { steamid = player.SteamId, team, newMusic = music }); } } catch (Exception e) @@ -544,7 +561,9 @@ internal class WeaponSynchronization { if (!_config.Additional.PinsEnabled || string.IsNullOrEmpty(player.SteamId)) return; - const string query = "INSERT INTO `wp_player_pins` (`steamid`, `weapon_team`, `id`) VALUES(@steamid, @team, @newPin) ON DUPLICATE KEY UPDATE `id` = @newPin"; + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "INSERT OR REPLACE INTO wp_player_pins (steamid, weapon_team, id) VALUES(@steamid, @team, @newPin)" + : "INSERT INTO `wp_player_pins` (`steamid`, `weapon_team`, `id`) VALUES(@steamid, @team, @newPin) ON DUPLICATE KEY UPDATE `id` = @newPin"; try { @@ -553,7 +572,7 @@ internal class WeaponSynchronization // Loop through each team and insert/update accordingly foreach (var team in teams) { - await connection.ExecuteAsync(query, new { steamid = player.SteamId, team, newPin = pin }); + await connection.GetConnection().ExecuteAsync(query, new { steamid = player.SteamId, team, newPin = pin }); } } catch (Exception e) @@ -571,7 +590,7 @@ internal class WeaponSynchronization try { await using var connection = await _database.GetConnectionAsync(); - await using var transaction = await connection.BeginTransactionAsync(); + using var transaction = await connection.BeginTransactionAsync(); // Check if player's slot exists in GPlayerWeaponsInfo if (!WeaponPaints.GPlayerWeaponsInfo.TryGetValue(player.Slot, out var teamWeaponsInfo)) @@ -599,8 +618,9 @@ internal class WeaponSynchronization // Sync StatTrak values for the current team foreach (var (defindex, (statTrak, statTrakCount)) in statTrakWeapons) { - const string query = @" - UPDATE `wp_player_skins` + string query = Utility.Config?.DatabaseType?.ToLower() == "sqlite" + ? "UPDATE wp_player_skins SET weapon_stattrak = @StatTrak, weapon_stattrak_count = @StatTrakCount WHERE steamid = @steamid AND weapon_defindex = @weaponDefIndex AND weapon_team = @weaponTeam" + : @"UPDATE `wp_player_skins` SET `weapon_stattrak` = @StatTrak, `weapon_stattrak_count` = @StatTrakCount WHERE `steamid` = @steamid @@ -616,11 +636,11 @@ internal class WeaponSynchronization weaponTeam }; - await connection.ExecuteAsync(query, parameters, transaction); + await connection.GetConnection().ExecuteAsync(query, parameters, transaction); } } - await transaction.CommitAsync(); + await connection.CommitTransactionAsync(transaction); } catch (Exception e) { From 53fadf564da30d320a11c06b3e4133f48e283bb8 Mon Sep 17 00:00:00 2001 From: Eduardo Leonardo Rosa da Silva Date: Wed, 29 Oct 2025 15:32:42 -0300 Subject: [PATCH 2/2] Fix: Factory patten when opening connection mysql --- Database.cs | 27 +++-- WeaponPaints.cs | 308 ++++++++++++++++++++++++------------------------ 2 files changed, 168 insertions(+), 167 deletions(-) diff --git a/Database.cs b/Database.cs index 21dbe970..1bd46514 100644 --- a/Database.cs +++ b/Database.cs @@ -2,19 +2,20 @@ namespace WeaponPaints { - public class Database - { - private readonly IDatabaseConnection _connection; + public class Database + { + private readonly Func _connectionFactory; - public Database(IDatabaseConnection connection) - { - _connection = connection; - } + public Database(Func connectionFactory) + { + _connectionFactory = connectionFactory; + } - public async Task GetConnectionAsync() - { - await _connection.OpenAsync(); - return _connection; - } - } + public async Task GetConnectionAsync() + { + var connection = _connectionFactory(); + await connection.OpenAsync(); + return connection; + } + } } \ No newline at end of file diff --git a/WeaponPaints.cs b/WeaponPaints.cs index ec180710..7329f611 100644 --- a/WeaponPaints.cs +++ b/WeaponPaints.cs @@ -13,173 +13,173 @@ namespace WeaponPaints; [MinimumApiVersion(338)] public partial class WeaponPaints : BasePlugin, IPluginConfig { - internal static WeaponPaints Instance { get; private set; } = new(); + internal static WeaponPaints Instance { get; private set; } = new(); - public WeaponPaintsConfig Config { get; set; } = new(); + public WeaponPaintsConfig Config { get; set; } = new(); private static WeaponPaintsConfig _config { get; set; } = new(); public override string ModuleAuthor => "Nereziel & daffyy"; - public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based"; - public override string ModuleName => "WeaponPaints"; - public override string ModuleVersion => "3.2a"; + public override string ModuleDescription => "Skin, gloves, agents and knife selector, standalone and web-based"; + public override string ModuleName => "WeaponPaints"; + public override string ModuleVersion => "3.2a"; - public override void Load(bool hotReload) - { - // Hardcoded hotfix needs to be changed later (Not needed 17.09.2025) - //if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - // Patch.PerformPatch("0F 85 ? ? ? ? 31 C0 B9 ? ? ? ? BA ? ? ? ? 66 0F EF C0 31 F6 31 FF 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 0F 29 45 ? 48 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? 66 89 45 ? E8 ? ? ? ? 41 89 C5 85 C0 0F 8E", "90 90 90 90 90 90"); - //else - // Patch.PerformPatch("74 ? 48 8D 0D ? ? ? ? FF 15 ? ? ? ? EB ? BA", "EB"); - - Instance = this; + public override void Load(bool hotReload) + { + // Hardcoded hotfix needs to be changed later (Not needed 17.09.2025) + //if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + // Patch.PerformPatch("0F 85 ? ? ? ? 31 C0 B9 ? ? ? ? BA ? ? ? ? 66 0F EF C0 31 F6 31 FF 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 48 C7 45 ? ? ? ? ? 0F 29 45 ? 48 C7 45 ? ? ? ? ? C7 45 ? ? ? ? ? 66 89 45 ? E8 ? ? ? ? 41 89 C5 85 C0 0F 8E", "90 90 90 90 90 90"); + //else + // Patch.PerformPatch("74 ? 48 8D 0D ? ? ? ? FF 15 ? ? ? ? EB ? BA", "EB"); - if (hotReload) - { - OnMapStart(string.Empty); - - GPlayerWeaponsInfo.Clear(); - GPlayersKnife.Clear(); - GPlayersGlove.Clear(); - GPlayersAgent.Clear(); - GPlayersPin.Clear(); - GPlayersMusic.Clear(); + Instance = this; - foreach (var player in Enumerable - .OfType(Utilities.GetPlayers().TakeWhile(_ => WeaponSync != null)) - .Where(player => player.IsValid && - !string.IsNullOrEmpty(player.IpAddress) && player is - { IsBot: false, Connected: PlayerConnectedState.PlayerConnected })) - { - var 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 (hotReload) + { + OnMapStart(string.Empty); - _ = Task.Run(async () => - { - if (WeaponSync != null) await WeaponSync.GetPlayerData(playerInfo); - }); - } - } + GPlayerWeaponsInfo.Clear(); + GPlayersKnife.Clear(); + GPlayersGlove.Clear(); + GPlayersAgent.Clear(); + GPlayersPin.Clear(); + GPlayersMusic.Clear(); - Utility.LoadSkinsFromFile(ModuleDirectory + $"/data/skins_{_config.SkinsLanguage}.json", Logger); - Utility.LoadGlovesFromFile(ModuleDirectory + $"/data/gloves_{_config.SkinsLanguage}.json", Logger); - Utility.LoadAgentsFromFile(ModuleDirectory + $"/data/agents_{_config.SkinsLanguage}.json", Logger); - Utility.LoadMusicFromFile(ModuleDirectory + $"/data/music_{_config.SkinsLanguage}.json", Logger); - Utility.LoadPinsFromFile(ModuleDirectory + $"/data/collectibles_{_config.SkinsLanguage}.json", Logger); + foreach (var player in Enumerable + .OfType(Utilities.GetPlayers().TakeWhile(_ => WeaponSync != null)) + .Where(player => player.IsValid && + !string.IsNullOrEmpty(player.IpAddress) && player is + { IsBot: false, Connected: PlayerConnectedState.PlayerConnected })) + { + var 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] + }; - RegisterListeners(); - } + _ = Task.Run(async () => + { + if (WeaponSync != null) await WeaponSync.GetPlayerData(playerInfo); + }); + } + } - public void OnConfigParsed(WeaponPaintsConfig config) - { - Config = config; - _config = config; + Utility.LoadSkinsFromFile(ModuleDirectory + $"/data/skins_{_config.SkinsLanguage}.json", Logger); + Utility.LoadGlovesFromFile(ModuleDirectory + $"/data/gloves_{_config.SkinsLanguage}.json", Logger); + Utility.LoadAgentsFromFile(ModuleDirectory + $"/data/agents_{_config.SkinsLanguage}.json", Logger); + Utility.LoadMusicFromFile(ModuleDirectory + $"/data/music_{_config.SkinsLanguage}.json", Logger); + Utility.LoadPinsFromFile(ModuleDirectory + $"/data/collectibles_{_config.SkinsLanguage}.json", Logger); - // Validar configurações de banco de dados - if (config.DatabaseType.ToLower() == "mysql") - { - if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1) - { - Logger.LogError("You need to setup MySQL Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!"); - Unload(false); - return; - } - } - else if (config.DatabaseType.ToLower() == "sqlite") - { - if (string.IsNullOrEmpty(config.DatabasePath)) - { - Logger.LogError("You need to setup SQLite Database path in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!"); - Unload(false); - return; - } - } - else - { - Logger.LogError("Invalid DatabaseType. Use 'mysql' or 'sqlite'."); - Unload(false); - return; - } + RegisterListeners(); + } - if (!File.Exists(Path.GetDirectoryName(Path.GetDirectoryName(ModuleDirectory)) + "/gamedata/weaponpaints.json")) - { - Logger.LogError("You need to upload \"weaponpaints.json\" to \"gamedata directory\"!"); - Unload(false); - return; - } - - // Criar conexão baseada no tipo de banco - IDatabaseConnection connection; - if (config.DatabaseType.ToLower() == "mysql") - { - var builder = new MySqlConnectionStringBuilder - { - Server = config.DatabaseHost, - UserID = config.DatabaseUser, - Password = config.DatabasePassword, - Database = config.DatabaseName, - Port = (uint)config.DatabasePort, - Pooling = true, - MaximumPoolSize = 640, - }; - connection = new MySQLConnection(builder.ConnectionString, Logger); - } - else // SQLite - { - // Garantir que o diretório existe - var dbPath = Path.GetFullPath(config.DatabasePath); - var dbDirectory = Path.GetDirectoryName(dbPath); - if (!string.IsNullOrEmpty(dbDirectory) && !Directory.Exists(dbDirectory)) - { - Directory.CreateDirectory(dbDirectory); - } - - var connectionString = $"Data Source={dbPath}"; - Logger.LogInformation($"[WeaponPaints] SQLite database path: {dbPath}"); - - connection = new SQLiteConnection(connectionString, Logger); - } + public void OnConfigParsed(WeaponPaintsConfig config) + { + Config = config; + _config = config; - Database = new Database(connection); + // Validar configurações de banco de dados + if (config.DatabaseType.ToLower() == "mysql") + { + if (config.DatabaseHost.Length < 1 || config.DatabaseName.Length < 1 || config.DatabaseUser.Length < 1) + { + Logger.LogError("You need to setup MySQL Database credentials in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!"); + Unload(false); + return; + } + } + else if (config.DatabaseType.ToLower() == "sqlite") + { + if (string.IsNullOrEmpty(config.DatabasePath)) + { + Logger.LogError("You need to setup SQLite Database path in \"configs/plugins/WeaponPaints/WeaponPaints.json\"!"); + Unload(false); + return; + } + } + else + { + Logger.LogError("Invalid DatabaseType. Use 'mysql' or 'sqlite'."); + Unload(false); + return; + } - Utility.Config = config; - Task.Run(async () => await Utility.CheckDatabaseTables()); - _localizer = Localizer; - Utility.ShowAd(ModuleVersion); - Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger)); - } + if (!File.Exists(Path.GetDirectoryName(Path.GetDirectoryName(ModuleDirectory)) + "/gamedata/weaponpaints.json")) + { + Logger.LogError("You need to upload \"weaponpaints.json\" to \"gamedata directory\"!"); + Unload(false); + return; + } - public override void OnAllPluginsLoaded(bool hotReload) - { - try - { - MenuApi = MenuCapability.Get(); - - if (Config.Additional.KnifeEnabled) - SetupKnifeMenu(); - if (Config.Additional.SkinEnabled) - SetupSkinsMenu(); - if (Config.Additional.GloveEnabled) - SetupGlovesMenu(); - if (Config.Additional.AgentEnabled) - SetupAgentsMenu(); - if (Config.Additional.MusicEnabled) - SetupMusicMenu(); - if (Config.Additional.PinsEnabled) - SetupPinsMenu(); - - RegisterCommands(); - } - catch (Exception) - { - MenuApi = null; - Logger.LogError("Error while loading required plugins"); - throw; - } - } + // Criar factory de conexão baseada no tipo de banco + Func connectionFactory; + if (config.DatabaseType.ToLower() == "mysql") + { + var builder = new MySqlConnectionStringBuilder + { + Server = config.DatabaseHost, + UserID = config.DatabaseUser, + Password = config.DatabasePassword, + Database = config.DatabaseName, + Port = (uint)config.DatabasePort, + Pooling = true, + MaximumPoolSize = 640, + }; + connectionFactory = () => new MySQLConnection(builder.ConnectionString, Logger); + } + else // SQLite + { + // Garantir que o diretório existe + var dbPath = Path.GetFullPath(config.DatabasePath); + var dbDirectory = Path.GetDirectoryName(dbPath); + if (!string.IsNullOrEmpty(dbDirectory) && !Directory.Exists(dbDirectory)) + { + Directory.CreateDirectory(dbDirectory); + } + + var connectionString = $"Data Source={dbPath}"; + Logger.LogInformation($"[WeaponPaints] SQLite database path: {dbPath}"); + + connectionFactory = () => new SQLiteConnection(connectionString, Logger); + } + + Database = new Database(connectionFactory); + + Utility.Config = config; + Task.Run(async () => await Utility.CheckDatabaseTables()); + _localizer = Localizer; + Utility.ShowAd(ModuleVersion); + Task.Run(async () => await Utility.CheckVersion(ModuleVersion, Logger)); + } + + public override void OnAllPluginsLoaded(bool hotReload) + { + try + { + MenuApi = MenuCapability.Get(); + + if (Config.Additional.KnifeEnabled) + SetupKnifeMenu(); + if (Config.Additional.SkinEnabled) + SetupSkinsMenu(); + if (Config.Additional.GloveEnabled) + SetupGlovesMenu(); + if (Config.Additional.AgentEnabled) + SetupAgentsMenu(); + if (Config.Additional.MusicEnabled) + SetupMusicMenu(); + if (Config.Additional.PinsEnabled) + SetupPinsMenu(); + + RegisterCommands(); + } + catch (Exception) + { + MenuApi = null; + Logger.LogError("Error while loading required plugins"); + throw; + } + } }