refatore e mande o código COMPLETO:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Quarry Computer", "Marte6", "1.0.0")]
    [Description("Manages quarry operations and configurations with in-game UI")]
    public class QuarryComputer : CovalencePlugin
    {
        [PluginReference]
        private Plugin ImageLibrary = null,
            LangAPI = null,
            Notify = null;

        #region Constants
        private const string BaseItemName = "arcade.machine.chippy";
        private const string BaseDeployedItemName = "chippyarcademachine";
        private const string QuarryPrefab = "assets/content/structures/excavator/prefabs/excavatorsignalcomputer.prefab";
        private const string QuarryOutputStoragePrefab = "assets/prefabs/deployable/hot air balloon/subents/hab_storage.prefab";
        private const string QuarryFuelStoragePrefab = "assets/content/vehicles/boats/rowboat/subents/rowboat_storage.prefab";
        private const string StorageAdaptorPrefab = "assets/prefabs/deployable/playerioents/industrialadaptors/storageadaptor.deployed.prefab";

        private const ulong QuarrySkinId = 3341965622;

        private const string UiBackground = "6iYcl0UppZxwaotNu6kghxTF7s8a4r4d";
        private const string UiMainPanel = "VsUNAYUweeIfW5qvG1zHcQ09hy06GGFi";
        private const string UiLeftPanel = "6k3PPUUOyd8A6RgqGBan9cMLn59GTzRS";
        private const string UiRightPanel = "o9C5OcIYWCoOsRpcULoyfKPGGxb8LAoJ";
        private const string UiPopupOverlayBlock = "Mu8AqzfN17Djw3TstzIsjnJqKi4W5n5j";
        private const string UiPopupShadow = "JVQZBnIR9vmF844dkfYsuOymwWBTCeJV";
        private const string UiPopupBorder = "tmZZ1WqIBuBlqvNeabQH6D6wvK5Gfz7u";
        private const string UiPopupBackground = "3kNfPEASr9RkcBTB9vtMLoxkpKfqc4FU";

        private const string CommandUiClose = "3bizteteO5ic8z82GJHeQx77hlDMLcI9";
        private const string CommandUiRemove = "fl6n4DHugCuZKCrLHpZUF4ZNvEGIW2px";
        private const string CommandUiConfirmRemove = "PTZdQzOalxnZFiwDkiKgMdk1wbuG6T64";
        private const string CommandUiCancelRemove = "09stuljgGWtJzQBvFevq2chgWvZNvodr";
        private const string CommandUiUpgrade = "mSjiZxaTD4hdq9hUHcLGdQviIPzfksgK";
        private const string CommandUiConfirm = "gTpJiMwJn7JSbSWFr8fSjY4nHg72Fryl";
        private const string CommandUiCancelUpgrade = "B3xei8Zq8VVr4zptxJxYxEfW3sh40x82";

        private const Item.Flag ExtractedItemFlag = (Item.Flag)(1 << 78);
        #endregion

        #region Fields
        private static QuarryComputer _instance;
        private readonly List<string> _permissions = new() { "quarrycomputer.give", "quarrycomputer.industrial", "quarrycomputer.vip" };
        private static readonly HashSet<ulong> PlayersWithPopup = new();
        private static readonly Dictionary<ulong, QuarryComputerBehaviour> OpenedQuarryInterfaces = new();
        private static readonly HashSet<QuarryComputerBehaviour> QuarryCheckStatusList = new();
        private static readonly Dictionary<BaseEntity, QuarryComputerBehaviour> ContainerQuarryMap = new();
        #endregion

        #region Initialization
        private void OnServerInitialized()
        {
            _instance = this;
            RegisterPermissions();
            RegisterCommands();
            InitializeExistingQuarries();
        }

        private void Unload()
        {
            DestroyAllUi();
            UnloadAllQuarryBehaviours();
        }
        #endregion

        #region Configuration
        private Configuration _config;

        private class Configuration
        {
            [JsonProperty("Use LangAPI Plugin")]
            public bool UseLangAPI { get; set; }

            [JsonProperty("Use Notify Plugin")]
            public bool UseNotify { get; set; }

            [JsonProperty("Give Quarry Command")]
            public string[] GiveQuarryCommand { get; set; }

            [JsonProperty("Remove Quarry Command")]
            public string[] RemoveQuarryCommand { get; set; }

            [JsonProperty("Fuel Configuration")]
            public FuelConfiguration FuelConfiguration { get; set; }

            [JsonProperty("No Upgrades (Level 1)")]
            public NoUpgrades NoUpgrades { get; set; }

            [JsonProperty("Upgrades (Level 2+)")]
            public List<UpgradeOption> Upgrades { get; set; }

            [JsonProperty("Keep Upgrades On Remove Quarry")]
            public bool KeepUpgradesOnRemoval { get; set; }

            [JsonProperty("Profiles")]
            public UserProfiles Profiles { get; set; }

            [JsonProperty("Version")]
            public VersionNumber Version { get; set; }
        }

        private class FuelConfiguration
        {
            [JsonProperty("Shortname")]
            public string Shortname { get; set; }

            [JsonProperty("Resource Extraction Interval In Seconds")]
            public int ResourceExtractionInterval { get; set; }

            [JsonProperty("Fuel Required Per Extraction")]
            public int FuelRequiredPerExtraction { get; set; }
        }

        private class NoUpgrades
        {
            [JsonProperty("Storage Slots")]
            public StorageSlots StorageSlots { get; set; }

            [JsonProperty("Resources Output Per Extraction")]
            public List<ResourceItem> ResourcesOutput { get; set; }
        }

        private class StorageSlots
        {
            [JsonProperty("Fuel")]
            public int FuelSlots { get; set; }

            [JsonProperty("Resources")]
            public int OutputSlots { get; set; }
        }

        private class ResourceItem
        {
            [JsonProperty("Shortname")]
            public string Shortname { get; set; }

            [JsonProperty("Amount")]
            public int Amount { get; set; }
        }

        private class UpgradeOption
        {
            [JsonProperty("Storage Slots")]
            public StorageSlots StorageSlots { get; set; }

            [JsonProperty("Resources Output Per Extraction")]
            public List<ResourceItem> ResourcesOutput { get; set; }

            [JsonProperty("Required Items To Upgrade")]
            public List<ResourceItem> UpgradeItems { get; set; }
        }

        private class UserProfiles
        {
            [JsonProperty("Default (No Permission)")]
            public UserProfile Default { get; set; }

            [JsonProperty("VIP (quarrycomputer.vip Permission)")]
            public UserProfile VIP { get; set; }
        }

        private class UserProfile
        {
            [JsonProperty("Quarry Limit")]
            public int QuarryLimit { get; set; }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config != null)
                {
                    if (_config.Version < Version)
                        UpdateConfigValues();

                    SaveConfig();
                }
                else
                {
                    throw new Exception();
                }
            }
            catch
            {
                PrintError("Your configuration file contains an error. Using default configuration values.");
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig() => _config = CreateDefaultConfig();

        protected override void SaveConfig() => Config.WriteObject(_config);

        private void UpdateConfigValues()
        {
            PrintWarning("Config update detected! Updating config values...");

            _config.Version = Version;

            PrintWarning("Config update completed!");
        }

        private Configuration CreateDefaultConfig()
        {
            return new Configuration
            {
                GiveQuarryCommand = new[] { "gq", "givequarry" },
                RemoveQuarryCommand = new[] { "rq", "removequarry" },
                UseLangAPI = false,
                UseNotify = true,
                FuelConfiguration = new FuelConfiguration
                {
                    Shortname = "charcoal",
                    ResourceExtractionInterval = 6,
                    FuelRequiredPerExtraction = 1,
                },
                NoUpgrades = new NoUpgrades
                {
                    StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
                    ResourcesOutput = new List<ResourceItem>
                    {
                        new ResourceItem { Shortname = "crude.oil", Amount = 1 },
                        new ResourceItem { Shortname = "stones", Amount = 1 },
                    },
                },
                Upgrades = new List<UpgradeOption>
                {
                    new UpgradeOption
                    {
                        StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
                        ResourcesOutput = new List<ResourceItem>
                        {
                            new ResourceItem { Shortname = "crude.oil", Amount = 2 },
                            new ResourceItem { Shortname = "metal.ore", Amount = 1 },
                            new ResourceItem { Shortname = "stones", Amount = 2 },
                        },
                        UpgradeItems = new List<ResourceItem>
                        {
                            new ResourceItem { Shortname = "scrap", Amount = 1000 },
                            new ResourceItem { Shortname = "pumpkin", Amount = 1000 },
                            new ResourceItem { Shortname = "bone.fragments", Amount = 1000 },
                        },
                    },
                    new UpgradeOption
                    {
                        StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
                        ResourcesOutput = new List<ResourceItem>
                        {
                            new ResourceItem { Shortname = "crude.oil", Amount = 3 },
                            new ResourceItem { Shortname = "hq.metal.ore", Amount = 3 },
                            new ResourceItem { Shortname = "metal.ore", Amount = 3 },
                            new ResourceItem { Shortname = "stones", Amount = 3 },
                            new ResourceItem { Shortname = "sulfur.ore", Amount = 3 },
                        },
                        UpgradeItems = new List<ResourceItem>
                        {
                            new ResourceItem { Shortname = "scrap", Amount = 5000 },
                            new ResourceItem { Shortname = "pumpkin", Amount = 1000 },
                            new ResourceItem { Shortname = "cloth", Amount = 10000 },
                            new ResourceItem { Shortname = "red.berry", Amount = 1000 },
                            new ResourceItem { Shortname = "bone.fragments", Amount = 1000 },
                        },
                    },
                },
                KeepUpgradesOnRemoval = true,
                Profiles = new UserProfiles
                {
                    Default = new UserProfile { QuarryLimit = 1 },
                    VIP = new UserProfile { QuarryLimit = 3 },
                },
            };
        }
        #endregion

        #region Localization
        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(
                new Dictionary<string, string>
                {
                    ["NoPermission"] = "You don't have permissions to use this command",
                    ["NoBuildingAuth"] = "You must have building auth to use this",
                    ["NotMiningQuarry"] = "This object is not a Mining Quarry",
                    ["NotOwner"] = "This object belongs to another owner",
                    ["QuarryRemoved"] = "Mining Quarry Removed",
                    ["NoQuarriesFound"] = "No quarries found",
                },
                this
            );
        }

        public string GetItemDisplayName(BasePlayer player, string itemShortName)
        {
            ItemDefinition itemDefinition = ItemManager.FindItemDefinition(itemShortName);
            var displayName = itemDefinition.displayName.translated;

            if (_config.UseLangAPI && LangAPI != null && LangAPI.Call<bool>("IsDefaultDisplayName", displayName))
            {
                var displayNameTranslated = LangAPI.Call<string>("GetItemDisplayName", itemShortName, displayName, player.UserIDString);
                if (!string.IsNullOrEmpty(displayNameTranslated))
                {
                    return displayNameTranslated;
                }
            }

            return displayName;
        }
        #endregion

        #region UiCommands
        [Command(CommandUiClose)]
        private void UiCloseCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            DestroyUi(basePlayer);
        }

        [Command(CommandUiRemove)]
        private void UiRemoveCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ToggleConfirmationPopup(basePlayer, "Remove the Quarry?", CommandUiConfirmRemove, CommandUiCancelRemove);
        }

        [Command(CommandUiConfirmRemove)]
        private void UiConfirmRemoveCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ClosePopup(basePlayer);
        }

        [Command(CommandUiCancelRemove)]
        private void UiCancelRemoveCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ClosePopup(basePlayer);
        }

        [Command(CommandUiUpgrade)]
        private void UiUpgradeCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ToggleConfirmationPopup(basePlayer, "Upgrade the Quarry?", CommandUiConfirm, CommandUiCancelUpgrade);
        }

        [Command(CommandUiConfirm)]
        private void UiConfirmCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ClosePopup(basePlayer);
        }

        [Command(CommandUiCancelUpgrade)]
        private void UiCancelUpgradeCommand(IPlayer player)
        {
            var basePlayer = player.Object as BasePlayer;
            ClosePopup(basePlayer);
        }
        #endregion

        #region Commands
        private void GiveQuarryCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = iplayer?.Object as BasePlayer;
            if (player == null || args == null || args.Length < 1)
                return;

            if (!iplayer.HasPermission("quarrycomputer.give"))
            {
                NotifyPlayer(iplayer, "NoPermission", 1);
                return;
            }

            var targetPlayer = BasePlayer.Find(args[0]);
            if (targetPlayer == null)
            {
                NotifyPlayer(iplayer, "PlayerNotFound", 1);
                return;
            }

            if (GiveQuarryItem(targetPlayer))
            {
                NotifyPlayer(iplayer, "QuarrySend", 0);
                NotifyPlayer(targetPlayer, "QuarryReceived", 0);
            }
            else
            {
                NotifyPlayer(iplayer, "QuarrySend", 0);
                NotifyPlayer(targetPlayer, "QuarryReceived", 0);
                NotifyPlayer(targetPlayer, "QuarryDropped", 1);
            }
        }

        private void RemoveQuarryCommand(IPlayer iplayer, string command, string[] args)
        {
            var player = iplayer?.Object as BasePlayer;
            if (player == null)
                return;

            if (!TryFindQuarryInCrosshair(player, out var quarryEntity))
            {
                NotifyPlayer(iplayer, "NotMiningQuarry", 1);
                return;
            }

            if (quarryEntity.OwnerID != player.userID)
            {
                NotifyPlayer(iplayer, "NotOwner", 1);
                return;
            }

            quarryEntity.Kill();
            NotifyPlayer(iplayer, "QuarryRemoved", 0);
        }
        #endregion

        #region UI Handling
        private void CreateUi(BasePlayer player, int quarryLevel)
        {
            var fuelName = GetItemDisplayName(player, _config.FuelConfiguration.Shortname);
            var container = new CuiElementContainer();
            AddBackground(container);
            AddMainPanel(container, fuelName);
            AddLeftPanel(container, quarryLevel);
            AddRightPanel(container);
            CuiHelper.AddUi(player, container);
        }

        private void AddBackground(CuiElementContainer container)
        {
            AddPanel(container, "0 0", "1 1", UiBackground, "Overlay", "0 0 0 0.9", true);
        }

        private void AddMainPanel(CuiElementContainer container, string fuelName)
        {
            AddPanel(container, "0.235 0.18", "0.765 0.784", UiMainPanel, UiBackground, "0.6 0.6 0.6 0.95", true);
            AddInnerSquare(container, UiMainPanel, "0 0.9570", "1 1", "0.39 0.39 0.39 1");
            AddText(
                container,
                UiMainPanel,
                "0.02 0.96",
                "1 1",
                $"Extraction Interval: {_config.FuelConfiguration.ResourceExtractionInterval} sec | Fuel per extraction: {_config.FuelConfiguration.FuelRequiredPerExtraction} {fuelName}",
                13,
                TextAnchor.MiddleLeft
            );
            AddCloseButton(container, UiMainPanel);
        }

        private void AddLeftPanel(CuiElementContainer container, int quarryLevel)
        {
            var parent = UiLeftPanel;
            AddPanel(container, "0 0", "0.5 0.94", parent, UiMainPanel, "0 0 0 0");
            AddPanelStructure(container, parent, $"Quarry Level {quarryLevel}", "0 0 1 1");

            AddText(container, parent, "0.38 0.679", "1 1", "Storage", 13, TextAnchor.MiddleLeft);
            AddText(container, parent, "0.09 0.590", "1 1", "Fuel: 3 slots", 13, TextAnchor.MiddleLeft);
            AddText(container, parent, "0.45 0.590", "1 1", "Resource: 6 slots", 13, TextAnchor.MiddleLeft);

            AddHorizontalLine(container, parent, "0.06 0.769", "0.89 0.77");

            AddText(container, parent, "0.34 0.490", "1 1", "Extraction", 13, TextAnchor.MiddleLeft);
            Dictionary<string, string> extractionTexts = new Dictionary<string, string>
            {
                { "charcoal", "10" },
                { "blueberries", "10" },
                { "hazmatsuit.arcticsuit", "10" },
                { "crude.oil", "10" },
                { "hq.metal.ore", "60" },
                { "grenade.f1", "10" },
            };
            AddDictionaryWithSpacing(container, parent, extractionTexts, 0.18f, 0.725f, 0.065f);

            AddRemoveButton(container, parent);
        }

        private void AddRightPanel(CuiElementContainer container)
        {
            var parent = UiRightPanel;
            AddPanel(container, "0.5 0", "1 0.94", parent, UiMainPanel, "0 0 0 0");
            AddPanelStructure(container, parent, "Upgrade to Level 2", "0.5 0 0 1");

            AddText(container, parent, "0.38 0.679", "1 1", "Storage", 13, TextAnchor.MiddleLeft);
            AddText(container, parent, "0.09 0.590", "1 1", "Fuel: 3 slots", 13, TextAnchor.MiddleLeft);
            AddText(container, parent, "0.45 0.590", "1 1", "Resource: 6 slots", 13, TextAnchor.MiddleLeft);

            AddHorizontalLine(container, parent, "0.06 0.769", "0.89 0.77");

            AddText(container, parent, "0.34 0.490", "1 1", "Extraction", 13, TextAnchor.MiddleLeft);

            Dictionary<string, string> extractionTexts = new Dictionary<string, string>
            {
                { "abovegroundpool", "10" },
                { "blueberries", "10" },
                { "hazmatsuit.arcticsuit", "10" },
                { "crude.oil", "10" },
                { "hq.metal.ore", "60" },
                { "grenade.f1", "10" },
                { "metal.ore", "100" },
                { "stones", "250" },
                { "sulfur.ore", "160" },
                { "explosive.timed", "2" },
                { "explosive.satchel", "2" },
                { "grenade.beancan", "4" },
            };
            AddDictionaryWithSpacing(container, parent, extractionTexts, 0.18f, 0.725f, 0.065f);

            AddHorizontalLine(container, parent, "0.06 0.464", "0.89 0.465");

            AddText(container, parent, "0.34 0.0", "1 0.88", "Requirements", 13, TextAnchor.MiddleLeft);
            Dictionary<string, string> requirementsTexts = new Dictionary<string, string>
            {
                { "abovegroundpool", "10" },
                { "blueberries", "10" },
                { "hazmatsuit.arcticsuit", "10" },
                { "crude.oil", "10" },
                { "hq.metal.ore", "60" },
                { "grenade.f1", "10" },
                { "metal.ore", "100" },
                { "stones", "250" },
                { "sulfur.ore", "160" },
                { "explosive.timed", "2" },
                { "explosive.satchel", "2" },
                { "grenade.beancan", "4" },
            };
            AddDictionaryWithSpacing(container, parent, requirementsTexts, 0.18f, 0.419f, 0.065f);

            AddUpgradeButton(container, parent);
        }

        private void AddPanelStructure(CuiElementContainer container, string parent, string title, string titleColor)
        {
            AddInnerSquare(container, parent, "0.10 0.05", "0.95 0.90", "0 0 0 0.97");
            AddInnerSquare(container, parent, "0.054 0.1033", "0.895 0.945", "0.8 0.8 0.8 1");
            AddInnerSquare(container, parent, "0.06 0.108", "0.89 0.94", titleColor);
            AddHorizontalLine(container, parent, "0.06 0.865", "0.89 0.865");

            AddText(container, parent, "0.1 0.84", "0.84 0.98", title, 15, TextAnchor.MiddleCenter);
        }

        private void AddDictionaryWithSpacing(CuiElementContainer container, string parent, Dictionary<string, string> texts, float initialAnchorX, float initialAnchorY, float spacing)
        {
            float anchorX = initialAnchorX;

            int i = 0;
            foreach (var item in texts)
            {
                i++;

                float anchorY = initialAnchorY - (spacing * i);

                if (i >= 5 && i < 9)
                {
                    anchorY = initialAnchorY - (spacing * (i - 4));
                    anchorX = initialAnchorX + 0.23F;
                }

                if (i >= 9)
                {
                    anchorY = initialAnchorY - (spacing * (i - 8));
                    anchorX = initialAnchorX + 0.47F;
                }

                float imageSize = 0.07f;

                float imageAnchorMinX = anchorX - (imageSize / 2);
                float imageAnchorMaxX = anchorX + (imageSize / 2);
                float imageAnchorMinY = anchorY + 0.04f - (imageSize / 2);
                float imageAnchorMaxY = anchorY + 0.02f + (imageSize / 2);

                AddImage(container, parent, item.Key, $"{imageAnchorMinX} {imageAnchorMinY}", $"{imageAnchorMaxX} {imageAnchorMaxY}", "ResourceImage");

                AddText(container, parent, $"{anchorX + 0.05f} {anchorY}", $"{anchorX + 0.05f + 0.8f} {anchorY + 0.06}", item.Value, 12, TextAnchor.MiddleLeft);
            }
        }

        private void AddTextsWithSpacing(CuiElementContainer container, string parent, string[] texts, float anchorX, float initialAnchorY, float spacing)
        {
            for (int i = 0; i < texts.Length; i++)
            {
                float anchorY = initialAnchorY - (spacing * i);
                AddText(container, parent, $"{anchorX} {anchorY}", $"{anchorX + 0.8f} {anchorY + 0.06}", texts[i], 12, TextAnchor.MiddleLeft);
            }
        }

        private void AddHorizontalLine(CuiElementContainer container, string parent, string anchorMin, string anchorMax)
        {
            AddInnerSquare(container, parent, anchorMin, anchorMax, "0.8 0.8 0.8 1");
        }

        private void AddImage(CuiElementContainer container, string parent, string resourceName, string anchorMin, string anchorMax, string imageName)
        {
            string imageUrl = ImageLibrary?.Call("GetImage", resourceName) as string;
            if (string.IsNullOrEmpty(imageUrl))
            {
                PrintWarning($"Failed to get image for item: {resourceName}");
                return;
            }

            container.Add(
                new CuiElement
                {
                    Name = imageName,
                    Parent = parent,
                    Components =
                    {
                        new CuiRawImageComponent { Png = imageUrl },
                        new CuiRectTransformComponent { AnchorMin = anchorMin, AnchorMax = anchorMax },
                    },
                }
            );
        }

        private void AddCloseButton(CuiElementContainer container, string parent)
        {
            container.Add(
                new CuiButton
                {
                    Button =
                    {
                        Color = "1 0 0 1",
                        Command = CommandUiClose,
                        Close = UiBackground,
                    },
                    RectTransform = { AnchorMin = "0.965 0.957", AnchorMax = "1 1" },
                    Text =
                    {
                        Text = "✖",
                        FontSize = 13,
                        Align = TextAnchor.MiddleCenter,
                        Color = "1 1 1 0.5",
                    },
                },
                parent
            );
        }

        private void AddRemoveButton(CuiElementContainer container, string parent)
        {
            AddButton(container, parent, "Remove Quarry", CommandUiRemove, "0.28", "0.11", "0.70", "0.16", "0.6 0.6 0.6 0.95", "1 0 0 1");
        }

        private void AddUpgradeButton(CuiElementContainer container, string parent)
        {
            AddButton(container, parent, "Upgrade", CommandUiUpgrade, "0.35", "0.11", "0.65", "0.16", "0.6 0.6 0.6 0.95", "0 1 0 1");
        }

        private void DestroyUi(BasePlayer player)
        {
            if (player == null)
                return;

            CuiHelper.DestroyUi(player, UiBackground);
            CuiHelper.DestroyUi(player, UiMainPanel);
            CuiHelper.DestroyUi(player, UiLeftPanel);
            CuiHelper.DestroyUi(player, UiRightPanel);
            CuiHelper.DestroyUi(player, UiPopupOverlayBlock);
            CuiHelper.DestroyUi(player, UiPopupShadow);
            CuiHelper.DestroyUi(player, UiPopupBorder);
            CuiHelper.DestroyUi(player, UiPopupBackground);

            OpenedQuarryInterfaces.Remove(player.userID);
            PlayersWithPopup.Remove(player.userID);
        }

        private void DestroyAllUi()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                DestroyUi(player);
            }
        }

        private void ToggleConfirmationPopup(BasePlayer player, string message, string confirmCommand, string cancelCommand)
        {
            if (player != null && !PlayersWithPopup.Contains(player.userID))
            {
                PlayersWithPopup.Add(player.userID);
                ShowConfirmationPopup(player, message, confirmCommand, cancelCommand);
            }
        }

        private void ShowConfirmationPopup(BasePlayer player, string message, string confirmCommand, string cancelCommand)
        {
            var container = new CuiElementContainer();
            AddPanel(container, "0 0", "1 1", UiPopupOverlayBlock, "Overlay", "0 0 0 0.9", true);
            AddPanel(container, "0.4 0.4", "0.6 0.6", UiPopupShadow, UiPopupOverlayBlock, "0 0 0 0.85");
            AddPanel(container, "0.0 0.09", "0.95 1.0", UiPopupBorder, UiPopupShadow, "1 1 1 1");
            AddPanel(container, "0.01 0.01", "0.991 0.985", UiPopupBackground, UiPopupBorder, "0 0 0 1");
            AddText(container, UiPopupBackground, "0 0", "1 1", message, 14, TextAnchor.MiddleCenter);
            AddButton(container, UiPopupBackground, "Yes", confirmCommand, "0.25", "0.05", "0.45", "0.20", "0.6 0.6 0.6 0.95", "0 1 0 1");
            AddButton(container, UiPopupBackground, "No", cancelCommand, "0.55", "0.05", "0.75", "0.20", "0.6 0.6 0.6 0.95", "1 0 0 1");
            CuiHelper.AddUi(player, container);
        }

        private void ClosePopup(BasePlayer player)
        {
            if (player != null)
            {
                CuiHelper.DestroyUi(player, UiPopupOverlayBlock);
                CuiHelper.DestroyUi(player, UiPopupShadow);
                CuiHelper.DestroyUi(player, UiPopupBorder);
                CuiHelper.DestroyUi(player, UiPopupBackground);

                PlayersWithPopup.Remove(player.userID);
            }
        }
        #endregion

        #region UI Helpers
        private void AddPanel(CuiElementContainer container, string anchorMin, string anchorMax, string panelName, string parent, string color, bool isCursorEnabled = false)
        {
            var panel = new CuiPanel
            {
                Image = { Color = color },
                RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax },
                CursorEnabled = isCursorEnabled,
            };

            container.Add(panel, parent, panelName);
        }

        private void AddInnerSquare(CuiElementContainer container, string parent, string anchorMin, string anchorMax, string color)
        {
            container.Add(new CuiPanel { Image = { Color = color }, RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax } }, parent);
        }

        private void AddText(CuiElementContainer container, string parent, string anchorMin, string anchorMax, string text, int fontSize, TextAnchor alignment)
        {
            container.Add(
                new CuiLabel
                {
                    Text =
                    {
                        Text = text,
                        FontSize = fontSize,
                        Font = "DroidSansMono.ttf",
                        Align = alignment,
                        Color = "1 1 1 1",
                    },
                    RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax },
                },
                parent
            );
        }

        private void AddButton(
            CuiElementContainer container,
            string parent,
            string text,
            string command,
            string anchorMinX,
            string anchorMinY,
            string anchorMaxX,
            string anchorMaxY,
            string bgColor,
            string textColor
        )
        {
            container.Add(
                new CuiButton
                {
                    Button =
                    {
                        Color = bgColor,
                        Command = command,
                        Close = "",
                    },
                    RectTransform = { AnchorMin = $"{anchorMinX} {anchorMinY}", AnchorMax = $"{anchorMaxX} {anchorMaxY}" },
                    Text =
                    {
                        Text = text,
                        FontSize = 14,
                        Font = "DroidSansMono.ttf",
                        Align = TextAnchor.MiddleCenter,
                        Color = textColor,
                    },
                },
                parent
            );
        }
        #endregion

        #region Game Hooks
        private void OnEntityBuilt(Planner planner, GameObject builtObject)
        {
            var player = planner?.GetOwnerPlayer();
            var entity = builtObject.GetComponent<BaseEntity>();

            if (player == null || entity == null || entity.ShortPrefabName != BaseDeployedItemName || entity.skinID != QuarrySkinId)
                return;

            var playerQuarryCount = BaseNetworkable.serverEntities.OfType<ExcavatorSignalComputer>().Count(x => x.OwnerID == player.userID);
            var playerQuarryLimit = _config.Profiles.Default.QuarryLimit;

            if (permission.UserHasPermission(player.UserIDString, "quarrycomputer.vip"))
            {
                playerQuarryLimit = _config.Profiles.VIP.QuarryLimit;
            }

            if (!player.IsBuildingAuthed() || playerQuarryCount >= playerQuarryLimit)
            {
                if (entity)
                    entity.Kill();

                NotifyPlayer(player.IPlayer, !player.IsBuildingAuthed() ? "NoBuildingAuth" : "QuarryLimitReached", 1);
                timer.Once(1, () => GiveQuarryItem(player));
                return;
            }

            DeployQuarry(player, entity);
            NextTick(() =>
            {
                entity?.Kill();
            });
        }

        private ItemContainer.CanAcceptResult? CanAcceptItem(ItemContainer container, Item item)
        {
            if (container.entityOwner is not StorageContainer || container.entityOwner.name == null)
                return null;

            QuarryComputerBehaviour quarryComputer;

            if (!ContainerQuarryMap.TryGetValue(container.entityOwner, out quarryComputer))
            {
                quarryComputer = container.entityOwner.GetComponentInParent<QuarryComputerBehaviour>();

                if (quarryComputer == null)
                    return null;

                ContainerQuarryMap[container.entityOwner] = quarryComputer;
            }

            if (container.entityOwner.name == QuarryFuelStoragePrefab)
            {
                if (item.info.shortname == _config.FuelConfiguration.Shortname)
                    QuarryCheckStatusList.Add(quarryComputer);
                else
                    return ItemContainer.CanAcceptResult.CannotAccept;
            }

            if (container.entityOwner.name == QuarryOutputStoragePrefab && !item.flags.HasFlag(ExtractedItemFlag))
                return ItemContainer.CanAcceptResult.CannotAccept;

            return null;
        }

        private object CanPickupEntity(BasePlayer player, IndustrialStorageAdaptor entity)
        {
            return entity.GetComponentInParent<QuarryComputerBehaviour>() != null ? (object)false : null;
        }

        private object OnExcavatorSuppliesRequest(ExcavatorSignalComputer computer, BasePlayer player)
        {
            return computer.GetComponent<QuarryComputerBehaviour>() != null ? (object)true : null;
        }

        private object OnButtonPress(PressButton button, BasePlayer player)
        {
            var outputContainer = button.GetParentEntity();
            if (outputContainer is not StorageContainer)
                return null;

            var quarry = outputContainer.GetComponentInParent<QuarryComputerBehaviour>();
            if (quarry == null || quarry.OwnerID != player.userID)
            {
                Puts("Belongs to another user");
                return null;
            }

            Puts($"quarry level: {quarry.Level}");

            OpenedQuarryInterfaces.Add(player.userID, quarry);
            CreateUi(player, quarry.Level);

            return null;
        }
        #endregion

        #region Quarry Management Methods
        private bool TryFindQuarryInCrosshair(BasePlayer player, out BaseEntity quarryEntity)
        {
            quarryEntity = null;
            int layerMask = LayerMask.GetMask("Default", "TransparentFX", "IgnoreRaycast", "Water");

            if (!Physics.Raycast(player.eyes.HeadRay(), out var hitInfo, 3f, layerMask, QueryTriggerInteraction.Ignore))
                return false;

            quarryEntity = hitInfo.collider.ToBaseEntity();
            return quarryEntity != null && quarryEntity.name == QuarryPrefab;
        }

        private bool GiveQuarryItem(BasePlayer player)
        {
            var item = CreateQuarryItem();

            if (player.inventory.GiveItem(item))
            {
                player.Command("note.inv", item.info.itemid, 1, item.name, (int)BaseEntity.GiveItemReason.PickedUp);
                return true;
            }
            item.Drop(player.inventory.containerMain.dropPosition, player.inventory.containerMain.dropVelocity);
            return false;
        }

        private Item CreateQuarryItem()
        {
            var item = ItemManager.CreateByName(BaseItemName, 1, QuarrySkinId);
            item.name = "Quarry Computer";
            return item;
        }

        private void DeployQuarry(BasePlayer player, BaseEntity entity)
        {
            var position = entity.transform.position;
            var rotation = Quaternion.Euler(0, entity.transform.rotation.eulerAngles.y + 90, 0);
            var quarry = GameManager.server.CreateEntity(QuarryPrefab, position, rotation);
            quarry.OwnerID = player.userID;
            quarry.Spawn();
            quarry.SendNetworkUpdateImmediate();

            AttachContainer(quarry, QuarryOutputStoragePrefab, new Vector3(0.05f, 0.75f, -0.21f), new Vector3(0, 180, 0), false, player);
            AttachContainer(quarry, QuarryFuelStoragePrefab, new Vector3(0.05f, 0.75f, 0.32f), new Vector3(90, 0, 0), true, player);

            quarry.gameObject.AddComponent<QuarryComputerBehaviour>();
        }

        private void AttachContainer(BaseEntity entity, string prefab, Vector3 localPosition, Vector3 localEulerAngles, bool isFuelContainer, BasePlayer player)
        {
            var container = GameManager.server.CreateEntity(prefab) as StorageContainer;
            container.SetParent(entity);
            container.transform.localPosition = localPosition;
            container.transform.localRotation = Quaternion.Euler(localEulerAngles);
            container.Spawn();
            container.SendNetworkUpdateImmediate();

            if (permission.UserHasPermission(player.UserIDString, "quarrycomputer.industrial"))
            {
                var adaptor = GameManager.server.CreateEntity(StorageAdaptorPrefab, container.transform.position, container.transform.rotation) as IndustrialStorageAdaptor;
                adaptor.SetParent(container, true, true);
                adaptor.transform.localPosition = isFuelContainer ? new Vector3(0.00f, -0.06f, -0.26f) : new Vector3(0.00f, 0.26f, 0.05f);
                adaptor.transform.rotation = container.transform.rotation * Quaternion.Euler(isFuelContainer ? new Vector3(0, 270, 90) : new Vector3(0, 90, 0));
                adaptor.Spawn();
                adaptor.SendNetworkUpdateImmediate();
            }

            if (!isFuelContainer)
            {
                var button = GameManager.server.CreateEntity("assets/prefabs/io/electric/switches/pressbutton/pressbutton.prefab") as PressButton;
                button.SetParent(container, true, true);
                button.transform.localPosition = new Vector3(0.40f, 1.60f, -0.13f);
                button.transform.rotation = container.transform.rotation * Quaternion.Euler(new Vector3(10, 90, 180));
                button.Spawn();
                button.SendNetworkUpdateImmediate();
            }
        }

        public bool CanTransferAllResources(StorageContainer outputContainer)
        {
            foreach (var resource in _config.NoUpgrades.ResourcesOutput)
            {
                if (!TryTransferResourceItem(outputContainer, resource.Shortname, resource.Amount))
                {
                    return false;
                }
            }
            return true;
        }

        public void HandleFuelConsumption(Item fuel, int requiredFuelAmount)
        {
            if (fuel.amount > requiredFuelAmount)
            {
                SafelyRemoveItem(fuel.SplitItem(requiredFuelAmount));
            }
            else
            {
                SafelyRemoveItem(fuel);
            }
        }

        public void TransferResources(StorageContainer outputContainer)
        {
            foreach (var resource in _config.NoUpgrades.ResourcesOutput)
            {
                TryTransferResourceItem(outputContainer, resource.Shortname, resource.Amount, true);
            }
        }

        public bool TryTransferResourceItem(StorageContainer container, string itemShortName, int amount, bool transfer = false)
        {
            if (amount <= 0)
                return false;

            var item = ItemManager.CreateByName(itemShortName, amount, 0uL);
            if (item == null)
                return false;

            if (transfer)
                item.SetFlag(ExtractedItemFlag, true);

            return TransferItem(container, item, transfer);
        }

        private bool TransferItem(StorageContainer container, Item item, bool transfer)
        {
            for (int i = 0; i < container.inventory.capacity; i++)
            {
                var slotItem = container.inventory.GetSlot(i);
                if (slotItem != null && slotItem.info == item.info && slotItem.CanStack(item) && TryStackToSlot(slotItem, item, transfer, container))
                {
                    return true;
                }
            }

            return PlaceInEmptySlot(container, item, transfer);
        }

        private bool TryStackToSlot(Item slotItem, Item item, bool transfer, StorageContainer container)
        {
            int availableSpace = slotItem.MaxStackable() - slotItem.amount;
            if (availableSpace <= 0)
                return false;

            if (availableSpace >= item.amount)
            {
                if (transfer && item.MoveToContainer(container.inventory, slotItem.position))
                    item.SetFlag(ExtractedItemFlag, false);

                return true;
            }
            else
            {
                UpdateItemStacks(item, slotItem, availableSpace);
                return false;
            }
        }

        private bool PlaceInEmptySlot(StorageContainer container, Item item, bool transfer)
        {
            for (int i = 0; i < container.inventory.capacity; i++)
            {
                if (container.inventory.GetSlot(i) == null && container.inventory.canAcceptItem(item, i))
                {
                    if (transfer && item.MoveToContainer(container.inventory, i))
                    {
                        item.SetFlag(ExtractedItemFlag, false);
                        return true;
                    }
                    return true;
                }
            }
            return false;
        }

        private void UpdateItemStacks(Item item, Item slotItem, int spaceToFill)
        {
            item.amount -= spaceToFill;
            slotItem.amount += spaceToFill;
            slotItem.MarkDirty();
        }
        #endregion

        #region Utility Methods
        private string Msg(string userid, string key, params object[] obj)
        {
            return string.Format(lang.GetMessage(key, this, userid), obj);
        }

        private void NotifyPlayer(IPlayer player, string key, int type, params object[] obj)
        {
            var UserIDString = player.Id;
            if (_config.UseNotify && Notify != null)
                Interface.Oxide.CallHook("SendNotify", UserIDString, type, Msg(UserIDString, key, obj));
            else
                player.Message(Msg(player.Id, key, obj));
        }

        private void NotifyPlayer(BasePlayer player, string key, int type, params object[] obj)
        {
            var UserIDString = player.UserIDString;
            if (_config.UseNotify && Notify != null)
                Interface.Oxide.CallHook("SendNotify", UserIDString, type, Msg(UserIDString, key, obj));
            else
                player.ChatMessage(Msg(UserIDString, key, obj));
        }

        public void SafelyRemoveItem(Item item)
        {
            item?.RemoveFromWorld();
            item?.RemoveFromContainer();
            item?.Remove();
        }

        private void RegisterPermissions()
        {
            foreach (string permissionName in _permissions)
                permission.RegisterPermission(permissionName, this);
        }

        private void RegisterCommands()
        {
            AddCovalenceCommand(_config.GiveQuarryCommand, nameof(GiveQuarryCommand));
            AddCovalenceCommand(_config.RemoveQuarryCommand, nameof(RemoveQuarryCommand));
        }

        private void InitializeExistingQuarries()
        {
            foreach (var signalComputer in UnityEngine.Object.FindObjectsOfType<ExcavatorSignalComputer>())
            {
                if (signalComputer.OwnerID != 0)
                {
                    signalComputer.gameObject.AddComponent<QuarryComputerBehaviour>();
                }
            }

            timer.Every(30, InitializeQuarries);
        }

        private void InitializeQuarries()
        {
            foreach (var quarry in QuarryCheckStatusList)
            {
                if (!quarry.IsOn)
                    quarry.StartMining();
            }

            QuarryCheckStatusList.Clear();
        }

        private void UnloadAllQuarryBehaviours()
        {
            var behaviours = UnityEngine.Object.FindObjectsOfType<QuarryComputerBehaviour>();
            foreach (var behaviour in behaviours)
            {
                behaviour.Unload();
                UnityEngine.Object.Destroy(behaviour);
            }
        }
        #endregion

        #region Quarry Behaviour Class
        private class QuarryComputerBehaviour : MonoBehaviour
        {
            private ExcavatorSignalComputer _signalComputer;
            public StorageContainer OutputContainer { get; private set; }
            public StorageContainer FuelContainer { get; private set; }
            public int Level { get; private set; }
            public ulong OwnerID { get; private set; }
            public bool IsOn = true;

            private void Awake()
            {
                InitializeSignalComputer();
                UpdateQuarryOwnerID();
                InitializeContainers();
                ScheduleRoutineTasks();
                UpdateQuarryLevel();
                UpdateQuarryCapacity();
            }

            private void InitializeSignalComputer()
            {
                _signalComputer = GetComponent<ExcavatorSignalComputer>();
                _signalComputer.SetFlag(BaseEntity.Flags.Reserved8, false);
                _signalComputer.chargePower = 0f;
            }

            private void UpdateQuarryOwnerID()
            {
                OwnerID = _signalComputer.OwnerID;
            }

            private void InitializeContainers()
            {
                foreach (var container in _signalComputer.children.Cast<StorageContainer>())
                {
                    if (container.name == QuarryOutputStoragePrefab)
                        OutputContainer = container;
                    else if (container.name == QuarryFuelStoragePrefab)
                        FuelContainer = container;
                }
            }

            private void UpdateQuarryLevel()
            {
                if (OutputContainer.OwnerID == 0)
                    Level = 1;
                else
                    Level = (int)OutputContainer.OwnerID;
            }

            private void UpdateQuarryCapacity()
            {
                OutputContainer.inventory.capacity = 12;
                FuelContainer.inventory.capacity = 6;
            }

            private void ScheduleRoutineTasks()
            {
                InvokeRepeating(nameof(CheckGroundIntegrity), 30f, 30f);
                InvokeRepeating(nameof(PerformResourceExtraction), 0f, _instance._config.FuelConfiguration.ResourceExtractionInterval);
            }

            public void StartMining()
            {
                CancelInvoke(nameof(PerformResourceExtraction));
                InvokeRepeating(nameof(PerformResourceExtraction), 0f, _instance._config.FuelConfiguration.ResourceExtractionInterval);
            }

            private void PerformResourceExtraction()
            {
                _instance.Puts("PerformResourceExtraction: " + _signalComputer.net.ID); //
                IsOn = true;

                if (FuelContainer == null || OutputContainer == null)
                    return;

                var fuelItem = FuelContainer.inventory.itemList.Find(item => item.info.shortname == _instance._config.FuelConfiguration.Shortname);
                int fuelRequired = _instance._config.FuelConfiguration.FuelRequiredPerExtraction;

                if (fuelItem == null || fuelItem.amount < fuelRequired)
                {
                    SetSignalComputerState(false);
                    CancelInvoke(nameof(PerformResourceExtraction));
                    IsOn = false;
                    return;
                }

                if (_instance.CanTransferAllResources(OutputContainer))
                {
                    _instance.HandleFuelConsumption(fuelItem, fuelRequired);
                    _instance.TransferResources(OutputContainer);
                    SetSignalComputerState(true);
                }
                else
                {
                    SetSignalComputerState(false);
                    CancelInvoke(nameof(PerformResourceExtraction));
                    IsOn = false;
                }
            }

            private void SetSignalComputerState(bool isActive)
            {
                _signalComputer.SetFlag(BaseEntity.Flags.Reserved8, isActive);
                _signalComputer.chargePower = isActive ? 1 : 0;
            }

            private void CheckGroundIntegrity()
            {
                if (_signalComputer.HasParent() && _signalComputer.GetParentEntity() is Tugboat)
                {
                    CancelInvoke(nameof(CheckGroundIntegrity));
                    return;
                }

                Vector3 origin = _signalComputer.transform.position + new Vector3(0, 0.1f, 0);
                if (!Physics.Raycast(origin, Vector3.down, out var hitInfo, 4f, LayerMask.GetMask("Terrain", "Construction")) || hitInfo.distance > 0.2f)
                {
                    HandleGroundLoss();
                }
            }

            private void HandleGroundLoss()
            {
                CancelInvoke(nameof(PerformResourceExtraction));
                CancelInvoke(nameof(CheckGroundIntegrity));
                _signalComputer.Kill();
                _instance.CreateQuarryItem()?.Drop(_signalComputer.transform.position, Vector3.zero);
                Effect.server.Run("assets/prefabs/deployable/quarry/effects/mining-quarry-deploy.prefab", _signalComputer.transform.position);
            }

            private void OnDestroy()
            {
                CancelInvoke(nameof(PerformResourceExtraction));
                CancelInvoke(nameof(CheckGroundIntegrity));
            }

            public void Unload()
            {
                _signalComputer.SetFlag(BaseEntity.Flags.Reserved8, false);
                _signalComputer.chargePower = 0f;
            }
        }
        #endregion
    }
}