Иконка ресурса

FREE DeathCounter : 1.3.5 1.3.5

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Newtonsoft.Json;

namespace Oxide.Plugins
{
    [Info("DeathCounter", "mleem97", "1.3.5")]
    [Description("Displays player death counts in the InfoPanel GUI")]
    public class DeathCounter : RustPlugin
    {
        #region Fields

        [PluginReference]
        Plugin InfoPanel;

        private Timer updateTimer;
        private Dictionary<ulong, int> playerDeaths = new Dictionary<ulong, int>();
        private List<string> panels = new List<string> { "DeathCounterPanel" };

        // Permission constants
        private const string PERMISSION_ADMIN = "deathcounter.admin";
        private const string PERMISSION_USE = "deathcounter.use";
        private const string PERMISSION_VIEW_ALL = "deathcounter.viewall";

        // Track if panel is registered
        private bool isPanelRegistered = false;

        #endregion

        #region Configuration

        private Configuration config;

        public class Configuration
        {
            [JsonProperty("Update Interval in seconds (Default: 10)")]
            public int UpdateInterval = 10;

            [JsonProperty("Panel Position (TopPanel/BottomPanel/LeftPanel/RightPanel)")]
            public string PanelPosition = "TopPanel";

            [JsonProperty("Show Own Deaths Only (true) or All Players (false)")]
            public bool ShowOwnDeathsOnly = true;

            [JsonProperty("Panel Background Color (RGBA: Red Green Blue Alpha)")]
            public string BackgroundColor = "0.1 0.1 0.1 0.4";

            [JsonProperty("Default Text Color (RGBA: Red Green Blue Alpha)")]
            public string TextColor = "1 0.2 0.2 1";

            [JsonProperty("Font Size (Default: 12)")]
            public int FontSize = 12;

            [JsonProperty("Panel Width (0.0 - 1.0, Default: 0.12)")]
            public float PanelWidth = 0.12f;

            [JsonProperty("Panel Height (0.0 - 1.0, Default: 0.95)")]
            public float PanelHeight = 0.95f;

            [JsonProperty("Auto-show Panel on Player Connect")]
            public bool AutoShowOnConnect = true;

            [JsonProperty("Death Icon URL (leave empty for default skull)")]
            public string DeathIconUrl = "https://i.imgur.com/YCmvxMN.png";

            [JsonProperty("Enable Debug Mode")]
            public bool DebugMode = false;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null) 
                {
                    LogWarning("Configuration file is null, creating new one...");
                    throw new Exception();
                }
                ValidateConfig();
            }
            catch (Exception ex)
            {
                LogError($"Error loading configuration: {ex.Message}");
                Config.WriteObject(config = new Configuration(), true);
            }
        }

        private void ValidateConfig()
        {
            bool configChanged = false;

            // Validate update interval
            if (config.UpdateInterval < 1 || config.UpdateInterval > 300)
            {
                LogWarning("Update interval out of range (1-300), resetting to 10");
                config.UpdateInterval = 10;
                configChanged = true;
            }

            // Validate panel dimensions
            if (config.PanelWidth < 0.01f || config.PanelWidth > 1.0f)
            {
                LogWarning("Panel width out of range (0.01-1.0), resetting to 0.12");
                config.PanelWidth = 0.12f;
                configChanged = true;
            }

            if (config.PanelHeight < 0.01f || config.PanelHeight > 1.0f)
            {
                LogWarning("Panel height out of range (0.01-1.0), resetting to 0.95");
                config.PanelHeight = 0.95f;
                configChanged = true;
            }

            // Validate font size
            if (config.FontSize < 8 || config.FontSize > 24)
            {
                LogWarning("Font size out of range (8-24), resetting to 12");
                config.FontSize = 12;
                configChanged = true;
            }

            if (configChanged)
            {
                SaveConfig();
            }
        }

        #endregion

        #region Localization

        protected override void LoadDefaultMessages()
        {
            // English (default) translations
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["DeathCount"] = "Deaths: {0}",
                ["YourDeaths"] = "You have died {0} times.",
                ["NoDeaths"] = "No deaths recorded yet.",
                ["TopDeaths"] = "Top 5 Deaths:",
                ["TopDeathsEntry"] = "{0}.{1}: {2} deaths",
                ["UnknownPlayer"] = "Unknown",
                ["PanelShown"] = "Death Counter panel is now shown.",
                ["PanelHidden"] = "Death Counter panel has been hidden.",
                ["DeathsReset"] = "Your deaths have been reset.",
                ["DeathsResetTarget"] = "Deaths for {0} have been reset.",
                ["PlayerNotFound"] = "Player not found.",
                ["NoPermission"] = "You don't have permission to use this command.",
                ["AllDeathsReset"] = "All deaths have been reset.",
                ["ConfigReloaded"] = "DeathCounter configuration has been reloaded.",
                ["AvailableCommands"] = "Available commands:",
                ["CmdDeaths"] = "/deaths - Shows your own death count",
                ["CmdDeathsTop"] = "/deathstop - Shows top 5 players with most deaths",
                ["CmdPanelShow"] = "/deathpanel show - Shows the Death Counter panel",
                ["CmdPanelHide"] = "/deathpanel hide - Hides the Death Counter panel",
                ["CmdPanelReset"] = "/deathpanel reset [playername] - Resets death count (Admin)",
                ["UnknownCommand"] = "Unknown command.Use /deathpanel for help.",
                ["InfoPanelNotLoaded"] = "InfoPanel plugin is not loaded or available."
            }, this, "en");

            // German translations
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["DeathCount"] = "Todesfälle: {0}",
                ["YourDeaths"] = "Du bist {0} mal gestorben.",
                ["NoDeaths"] = "Noch keine Todesfälle verzeichnet.",
                ["TopDeaths"] = "Top 5 Todesfälle:",
                ["TopDeathsEntry"] = "{0}.{1}: {2} Todesfälle",
                ["UnknownPlayer"] = "Unbekannt",
                ["PanelShown"] = "Death Counter Panel wird angezeigt.",
                ["PanelHidden"] = "Death Counter Panel wurde versteckt.",
                ["DeathsReset"] = "Todesfälle wurden zurückgesetzt.",
                ["DeathsResetTarget"] = "Todesfälle für {0} wurden zurückgesetzt.",
                ["PlayerNotFound"] = "Spieler nicht gefunden.",
                ["NoPermission"] = "Du hast keine Berechtigung für diesen Befehl.",
                ["AllDeathsReset"] = "Alle Todesfälle wurden zurückgesetzt.",
                ["ConfigReloaded"] = "DeathCounter Konfiguration wurde neu geladen.",
                ["AvailableCommands"] = "Verfügbare Befehle:",
                ["CmdDeaths"] = "/deaths - Zeigt deine eigenen Todesfälle an",
                ["CmdDeathsTop"] = "/deathstop - Zeigt die Top 5 Spieler mit den meisten Todesfällen",
                ["CmdPanelShow"] = "/deathpanel show - Zeigt das Death Counter Panel an",
                ["CmdPanelHide"] = "/deathpanel hide - Versteckt das Death Counter Panel",
                ["CmdPanelReset"] = "/deathpanel reset [spielername] - Setzt Todesfälle zurück (Admin)",
                ["UnknownCommand"] = "Unbekannter Befehl.Verwende /deathpanel für Hilfe.",
                ["InfoPanelNotLoaded"] = "InfoPanel Plugin ist nicht geladen oder verfügbar."
            }, this, "de");
        }

        private string Lang(string key, string id = null, params object[] args) => 
            string.Format(lang.GetMessage(key, this, id), args);

        #endregion

        #region Hooks

        void Init()
        {
            // Initialize config first
            if (config == null)
            {
                LoadConfig();
            }

            // Register permissions
            permission.RegisterPermission(PERMISSION_ADMIN, this);
            permission.RegisterPermission(PERMISSION_USE, this);
            permission.RegisterPermission(PERMISSION_VIEW_ALL, this);

            // Ensure all required files exist and are up to date
            EnsureRequiredFiles();
            
            LoadData();
        }

        private void EnsureRequiredFiles()
        {
            try
            {
                // Check and create/update configuration file
                EnsureConfigurationFile();
                
                // Check and create/update language files
                EnsureLanguageFiles();
                
                // Check and create data file if it doesn't exist
                EnsureDataFile();
                
                LogInfo("All required files checked and ensured");
            }
            catch (Exception ex)
            {
                LogError($"Error ensuring required files: {ex.Message}");
            }
        }

        private void EnsureConfigurationFile()
        {
            var configPath = $"{Interface.Oxide.ConfigDirectory}{System.IO.Path.DirectorySeparatorChar}DeathCounter.json";
            bool needsUpdate = false;
            
            if (!System.IO.File.Exists(configPath))
            {
                LogInfo("Configuration file not found, creating new one...");
                Config.WriteObject(new Configuration(), true);
                needsUpdate = true;
            }
            else
            {
                // Check if config file is outdated (version check)
                try
                {
                    var existingConfig = Config.ReadObject<Configuration>();
                    var newConfig = new Configuration();
                    
                    // Check if new properties are missing (simple version check)
                    var existingJson = JsonConvert.SerializeObject(existingConfig);
                    var newJson = JsonConvert.SerializeObject(newConfig);
                    
                    if (existingJson.Length < newJson.Length * 0.8) // If existing config is significantly smaller
                    {
                        LogWarning("Configuration file appears outdated, backing up and creating new one...");
                        System.IO.File.Copy(configPath, $"{configPath}.backup.{DateTime.Now:yyyyMMdd_HHmmss}");
                        Config.WriteObject(newConfig, true);
                        needsUpdate = true;
                    }
                }
                catch (Exception ex)
                {
                    LogWarning($"Could not validate config file: {ex.Message}.Creating new one...");
                    System.IO.File.Copy(configPath, $"{configPath}.backup.{DateTime.Now:yyyyMMdd_HHmmss}");
                    Config.WriteObject(new Configuration(), true);
                    needsUpdate = true;
                }
            }
            
            if (needsUpdate)
            {
                LogInfo("Configuration file created/updated successfully");
            }
        }

        private void EnsureLanguageFiles()
        {
            try
            {
                var langDir = $"{Interface.Oxide.DataDirectory}{System.IO.Path.DirectorySeparatorChar}lang";
                
                // Ensure language directories exist
                var enDir = $"{langDir}{System.IO.Path.DirectorySeparatorChar}en";
                var deDir = $"{langDir}{System.IO.Path.DirectorySeparatorChar}de";
                
                if (!System.IO.Directory.Exists(enDir))
                    System.IO.Directory.CreateDirectory(enDir);
                if (!System.IO.Directory.Exists(deDir))
                    System.IO.Directory.CreateDirectory(deDir);
                
                // Force recreation of language files to ensure they're up to date
                LoadDefaultMessages();
                
                LogInfo("Language files ensured and updated");
            }
            catch (Exception ex)
            {
                LogError($"Error ensuring language files: {ex.Message}");
            }
        }

        private void EnsureDataFile()
        {
            try
            {
                var dataPath = $"{Interface.Oxide.DataDirectory}{System.IO.Path.DirectorySeparatorChar}DeathCounter_Deaths.json";
                
                if (!System.IO.File.Exists(dataPath))
                {
                    LogInfo("Data file not found, creating new one...");
                    Interface.Oxide.DataFileSystem.WriteObject("DeathCounter_Deaths", new Dictionary<ulong, int>());
                }
                else
                {
                    // Validate data file integrity
                    try
                    {
                        var testData = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>("DeathCounter_Deaths");
                        if (testData == null)
                        {
                            LogWarning("Data file corrupted, creating backup and new file...");
                            System.IO.File.Copy(dataPath, $"{dataPath}.backup.{DateTime.Now:yyyyMMdd_HHmmss}");
                            Interface.Oxide.DataFileSystem.WriteObject("DeathCounter_Deaths", new Dictionary<ulong, int>());
                        }
                    }
                    catch (Exception ex)
                    {
                        LogError($"Data file validation failed: {ex.Message}.Creating backup and new file...");
                        System.IO.File.Copy(dataPath, $"{dataPath}.backup.{DateTime.Now:yyyyMMdd_HHmmss}");
                        Interface.Oxide.DataFileSystem.WriteObject("DeathCounter_Deaths", new Dictionary<ulong, int>());
                    }
                }
            }
            catch (Exception ex)
            {
                LogError($"Error ensuring data file: {ex.Message}");
            }
        }

        void Loaded()
        {
            // Don't initialize InfoPanel immediately - wait for OnServerInitialized
            LogInfo("DeathCounter plugin loaded, waiting for server initialization...");
        }

        void OnPluginLoaded(Plugin plugin)
        {
            if (plugin?.Title == "InfoPanel" || plugin?.Name == "InfoPanel")
            {
                LogInfo("InfoPanel detected, initializing DeathCounter integration...");
                InfoPanel = plugin;
                
                // Only initialize if server is already initialized
                if (IsServerInitialized())
                {
                    // Small delay to ensure InfoPanel is fully initialized
                    timer.Once(1f, () => {
                        InfoPanelInit();
                        LogInfo("InfoPanel integration reestablished");
                    });
                }
                else
                {
                    LogInfo("Server not yet initialized, will connect InfoPanel later");
                }
            }
        }
        
        private bool IsServerInitialized()
        {
            try
            {
                // Check if server is running and initialized
                return ServerMgr.Instance != null && BaseNetworkable.serverEntities != null;
            }
            catch
            {
                return false;
            }
        }

        void Unload()
        {
            try
            {
                LogInfo("Unloading DeathCounter plugin...");
                
                // Save data before unloading
                try
                {
                    SaveData();
                }
                catch (Exception ex)
                {
                    LogError($"Error saving data during unload: {ex.Message}");
                }
                
                // Destroy timer
                try
                {
                    if (updateTimer != null)
                    {
                        updateTimer.Destroy();
                        updateTimer = null;
                    }
                }
                catch (Exception ex)
                {
                    LogError($"Error destroying timer during unload: {ex.Message}");
                }
                
                // Enhanced InfoPanel cleanup with multiple safety strategies
                try
                {
                    LogInfo($"InfoPanel cleanup - panel registered: {isPanelRegistered}, InfoPanel available: {InfoPanel != null}");
                    
                    if (InfoPanel != null && isPanelRegistered)
                    {
                        try
                        {
                            // Strategy 1: Try to explicitly unregister our panel first
                            LogInfo("Attempting explicit panel unregistration...");
                            InfoPanel.Call("PanelUnregister", "DeathCounter", "DeathCounterPanel");
                            LogInfo("Panel unregistration completed");
                        }
                        catch (Exception unregisterEx)
                        {
                            LogInfo($"Panel unregistration failed (expected): {unregisterEx.Message}");
                        }
                        
                        try
                        {
                            // Strategy 2: Send empty panel list to signal cleanup
                            LogInfo("Sending empty panel list for cleanup...");
                            InfoPanel.Call("SendPanelInfo", "DeathCounter", new List<string>());
                            LogInfo("Empty panel list sent successfully");
                        }
                        catch (Exception cleanupEx)
                        {
                            LogInfo($"Empty panel list signal failed: {cleanupEx.Message}");
                        }
                        
                        // Strategy 3: Add small delay to let InfoPanel process
                        timer.Once(0.1f, () => {
                            LogInfo("InfoPanel cleanup delay completed");
                        });
                    }
                    else
                    {
                        LogInfo("Skipping InfoPanel cleanup - not registered or InfoPanel unavailable");
                    }
                    
                    // Reset our flag regardless of cleanup success
                    isPanelRegistered = false;
                    
                    LogInfo("InfoPanel cleanup sequence completed");
                }
                catch (Exception ex)
                {
                    LogError($"Error during InfoPanel cleanup: {ex.Message}");
                    isPanelRegistered = false; // Reset flag even if cleanup failed
                }
                
                LogInfo("DeathCounter plugin unloaded successfully");
            }
            catch (Exception ex)
            {
                LogError($"Error during plugin unload: {ex.Message}");
            }
        }

        void OnServerSave()
        {
            SaveData();
        }

        void OnPluginUnloaded(Plugin plugin)
        {
            if (plugin.Name == "InfoPanel")
            {
                LogWarning("InfoPanel plugin unloaded - GUI features disabled");
                InfoPanel = null;
                isPanelRegistered = false; // Reset panel registration when InfoPanel unloads
            }
        }

        void OnServerInitialized()
        {
            LogInfo("Server initialized, checking InfoPanel dependency...");
            
            // Check if InfoPanel is available
            CheckInfoPanelDependency();
            
            // Register InfoPanel if available
            if (InfoPanel != null)
            {
                InfoPanelInit();
                LogInfo("InfoPanel integration ready");
            }
            else
            {
                LogWarning("InfoPanel plugin not found - GUI features will be unavailable");
                LogWarning("Please install InfoPanel plugin by Ghosst for full functionality");
            }
            
            // Start update timer regardless of InfoPanel availability
            if (config?.UpdateInterval > 0)
            {
                updateTimer = timer.Every(config.UpdateInterval, UpdateAllPanels);
                LogInfo($"Started update timer with {config.UpdateInterval}s interval");
            }
        }

        private void CheckInfoPanelDependency()
        {
            try
            {
                // Try to get InfoPanel plugin reference
                var infoPanelPlugin = plugins.Find("InfoPanel");
                
                if (infoPanelPlugin == null)
                {
                    LogWarning("InfoPanel plugin not found in plugin list");
                    return;
                }
                
                if (!infoPanelPlugin.IsLoaded)
                {
                    LogWarning("InfoPanel plugin found but not loaded");
                    return;
                }
                
                // InfoPanel is available
                InfoPanel = infoPanelPlugin;
                LogInfo("InfoPanel plugin found and loaded successfully");
                
                // Test if we can call InfoPanel methods
                var result = InfoPanel.Call("API_VERSION");
                if (result != null)
                {
                    LogInfo($"InfoPanel API version: {result}");
                }
            }
            catch (Exception ex)
            {
                LogError($"Error checking InfoPanel dependency: {ex.Message}");
            }
        }

        void OnPlayerDeath(BasePlayer player, HitInfo info)
        {
            if (player == null) return;

            try
            {
                var playerId = player.userID;
                
                if (!playerDeaths.ContainsKey(playerId))
                    playerDeaths[playerId] = 0;
                
                playerDeaths[playerId]++;
                
                if (config?.DebugMode == true)
                    LogInfo($"Player {player.displayName} died.Total deaths: {playerDeaths[playerId]}");
                
                UpdatePlayerPanel(player);
                
                // Auto-save after every death to prevent data loss
                timer.Once(1f, () => SaveData());
            }
            catch (Exception ex)
            {
                LogError($"Error in OnPlayerDeath for {player?.displayName}: {ex.Message}");
            }
        }

        void OnPlayerConnected(BasePlayer player)
        {
            if (player == null || !HasPermission(player, PERMISSION_USE)) return;
            
            timer.Once(3f, () =>
            {
                try
                {
                    if (player == null || !player.IsConnected) return;
                    
                    if (InfoPanel != null && config?.AutoShowOnConnect == true)
                    {
                        // Check if InfoPanel GUI is loaded for the player
                        bool isGUILoaded = (bool?)InfoPanel.Call("IsPlayerGUILoaded", player.UserIDString) ?? false;
                        
                        if (isGUILoaded)
                        {
                            ShowPanelToPlayer(player);
                        }
                        else
                        {
                            // Retry after a delay if GUI is not ready
                            timer.Once(2f, () => {
                                if (player != null && player.IsConnected)
                                    ShowPanelToPlayer(player);
                            });
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogError($"Error in OnPlayerConnected for {player?.displayName}: {ex.Message}");
                }
            });
        }

        void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null) return;
            
            try
            {
                // Let InfoPanel handle its own cleanup during disconnection
                // Removed HidePanel call to avoid KeyNotFoundException errors
                if (config?.DebugMode == true)
                {
                    LogInfo($"Player {player.displayName} disconnected");
                }
            }
            catch (Exception ex)
            {
                LogError($"Error in OnPlayerDisconnected for {player?.displayName}: {ex.Message}");
            }
        }

        #endregion

        #region InfoPanel Integration

        public void InfoPanelInit()
        {
            try
            {
                // Check if already initialized to prevent duplicate registration
                if (isPanelRegistered)
                {
                    LogInfo("InfoPanel already initialized, skipping re-initialization");
                    return;
                }
                
                LogInfo("Initializing InfoPanel integration...");
                
                InfoPanel.Call("SendPanelInfo", "DeathCounter", panels);
                AddDeathCounterPanel();
                
                // Only restart timer if panel registration was successful
                if (isPanelRegistered)
                {
                    updateTimer?.Destroy();
                    if (config?.UpdateInterval > 0)
                    {
                        updateTimer = timer.Repeat(config.UpdateInterval, 0, () => UpdateAllPanels());
                        LogInfo($"Update timer started with {config.UpdateInterval}s interval");
                    }
                    
                    LogInfo("DeathCounter successfully integrated with InfoPanel");
                }
                else
                {
                    LogWarning("InfoPanel integration failed - panel registration unsuccessful");
                }
            }
            catch (Exception ex)
            {
                LogError($"Error initializing InfoPanel integration: {ex.Message}");
                isPanelRegistered = false;
            }
        }

        public void AddDeathCounterPanel()
        {
            try
            {
                // First check if panel is already registered to avoid duplicates
                if (isPanelRegistered)
                {
                    LogInfo("DeathCounter panel already registered, skipping registration");
                    return;
                }
                
                LogInfo("Attempting to register DeathCounter panel with InfoPanel...");
                var panelConfig = GetPanelConfig();
                LogInfo($"Panel config generated: {panelConfig.Length} characters");
                
                // Enhanced panel registration with verification
                var result = InfoPanel.Call("PanelRegister", "DeathCounter", "DeathCounterPanel", panelConfig);
                LogInfo($"PanelRegister result: {result} (type: {result?.GetType()})");
                
                bool success = result != null && (bool)result;
                
                if (success)
                {
                    // Double-check that InfoPanel actually has our panel registered
                    try
                    {
                        var verifyResult = InfoPanel.Call("IsPanelRegistered", "DeathCounter", "DeathCounterPanel");
                        bool isVerified = verifyResult != null && (bool)verifyResult;
                        
                        if (isVerified)
                        {
                            isPanelRegistered = true;
                            LogInfo("DeathCounter panel registered and verified successfully");
                        }
                        else
                        {
                            LogWarning("Panel registration reported success but verification failed");
                            isPanelRegistered = true; // Assume success since PanelRegister returned true
                        }
                    }
                    catch (Exception verifyEx)
                    {
                        LogInfo($"Panel verification not available: {verifyEx.Message}");
                        isPanelRegistered = true; // Assume success since PanelRegister returned true
                    }
                    
                    // Small delay before showing panels to ensure registration is complete
                    timer.Once(0.5f, () => {
                        // Show panel to connected players with permission
                        foreach (var player in BasePlayer.activePlayerList)
                        {
                            if (HasPermission(player, PERMISSION_USE))
                            {
                                ShowPanelToPlayer(player);
                            }
                        }
                    });
                }
                else
                {
                    LogError($"Failed to register DeathCounter panel with InfoPanel (result: {result})");
                    isPanelRegistered = false;
                }
            }
            catch (Exception ex)
            {
                LogError($"Error adding DeathCounter panel: {ex.Message}");
                isPanelRegistered = false;
            }
        }

        private string GetPanelConfig()
        {
            var panelConfig = new
            {
                Autoload = false,
                AnchorX = "Left",
                AnchorY = "Top",
                Available = true,
                BackgroundColor = config.BackgroundColor,
                Dock = config.PanelPosition,
                Width = config.PanelWidth,
                Height = config.PanelHeight,
                Margin = "0.005 0 0 0.005",
                Order = 10,
                Image = new
                {
                    AnchorX = "Left",
                    AnchorY = "Top",
                    Available = true,
                    BackgroundColor = "0.2 0.1 0.1 0.6",
                    Dock = config.PanelPosition,
                    Height = 0.3,
                    Margin = "0.05 0.05 0.35 0.05",
                    Order = 1,
                    Url = !string.IsNullOrEmpty(config.DeathIconUrl) ? config.DeathIconUrl : "https://i.imgur.com/YCmvxMN.png"
                },
                Text = new
                {
                    Align = "MiddleCenter",
                    AnchorX = "Left",
                    AnchorY = "Top",
                    Available = true,
                    BackgroundColor = "0 0 0 0",
                    Dock = config.PanelPosition,
                    FontColor = config.TextColor,
                    FontSize = config.FontSize,
                    Content = Lang("DeathCount", null, 0),
                    Height = 0.65,
                    Margin = "0.35 0.05 0.05 0.05",
                    Order = 2,
                    Width = 0.9
                }
            };

            return JsonConvert.SerializeObject(panelConfig, Formatting.Indented);
        }

        #endregion

        #region Panel Updates

        private void UpdatePlayerPanel(BasePlayer player)
        {
            if (InfoPanel == null || player == null || !isPanelRegistered) return;

            try
            {
                var playerId = player.userID;
                var deaths = GetPlayerDeaths(playerId);
                
                string content = Lang("DeathCount", player.UserIDString, deaths);
                string color = GetDeathColor(deaths);

                // Use correct InfoPanel naming convention: PanelName + "Text" for text elements
                InfoPanel.Call("SetPanelAttribute", "DeathCounter", "DeathCounterPanelText", "Content", content, player.UserIDString);
                InfoPanel.Call("SetPanelAttribute", "DeathCounter", "DeathCounterPanelText", "FontColor", color, player.UserIDString);
                InfoPanel.Call("RefreshPanel", "DeathCounter", "DeathCounterPanel", player.UserIDString);

                if (config?.DebugMode == true)
                    LogInfo($"Updated panel for {player.displayName}: {deaths} deaths");
            }
            catch (Exception ex)
            {
                LogError($"Error updating panel for {player?.displayName}: {ex.Message}");
            }
        }

        private void UpdateAllPanels()
        {
            if (InfoPanel == null || !isPanelRegistered) return;

            try
            {
                foreach (var player in BasePlayer.activePlayerList)
                {
                    if (HasPermission(player, PERMISSION_USE))
                    {
                        UpdatePlayerPanel(player);
                    }
                }
            }
            catch (Exception ex)
            {
                LogError($"Error updating all panels: {ex.Message}");
            }
        }

        private void ShowPanelToPlayer(BasePlayer player)
        {
            if (InfoPanel == null || player == null || !HasPermission(player, PERMISSION_USE) || !isPanelRegistered) return;
            
            try
            {
                UpdatePlayerPanel(player);
                InfoPanel.Call("ShowPanel", "DeathCounter", "DeathCounterPanel", player.UserIDString);

                if (config?.DebugMode == true)
                    LogInfo($"Showing panel to {player.displayName}");
            }
            catch (Exception ex)
            {
                LogError($"Error showing panel to {player?.displayName}: {ex.Message}");
            }
        }

        private string GetDeathColor(int deaths)
        {
            // Color gradient based on death count
            if (deaths == 0) return "0.2 0.8 0.2 1"; // Green
            if (deaths <= 3) return "0.8 0.8 0.2 1"; // Yellow
            if (deaths <= 7) return "0.8 0.6 0.2 1"; // Orange
            if (deaths <= 15) return "0.8 0.3 0.2 1"; // Red-Orange
            if (deaths <= 25) return "0.8 0.2 0.2 1"; // Red
            return "0.6 0.1 0.1 1"; // Dark Red
        }

        #endregion

        #region Helper Methods

        private bool HasPermission(BasePlayer player, string permission)
        {
            return this.permission.UserHasPermission(player.UserIDString, permission);
        }

        private bool IsAdmin(BasePlayer player)
        {
            return player.IsAdmin || HasPermission(player, PERMISSION_ADMIN);
        }

        private void LogInfo(string message)
        {
            try
            {
                if (config?.DebugMode == true)
                    Puts($"[INFO] {message}");
            }
            catch
            {
                // Fallback if config is null
                Puts($"[INFO] {message}");
            }
        }

        private void LogWarning(string message)
        {
            try
            {
                PrintWarning($"[WARNING] {message}");
            }
            catch
            {
                // Fallback
                Puts($"[WARNING] {message}");
            }
        }

        private void LogError(string message)
        {
            try
            {
                PrintError($"[ERROR] {message}");
            }
            catch
            {
                // Fallback
                Puts($"[ERROR] {message}");
            }
        }

        #endregion

        #region Data Management

        private int GetPlayerDeaths(ulong playerId)
        {
            return playerDeaths.ContainsKey(playerId) ? playerDeaths[playerId] : 0;
        }

        void LoadData()
        {
            try
            {
                playerDeaths = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>("DeathCounter_Deaths");
                if (playerDeaths == null)
                {
                    LogWarning("Death data was null, initializing empty dictionary");
                    playerDeaths = new Dictionary<ulong, int>();
                    SaveData(); // Save empty data immediately
                }
                else
                {
                    LogInfo($"Loaded death data for {playerDeaths.Count} players");
                }
            }
            catch (Exception ex)
            {
                LogError($"Error loading death data: {ex.Message}");
                LogWarning("Initializing with empty death data");
                playerDeaths = new Dictionary<ulong, int>();
                SaveData(); // Save empty data immediately
            }
        }

        void SaveData()
        {
            try
            {
                Interface.Oxide.DataFileSystem.WriteObject("DeathCounter_Deaths", playerDeaths);
                if (config?.DebugMode == true)
                    LogInfo($"Saved death data for {playerDeaths.Count} players");
            }
            catch (Exception ex)
            {
                LogError($"Error saving death data: {ex.Message}");
            }
        }

        #endregion

        #region Chat Commands

        [ChatCommand("deaths")]
        void DeathsCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;

            if (!HasPermission(player, PERMISSION_USE))
            {
                SendReply(player, Lang("NoPermission", player.UserIDString));
                return;
            }

            var deaths = GetPlayerDeaths(player.userID);
            SendReply(player, Lang("YourDeaths", player.UserIDString, deaths));
        }

        [ChatCommand("deathstop")]
        void DeathsTopCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;

            if (!HasPermission(player, PERMISSION_USE))
            {
                SendReply(player, Lang("NoPermission", player.UserIDString));
                return;
            }

            var topDeaths = playerDeaths.OrderByDescending(x => x.Value).Take(5).ToList();

            if (topDeaths.Count == 0)
            {
                SendReply(player, Lang("NoDeaths", player.UserIDString));
                return;
            }

            SendReply(player, Lang("TopDeaths", player.UserIDString));
            for (int i = 0; i < topDeaths.Count; i++)
            {
                var targetPlayer = BasePlayer.FindByID(topDeaths[i].Key);
                var playerName = targetPlayer?.displayName ?? Lang("UnknownPlayer", player.UserIDString);
                SendReply(player, Lang("TopDeathsEntry", player.UserIDString, i + 1, playerName, topDeaths[i].Value));
            }
        }

        [ChatCommand("deathpanel")]
        void DeathPanelCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;

            if (!HasPermission(player, PERMISSION_USE))
            {
                SendReply(player, Lang("NoPermission", player.UserIDString));
                return;
            }

            if (args.Length == 0)
            {
                SendReply(player, Lang("AvailableCommands", player.UserIDString));
                SendReply(player, Lang("CmdDeaths", player.UserIDString));
                SendReply(player, Lang("CmdDeathsTop", player.UserIDString));
                SendReply(player, Lang("CmdPanelShow", player.UserIDString));
                SendReply(player, Lang("CmdPanelHide", player.UserIDString));
                if (IsAdmin(player))
                    SendReply(player, Lang("CmdPanelReset", player.UserIDString));
                return;
            }

            switch (args[0].ToLower())
            {
                case "show":
                    if (InfoPanel != null)
                    {
                        ShowPanelToPlayer(player);
                        SendReply(player, Lang("PanelShown", player.UserIDString));
                    }
                    else
                    {
                        SendReply(player, Lang("InfoPanelNotLoaded", player.UserIDString));
                    }
                    break;

                case "hide":
                    if (InfoPanel != null && isPanelRegistered)
                    {
                        try
                        {
                            InfoPanel.Call("HidePanel", "DeathCounter", "DeathCounterPanel", player.UserIDString);
                            SendReply(player, Lang("PanelHidden", player.UserIDString));
                        }
                        catch (Exception ex)
                        {
                            LogError($"Error hiding panel for {player.displayName}: {ex.Message}");
                            SendReply(player, "Error hiding panel.");
                        }
                    }
                    else
                    {
                        SendReply(player, Lang("InfoPanelNotLoaded", player.UserIDString));
                    }
                    break;

                case "reset":
                    if (!IsAdmin(player))
                    {
                        SendReply(player, Lang("NoPermission", player.UserIDString));
                        return;
                    }

                    if (args.Length > 1)
                    {
                        var targetPlayer = BasePlayer.Find(args[1]);
                        if (targetPlayer != null)
                        {
                            playerDeaths[targetPlayer.userID] = 0;
                            UpdatePlayerPanel(targetPlayer);
                            SendReply(player, Lang("DeathsResetTarget", player.UserIDString, targetPlayer.displayName));
                            SaveData();
                        }
                        else
                        {
                            SendReply(player, Lang("PlayerNotFound", player.UserIDString));
                        }
                    }
                    else
                    {
                        playerDeaths[player.userID] = 0;
                        UpdatePlayerPanel(player);
                        SendReply(player, Lang("DeathsReset", player.UserIDString));
                        SaveData();
                    }
                    break;

                default:
                    SendReply(player, Lang("UnknownCommand", player.UserIDString));
                    break;
            }
        }

        #endregion

        #region Console Commands

        [ConsoleCommand("deathcounter.reset")]
        void ResetDeathsConsole(ConsoleSystem.Arg arg)
        {
            if (!arg.IsRcon && (arg.Connection == null || arg.Connection.authLevel < 2))
            {
                arg.ReplyWith("Access denied.Admin permission required.");
                return;
            }

            try
            {
                if (arg.Args.Length > 0)
                {
                    var targetPlayer = BasePlayer.Find(arg.Args[0]);
                    if (targetPlayer != null)
                    {
                        playerDeaths[targetPlayer.userID] = 0;
                        UpdatePlayerPanel(targetPlayer);
                        arg.ReplyWith($"Death count reset for {targetPlayer.displayName}");
                        SaveData();
                    }
                    else
                    {
                        arg.ReplyWith("Player not found.");
                    }
                }
                else
                {
                    int playersReset = playerDeaths.Count;
                    playerDeaths.Clear();
                    SaveData();
                    arg.ReplyWith($"All death counts reset.Affected {playersReset} players.");
                    
                    // Update all active players
                    foreach (var player in BasePlayer.activePlayerList)
                    {
                        UpdatePlayerPanel(player);
                    }
                }
            }
            catch (Exception ex)
            {
                arg.ReplyWith($"Error resetting death counts: {ex.Message}");
                LogError($"Console command error: {ex.Message}");
            }
        }

        [ConsoleCommand("deathcounter.reload")]
        void ReloadPluginConsole(ConsoleSystem.Arg arg)
        {
            if (!arg.IsRcon && (arg.Connection == null || arg.Connection.authLevel < 2))
            {
                arg.ReplyWith("Access denied.Admin permission required.");
                return;
            }

            try
            {
                LoadConfig();
                
                // Reinitialize timer with new interval
                updateTimer?.Destroy();
                if (config?.UpdateInterval > 0)
                {
                    updateTimer = timer.Repeat(config.UpdateInterval, 0, () => UpdateAllPanels());
                }
                
                arg.ReplyWith("DeathCounter configuration reloaded successfully.");
            }
            catch (Exception ex)
            {
                arg.ReplyWith($"Error reloading configuration: {ex.Message}");
                LogError($"Console reload error: {ex.Message}");
            }
        }

        [ConsoleCommand("deathcounter.status")]
        void StatusConsole(ConsoleSystem.Arg arg)
        {
            if (!arg.IsRcon && (arg.Connection == null || arg.Connection.authLevel < 2))
            {
                arg.ReplyWith("Access denied.Admin permission required.");
                return;
            }

            try
            {
                var totalPlayers = playerDeaths.Count;
                var totalDeaths = playerDeaths.Values.Sum();
                var infoPanelStatus = InfoPanel != null ? "Loaded" : "Not Found";
                var activePlayers = BasePlayer.activePlayerList.Count;

                arg.ReplyWith($"=== DeathCounter Status ===");
                arg.ReplyWith($"Plugin Version: 1.3.1");
                arg.ReplyWith($"InfoPanel Status: {infoPanelStatus}");
                arg.ReplyWith($"Total Players Tracked: {totalPlayers}");
                arg.ReplyWith($"Total Deaths Recorded: {totalDeaths}");
                arg.ReplyWith($"Active Players Online: {activePlayers}");
                arg.ReplyWith($"Update Interval: {config?.UpdateInterval ?? 10}s");
                arg.ReplyWith($"Debug Mode: {(config?.DebugMode == true ? "Enabled" : "Disabled")}");
            }
            catch (Exception ex)
            {
                arg.ReplyWith($"Error getting status: {ex.Message}");
                LogError($"Console status error: {ex.Message}");
            }
        }

        #endregion
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху