Untitled

 avatar
unknown
plain_text
9 months ago
45 kB
10
Indexable
using System; 
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("PRZCore", "ShapedByFire", "1.0.0")]
    [Description("Plugin Manager, Config Editor and Permission Manager for PRZ plugins, with limited support for other plugins.")]
    public class PRZCore : CovalencePlugin
    {
        private const string UiPrefix = "PRZCoreUI_";
        private const string UiConfigPrefix = "PRZCoreConfig_";
        private const string UiPermPrefix = "PRZCorePerm_";
        private const string PermissionUse = "przcore.use";
        
        private readonly HashSet<string> ExcludedPlugins = new(StringComparer.OrdinalIgnoreCase) { "RustCore", "PRZCore", "UnityCore" };
        private HashSet<string> TrackedPlugins = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        private HashSet<string> PluginsStatus = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        
        private Dictionary<string, int> _pagePositions = new Dictionary<string, int>();
        private Dictionary<string, string> _configEditBuffer = new Dictionary<string, string>();

        private void Init()
        {
            TrackPlugins();
            
            permission.RegisterPermission(PermissionUse, this);
            
            AddCovalenceCommand("przcore", "CmdPrzcore");
            AddCovalenceCommand("przcore.reload", "CmdPrzcoreReload");
            AddCovalenceCommand("przcore.unload", "CmdPrzcoreUnload");
            AddCovalenceCommand("przcore.reloadall", "CmdPrzcoreReloadAll");
            AddCovalenceCommand("przcore.scan", "CmdPrzCoreScan");
            AddCovalenceCommand("przcore.closeui", "CmdPrzcoreCloseUI");
            AddCovalenceCommand("przcore.changepage", "CmdPrzcoreChangePage");
            
            AddCovalenceCommand("przcore.openconfig", "CmdPrzcoreOpenConfig");
            AddCovalenceCommand("przcore.saveconfig", "CmdPrzcoreSaveConfig");
            AddCovalenceCommand("przcore.resetconfig", "CmdPrzcoreResetConfig");
            AddCovalenceCommand("przcore.closeconfig", "CmdPrzcoreCloseConfig");
            AddCovalenceCommand("przcore.updateconfig", "CmdPrzcoreUpdateConfig");
            
            AddCovalenceCommand("przcore.manageperm", "CmdPrzcoreManagePerm");
            AddCovalenceCommand("przcore.toggleperm", "CmdPrzcoreTogglePerm");
            AddCovalenceCommand("przcore.toggleadmin", "CmdPrzcoreToggleAdmin");
            AddCovalenceCommand("przcore.closeperm", "CmdPrzcoreClosePerm");
            AddCovalenceCommand("przcore.changepageperm", "CmdPrzcoreChangePagePerm");
        }
        
        private void OnPluginLoaded(Plugin plugin)
        {
            if (!ExcludedPlugins.Contains(plugin.Name))
                TrackedPlugins.Add(plugin.Name);

            PluginsStatus.Add(plugin.Name);
        }

        private void OnPluginUnloaded(Plugin plugin)
        {
            PluginsStatus.Remove(plugin.Name);
        }

        private void TrackPlugins()
        {
            var allPlugins = plugins.GetAll().Select(p => p.Name);
            
            if (!PluginsStatus.SetEquals(allPlugins))
            {
                PluginsStatus.Clear();
                foreach (var name in allPlugins)
                    PluginsStatus.Add(name);
            }
            
            foreach (var name in allPlugins)
            {
                if (!ExcludedPlugins.Contains(name))
                    TrackedPlugins.Add(name);
            }
        }
        
        #region Commands
        private void CmdPrzcore(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(PermissionUse)) { player.Reply("You don't have permission to use this command."); return; }

            _pagePositions[player.Id] = 0;
            ShowMainUI(player);
        }

        private void CmdPrzcoreChangePage(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(PermissionUse)) { player.Reply("You don't have permission to use this command."); return; }
            
            if (args.Length < 1) return;
            int page = int.Parse(args[0]);
            
            _pagePositions[player.Id] = Math.Max(0, page);
            UpdateMainUIContent(player);
        }

        private void CmdPrzcoreReload(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string pluginName = args[0];

            Interface.Oxide.ReloadPlugin(pluginName);
            player.Reply($"Reloaded {pluginName}");
            timer.Once(0.1f, () => UpdateMainUIContent(player));
        }

        private void CmdPrzcoreUnload(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string pluginName = args[0];
            if (pluginName.Equals("PRZCore", StringComparison.OrdinalIgnoreCase))
            {
                player.Reply("Cannot unload PRZCore");
                return;
            }

            Interface.Oxide.UnloadPlugin(pluginName);
            player.Reply($"Unloaded {pluginName}");
            timer.Once(0.1f, () => UpdateMainUIContent(player));
        }

        private void CmdPrzcoreReloadAll(IPlayer player, string command, string[] args)
        {
            var pluginstoreload = TrackedPlugins.ToList();
            int count = 0;
            foreach (var p in pluginstoreload)
            {
                try
                {
                    Interface.Oxide.ReloadPlugin(p);
                    count++;
                }
                catch { }
            }
            player.Reply($"Reloaded {count} plugins.");
            UpdateMainUIContent(player);
        }

        private void CmdPrzCoreScan(IPlayer player, string command, string[] args)
        {
            int before = TrackedPlugins.Count;
            TrackPlugins();
            int after = TrackedPlugins.Count;
            int newPlugins = after - before;
            
            if (newPlugins > 0)
                player.Reply($"Found {newPlugins} new plugin(s). Total tracked: {after}");
            else
                player.Reply($"No new plugins found. Total tracked: {after}");
            
            UpdateMainUIContent(player);
        }

        private void CmdPrzcoreCloseUI(IPlayer player, string command, string[] args)
        {
            DestroyAllUI(player);
            _pagePositions.Remove(player.Id);
        }

        private void CmdPrzcoreOpenConfig(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            ShowConfigUI(player, args[0]);
        }

        private void CmdPrzcoreUpdateConfig(IPlayer player, string command, string[] args)
        {
            if (args.Length < 2) return;
            string pluginName = args[0];
            string newJson = string.Join(" ", args.Skip(1));
            
            _configEditBuffer[$"{player.Id}_{pluginName}"] = newJson;
        }

        private void CmdPrzcoreSaveConfig(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string pluginName = args[0];
            
            if (!_configEditBuffer.ContainsKey($"{player.Id}_{pluginName}"))
            {
                player.Reply("No config data to save.");
                return;
            }

            string json = _configEditBuffer[$"{player.Id}_{pluginName}"];
            SaveConfig(player, pluginName, json);
        }

        private void CmdPrzcoreResetConfig(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string pluginName = args[0];

            string filePath = $"{Interface.Oxide.ConfigDirectory}/{pluginName}.json";
            
            try
            {
                if (System.IO.File.Exists(filePath))
                {
                    System.IO.File.Delete(filePath);
                    player.Reply($"Deleted config file for {pluginName}. Reloading plugin to generate defaults...");
                }
                else
                {
                    player.Reply($"No config file found for {pluginName}. Reloading plugin to generate defaults...");
                }

                _configEditBuffer.Remove($"{player.Id}_{pluginName}");

                timer.Once(0.5f, () =>
                {
                    try
                    {
                        Interface.Oxide.ReloadPlugin(pluginName);
                        player.Reply($"{pluginName} reloaded with default configuration.");
                    }
                    catch (Exception ex)
                    {
                        player.Reply($"Error reloading {pluginName}: {ex.Message}");
                    }
                    
                    timer.Once(1f, () =>
                    {
                        var basePlayer = player.Object as BasePlayer;
                        if (basePlayer != null)
                        {
                            var iplayer = covalence.Players.FindPlayerById(player.Id);
                            if (iplayer != null)
                                ShowConfigUI(iplayer, pluginName);
                        }
                    });
                });
            }
            catch (Exception ex)
            {
                player.Reply($"Error resetting config: {ex.Message}");
            }
        }

        private void CmdPrzcoreCloseConfig(IPlayer player, string command, string[] args)
        {
            DestroyConfigUI(player);
        }

        private void CmdPrzcoreManagePerm(IPlayer player, string command, string[] args)
        {
            _pagePositions[$"{player.Id}_perm"] = 0;
            ShowPermissionsUI(player);
        }

        private void CmdPrzcoreChangePagePerm(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            int page = int.Parse(args[0]);
            
            string key = $"{player.Id}_perm";
            _pagePositions[key] = Math.Max(0, page);
            UpdatePermissionsUIContent(player);
        }

        private void CmdPrzcoreTogglePerm(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string targetPlayerId = args[0];

            var targetPlayer = players.FindPlayer(targetPlayerId);
            if (targetPlayer == null)
            {
                player.Reply("Player not found.");
                return;
            }

            var baseTargetPlayer = targetPlayer.Object as BasePlayer;
            int authLevel = GetPlayerAuthLevel(baseTargetPlayer);
            
            // Check if player is owner - can grant but not revoke
            if (authLevel >= 3)
            {
                if (!permission.UserHasPermission(targetPlayer.Id, PermissionUse))
                {
                    permission.GrantUserPermission(targetPlayer.Id, PermissionUse, null);
                    player.Reply($"Granted przcore.use to {targetPlayer.Name} (Owner)");
                }
                else
                {
                    player.Reply($"Cannot revoke permission from server owner {targetPlayer.Name}");
                }
                timer.Once(0.1f, () => UpdatePermissionsUIContent(player));
                return;
            }

            if (permission.UserHasPermission(targetPlayer.Id, PermissionUse))
            {
                permission.RevokeUserPermission(targetPlayer.Id, PermissionUse);
                player.Reply($"Revoked przcore.use from {targetPlayer.Name}");
            }
            else
            {
                permission.GrantUserPermission(targetPlayer.Id, PermissionUse, null);
                player.Reply($"Granted przcore.use to {targetPlayer.Name}");
            }

            timer.Once(0.1f, () => UpdatePermissionsUIContent(player));
        }

        private int GetPlayerAuthLevel(BasePlayer player)
        {
            if (player == null) return 0;
            
            // Check ServerUsers for persistent auth level
            if (ServerUsers.Is(player.userID, ServerUsers.UserGroup.Owner))
                return 3;
            if (ServerUsers.Is(player.userID, ServerUsers.UserGroup.Moderator))
                return 2;
            
            // Fallback to connection auth level
            if (player.net?.connection != null)
                return (int)player.net.connection.authLevel;
            
            return 0;
        }

        private void CmdPrzcoreToggleAdmin(IPlayer player, string command, string[] args)
        {
            if (args.Length < 1) return;
            string targetPlayerId = args[0];

            var targetPlayer = players.FindPlayer(targetPlayerId);
            if (targetPlayer == null)
            {
                player.Reply("Player not found.");
                return;
            }

            var basePlayer = targetPlayer.Object as BasePlayer;
            if (basePlayer == null)
            {
                player.Reply("Unable to access player object.");
                return;
            }

            // Check if player is owner (auth level 3) - cannot be changed
            int authLevel = GetPlayerAuthLevel(basePlayer);
            if (authLevel >= 3)
            {
                player.Reply($"Cannot modify owner privileges for {targetPlayer.Name}");
                timer.Once(0.1f, () => UpdatePermissionsUIContent(player));
                return;
            }

            if (authLevel >= 2)
            {
                // Revoke admin
                ServerUsers.Remove(basePlayer.userID);
                basePlayer.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false);
                basePlayer.SendNetworkUpdateImmediate();
                if (basePlayer.net?.connection != null)
                    basePlayer.net.connection.authLevel = 0;
                ServerUsers.Save();
                player.Reply($"Revoked admin from {targetPlayer.Name} (persistent)");
            }
            else
            {
                // Grant admin
                ServerUsers.Set(basePlayer.userID, ServerUsers.UserGroup.Moderator, basePlayer.displayName, "Granted by PRZCore");
                basePlayer.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, true);
                basePlayer.SendNetworkUpdateImmediate();
                if (basePlayer.net?.connection != null)
                    basePlayer.net.connection.authLevel = (uint)2;
                ServerUsers.Save();
                player.Reply($"Granted admin to {targetPlayer.Name} (persistent)");
            }

            timer.Once(0.1f, () => UpdatePermissionsUIContent(player));
        }

        private void CmdPrzcoreClosePerm(IPlayer player, string command, string[] args)
        {
            DestroyPermissionsUI(player);
            _pagePositions.Remove($"{player.Id}_perm");
        }
        #endregion

        #region Main UI
        private void ShowMainUI(IPlayer iplayer)
        {
            var player = iplayer.Object as BasePlayer;
            if (player == null) return;
            DestroyUi(iplayer);

            string panelName = UiPrefix + player.userID;
            var elements = new CuiElementContainer();

            // Main background panel
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.05 0.05 0.05 1" },
                RectTransform = { AnchorMin = "0.2 0.15", AnchorMax = "0.8 0.85" },
                CursorEnabled = true
            }, "Overlay", panelName);

            // Title
            elements.Add(new CuiLabel
            {
                Text = { Text = "PRZCore - Plugin Manager", FontSize = 20, Align = TextAnchor.MiddleCenter },
                RectTransform = { AnchorMin = "0.02 0.93", AnchorMax = "0.98 0.98" }
            }, panelName);

            // Footer hint
            elements.Add(new CuiLabel
            {
                Text = { Text = "Bind the Plugin Manager to F2 using this console command: bind f2 chat.say /przcore", FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "0.6 0.6 0.3 1" },
                RectTransform = { AnchorMin = "0.25 0.02", AnchorMax = "0.75 0.05" }
            }, panelName);
            
            // Close button
            elements.Add(new CuiButton
            {
                Button = { Command = "przcore.closeui", Color = "0.8 0.2 0.2 1" },
                RectTransform = { AnchorMin = "0.88 0.94", AnchorMax = "0.98 0.98" },
                Text = { Text = "✖ Close", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panelName);

            // Top buttons
            elements.Add(new CuiButton
            {
                Button = { Command = "przcore.scan", Color = "0.3 0.4 0.5 1" },
                RectTransform = { AnchorMin = "0.02 0.86", AnchorMax = "0.245 0.91" },
                Text = { Text = "Update Plugins List", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panelName);
            
            elements.Add(new CuiButton
            {
                Button = { Command = "przcore.reloadall", Color = "0.25 0.5 0.5 1" },
                RectTransform = { AnchorMin = "0.265 0.86", AnchorMax = "0.49 0.91" },
                Text = { Text = "Reload All Plugins", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panelName);

            elements.Add(new CuiButton
            {
                Button = { Command = "przcore.manageperm", Color = "0.5 0.35 0.25 1" },
                RectTransform = { AnchorMin = "0.51 0.86", AnchorMax = "0.735 0.91" },
                Text = { Text = "Permissions Manager", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panelName);

            CuiHelper.AddUi(player, elements);
            
            // Show the content panel separately
            UpdateMainUIContent(iplayer);
        }

        private void UpdateMainUIContent(IPlayer iplayer)
        {
            var player = iplayer.Object as BasePlayer;
            if (player == null) return;

            string panelName = UiPrefix + player.userID;
            string contentPanelName = panelName + "_content";
            
            // Destroy only the content panel
            CuiHelper.DestroyUi(player, contentPanelName);

            var Pluginslist = TrackedPlugins.OrderBy(n => n).ToList();
            var elements = new CuiElementContainer();

            // Content container panel (lighter gray)
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.08 0.08 0.08 1" },
                RectTransform = { AnchorMin = "0.02 0.08", AnchorMax = "0.98 0.84" }
            }, panelName, contentPanelName);

            // Column headers
            elements.Add(new CuiLabel
            {
                Text = { Text = "Plugin Name", FontSize = 14, Align = TextAnchor.MiddleLeft, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.02 0.94", AnchorMax = "0.22 0.99" }
            }, contentPanelName);

            elements.Add(new CuiLabel
            {
                Text = { Text = "Status", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.22 0.94", AnchorMax = "0.32 0.99" }
            }, contentPanelName);

            elements.Add(new CuiLabel
            {
                Text = { Text = "Actions", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.34 0.94", AnchorMax = "0.98 0.99" }
            }, contentPanelName);

            int itemsPerPage = 10;
            int totalPages = (int)Math.Ceiling((double)Pluginslist.Count / itemsPerPage);
            int currentPage = _pagePositions.ContainsKey(iplayer.Id) ? _pagePositions[iplayer.Id] : 0;
            
            // Ensure page is within bounds
            if (currentPage >= totalPages && totalPages > 0)
                currentPage = totalPages - 1;
            if (currentPage < 0)
                currentPage = 0;
            
            _pagePositions[iplayer.Id] = currentPage;

            // Pagination controls
            if (totalPages > 1)
            {
                // Previous page button
                if (currentPage > 0)
                {
                    elements.Add(new CuiButton
                    {
                        Button = { Command = $"przcore.changepage {currentPage - 1}", Color = "0.3 0.3 0.3 1" },
                        RectTransform = { AnchorMin = "0.35 0.01", AnchorMax = "0.42 0.05" },
                        Text = { Text = "◄ Previous", FontSize = 12, Align = TextAnchor.MiddleCenter }
                    }, contentPanelName);
                }

                // Page indicator
                elements.Add(new CuiLabel
                {
                    Text = { Text = $"Page {currentPage + 1} of {totalPages}", FontSize = 12, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                    RectTransform = { AnchorMin = "0.43 0.01", AnchorMax = "0.57 0.05" }
                }, contentPanelName);

                // Next page button
                if (currentPage < totalPages - 1)
                {
                    elements.Add(new CuiButton
                    {
                        Button = { Command = $"przcore.changepage {currentPage + 1}", Color = "0.3 0.3 0.3 1" },
                        RectTransform = { AnchorMin = "0.58 0.01", AnchorMax = "0.65 0.05" },
                        Text = { Text = "Next ►", FontSize = 12, Align = TextAnchor.MiddleCenter }
                    }, contentPanelName);
                }
            }

            // Calculate item range for current page
            int startIndex = currentPage * itemsPerPage;
            int endIndex = Math.Min(startIndex + itemsPerPage, Pluginslist.Count);

            float startY = 0.91f, rowHeight = 0.08f;
            
            for (int i = startIndex; i < endIndex; i++)
            {
                string name = Pluginslist[i];
                int displayIndex = i - startIndex;
                float top = startY - displayIndex * rowHeight;
                float bottom = top - rowHeight + 0.005f;

                bool isLoaded = PluginsStatus.Contains(name);
                string statusText = isLoaded ? "● Active" : "○ Inactive";
                string statusColor = isLoaded ? "0.2 0.8 0.2 1" : "0.8 0.2 0.2 1";

                elements.Add(new CuiLabel
                {
                    Text = { Text = name, FontSize = 14, Align = TextAnchor.MiddleLeft },
                    RectTransform = { AnchorMin = $"0.02 {bottom}", AnchorMax = $"0.22 {top}" }
                }, contentPanelName);

                elements.Add(new CuiLabel
                {
                    Text = { Text = statusText, FontSize = 14, Align = TextAnchor.MiddleCenter, Color = statusColor },
                    RectTransform = { AnchorMin = $"0.22 {bottom}", AnchorMax = $"0.32 {top}" }
                }, contentPanelName);
                
                elements.Add(new CuiButton
                {
                    Button = { Command = $"przcore.reload {name}", Color = "0.25 0.5 0.25 1" },
                    RectTransform = { AnchorMin = $"0.34 {bottom}", AnchorMax = $"0.5 {top}" },
                    Text = { Text = "↻ Reload", FontSize = 14, Align = TextAnchor.MiddleCenter }
                }, contentPanelName);

                elements.Add(new CuiButton
                {
                    Button = { Command = $"przcore.unload {name}", Color = "0.5 0.25 0.25 1" },
                    RectTransform = { AnchorMin = $"0.51 {bottom}", AnchorMax = $"0.67 {top}" },
                    Text = { Text = "✖ Unload", FontSize = 14, Align = TextAnchor.MiddleCenter }
                }, contentPanelName);

                elements.Add(new CuiButton
                {
                    Button = { Command = $"przcore.openconfig {name}", Color = "0.25 0.25 0.5 1" },
                    RectTransform = { AnchorMin = $"0.68 {bottom}", AnchorMax = $"0.98 {top}" },
                    Text = { Text = "⚙ Edit Configuration", FontSize = 14, Align = TextAnchor.MiddleCenter }
                }, contentPanelName);
            }

            CuiHelper.AddUi(player, elements);
        }

        private void DestroyUi(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            if (basePlayer == null) return;
            CuiHelper.DestroyUi(basePlayer, UiPrefix + basePlayer.userID);
        }

        private void DestroyAllUI(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            if (basePlayer == null) return;
            CuiHelper.DestroyUi(basePlayer, UiPrefix + basePlayer.userID);
            CuiHelper.DestroyUi(basePlayer, UiConfigPrefix + basePlayer.userID);
            CuiHelper.DestroyUi(basePlayer, UiPermPrefix + basePlayer.userID);
        }
        #endregion

        #region Config Editor UI
        private void ShowConfigUI(IPlayer iplayer, string pluginName) 
        { 
            var player = iplayer.Object as BasePlayer; 
            if (player == null) return;
            
            DestroyConfigUI(iplayer);
            
            string filePath = $"{Interface.Oxide.ConfigDirectory}/{pluginName}.json"; 
            string displayJson = "{}";
            
            if (System.IO.File.Exists(filePath)) 
            { 
                try 
                { 
                    string raw = System.IO.File.ReadAllText(filePath); 
                    try 
                    { 
                        var parsed = JsonConvert.DeserializeObject(raw); 
                        if (parsed is string innerJson) 
                        { 
                            try 
                            { 
                                var innerObj = JsonConvert.DeserializeObject(innerJson); 
                                displayJson = JsonConvert.SerializeObject(innerObj, Formatting.Indented); 
                            }
                            catch 
                            { 
                                displayJson = innerJson; 
                            } 
                        }
                        else 
                        { 
                            displayJson = JsonConvert.SerializeObject(parsed, Formatting.Indented); 
                        } 
                    }
                    catch 
                    { 
                        displayJson = raw; 
                    } 
                    displayJson = displayJson.Replace("\r\n", "\n").Replace("\r", "\n"); 
                }
                catch (Exception ex) 
                { 
                    iplayer.Reply($"Error reading config: {ex.Message}"); 
                    displayJson = "Error loading config file"; 
                } 
            }
            else 
            { 
                var plugin = plugins.GetAll().FirstOrDefault(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)); 
                if (plugin != null && plugin.Config != null) 
                { 
                    try 
                    { 
                        displayJson = JsonConvert.SerializeObject(plugin.Config, Formatting.Indented); 
                    }
                    catch { } 
                }
                else 
                { 
                    displayJson = "No config file found"; 
                } 
            }
            
            _configEditBuffer[$"{iplayer.Id}_{pluginName}"] = displayJson;
            
            string panelName = UiConfigPrefix + player.userID; 
            var elements = new CuiElementContainer();
            
            elements.Add(new CuiPanel 
            { 
                Image = { Color = "0.05 0.05 0.05 1" }, 
                RectTransform = { AnchorMin = "0.2 0.15", AnchorMax = "0.8 0.85" }, 
                CursorEnabled = true 
            }, "Overlay", panelName);
            
            elements.Add(new CuiLabel 
            { 
                Text = { Text = $"PRZCore - Config Editor ({pluginName})", FontSize = 20, Align = TextAnchor.MiddleCenter }, 
                RectTransform = { AnchorMin = "0.02 0.93", AnchorMax = "0.98 0.98" } 
            }, panelName);
            
            elements.Add(new CuiButton 
            { 
                Button = { Command = "przcore.closeconfig", Color = "0.8 0.2 0.2 1" }, 
                RectTransform = { AnchorMin = "0.88 0.94", AnchorMax = "0.98 0.98" }, 
                Text = { Text = "✖ Close", FontSize = 14, Align = TextAnchor.MiddleCenter } 
            }, panelName);
            
            elements.Add(new CuiButton 
            { 
                Button = { Command = $"przcore.saveconfig {pluginName}", Color = "0.2 0.6 0.2 1" }, 
                RectTransform = { AnchorMin = "0.02 0.86", AnchorMax = "0.18 0.91" }, 
                Text = { Text = "💾 Save Config", FontSize = 14, Align = TextAnchor.MiddleCenter } 
            }, panelName);
            
            elements.Add(new CuiButton 
            { 
                Button = { Command = $"przcore.resetconfig {pluginName}", Color = "0.6 0.3 0.2 1" }, 
                RectTransform = { AnchorMin = "0.19 0.86", AnchorMax = "0.37 0.91" }, 
                Text = { Text = "🔄 Reset to Default", FontSize = 14, Align = TextAnchor.MiddleCenter } 
            }, panelName);
            
            elements.Add(new CuiPanel 
            { 
                Image = { Color = "0.03 0.03 0.03 1" }, 
                RectTransform = { AnchorMin = "0.02 0.08", AnchorMax = "0.98 0.84" } 
            }, panelName, panelName + "_content");
            
            elements.Add(new CuiElement 
            { 
                Parent = panelName + "_content", 
                Components = 
                { 
                    new CuiInputFieldComponent 
                    { 
                        Align = TextAnchor.UpperLeft, 
                        FontSize = 11, 
                        Command = $"przcore.updateconfig {pluginName}", 
                        Text = displayJson, 
                        LineType = UnityEngine.UI.InputField.LineType.MultiLineNewline, 
                        Font = "robotocondensed-regular.ttf", 
                        CharsLimit = 8000 
                    }, 
                    new CuiRectTransformComponent 
                    { 
                        AnchorMin = "0.01 0.01", 
                        AnchorMax = "0.99 0.99" 
                    } 
                } 
            });
            
            CuiHelper.AddUi(player, elements); 
        }
        
        private void SaveConfig(IPlayer player, string pluginName, string json)
        {
            object parsedObj;
            try
            {
                parsedObj = JsonConvert.DeserializeObject(json);
                if (parsedObj == null)
                {
                    player.Reply("Invalid JSON format.");
                    return;
                }
            }
            catch (Exception ex)
            {
                player.Reply($"Invalid JSON: {ex.Message}");
                return;
            }
            try
            {
                string formattedJson = JsonConvert.SerializeObject(parsedObj, Formatting.Indented);
                formattedJson = formattedJson.Replace("\r\n", "\n").Replace("\r", "\n");
                string filePath = $"{Interface.Oxide.ConfigDirectory}/{pluginName}.json";
                System.IO.File.WriteAllText(filePath, formattedJson);
                _configEditBuffer.Remove($"{player.Id}_{pluginName}");
                player.Reply($"Config for {pluginName} saved successfully! Reloading plugin in 1 second...");
                timer.Once(1f, () =>
                {
                    try
                    {
                        Interface.Oxide.ReloadPlugin(pluginName);
                    }
                    catch (Exception ex)
                    {
                        player.Reply($"Error reloading {pluginName}: {ex.Message}");
                    }
                    timer.Once(0.1f, () =>
                    {
                        var basePlayer = player.Object as BasePlayer;
                        if (basePlayer != null)
                        {
                            var iplayer = covalence.Players.FindPlayerById(player.Id);
                            if (iplayer != null)
                                ShowConfigUI(iplayer, pluginName);
                        }
                    });
                });
            }
            catch (Exception ex)
            {
                player.Reply($"Error saving config: {ex.Message}");
            }
        }

        private void DestroyConfigUI(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            if (basePlayer == null) return;
            CuiHelper.DestroyUi(basePlayer, UiConfigPrefix + basePlayer.userID);
        }
        #endregion

        #region Permissions Manager UI
        private void ShowPermissionsUI(IPlayer iplayer)
        {
            var player = iplayer.Object as BasePlayer;
            if (player == null) return;

            DestroyPermissionsUI(iplayer);

            string panelName = UiPermPrefix + player.userID;
            var elements = new CuiElementContainer();

            // Main background panel
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.05 0.05 0.05 1" },
                RectTransform = { AnchorMin = "0.2 0.15", AnchorMax = "0.8 0.85" },
                CursorEnabled = true
            }, "Overlay", panelName);

            // Title
            elements.Add(new CuiLabel
            {
                Text = { Text = "PRZCore - Permission Manager", FontSize = 20, Align = TextAnchor.MiddleCenter },
                RectTransform = { AnchorMin = "0.02 0.93", AnchorMax = "0.98 0.98" }
            }, panelName);

            // Close button
            elements.Add(new CuiButton
            {
                Button = { Command = "przcore.closeperm", Color = "0.8 0.2 0.2 1" },
                RectTransform = { AnchorMin = "0.88 0.94", AnchorMax = "0.98 0.98" },
                Text = { Text = "✖ Close", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panelName);

            CuiHelper.AddUi(player, elements);
            
            // Show the content panel separately
            UpdatePermissionsUIContent(iplayer);
        }

        private void UpdatePermissionsUIContent(IPlayer iplayer)
        {
            var player = iplayer.Object as BasePlayer;
            if (player == null) return;

            var onlinePlayers = players.Connected.OrderBy(p => p.Name).ToList();

            string panelName = UiPermPrefix + player.userID;
            string contentPanelName = panelName + "_content";
            
            // Destroy only the content panel
            CuiHelper.DestroyUi(player, contentPanelName);

            var elements = new CuiElementContainer();

            // Content container panel (lighter gray)
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.08 0.08 0.08 1" },
                RectTransform = { AnchorMin = "0.02 0.08", AnchorMax = "0.98 0.84" }
            }, panelName, contentPanelName);

            // Column headers
            elements.Add(new CuiLabel
            {
                Text = { Text = "Player Name", FontSize = 14, Align = TextAnchor.MiddleLeft, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.03 0.94", AnchorMax = "0.33 0.99" }
            }, contentPanelName);

            elements.Add(new CuiLabel
            {
                Text = { Text = "Authorization", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.33 0.94", AnchorMax = "0.46 0.99" }
            }, contentPanelName);

            elements.Add(new CuiLabel
            {
                Text = { Text = "PRZ Permissions", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.46 0.94", AnchorMax = "0.61 0.99" }
            }, contentPanelName);

            elements.Add(new CuiLabel
            {
                Text = { Text = "Actions", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                RectTransform = { AnchorMin = "0.61 0.94", AnchorMax = "0.97 0.99" }
            }, contentPanelName);

            int itemsPerPage = 12;
            int totalPages = (int)Math.Ceiling((double)onlinePlayers.Count / itemsPerPage);
            string pageKey = $"{iplayer.Id}_perm";
            int currentPage = _pagePositions.ContainsKey(pageKey) ? _pagePositions[pageKey] : 0;
            
            // Ensure page is within bounds
            if (currentPage >= totalPages && totalPages > 0)
                currentPage = totalPages - 1;
            if (currentPage < 0)
                currentPage = 0;
            
            _pagePositions[pageKey] = currentPage;

            // Pagination controls and player count
            if (totalPages > 1)
            {
                // Previous page button
                if (currentPage > 0)
                {
                    elements.Add(new CuiButton
                    {
                        Button = { Command = $"przcore.changepageperm {currentPage - 1}", Color = "0.3 0.3 0.3 1" },
                        RectTransform = { AnchorMin = "0.30 0.01", AnchorMax = "0.37 0.05" },
                        Text = { Text = "◄ Previous", FontSize = 12, Align = TextAnchor.MiddleCenter }
                    }, contentPanelName);
                }

                // Page indicator
                elements.Add(new CuiLabel
                {
                    Text = { Text = $"Page {currentPage + 1} of {totalPages}", FontSize = 12, Align = TextAnchor.MiddleCenter, Color = "0.8 0.8 0.8 1" },
                    RectTransform = { AnchorMin = "0.38 0.01", AnchorMax = "0.52 0.05" }
                }, contentPanelName);

                // Next page button
                if (currentPage < totalPages - 1)
                {
                    elements.Add(new CuiButton
                    {
                        Button = { Command = $"przcore.changepageperm {currentPage + 1}", Color = "0.3 0.3 0.3 1" },
                        RectTransform = { AnchorMin = "0.53 0.01", AnchorMax = "0.60 0.05" },
                        Text = { Text = "Next ►", FontSize = 12, Align = TextAnchor.MiddleCenter }
                    }, contentPanelName);
                }
            }

            // Player count label
            elements.Add(new CuiLabel
            {
                Text = { Text = $"Online Players: {onlinePlayers.Count}", FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "0.6 0.6 0.6 1" },
                RectTransform = { AnchorMin = "0.65 0.01", AnchorMax = "0.95 0.05" }
            }, contentPanelName);

            // Calculate item range for current page
            int startIndex = currentPage * itemsPerPage;
            int endIndex = Math.Min(startIndex + itemsPerPage, onlinePlayers.Count);

            float startY = 0.91f;
            float rowHeight = 0.07f;

            for (int i = startIndex; i < endIndex; i++)
            {
                var targetPlayer = onlinePlayers[i];
                int displayIndex = i - startIndex;
                float top = startY - displayIndex * rowHeight;
                float bottom = top - rowHeight + 0.005f;

                if (bottom < 0.08f) break;

                var baseTargetPlayer = targetPlayer.Object as BasePlayer;
                int authLevel = GetPlayerAuthLevel(baseTargetPlayer);
                
                bool isOwner = authLevel >= 3;
                bool isAdmin = authLevel >= 2;
                string authLevelText = isOwner ? "Owner (3)" : (isAdmin ? "Admin (2)" : "Player (0)");
                string authLevelColor = isOwner ? "0.9 0.3 0.3 1" : (isAdmin ? "0.8 0.6 0.2 1" : "0.6 0.6 0.6 1");

                bool hasPermission = permission.UserHasPermission(targetPlayer.Id, PermissionUse);
                string permStatusText = hasPermission ? "✓ Granted" : "✗ None";
                string permStatusColor = hasPermission ? "0.2 0.8 0.2 1" : "0.8 0.2 0.2 1";
                
                string permButtonText = isOwner ? (hasPermission ? "Owner (Protected)" : "Grant Permissions") : (hasPermission ? "Revoke Permissions" : "Grant Permissions");
                string permButtonColor = isOwner ? (hasPermission ? "0.3 0.3 0.3 1" : "0.3 0.6 0.3 1") : (hasPermission ? "0.6 0.3 0.3 1" : "0.3 0.6 0.3 1");
                string permCommand = (isOwner && hasPermission) ? "" : $"przcore.toggleperm {targetPlayer.Id}";
                
                string adminButtonText = isOwner ? "Owner (Protected)" : (isAdmin ? "Revoke Admin" : "Grant Admin");
                string adminButtonColor = isOwner ? "0.3 0.3 0.3 1" : (isAdmin ? "0.7 0.4 0.2 1" : "0.4 0.5 0.7 1");
                string adminCommand = isOwner ? "" : $"przcore.toggleadmin {targetPlayer.Id}";

                string displayName = targetPlayer.Name.Length > 20 ? targetPlayer.Name.Substring(0, 17) + "..." : targetPlayer.Name;
                elements.Add(new CuiLabel
                {
                    Text = { Text = displayName, FontSize = 14, Align = TextAnchor.MiddleLeft },
                    RectTransform = { AnchorMin = $"0.03 {bottom}", AnchorMax = $"0.33 {top}" }
                }, contentPanelName);

                elements.Add(new CuiLabel
                {
                    Text = { Text = authLevelText, FontSize = 14, Align = TextAnchor.MiddleCenter, Color = authLevelColor },
                    RectTransform = { AnchorMin = $"0.33 {bottom}", AnchorMax = $"0.46 {top}" }
                }, contentPanelName);

                elements.Add(new CuiLabel
                {
                    Text = { Text = permStatusText, FontSize = 14, Align = TextAnchor.MiddleCenter, Color = permStatusColor },
                    RectTransform = { AnchorMin = $"0.46 {bottom}", AnchorMax = $"0.61 {top}" }
                }, contentPanelName);

                elements.Add(new CuiButton
                {
                    Button = { Command = adminCommand, Color = adminButtonColor },
                    RectTransform = { AnchorMin = $"0.61 {bottom}", AnchorMax = $"0.79 {top}" },
                    Text = { Text = adminButtonText, FontSize = 14, Align = TextAnchor.MiddleCenter }
                }, contentPanelName);

                elements.Add(new CuiButton
                {
                    Button = { Command = permCommand, Color = permButtonColor },
                    RectTransform = { AnchorMin = $"0.80 {bottom}", AnchorMax = $"0.98 {top}" },
                    Text = { Text = permButtonText, FontSize = 14, Align = TextAnchor.MiddleCenter }
                }, contentPanelName);
            }

            if (onlinePlayers.Count == 0)
            {
                elements.Add(new CuiLabel
                {
                    Text = { Text = "No online players found.", FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "0.6 0.6 0.6 1" },
                    RectTransform = { AnchorMin = "0.3 0.4", AnchorMax = "0.7 0.6" }
                }, contentPanelName);
            }

            CuiHelper.AddUi(player, elements);
        }

        private void DestroyPermissionsUI(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            if (basePlayer == null) return;
            CuiHelper.DestroyUi(basePlayer, UiPermPrefix + basePlayer.userID);
        }
        #endregion
    }
}
Editor is loading...
Leave a Comment