item que não podem ser reciclaados estão sumindo ao entrar, corrija
using System;
using System.Collections.Generic;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Recyclerbox", "Marte6", "2.1.1")]
    [Description("Turn a large wooden box into a Recycler.")]
    public class Recyclerbox : CovalencePlugin
    {
        #region Fields

        private Configuration _config;

        [PluginReference]
        private Plugin NoEscape; // Reference to NoEscape plugin for raid block checks

        private const string UiOverlay = "RecyclerOverlay";
        private const string PrefabLargeBox = "assets/prefabs/deployable/large wood storage/box.wooden.large.prefab";
        private const string PrefabItemDrop = "assets/prefabs/misc/item drop/item_drop.prefab";

        private readonly Item.Flag ItemScrapedFlag = (Item.Flag)(1 << 78);
        private readonly Dictionary<ulong, (StorageContainer recyclerBox, BasePlayer player)> recyclerInstances = new();
        private readonly Dictionary<ulong, (DroppedItemContainer container, BasePlayer player)> droppedContainers = new();

        #endregion Fields

        #region Permissions

        private const string PermGet = "recyclerbox.get";
        private const string PermTransform = "recyclerbox.transform";
        private const string PermVirtual = "recyclerbox.virtual";

        private static readonly List<string> PermissionList = new() { PermGet, PermTransform, PermVirtual };

        #endregion Permissions

        #region Initialization

        private void OnServerInitialized()
        {
            // Register permissions and commands
            foreach (string perm in PermissionList)
                permission.RegisterPermission(perm, this);

            AddCovalenceCommand(_config.CommandsGet, nameof(CmdGetRecyclerBox));
            AddCovalenceCommand(_config.CommandsTransform, nameof(CmdTransformRecyclerBox));
            AddCovalenceCommand(_config.CommandsVirtual, nameof(CmdOpenVirtualRecyclerBox));
        }

        private void Unload()
        {
            // Cleanup on plugin unload
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, UiOverlay);
                DestroyVirtualRecycler(player);
            }

            DestroyTemporaryContainers();
        }

        #endregion Initialization

        #region Configuration

        protected class Configuration
        {
            [JsonProperty("Get Recycler Box Command")]
            public string[] CommandsGet { get; set; } = { "getrec", "getrecycler", "recyclerbox" };

            [JsonProperty("Transform Recycler Box Command")]
            public string[] CommandsTransform { get; set; } = { "trarec", "boxtorecycler", "transformrecycler", "transformbox" };

            [JsonProperty("Virtual Recycler Box Command")]
            public string[] CommandsVirtual { get; set; } = { "rec", "vrec", "virtualrecycler" };

            [JsonProperty("Recycler Skin ID")]
            public ulong RecyclerSkinId { get; set; } = 2994391115;

            [JsonProperty("Recycler Efficiency")]
            public float RecyclerEfficiency { get; set; } = 0.6f;

            [JsonProperty("Scrap Ratio")]
            public float ScrapRatio { get; set; } = 1.2f;

            [JsonProperty("Enable Prefab Effects")]
            public bool EnablePrefabEffects { get; set; } = true;

            [JsonProperty("Lock Recycler While In Use")]
            public bool LockRecycler { get; set; } = false;

            [JsonProperty("Raid Block Required (No Escape plugin dependency)")]
            public bool RequireRaidBlock { get; set; } = true;

            [JsonProperty("Prefab Effect on Open")]
            public string PrefabOnOpen { get; set; } = "assets/bundled/prefabs/fx/build/promote_toptier.prefab";

            [JsonProperty("Prefab Effect on Close")]
            public string PrefabOnClose { get; set; } = "assets/bundled/prefabs/fx/build/promote_toptier.prefab";

            [JsonProperty("Transfer Recycled Items to Inventory")]
            public bool TransferToInventory { get; set; } = false;

            [JsonProperty("Blacklisted Items")]
            public string[] BlacklistedItems { get; set; } = { "lmg.m249" };

            [JsonProperty("Blacklisted Skins")]
            public List<ulong> BlacklistedSkins { get; set; } = new() { 2994391115 };

            public string ToJson() => JsonConvert.SerializeObject(this);

            public static Dictionary<string, object> FromJson(string json) => JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
        }

        protected override void LoadDefaultConfig() => _config = new Configuration();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null)
                    throw new JsonException();

                var currentConfigDict = Configuration.FromJson(_config.ToJson());
                var defaultConfigDict = Configuration.FromJson(new Configuration().ToJson());

                if (currentConfigDict.Count != defaultConfigDict.Count)
                {
                    Puts("Configuration appears outdated; updating and saving...");
                    SaveConfig();
                }
                else
                {
                    foreach (var key in currentConfigDict.Keys)
                    {
                        if (!defaultConfigDict.ContainsKey(key))
                        {
                            Puts("Configuration appears outdated; updating and saving...");
                            SaveConfig();
                            break;
                        }
                    }
                }
            }
            catch
            {
                Puts("Configuration file is invalid; loading defaults.");
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig()
        {
            Puts("Saving changes to configuration.");
            Config.WriteObject(_config, true);
        }

        #endregion Configuration

        #region Localization

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(
                new Dictionary<string, string>
                {
                    ["RecyclerTitle"] = "RECYCLER BOX",
                    ["RecyclerSubtitle"] = "Items are instantly recycled",
                    ["RecyclerItemMissingMsg"] = "Recycler Box: You aren't holding a Large Wooden Box.",
                    ["RecyclerCreatedMsg"] = "Recycler Box: The Box has been converted into a Recycler.",
                    ["RecyclerAlreadyMsg"] = "Recycler Box: This Box is currently a Recycler.",
                    ["NotAllowed"] = "You do not have permission to use that command.",
                    ["GotRecyclerbox"] = "Recycler Box sent to inventory.",
                    ["Denied Privilege"] = "You cannot recycle within someone's building privilege",
                    ["Denied Swimming"] = "You cannot recycle while swimming",
                    ["Denied Falling"] = "You cannot recycle while falling",
                    ["Denied Mounted"] = "You cannot recycle while mounted",
                    ["Denied Wounded"] = "You cannot recycle while wounded",
                    ["Denied Ship"] = "You cannot recycle while on a ship",
                    ["Denied Elevator"] = "You cannot recycle while on an elevator",
                    ["Denied Balloon"] = "You cannot recycle while on a balloon",
                    ["Denied Safe Zone"] = "You cannot recycle while in a safe zone",
                    ["Denied Hook Denied"] = "You can't recycle right now",
                    ["RecycleDropped"] = "You left items in the recycler and dropped them on the ground!",
                },
                this
            );

            lang.RegisterMessages(
                new Dictionary<string, string>
                {
                    // Portuguese (Brazil) translations
                    ["RecyclerTitle"] = "CAIXA RECICLADORA",
                    ["RecyclerSubtitle"] = "Itens são reciclados instantaneamente",
                    ["RecyclerItemMissingMsg"] = "Recyclerbox: Você não está segurando uma Caixa Grande de Madeira.",
                    ["RecyclerCreatedMsg"] = "Recyclerbox: Você transformou a Caixa em um Reciclador.",
                    ["RecyclerAlreadyMsg"] = "Recyclerbox: Esta Caixa já é um Reciclador.",
                    ["NotAllowed"] = "Você não tem permissão para usar esse comando.",
                    ["GotRecyclerbox"] = "Recyclerbox enviada para o inventário.",
                    ["Denied Privilege"] = "Você não pode reciclar dentro do privilégio de construção de outro player",
                    ["Denied Swimming"] = "Você não pode reciclar enquanto nada",
                    ["Denied Falling"] = "Você não pode reciclar enquanto cai",
                    ["Denied Mounted"] = "Você não pode reciclar enquanto estiver montado",
                    ["Denied Wounded"] = "Você não pode reciclar enquanto estiver ferido",
                    ["Denied Ship"] = "Você não pode reciclar enquanto estiver em um navio",
                    ["Denied Elevator"] = "Você não pode reciclar enquanto estiver em um elevador",
                    ["Denied Balloon"] = "Você não pode reciclar enquanto estiver em um balão",
                    ["Denied Safe Zone"] = "Você não pode reciclar enquanto estiver em uma zona segura",
                    ["Denied Hook Denied"] = "Você não pode reciclar agora",
                    ["RecycleDropped"] = "Você deixou itens no reciclador e os deixou cair no chão!",
                },
                this,
                "pt-BR"
            );

            lang.RegisterMessages(
                new Dictionary<string, string>
                {
                    // German translations
                    ["RecyclerTitle"] = "RECYCLERBOX",
                    ["RecyclerSubtitle"] = "Gegenstände werden sofort recycelt",
                    ["RecyclerItemMissingMsg"] = "Recyclerbox: Du hast keine große Holzkiste in der Hand. (Blau hinterlegt)",
                    ["RecyclerCreatedMsg"] = "Recyclerbox: Die Kiste wurde in ein Recyclerbox umgewandelt.",
                    ["RecyclerAlreadyMsg"] = "Recyclerbox: Diese Kiste ist bereits eine Recyclerbox.",
                    ["NotAllowed"] = "Du hast keine Berechtigung, diesen Befehl zu benutzen.",
                    ["GotRecyclerbox"] = "Die Recyclerbox ist deinem Inventar gutgeschrieben worden.",
                    ["Denied Privilege"] = "Du kannst momentan nicht recyceln, du befindest dich in einem fremden Bauradius.",
                    ["Denied Swimming"] = "Du kannst momentan nicht recyceln, während Du schwimmst.",
                    ["Denied Falling"] = "Du kannst momentan nicht recyceln, während Du im freienfall bist.",
                    ["Denied Mounted"] = "Du kannst momentan nicht recyceln, während Du auf einem Fahrzeug sitzt.",
                    ["Denied Wounded"] = "Du kannst momentan nicht recyceln, während Du verletzt bist.",
                    ["Denied Ship"] = "Du kannst momentan nicht recyceln, da Du dich auf einem Schiff befindest.",
                    ["Denied Elevator"] = "Du kannst momentan nicht recyceln, da Du dich im Aufzug befindest.",
                    ["Denied Balloon"] = "Du kannst momentan nicht recyceln, da Du dich im Ballon befindest.",
                    ["Denied Safe Zone"] = "Du kannst momentan nicht recyceln, da Du dich in einer sicheren Zone befindest.",
                    ["Denied Hook Denied"] = "Du kannst momentan nicht recyceln.",
                    ["RecycleDropped"] = "Du hast Gegenstände im Recycler gelassen und auf den Boden fallen lassen!",
                },
                this,
                "de"
            );
        }

        #endregion Localization

        #region Hooks

        private void OnLootEntityEnd(BasePlayer player, StorageContainer container)
        {
            // Remove UI when looting ends
            if (container.skinID != _config.RecyclerSkinId || player == null)
                return;

            DestroyVirtualRecycler(player);
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null)
                return;

            DestroyVirtualRecycler(player);

            if (droppedContainers.Count == 0)
                return;

            var containerList = Pool.Get<List<KeyValuePair<ulong, (DroppedItemContainer, BasePlayer)>>>();
            containerList.AddRange(droppedContainers);

            foreach (var (uid, (container, target)) in containerList)
            {
                if (!IsEntityValid(container) || !IsEntityValid(target) || target.userID == player.userID)
                {
                    if (IsEntityValid(container))
                        container.Kill();

                    droppedContainers.Remove(uid);
                }
            }

            Pool.FreeUnmanaged(ref containerList);
        }

        private void OnLootEntity(BasePlayer player, StorageContainer storageContainer)
        {
            if (storageContainer.skinID != _config.RecyclerSkinId)
                return;

            var itemContainer = storageContainer.inventory;
            itemContainer.capacity = 42;

            if (_config.EnablePrefabEffects)
                Effect.server.Run(_config.PrefabOnOpen, player.GetNetworkPosition());

            if (_config.LockRecycler)
                itemContainer.entityOwner.SetFlag(BaseEntity.Flags.Locked, true);

            CreateUI(player);
        }

        private void OnItemRemovedFromContainer(ItemContainer container, Item item)
        {
            if (container?.entityOwner?.skinID == _config.RecyclerSkinId)
            {
                item.SetFlag(ItemScrapedFlag, false);
            }
        }

        private void OnItemAddedToContainer(ItemContainer container, Item item)
        {
            if (container?.entityOwner?.skinID != _config.RecyclerSkinId)
                return;

            if (item.flags.HasFlag(ItemScrapedFlag))
                return;

            BasePlayer player = BasePlayer.FindByID(container.entityOwner.OwnerID);
            if (player != null && _config.RequireRaidBlock && IsRaidBlocked(player))
                return;

            SalvageItem(container, item);
        }

        private void OnPlayerLootEnd(PlayerLoot inventory)
        {
            var player = inventory.baseEntity;
            if (player == null)
                return;

            foreach (var container in inventory.containers)
            {
                if (container?.entityOwner?.skinID == _config.RecyclerSkinId)
                {
                    CuiHelper.DestroyUi(player, UiOverlay);

                    if (!container.entityOwner.IsBusy())
                    {
                        if (_config.EnablePrefabEffects)
                            Effect.server.Run(_config.PrefabOnClose, player.GetNetworkPosition());

                        if (_config.LockRecycler)
                            container.entityOwner.SetFlag(BaseEntity.Flags.Locked, false);
                    }
                }
            }
        }

        private object CanLootEntity(BasePlayer player, DroppedItemContainer container)
        {
            if (container.IsValid() && droppedContainers.TryGetValue(container.net.ID.Value, out var tuple) && tuple.player.userID != player.userID)
                return true;

            return null;
        }

        private void OnEntityKill(DroppedItemContainer container)
        {
            if (IsEntityValid(container))
                droppedContainers.Remove(container.net.ID.Value);
        }

        private object CanAcceptItem(ItemContainer container, Item item, int targetPos)
        {
            if (container?.entityOwner?.skinID == _config.RecyclerSkinId)
            {
                if (_config.BlacklistedItems.Contains(item.info.shortname) || _config.BlacklistedSkins.Contains(item.skin))
                {
                    return ItemContainer.CanAcceptResult.CannotAcceptRightNow;
                }
            }

            return null;
        }

        #endregion Hooks

        #region Utility Methods

        private bool IsRaidBlocked(BasePlayer player)
        {
            // Check if the player is raid-blocked via the NoEscape plugin
            return NoEscape != null && NoEscape.Call<bool>("IsRaidBlocked", player);
        }

        private void SalvageItem(ItemContainer container, Item item)
        {
            bool isFromVirtual = _config.TransferToInventory && container?.entityOwner?.name == "Virtual";
            BasePlayer player = isFromVirtual ? BasePlayer.FindByID(container.entityOwner.OwnerID) : null;

            if (item.info.Blueprint == null || container == null)
            {
                TryMoveItemBack(item, container, player);
                return;
            }

            float efficiency = _config.RecyclerEfficiency;
            if (item.hasCondition)
                efficiency = Mathf.Clamp01(efficiency * item.conditionNormalized);

            int totalAmount = item.amount;

            if (item.info.Blueprint.scrapFromRecycle > 0)
            {
                ProduceScrap(item, container, player, isFromVirtual, efficiency, totalAmount);
            }

            foreach (var ingredient in item.info.Blueprint.ingredients)
            {
                if (ingredient.itemDef.shortname == "scrap")
                    continue;

                float rawAmount = totalAmount * efficiency * ingredient.amount / item.info.Blueprint.amountToCreate;
                CreateResourceItem(ingredient.itemDef, rawAmount, container, player, isFromVirtual);
            }

            item.UseItem(totalAmount);
        }

        private void ProduceScrap(Item item, ItemContainer container, BasePlayer player, bool isFromVirtual, float efficiency, int totalAmount)
        {
            float scrapRatio = _config.ScrapRatio;
            float calculatedScrap = item.info.Blueprint.scrapFromRecycle * totalAmount * scrapRatio;
            int scrapAmount = Mathf.FloorToInt(calculatedScrap);

            if (scrapAmount > 0 || UnityEngine.Random.value < calculatedScrap - scrapAmount)
            {
                Item scrapItem = ItemManager.CreateByName("scrap", scrapAmount + 1);
                if (!isFromVirtual)
                    scrapItem.SetFlag(ItemScrapedFlag, true);

                if (!TryMoveItemBack(scrapItem, container, player))
                    scrapItem.Drop(player?.GetCenter() ?? Vector3.zero, player?.GetDropVelocity() ?? Vector3.zero);
            }
        }

        private bool TryMoveItemBack(Item item, ItemContainer container, BasePlayer player)
        {
            if (container != null && item.MoveToContainer(container))
            {
                return true;
            }

            // If cannot move into the container, drop items at player's position
            item.Drop(player?.GetCenter() ?? Vector3.zero, player?.GetDropVelocity() ?? Vector3.zero);
            return false;
        }

        // Correct goods creation upon recycling
        private void CreateResourceItem(ItemDefinition itemDef, float amount, ItemContainer container, BasePlayer player, bool isFromVirtual)
        {
            int itemsToCreate = Mathf.FloorToInt(amount);
            if (amount < 1f && UnityEngine.Random.value > 0.5f)
                itemsToCreate = 1;

            for (int i = itemsToCreate; i > 0; )
            {
                int stackSize = Mathf.Min(itemDef.stackable, i);
                Item newItem = ItemManager.Create(itemDef, stackSize);
                if (!isFromVirtual)
                    newItem.SetFlag(ItemScrapedFlag, true);

                if (!TryMoveItemBack(newItem, container, player))
                    newItem.Drop(player?.GetCenter() ?? Vector3.zero, player?.GetDropVelocity() ?? Vector3.zero);

                i -= stackSize;
            }
        }

        private void ProcessScrap(Item item, ItemContainer container, BasePlayer player, bool isFromVirtual, float efficiency, int totalAmount)
        {
            float scrapRatio = _config.ScrapRatio;
            float scrapCalc = item.info.Blueprint.scrapFromRecycle * totalAmount * scrapRatio;
            int scrapAmount = (int)scrapCalc;

            try
            {
                if (scrapAmount >= 1 || UnityEngine.Random.value < scrapRatio)
                {
                    scrapAmount = Math.Max(scrapAmount, 1);
                    Item scrapItem = ItemManager.CreateByName("scrap", scrapAmount);

                    if (!isFromVirtual)
                        scrapItem.SetFlag(ItemScrapedFlag, true);

                    TryMoveItemBack(scrapItem, container, player);
                }
            }
            catch
            {
                Puts($"Error processing scrap from item {item.info.shortname}, amount {totalAmount}.", this);
            }
        }

        private void CreateUI(BasePlayer player)
        {
            var elements = new CuiElementContainer();

            var mainUIPanel = elements.Add(
                new CuiPanel
                {
                    Image = { Color = "1 0.96 0.88 0.15" },
                    RectTransform =
                    {
                        AnchorMin = "0.5 0",
                        AnchorMax = "0.5 0",
                        OffsetMin = "192.5 610",
                        OffsetMax = "572.5 633",
                    },
                    CursorEnabled = false,
                },
                "Overlay",
                UiOverlay
            );

            elements.Add(
                new CuiLabel
                {
                    Text =
                    {
                        Text = lang.GetMessage("RecyclerTitle", this, player.UserIDString),
                        Align = TextAnchor.MiddleCenter,
                        FontSize = 18,
                        Color = "1 1 1 1",
                        Font = "robotocondensed-bold.ttf",
                    },
                    RectTransform = { AnchorMin = "0 0", AnchorMax = "1 3" },
                },
                mainUIPanel
            );

            elements.Add(
                new CuiLabel
                {
                    Text =
                    {
                        Text = lang.GetMessage("RecyclerSubtitle", this, player.UserIDString),
                        Align = TextAnchor.MiddleCenter,
                        FontSize = 14,
                        Color = "1 1 1 1",
                        Font = "robotocondensed-regular.ttf",
                    },
                    RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
                },
                mainUIPanel
            );

            CuiHelper.AddUi(player, elements);
        }

        public bool IsEntityValid(BaseNetworkable entity) => entity?.IsValid() == true && !entity.IsDestroyed;

        private StorageContainer CreateVirtualRecycler(BasePlayer player)
        {
            var recyclerBox = GameManager.server.CreateEntity(PrefabLargeBox, player.transform.position.WithY(-5f), Quaternion.identity) as StorageContainer;
            recyclerBox.skinID = _config.RecyclerSkinId;

            if (recyclerBox == null)
                return null;

            recyclerBox.enableSaving = false;
            recyclerBox.Spawn();

            if (!IsEntityValid(recyclerBox))
                return null;

            recyclerBox.name = "Virtual";
            recyclerBox.OwnerID = player.userID;
            recyclerBox.SetFlag(BaseEntity.Flags.Locked, true);
            recyclerBox.UpdateNetworkGroup();
            recyclerBox.gameObject.layer = 0;
            recyclerBox.SendNetworkUpdateImmediate(true);

            OpenContainer(player, recyclerBox);

            recyclerInstances[recyclerBox.net.ID.Value] = (recyclerBox, player);

            return recyclerBox;
        }

        private void OpenContainer(BasePlayer player, StorageContainer container)
        {
            player.Invoke(
                () =>
                {
                    if (IsEntityValid(container))
                    {
                        player.EndLooting();

                        if (!player.inventory.loot.StartLootingEntity(container, false))
                            return;

                        player.inventory.loot.AddContainer(container.inventory);
                        player.inventory.loot.SendImmediate();
                        player.ClientRPC(RpcTarget.Player("RPC_OpenLootPanel", player), container.panelName);
                        player.SendNetworkUpdate();
                    }
                },
                0.2f
            );
        }

        private StorageContainer GetPlayerRecycler(ulong userId)
        {
            foreach (var (recycler, player) in recyclerInstances.Values)
                if (player?.userID == userId)
                    return recycler;

            return null;
        }

        private void DropRecyclerContents(StorageContainer recyclerBox, BasePlayer player)
        {
            if (player?.inventory?.containerMain == null)
                return;

            if (recyclerBox?.inventory?.itemList == null || recyclerBox.inventory.itemList.Count == 0)
                return;

            var itemsToDrop = Pool.Get<List<Item>>();
            itemsToDrop.AddRange(recyclerBox.inventory.itemList);

            player.ChatMessage(lang.GetMessage("RecycleDropped", this, player.UserIDString));
            Pool.FreeUnmanaged(ref itemsToDrop);

            var dropContainer = GameManager.server.CreateEntity(PrefabItemDrop, player.transform.position + Vector3.up, default) as DroppedItemContainer;

            if (dropContainer == null)
                return;

            dropContainer.enableSaving = false;
            dropContainer.lootPanelName = "generic_resizable";
            dropContainer.playerSteamID = player.userID;

            // Pass an array as expected by the TakeFrom method
            dropContainer.TakeFrom(new[] { recyclerBox.inventory });
            dropContainer.Spawn();

            if (IsEntityValid(dropContainer))
            {
                droppedContainers[dropContainer.net.ID.Value] = (dropContainer, player);
            }
        }

        private void DestroyVirtualRecycler(BasePlayer player)
        {
            var recycler = GetPlayerRecycler(player.userID);
            if (IsEntityValid(recycler) && recyclerInstances.TryGetValue(recycler.net.ID.Value, out var instance))
            {
                DropRecyclerContents(recycler, instance.player);
                recyclerInstances.Remove(recycler.net.ID.Value);
                recycler.Kill();
            }
        }

        private void DestroyTemporaryContainers()
        {
            if (droppedContainers.Count == 0)
                return;

            var containerList = Pool.Get<List<KeyValuePair<ulong, (DroppedItemContainer, BasePlayer)>>>();
            containerList.AddRange(droppedContainers);

            foreach (var (uid, (container, _)) in containerList)
            {
                if (IsEntityValid(container))
                    container.Kill();

                droppedContainers.Remove(uid);
            }

            Pool.FreeUnmanaged(ref containerList);
        }

        private void OpenVirtualRecycler(BasePlayer player)
        {
            if (!player || !CanPlayerOpenRecycler(player))
                return;

            DestroyVirtualRecycler(player);
            CreateVirtualRecycler(player);
        }

        private bool CanPlayerOpenRecycler(BasePlayer player)
        {
            string userString = player.UserIDString;

            if (!player?.IsAlive() ?? true)
                player.ChatMessage(lang.GetMessage("Denied Hook Denied", this, userString));
            else if (player.IsWounded())
                player.ChatMessage(lang.GetMessage("Denied Wounded", this, userString));
            else if (!player.CanBuild())
                player.ChatMessage(lang.GetMessage("Denied Privilege", this, userString));
            else if (player.IsSwimming())
                player.ChatMessage(lang.GetMessage("Denied Swimming", this, userString));
            else if (!player.IsOnGround() || player.IsFlying || player.isInAir)
                player.ChatMessage(lang.GetMessage("Denied Falling", this, userString));
            else if (player.isMounted || player.GetParentEntity() is BaseMountable)
                player.ChatMessage(lang.GetMessage("Denied Mounted", this, userString));
            else if (player.GetComponentInParent<CargoShip>())
                player.ChatMessage(lang.GetMessage("Denied Ship", this, userString));
            else if (player.GetComponentInParent<HotAirBalloon>())
                player.ChatMessage(lang.GetMessage("Denied Balloon", this, userString));
            else if (player.GetComponentInParent<Lift>())
                player.ChatMessage(lang.GetMessage("Denied Elevator", this, userString));
            else
                return true;

            return false;
        }

        #endregion Utility Methods

        #region Command Handlers

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

            if (!iplayer.HasPermission(PermGet))
            {
                player.ChatMessage(lang.GetMessage("NotAllowed", this, player.UserIDString));
                return;
            }

            var recyclerBox = ItemManager.CreateByName("box.wooden.large");
            recyclerBox.skin = _config.RecyclerSkinId;

            player.GiveItem(recyclerBox, BaseEntity.GiveItemReason.PickedUp);
            player.ChatMessage(lang.GetMessage("GotRecyclerbox", this, player.UserIDString));
        }

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

            if (!iplayer.HasPermission(PermTransform))
            {
                player.ChatMessage(lang.GetMessage("NotAllowed", this, player.UserIDString));
                return;
            }

            Item activeItem = player.GetActiveItem();
            if (activeItem == null || activeItem.info.shortname != "box.wooden.large")
            {
                player.ChatMessage(lang.GetMessage("RecyclerItemMissingMsg", this, player.UserIDString));
                return;
            }

            if (activeItem.skin == _config.RecyclerSkinId)
            {
                player.ChatMessage(lang.GetMessage("RecyclerAlreadyMsg", this, player.UserIDString));
                return;
            }

            player.ChatMessage(lang.GetMessage("RecyclerCreatedMsg", this, player.UserIDString));
            activeItem.skin = _config.RecyclerSkinId;
        }

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

            if (!iplayer.HasPermission(PermVirtual))
            {
                player.ChatMessage(lang.GetMessage("NotAllowed", this, player.UserIDString));
                return;
            }

            OpenVirtualRecycler(player);
        }

        #endregion Command Handlers
    }
}