Temp fix August update before pligin upate

here a temp fix for the August update:

 

using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Text;
using Rust.Ai.Gen2;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace Oxide.Plugins
{
    [Info("Zone Manager", "k1lly0u", "3.1.12")]
    [Description("An advanced management system for creating in-game zones")]
    public class ZoneManager : RustPlugin
    {
        #region Fields
        [PluginReference] Plugin Backpacks, PopupNotifications, Spawns;

        private StoredData storedData;

        private DynamicConfigFile data;


        private readonly Hash<string, Zone> zones = new Hash<string, Zone>();
        private readonly Hash<Plugin, HashSet<string>> temporaryZones = new Hash<Plugin, HashSet<string>>();

        private static readonly Hash<ulong, EntityZones> zonedPlayers = new Hash<ulong, EntityZones>();

        private static readonly Hash<NetworkableId, EntityZones> zonedEntities = new Hash<NetworkableId, EntityZones>();

        private readonly Dictionary<ulong, string> lastPlayerZone = new Dictionary<ulong, string>();


        private readonly ZoneFlags globalFlags = new ZoneFlags();

        private readonly ZoneFlags adminBypass = new ZoneFlags();


        private static readonly ZoneFlags tempFlags = new ZoneFlags();

        private static readonly StringBuilder sb = new StringBuilder();


        private bool zonesInitialized = false;


        private static ZoneManager Instance { get; set; }

        private const string PERMISSION_ZONE = "zonemanager.zone";

        private const string PERMISSION_IGNORE_FLAG = "zonemanager.ignoreflag.";

        private const int PLAYER_MASK = 131072;

        private const int TARGET_LAYERS = ~(1 << 10 | 1 << 18 | 1 << 28 | 1 << 29);
        #endregion

        #region Oxide Hooks
        private void Init()
        {
            Instance = this;

            adminBypass.SetFlags(ZoneFlags.NoBuild, ZoneFlags.NoDeploy, ZoneFlags.NoCup, ZoneFlags.NoUpgrade, ZoneFlags.NoChat, ZoneFlags.NoVoice, ZoneFlags.KillSleepers, ZoneFlags.EjectSleepers, ZoneFlags.NoSignUpdates);

            lang.RegisterMessages(Messages, this);
            
            permission.RegisterPermission(PERMISSION_ZONE, this);

            foreach (string flag in ZoneFlags.NameToIndex.Keys)
                permission.RegisterPermission(PERMISSION_IGNORE_FLAG + flag.ToLower(), this);

            LoadData();
        }

        private void OnServerInitialized() => InitializeZones();

        private void OnTerrainInitialized() => InitializeZones();

        private void OnPlayerConnected(BasePlayer player) => updateBehaviour.QueueUpdate(player);

        private void OnPluginUnloaded(Plugin plugin)
        {
            if (!temporaryZones.TryGetValue(plugin, out HashSet<string> set))
                return;

            foreach (string zoneId in set)
            {
                if (!zones.TryGetValue(zoneId, out Zone zone))
                    continue;

                if (zone.definition.Owner != plugin)
                    continue;
            
                zones.Remove(zoneId);

                UnityEngine.Object.DestroyImmediate(zone.gameObject);
                Interface.CallHook("OnZoneErased", zoneId);
            }

            temporaryZones.Remove(plugin);
        }

        private void OnEntityKill(BaseEntity baseEntity)
        {
            if (!baseEntity || !baseEntity.IsValid() || baseEntity.IsDestroyed)
                return;

            if (!zonedEntities.TryGetValue(baseEntity.net.ID, out EntityZones entityZones)) 
                return;

            for (int i = entityZones.Zones.Count - 1; i >= 0; i--)
            {
                Zone zone = entityZones.Zones[i];
                if (!zone)
                    continue;

                zone.OnEntityExitZone(baseEntity, false, true);
            }

            zonedEntities.Remove(baseEntity.net.ID);
        }

        private void Unload()
        {
            DestroyUpdateBehaviour();

            foreach (BasePlayer player in BasePlayer.activePlayerList)
                CuiHelper.DestroyUi(player, ZMUI);

            foreach (KeyValuePair<string, Zone> kvp in zones)
                UnityEngine.Object.DestroyImmediate(kvp.Value.gameObject);

            zones.Clear();
            temporaryZones.Clear();
            zonedPlayers.Clear();
            zonedEntities.Clear();
            
            Instance = null;
            Configuration = null;
        }
        #endregion

        #region UpdateQueue
        private UpdateBehaviour m_UpdateBehaviour;
        
        private UpdateBehaviour updateBehaviour
        {
            get
            {
                if (m_UpdateBehaviour) 
                    return m_UpdateBehaviour;
                
                m_UpdateBehaviour = new GameObject("ZoneManager.UpdateBehaviour").AddComponent<UpdateBehaviour>();

                foreach (BasePlayer player in BasePlayer.activePlayerList)
                    m_UpdateBehaviour.QueueUpdate(player);

                return m_UpdateBehaviour;
            }
        }

        private void DestroyUpdateBehaviour()
        {
            if (updateBehaviour)
                UnityEngine.Object.Destroy(updateBehaviour.gameObject);
        }

        // Queue and check players for new zones and that they are still in old zones. Previously any plugin that put a player to sleep and teleports them out of a zone
        // without calling the OnPlayerSleep hook would bypass a player zone update which would result in players being registered in zones they were no longer in.
        // Options are to either continually check and update players, or have every plugin that teleports players call the hook...
        private class UpdateBehaviour : MonoBehaviour
        {
            private readonly System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

            private readonly Queue<BasePlayer> playerUpdateQueue = new Queue<BasePlayer>();

            private const float MAX_MS = 0.25f;

            private void OnDestroy()
            {
                playerUpdateQueue.Clear();
            }

            public void QueueUpdate(BasePlayer player)
            {
                if (!playerUpdateQueue.Contains(player))
                    playerUpdateQueue.Enqueue(player);
            }

            public void Reset() => playerUpdateQueue.Clear();

            private void Update()
            {
                if (Time.frameCount % 10 != 0)
                    return;

                sw.Reset();
                sw.Start();

                while (playerUpdateQueue.Count > 0)
                {
                    if (sw.Elapsed.TotalMilliseconds >= MAX_MS)
                    {
                        sw.Stop();
                        return;
                    }

                    BasePlayer player = playerUpdateQueue.Dequeue();
                    if (!player || !player.IsConnected)
                        continue;

                    Instance?.UpdatePlayerZones(player);

                    InvokeHandler.Invoke(this, () => QueueUpdate(player), 2f);
                }
            }
        }
        #endregion

        #region Flag Hooks
        private void OnEntityBuilt(Planner planner, GameObject gameObject)
        {
            if (!planner || !gameObject)
                return;

            BasePlayer player = planner.GetOwnerPlayer();
            if (!player)
                return;

            BaseEntity entity = gameObject.ToBaseEntity();
            if (!entity)
                return;

            if (entity is BuildingBlock block)
            {
                if (!HasPlayerFlag(player, ZoneFlags.NoBuild)) 
                    return;
                
                List<ItemAmount> list = block.BuildCost().Items;

                block.Invoke(() =>
                {
                    for (int i = 0; i < list?.Count; i++)
                    {
                        ItemAmount itemAmount = list[i];
                        player.GiveItem(ItemManager.Create(itemAmount.itemDef, Mathf.Clamp(Mathf.RoundToInt(itemAmount.amount), 1, int.MaxValue)));
                    }

                    if (entity && !entity.IsDestroyed)
                        entity.Kill(BaseNetworkable.DestroyMode.Gib);
                }, 0.1f);

                SendMessage(player, Message("noBuild", player.UserIDString));
            }
            else if (entity is SimpleBuildingBlock)
            {
                if (!HasPlayerFlag(player, ZoneFlags.NoBuild)) 
                    return;
                
                KillEntityAndReturnItem(player, entity, planner.GetItem());
                SendMessage(player, Message("noBuild", player.UserIDString));
            }
            else
            {
                if (entity is BuildingPrivlidge)
                {
                    if (!HasPlayerFlag(player, ZoneFlags.NoCup)) 
                        return;
                    
                    KillEntityAndReturnItem(player, entity, planner.GetItem());
                    SendMessage(player, Message("noCup", player.UserIDString));
                }
                else
                {
                    if (!HasPlayerFlag(player, ZoneFlags.NoDeploy)) 
                        return;
                    
                    KillEntityAndReturnItem(player, entity, planner.GetItem());                       
                    SendMessage(player, Message("noDeploy", player.UserIDString));
                }
            }
        }

        private object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum grade)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoUpgrade))
            {
                SendMessage(player, Message("noUpgrade", player.UserIDString));
                return true;
            }
            return null;
        }

        private void OnItemDeployed(Deployer deployer, ItemModDeployable itemModDeployable, BaseEntity deployedEntity) // DoDeploy_Regular
        {
            BasePlayer player = deployer.GetOwnerPlayer();
            if (!player)
                return;

            if (HasPlayerFlag(player, ZoneFlags.NoDeploy))
            {
                KillEntityAndReturnItem(player, deployedEntity, deployer.GetItem());
                SendMessage(player, Message("noDeploy", player.UserIDString));
            }
        }
                
        private void OnItemDeployed(Deployer deployer, BaseEntity parentEntity, BaseEntity deployedEntity) // DoDeploy_Slot
        {
            BasePlayer player = deployer.GetOwnerPlayer();
            if (!player)
                return;

            if (HasPlayerFlag(player, ZoneFlags.NoDeploy))
            {
                KillEntityAndReturnItem(player, deployedEntity, deployer.GetItem());
                SendMessage(player, Message("noDeploy", player.UserIDString));
            }
        }

        private void KillEntityAndReturnItem(BasePlayer player, BaseEntity entity, Item item)
        {
            ItemDefinition itemDefinition = item?.info;
            //int amount = item.amount;
            ulong skin = item?.skin ?? 0UL;

            entity.Invoke(() =>
            {
                if (entity && !entity.IsDestroyed)
                    entity.Kill(BaseNetworkable.DestroyMode.Gib);

                if (itemDefinition)
                    player.GiveItem(ItemManager.Create(itemDefinition, 1, skin));

            }, 0.1f);
        }

        private void OnItemUse(Item item, int amount)
        {
            BaseEntity entity = item?.parent?.entityOwner;
            if (!entity)
                return;

            if (entity is FlameTurret or AutoTurret or GunTrap)
            {
                if (HasEntityFlag(entity, ZoneFlags.InfiniteTrapAmmo))
                    item.amount += amount;
                return;
            }

            if (entity is not SearchLight) 
                return;
            
            if (HasEntityFlag(entity, ZoneFlags.AlwaysLights))
            {
                item.amount += amount;
                return;
            }

            if (!HasEntityFlag(entity, ZoneFlags.AutoLights)) 
                return;
            
            if (TOD_Sky.Instance.Cycle.Hour > Configuration.AutoLights.OnTime || TOD_Sky.Instance.Cycle.Hour < Configuration.AutoLights.OffTime)
                item.amount += amount;
        }
               
        private object OnPlayerChat(BasePlayer player, string message, ConVar.Chat.ChatChannel channel)
        {
            if (!player)
                return null;

            if (!HasPlayerFlag(player, ZoneFlags.NoChat)) 
                return null;
            
            SendMessage(player, Message("noChat", player.UserIDString));
            return true;
        }

        private object OnBetterChat(Oxide.Core.Libraries.Covalence.IPlayer iPlayer, string message)
        {
            BasePlayer player = iPlayer.Object as BasePlayer;
            return OnPlayerChat(player, message, ConVar.Chat.ChatChannel.Global);
        }

        private object OnPlayerVoice(BasePlayer player, Byte[] data)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoVoice))
            {
                SendMessage(player, Message("noVoice", player.UserIDString));
                return true;
            }
            return null;
        }

        private object OnServerCommand(ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();
            if (!player || string.IsNullOrEmpty(arg.cmd?.Name))
                return null;

            if (arg.cmd.Name == "kill" && HasPlayerFlag(player, ZoneFlags.NoSuicide))
            {
                SendMessage(player, Message("noSuicide", player.UserIDString));
                return true;
            }
            return null;
        }

        private void OnPlayerDisconnected(BasePlayer player)
        {
            if (!player)
                return;

            if (HasPlayerFlag(player, ZoneFlags.KillSleepers))
            {
                player.Die();
                return;
            }

            if (HasPlayerFlag(player, ZoneFlags.EjectSleepers))
            {
                if (!zonedPlayers.TryGetValue(player.userID, out EntityZones entityZones) || entityZones.Count == 0)
                    return;

                foreach (Zone zone in entityZones.Zones)
                {
                    if (!zone)
                        continue;

                    if (HasFlag(zone, ZoneFlags.EjectSleepers))
                    {
                        EjectPlayer(player, zone);
                        return;
                    }
                }
            }
        }
        
        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo)
        {
            if (!entity || GetEntityComponent<ResourceDispenser>(entity))
                return null;

            BasePlayer attacker = hitinfo.InitiatorPlayer;
            BasePlayer victim = entity as BasePlayer;

            if (victim)
            {                
                if (hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Fall)
                {
                    if (HasPlayerFlag(victim, ZoneFlags.NoFallDamage))
                        return true;
                }

                if (victim.IsSleeping() && HasPlayerFlag(victim, ZoneFlags.SleepGod))
                    return true;

                if (attacker)
                {
                    if (IsNpc(victim))
                        return null;

                    if (HasPlayerFlag(victim, ZoneFlags.PvpGod))
                    {
                        if (attacker == victim && hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Suicide)
                        {
                            if (HasPlayerFlag(victim, ZoneFlags.NoSuicide))
                                return true;
                            return null;
                        }
                        if (IsNpc(attacker) && Configuration.NPCHurtPvpGod)
                            return null;

                        return true;
                    }
                    
                    if (HasPlayerFlag(attacker, ZoneFlags.PvpGod) && !IsNpc(attacker))                    
                        return true;                    
                }
                
                else if (HasPlayerFlag(victim, ZoneFlags.PveGod) && !IsNpc(victim))
                    return true;
                
                else if (hitinfo.Initiator is FireBall && HasPlayerFlag(victim, ZoneFlags.PvpGod))
                    return true;
                
                return null;
            }

            BaseNpc baseNpc = entity as BaseNpc;
            if (baseNpc)
            {
                if (HasEntityFlag(baseNpc, ZoneFlags.NoPve))
                {
                    if (attacker && CanBypass(attacker, ZoneFlags.NoPve))
                        return null;
                    return true;
                }
                return null;
            }

            if (entity is BuildingBlock or SimpleBuildingBlock)
            {
                if (HasEntityFlag(entity, ZoneFlags.NoBuildingDamage))
                {
                    if (attacker)
                    {
                        if (CanBypass(attacker, ZoneFlags.NoBuildingDamage))
                            return null;

                        if (HasPlayerFlag(attacker, ZoneFlags.NoBuildingDamage))
                            return true;
                    }
                    
                    if (hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Decay && Configuration.DecayDamageUndestr)
                        return null;
                    
                    return true;
                }
            }

            if (entity is not LootContainer && entity is not PatrolHelicopter)
            {
                if (HasEntityFlag(entity, ZoneFlags.UnDestr))
                {
                    if (attacker)
                    {
                        if (CanBypass(attacker, ZoneFlags.UnDestr))
                            return null;

                        if (HasPlayerFlag(attacker, ZoneFlags.UnDestr))
                            return true;
                    }

                    if (hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Decay && Configuration.DecayDamageUndestr)
                        return null;

                    return true;
                }
            }

            return null;
        }

        private void OnEntitySpawned(BaseEntity baseEntity)
            => NextTick(() => CanSpawn(baseEntity));

        private void CanSpawn(BaseEntity baseEntity)
        {
            if (!baseEntity.IsValid() || baseEntity.IsDestroyed)
                return;

            if (Interface.CallHook("CanSpawnInZone", baseEntity) != null)
                return;

            if (baseEntity is BaseCorpse corpse)
            {
                if (HasEntityFlag(corpse, ZoneFlags.NoCorpse) && !CanBypass(corpse.OwnerID, ZoneFlags.NoCorpse))
                    corpse.Invoke(() => baseEntity.Kill(BaseNetworkable.DestroyMode.None), 0.1f);
            }
            if (baseEntity is LootContainer or JunkPile)
            {
                if (HasEntityFlag(baseEntity, ZoneFlags.NoLootSpawns))
                    baseEntity.Invoke(() => baseEntity.Kill(BaseNetworkable.DestroyMode.None), 0.1f);
            }
            else if (baseEntity is BaseNpc or BaseNPC2 or NPCPlayer)
            {
                if (HasEntityFlag(baseEntity, ZoneFlags.NoNPCSpawns))
                    baseEntity.Invoke(() => baseEntity.Kill(BaseNetworkable.DestroyMode.None), 0.1f);
            }
            else if (baseEntity is DroppedItem or WorldItem)
            {
                if (HasEntityFlag(baseEntity, ZoneFlags.NoDrop))
                {
                    ((WorldItem)baseEntity).item.Remove(0f);
                    baseEntity.Invoke(() => baseEntity.Kill(BaseNetworkable.DestroyMode.None), 0.1f);
                }
            }
            else if (baseEntity is DroppedItemContainer)
            {
                if (HasEntityFlag(baseEntity, ZoneFlags.NoDrop))
                    baseEntity.Invoke(() => baseEntity.Kill(BaseNetworkable.DestroyMode.None), 0.1f);
            }
        }

        private object CanBeWounded(BasePlayer player, HitInfo hitinfo) => HasPlayerFlag(player, ZoneFlags.NoWounded) ? (object)false : null;

        private object CanUpdateSign(BasePlayer player, Signage sign)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoSignUpdates))
            {
                SendMessage(player, Message("noSignUpdates", player.UserIDString));
                return false;
            }
            return null;
        }

        private object OnOvenToggle(BaseOven oven, BasePlayer player)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoOvenToggle))
            {
                SendMessage(player, Message("noOvenToggle", player.UserIDString));
                return true;
            }
            return null;
        }

        private object CanUseVending(BasePlayer player, VendingMachine machine)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoVending))
            {
                SendMessage(player, Message("noVending", player.UserIDString));
                return false;
            }
            return null;
        }

        private object CanHideStash(BasePlayer player, StashContainer stash)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoStash))
            {
                SendMessage(player, Message("noStash", player.UserIDString));
                return false;
            }
            return null;
        }

        private object CanCraft(ItemCrafter itemCrafter, ItemBlueprint bp, int amount)
        {
            BasePlayer player = itemCrafter.GetComponent<BasePlayer>();
            if (player && HasPlayerFlag(player, ZoneFlags.NoCraft))
            {
                SendMessage(player, Message("noCraft", player.UserIDString));
                return false;
            }
            return null;
        }

        private void OnDoorOpened(Door door, BasePlayer player)
        {
            if (HasPlayerFlag(player, ZoneFlags.NoDoorAccess))
            {
                SendMessage(player, Message("noDoor", player.UserIDString));
                door.CloseRequest();
            }
        }

        private object OnSprayCreate(SprayCan sprayCan, Vector3 position, Quaternion rotation)
        {
            if (!sprayCan)
                return null;

            BasePlayer player = sprayCan.GetOwnerPlayer();
            if (!player)
                return null;

            if (HasPlayerFlag(player, ZoneFlags.NoSprays))
            {
                SendMessage(player, Message("nosprays", player.UserIDString));
                return false;
            }

            return null;
        }

        #region Looting Hooks
        private object CanLootPlayer(BasePlayer target, BasePlayer looter) => OnLootPlayerInternal(looter, target);

        private void OnLootPlayer(BasePlayer looter, BasePlayer target) => OnLootPlayerInternal(looter, target);

        private object OnLootPlayerInternal(BasePlayer looter, BasePlayer target)
        {
            if (HasPlayerFlag(looter, ZoneFlags.NoPlayerLoot) || (target != null && HasPlayerFlag(target, ZoneFlags.NoPlayerLoot)))
            {
                if (looter == target && Backpacks != null)
                {
                    object hookResult = Backpacks.Call("CanLootPlayer", target, looter);
                    if (hookResult is bool result && result)
                        return true;
                }

                SendMessage(looter, Message("noLoot", looter.UserIDString));
                NextTick(looter.EndLooting);
                return false;
            }
            return null;
        }

        private void OnLootEntity(BasePlayer player, BaseEntity entity)
        {
            if (entity is LootableCorpse corpse)
                OnLootCorpse(corpse, player);
            if (entity is DroppedItemContainer container)
                OnLootContainer(container, player);
            if (entity is StorageContainer)
                OnLootInternal(player, ZoneFlags.NoBoxLoot);
        }

        private object CanLootEntity(BasePlayer player, LootableCorpse corpse)
        {
            if (corpse is NPCPlayerCorpse)
            {
                if (!HasPlayerFlag(player, ZoneFlags.NoNPCLoot)) 
                    return null;
                
                SendMessage(player, Message("noLoot", player.UserIDString));
                return false;
            }

            if (corpse.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf))
                return null;
            
            return CanLootInternal(player, ZoneFlags.NoPlayerLoot);
        }

        private void OnLootCorpse(LootableCorpse corpse, BasePlayer player)
        {
            if (corpse is NPCPlayerCorpse)
            {
                if (!HasPlayerFlag(player, ZoneFlags.NoNPCLoot)) 
                    return;
                
                SendMessage(player, Message("noLoot", player.UserIDString));
                NextTick(player.EndLooting);
                return;
            }

            if (corpse.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf))
                return;

            OnLootInternal(player, ZoneFlags.NoPlayerLoot);
        }

        private void OnLootContainer(DroppedItemContainer container, BasePlayer player)
        {
            if (container.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf))
                return;

            OnLootInternal(player, ZoneFlags.NoPlayerLoot);
        }

        private object CanLootEntity(BasePlayer player, DroppedItemContainer container)
        {
            if (container.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf))
                return null;

            return CanLootInternal(player, ZoneFlags.NoPlayerLoot);
        }

        private object CanLootEntity(BasePlayer player, StorageContainer container) => CanLootInternal(player, ZoneFlags.NoBoxLoot);

        private object CanLootInternal(BasePlayer player, int flag)
        {
            if (!player || !HasPlayerFlag(player, flag)) 
                return null;
            
            SendMessage(player, Message("noLoot", player.UserIDString));
            return false;
        }

        private void OnLootInternal(BasePlayer player, int flag)
        {
            if (!player || !HasPlayerFlag(player, flag)) 
                return;
            
            SendMessage(player, Message("noLoot", player.UserIDString));
            NextTick(player.EndLooting);
        }
        #endregion

        #region Pickup Hooks
        private object CanPickupEntity(BasePlayer player, BaseCombatEntity entity) => CanPickupInternal(player, ZoneFlags.NoEntityPickup);

        private object CanPickupLock(BasePlayer player, BaseLock baseLock) => CanPickupInternal(player, ZoneFlags.NoEntityPickup);

        private object OnItemPickup(Item item, BasePlayer player) => CanPickupInternal(player, ZoneFlags.NoPickup);

        private object CanPickupInternal(BasePlayer player, int flag)
        {
            if (!HasPlayerFlag(player, flag)) 
                return null;
            
            SendMessage(player, Message("noPickup", player.UserIDString));
            return false;
        }
        #endregion

        #region Gather Hooks        
        private object CanLootEntity(ResourceContainer container, BasePlayer player) => OnGatherInternal(player);

        private object OnCollectiblePickup(Item item, BasePlayer player) => OnGatherInternal(player);

        private object OnGrowableGather(GrowableEntity plant, Item item, BasePlayer player) => OnGatherInternal(player);

        private object OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item) => OnGatherInternal(player);

        private object OnGatherInternal(BasePlayer player)
        {
            if (!player || !HasPlayerFlag(player, ZoneFlags.NoGather)) 
                return null;
            
            SendMessage(player, Message("noGather", player.UserIDString));
            return true;

        }
        #endregion

        #region Targeting Hooks
        private object OnTurretTarget(AutoTurret turret, BasePlayer player) => OnTargetPlayerInternal(player, ZoneFlags.NoTurretTargeting);

        private object CanBradleyApcTarget(BradleyAPC apc, BasePlayer player)
        {
            if (player && HasPlayerFlag(player, ZoneFlags.NoAPCTargeting))
                return false;
            return null;
        }

        private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player)
        {
            if (!player || !HasPlayerFlag(player, ZoneFlags.NoHeliTargeting)) 
                return null;
            
            heli.interestZoneOrigin = heli.GetRandomPatrolDestination();
            return false;
        }

        private object CanHelicopterStrafeTarget(PatrolHelicopterAI heli, BasePlayer player)
        {
            if (player && HasPlayerFlag(player, ZoneFlags.NoHeliTargeting))
                return false;
            return null;
        }

        private object OnHelicopterTarget(HelicopterTurret turret, BasePlayer player) => OnTargetPlayerInternal(player, ZoneFlags.NoHeliTargeting);

        private object OnNpcTarget(BaseCombatEntity entity, BasePlayer player) => OnTargetPlayerInternal(player, ZoneFlags.NoNPCTargeting);

        private object OnTargetPlayerInternal(BasePlayer player, int flag)
        {
            if (player && HasPlayerFlag(player, flag))
                return true;
            return null;
        }
        #endregion

        #region Mounting Hooks
        private object CanMountEntity(BasePlayer player, BaseMountable entity)
        {
            if (!player || !entity)
                return null;

            if (!entity.VehicleParent())
                return null;

            if (!HasPlayerFlag(player, ZoneFlags.NoVehicleMounting)) 
                return null;
            
            SendMessage(player, Message("novehiclemounting", player.UserIDString));
            return false;
        }

        private object CanDismountEntity(BasePlayer player, BaseMountable entity)
        {
            if (!player || !entity)
                return null;

            if (!entity.VehicleParent())
                return null;

            if (!HasPlayerFlag(player, ZoneFlags.NoVehicleDismounting)) 
                return null;
            
            SendMessage(player, Message("novehicledismounting", player.UserIDString));
            return false;

        }
        #endregion

        #region Additional KillSleeper Checks
        private void OnPlayerSleep(BasePlayer player)
        {
            if (!player || player.IsNpc || !player.userID.IsSteamId())
                return;

            //player.Invoke(()=> UpdatePlayerZones(player), 1f); // Manually update the zones a player is in. Sleeping players don't trigger OnTriggerEnter or OnTriggerExit            

            timer.In(2f, () =>
            {
                if (!player || !player.IsSleeping())
                    return;

                if (player.IsConnected) 
                    return;
                
                if (HasPlayerFlag(player, ZoneFlags.KillSleepers))
                {
                    player.Invoke(() => KillSleepingPlayer(player), 3f);
                    return;
                }

                if (HasPlayerFlag(player, ZoneFlags.EjectSleepers))
                {
                    player.Invoke(() =>
                    {
                        if (!player || !player.IsSleeping())
                            return;

                        if (!zonedPlayers.TryGetValue(player.userID, out EntityZones entityZones) || entityZones.Count == 0)
                            return;

                        foreach (Zone zone in entityZones.Zones)
                        {
                            if (!zone)
                                continue;

                            if (HasFlag(zone, ZoneFlags.EjectSleepers))
                                EjectPlayer(player, zone);
                        }
                    }, 3f);
                }
            });
        }

        private void OnPlayerSleepEnd(BasePlayer player) => updateBehaviour.QueueUpdate(player);

        private void KillSleepingPlayer(BasePlayer player)
        {
            if (!player || !player.IsSleeping())
                return;

            if (!HasPlayerFlag(player, ZoneFlags.KillSleepers)) 
                return;
            
            if (player.IsConnected)
                OnPlayerSleep(player);
            else player.Die();
        }

        private void UpdatePlayerZones(BasePlayer player)
        {
            if (!player)
                return;

            if (zonedPlayers.TryGetValue(player.userID, out EntityZones entityZones))
            {
                List<Zone> list = Pool.Get<List<Zone>>();
                list.AddRange(entityZones.Zones);
                
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    Zone zone = list[i];
                    if (!zone || !zone.definition.Enabled)
                        continue;

                    if (zone.definition.Size != Vector3.zero)
                    {
                        if (!IsInsideBounds(zone, player.transform.position))
                            OnPlayerExitZone(player, zone);
                    }
                    else
                    {
                        if (Vector3.Distance(player.transform.position, zone.transform.position) > zone.definition.Radius)
                            OnPlayerExitZone(player, zone);
                    }
                }
                
                Pool.FreeUnmanaged(ref list);
            }

            foreach (Zone zone in zones.Values)
            {
                if (!zone)
                    continue;

                if (entityZones != null && entityZones.Zones.Contains(zone))
                    continue;

                if (zone.definition.Size != Vector3.zero)
                {
                    if (IsInsideBounds(zone, player.transform.position))
                        OnPlayerEnterZone(player, zone);
                }
                else
                {
                    if (Vector3.Distance(player.transform.position, zone.transform.position) <= zone.definition.Radius)
                        OnPlayerEnterZone(player, zone);
                }
            }

            if (player.HasPlayerFlag(BasePlayer.PlayerFlags.SafeZone) && !player.InSafeZone())
                player.SetPlayerFlag(BasePlayer.PlayerFlags.SafeZone, false);
        }

        private bool IsInsideBounds(Zone zone, Vector3 worldPos) => zone?.collider?.ClosestPoint(worldPos) == worldPos;
        #endregion
        
        private T GetEntityComponent<T>(BaseEntity entity) where T : EntityComponentBase
        {
            for (int i = 0; i < entity.Components.Count; i++)
            {
                EntityComponentBase component = entity.Components[i];
                if (component is T t)
                    return t;
            }

            return null;
        }
        #endregion

        #region Zone Functions
        private void InitializeZones()
        {
            if (zonesInitialized)
                return;

            foreach (Zone.Definition definition in storedData.definitions)
            {
                Zone zone = new GameObject().AddComponent<Zone>();
                zone.InitializeZone(definition);

                zones.Add(definition.Id, zone);
            }

            foreach (Zone zone in zones.Values)
                zone.FindZoneParent();

            zonesInitialized = true;

            UnsubscribeAll();
            UpdateHookSubscriptions();
        }

        private static bool ReverseVelocity(BaseVehicle baseVehicle)
        {
            if (baseVehicle is BaseVehicleModule module)
                baseVehicle = module.Vehicle;

            if (!baseVehicle || !baseVehicle.IsVehicleRoot() || !baseVehicle.rigidBody) 
                return false;
            
            if (baseVehicle.AnyMounted() && baseVehicle is BaseHelicopter)
            {
                baseVehicle.rigidBody.velocity *= -1f;
                Vector3 euler = baseVehicle.transform.eulerAngles;
                baseVehicle.transform.rotation = Quaternion.Euler(euler.x, euler.y - 180f, euler.z);
            }
            else
            {
                Vector3 force = (baseVehicle.rigidBody.velocity.normalized * -1f) * baseVehicle.rigidBody.mass * 4f;
                baseVehicle.rigidBody.velocity = Vector3.zero;
                baseVehicle.rigidBody.AddForce(force, ForceMode.Impulse);
            }

            return true;
        }

        private void EjectPlayer(BasePlayer player, Zone zone)
        {
            if (zone.keepInList.Contains(player.userID.Get()) || zone.whitelist.Contains(player.userID.Get()))
                return;

            if (!string.IsNullOrEmpty(zone.definition.Permission))
            {
                if (HasPermission(player, zone.definition.Permission))
                    return;
            }

            if (player.isMounted && ReverseVelocity(player.GetMountedVehicle()))
            {
                SendMessage(player, Message("eject", player.UserIDString));
                return;
            }

            Vector3 position = Vector3.zero;
            if (Spawns && !string.IsNullOrEmpty(zone.definition.EjectSpawns))
            {
                object success = Spawns.Call("GetRandomSpawn", zone.definition.EjectSpawns);
                if (success is Vector3 vector3)
                    position = vector3;
            }

            if (position == Vector3.zero)
            {
                float distance = zone.definition.Size != Vector3.zero ? Mathf.Max(zone.definition.Size.x, zone.definition.Size.z) : zone.definition.Radius;

                position = zone.transform.position + (((player.transform.position.XZ3D() - zone.transform.position.XZ3D()).normalized) * (distance + 10f));

                if (Physics.Raycast(new Ray(new Vector3(position.x, position.y + 300, position.z), Vector3.down), out RaycastHit rayHit, 500, TARGET_LAYERS, QueryTriggerInteraction.Ignore))
                    position.y = rayHit.point.y;
                else position.y = TerrainMeta.HeightMap.GetHeight(position);
            }

            player.MovePosition(position);
            //player.ClientRPCPlayer(null, player, "ForcePositionTo", player.transform.position);
            player.ClientRPC(RpcTarget.Player("ForcePositionTo", player), player.transform.position);
            player.SendNetworkUpdateImmediate();

            SendMessage(player, Message("eject", player.UserIDString));
        }

        private void AttractPlayer(BasePlayer player, Zone zone)
        {
            if (player.isMounted && ReverseVelocity(player.GetMountedVehicle()))
            {
                SendMessage(player, Message("attract", player.UserIDString));
                return;
            }

            float distance = zone.definition.Size != Vector3.zero ? Mathf.Max(zone.definition.Size.x, zone.definition.Size.z) : zone.definition.Radius;

            Vector3 position = zone.transform.position + (player.transform.position - zone.transform.position).normalized * (distance - 5f);
            position.y = TerrainMeta.HeightMap.GetHeight(position);

            player.MovePosition(position);
            //player.ClientRPCPlayer(null, player, "ForcePositionTo", player.transform.position);
            player.ClientRPC(RpcTarget.Player("ForcePositionTo", player), player.transform.position);
            player.SendNetworkUpdateImmediate();

            SendMessage(player, Message("attract", player.UserIDString));
        }

        private void ShowZone(BasePlayer player, string zoneId, float time = 30)
        {
            Zone zone = GetZoneByID(zoneId);
            if (!zone)
                return;

            if (zone.definition.Size != Vector3.zero)
            {
                Vector3 center = zone.definition.Location;
                Quaternion rotation = Quaternion.Euler(zone.definition.Rotation);
                Vector3 size = zone.definition.Size / 2;
                Vector3 point1 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z + size.z), center, rotation);
                Vector3 point2 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z + size.z), center, rotation);
                Vector3 point3 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z - size.z), center, rotation);
                Vector3 point4 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z - size.z), center, rotation);
                Vector3 point5 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z + size.z), center, rotation);
                Vector3 point6 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z + size.z), center, rotation);
                Vector3 point7 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z - size.z), center, rotation);
                Vector3 point8 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z - size.z), center, rotation);

                player.SendConsoleCommand("ddraw.line", time, Color.blue, point1, point2);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point1, point3);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point1, point5);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point4, point2);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point4, point3);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point4, point8);

                player.SendConsoleCommand("ddraw.line", time, Color.blue, point5, point6);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point5, point7);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point6, point2);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point8, point6);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point8, point7);
                player.SendConsoleCommand("ddraw.line", time, Color.blue, point7, point3);
            }
            else player.SendConsoleCommand("ddraw.sphere", time, Color.blue, zone.definition.Location, zone.definition.Radius);
        }

        private Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Quaternion rotation) => rotation * (point - pivot) + pivot;

        #endregion

        #region Component
        public class Zone : MonoBehaviour
        {
            public Definition definition;

            public ZoneFlags disabledFlags = new ZoneFlags();

            public Zone parent;


            public List<BasePlayer> players = Pool.Get<List<BasePlayer>>();

            public List<BaseEntity> entities = Pool.Get<List<BaseEntity>>();

            private List<IOEntity> ioEntities = Pool.Get<List<IOEntity>>();


            public List<ulong> keepInList = Pool.Get<List<ulong>>();

            public List<ulong> whitelist = Pool.Get<List<ulong>>();

            public Hash<ulong, EntityZones> entityZones = new Hash<ulong, EntityZones>();


            private Rigidbody rigidbody;

            public Collider collider;

            public Bounds colliderBounds;


            private ChildSphereTrigger<TriggerRadiation> radiation;

            private ChildSphereTrigger<TriggerComfort> comfort;

            private ChildSphereTrigger<TriggerTemperature> temperature;

            private ChildSphereTrigger<TriggerSafeZone> safeZone;


            private readonly Hash<BaseVehicle, float> lastReversedTimes = new Hash<BaseVehicle, float>();

            private int creationFrame;

            private bool isTogglingLights = false;

            private void Awake()
            {
                gameObject.layer = (int)Layer.Reserved1;
                gameObject.name = "ZoneManager";
                enabled = false;

                creationFrame = Time.frameCount;
            }

            private void OnDestroy()
            {
                EmptyZone();

                Pool.FreeUnmanaged(ref players);
                Pool.FreeUnmanaged(ref entities);
                Pool.FreeUnmanaged(ref ioEntities);
                Pool.FreeUnmanaged(ref keepInList);
                Pool.FreeUnmanaged(ref whitelist);

                Interface.CallHook("OnZoneDestroyed", definition.Id);
            }

            private void EmptyZone()
            {
                RemovePlayersFromTriggers();

                keepInList.Clear();

                ioEntities.Clear();

                for (int i = players.Count - 1; i >= 0; i--)
                    Instance?.OnPlayerExitZone(players[i], this);

                for (int i = entities.Count - 1; i >= 0; i--)
                    Instance?.OnEntityExitZone(entities[i], this);
            }

            #region Zone Initialization
            public void InitializeZone(Definition definition)
            {
                if (this.definition == null)
                    Interface.CallHook("OnZoneInitialize", definition.Id);
                
                this.definition = definition;

                transform.position = definition.Location;

                transform.rotation = Quaternion.Euler(definition.Rotation);

                if (definition.Enabled)
                {
                    RegisterPermission();

                    InitializeCollider();

                    InitializeAutoLights();

                    InitializeRadiation();

                    InitializeSafeZone();

                    InitializeComfort();

                    InitializeTemperature();

                    RemovePlayersFromTriggers();

                    AddPlayersToTriggers();

                    OnZoneFlagsChanged();
                }
                else
                {
                    InvokeHandler.CancelInvoke(this, CheckAlwaysLights);
                    InvokeHandler.CancelInvoke(this, CheckLights);

                    if (isLightsOn)
                        ServerMgr.Instance.StartCoroutine(ToggleLights(false));

                    EmptyZone();

                    if (collider)
                        DestroyImmediate(collider);

                    if (rigidbody)
                        DestroyImmediate(rigidbody);
                }

                enabled = definition.Enabled;
            }

            public void FindZoneParent()
            {
                if (string.IsNullOrEmpty(definition.ParentID))
                    return;

                if (Instance == null)
                {
                    Debug.LogError($"[ZoneManager] Zone attempted to find parent zone, but plugin instance is null...");
                    return;
                }

                Instance.zones.TryGetValue(definition.ParentID, out parent);
            }

            public void Reset()
            {
                InvokeHandler.CancelInvoke(this, CheckAlwaysLights);
                InvokeHandler.CancelInvoke(this, CheckLights);

                if (isLightsOn)
                    ServerMgr.Instance.StartCoroutine(ToggleLights(false));

                EmptyZone();

                InitializeZone(definition);
                FindZoneParent();
            }

            public void OnZoneFlagsChanged()
            {
                if (HasFlag(ZoneFlags.PoweredSwitches))
                {
                    if (!InvokeHandler.IsInvoking(this, IOTick))
                        InvokeHandler.InvokeRandomized(this, IOTick, 0f, 1f, 0.1f);
                }
                else InvokeHandler.CancelInvoke(this, IOTick);
            }

            private void RegisterPermission()
            {
                if (Instance == null)
                {
                    Debug.LogError($"[ZoneManager] Zone attempted to register permission, but plugin instance is null...");
                    return;
                }

                if (!string.IsNullOrEmpty(definition.Permission) && !Instance.permission.PermissionExists(definition.Permission))
                    Instance.permission.RegisterPermission(definition.Permission, Instance);
            }

            private void InitializeCollider()
            {
                if (collider)
                    DestroyImmediate(collider);

                if (rigidbody)
                    DestroyImmediate(rigidbody);

                rigidbody = gameObject.AddComponent<Rigidbody>();
                rigidbody.useGravity = false;
                rigidbody.isKinematic = true;
                rigidbody.detectCollisions = true;
                rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;

                SphereCollider sphereCollider = gameObject.GetComponent<SphereCollider>();
                BoxCollider boxCollider = gameObject.GetComponent<BoxCollider>();

                if (definition.Size != Vector3.zero)
                {
                    if (sphereCollider)
                        Destroy(sphereCollider);

                    if (!boxCollider)
                    {
                        boxCollider = gameObject.AddComponent<BoxCollider>();
                        boxCollider.isTrigger = true;
                    }
                    boxCollider.size = definition.Size;
                    colliderBounds = boxCollider.bounds;
                    collider = boxCollider;
                }
                else
                {
                    if (boxCollider)
                        Destroy(boxCollider);

                    if (!sphereCollider)
                    {
                        sphereCollider = gameObject.AddComponent<SphereCollider>();
                        sphereCollider.isTrigger = true;
                    }
                    sphereCollider.radius = definition.Radius;
                    colliderBounds = sphereCollider.bounds;
                    collider = sphereCollider;
                }
            }
            #endregion

            #region Triggers
            private void InitializeRadiation()
            {                
                if (definition.Radiation > 0)
                {
                    radiation ??= new ChildSphereTrigger<TriggerRadiation>(gameObject, "Radiation");
                    radiation.Trigger.RadiationAmountOverride = definition.Radiation;
                    radiation.Collider.radius = collider is SphereCollider ? definition.Radius : Mathf.Min(definition.Size.x, definition.Size.y, definition.Size.z) * 0.5f;
                    radiation.Trigger.enabled = this.enabled;
                }
                else radiation?.Destroy();
            }

            private void InitializeComfort()
            {
                if (definition.Comfort > 0)
                {
                    comfort ??= new ChildSphereTrigger<TriggerComfort>(gameObject, "Comfort");
                    comfort.Trigger.baseComfort = definition.Comfort;
                    comfort.Trigger.triggerSize = comfort.Collider.radius = collider is SphereCollider ? definition.Radius : Mathf.Min(definition.Size.x, definition.Size.y, definition.Size.z) * 0.5f;
                    comfort.Trigger.enabled = this.enabled;
                }
                else comfort?.Destroy();
            }

            private void InitializeTemperature()
            {
                if (definition.Temperature != 0)
                {
                    temperature ??= new ChildSphereTrigger<TriggerTemperature>(gameObject, "Temperature");
                    temperature.Trigger.Temperature = definition.Temperature;
                    temperature.Trigger.triggerSize = temperature.Collider.radius = collider is SphereCollider ? definition.Radius : Mathf.Min(definition.Size.x, definition.Size.y, definition.Size.z) * 0.5f;
                    temperature.Trigger.enabled = this.enabled;
                }
                else temperature?.Destroy();
            }

            private void InitializeSafeZone()
            {
                if (definition.SafeZone)
                {
                    safeZone ??= new ChildSphereTrigger<TriggerSafeZone>(gameObject, "SafeZone");
                }
                else safeZone?.Destroy();
            }
                        
            private void AddToTrigger(TriggerBase triggerBase, BasePlayer player)
            {
                if (!triggerBase || !player)
                    return;

                triggerBase.entityContents ??= new HashSet<BaseEntity>();

                if (!triggerBase.entityContents.Add(player)) 
                    return;
                
                player.EnterTrigger(triggerBase);

                if (triggerBase is not TriggerSafeZone) 
                    return;
                
                if (player.IsItemHoldRestricted(player.inventory.containerBelt.FindItemByUID(player.svActiveItemID)))
                    player.UpdateActiveItem(default(ItemId));

                player.SetPlayerFlag(BasePlayer.PlayerFlags.SafeZone, true);
            }

            private void RemoveFromTrigger(TriggerBase triggerBase, BasePlayer player)
            {
                if (!triggerBase || !player)
                    return;

                if (triggerBase.entityContents == null || !triggerBase.entityContents.Contains(player)) 
                    return;
                
                triggerBase.entityContents.Remove(player);
                player.LeaveTrigger(triggerBase);

                if (triggerBase is not TriggerSafeZone) 
                    return;
                
                if (!player.InSafeZone())
                    player.SetPlayerFlag(BasePlayer.PlayerFlags.SafeZone, false);
            }

            private void AddPlayersToTriggers()
            {
                for (int i = 0; i < players.Count; i++)
                {
                    BasePlayer player = players[i];

                    if (safeZone != null)
                        AddToTrigger(safeZone.Trigger, player);

                    if (radiation != null)
                        AddToTrigger(radiation.Trigger, player);

                    if (comfort != null)
                        AddToTrigger(comfort.Trigger, player);

                    if (temperature != null)
                        AddToTrigger(temperature.Trigger, player);
                }
            }

            private void RemovePlayersFromTriggers()
            {
                for (int i = 0; i < players.Count; i++)                    
                {
                    BasePlayer player = players[i];

                    if (safeZone != null)
                        RemoveFromTrigger(safeZone.Trigger, player);

                    if (radiation != null)
                        RemoveFromTrigger(radiation.Trigger, player);

                    if (comfort != null)
                        RemoveFromTrigger(comfort.Trigger, player);

                    if (temperature != null)
                        RemoveFromTrigger(temperature.Trigger, player);
                }
            }

            private class ChildSphereTrigger<T> where T : TriggerBase
            {
                public GameObject Object { get; private set; }

                public SphereCollider Collider { get; private set; }

                public T Trigger { get; private set; }

                public ChildSphereTrigger(GameObject parent, string name)
                {
                    Object = parent.CreateChild();
                    Object.name = name;
                    Object.layer = (int)Layer.TransparentFX;

                    Collider = Object.AddComponent<SphereCollider>();
                    Collider.isTrigger = true;

                    Trigger = Object.AddComponent<T>();
                    Trigger.interestLayers = 0;
                }

                public void Destroy() => UnityEngine.Object.Destroy(Object);
            }
            #endregion

            #region Autolights
            private bool isLightsOn = false;

            private void InitializeAutoLights()
            {
                if (HasFlag(ZoneFlags.AlwaysLights))
                {
                    isLightsOn = true;

                    InvokeHandler.CancelInvoke(this, CheckAlwaysLights);
                    InvokeHandler.InvokeRandomized(this, CheckAlwaysLights, 5f, 60f, 10f);
                }
                else if (HasFlag(ZoneFlags.AutoLights))
                {
                    InvokeHandler.CancelInvoke(this, CheckLights);
                    InvokeHandler.InvokeRandomized(this, CheckLights, 5f, 20f, 10f);
                }
            }

            private void CheckAlwaysLights()
            {
                ServerMgr.Instance.StartCoroutine(ToggleLights(true));
            }

            private void CheckLights()
            {
                float currentTime = TOD_Sky.Instance.Cycle.Hour;

                bool shouldBeActive = currentTime > Configuration.AutoLights.OnTime || currentTime < Configuration.AutoLights.OffTime;

                if (shouldBeActive == isLightsOn) 
                    return;
                
                isLightsOn = shouldBeActive;
                ServerMgr.Instance.StartCoroutine(ToggleLights(isLightsOn));
            }

            private IEnumerator ToggleLights(bool active)
            {
                while (isTogglingLights)
                    yield return null;

                isTogglingLights = true;

                bool requiresFuel = Configuration.AutoLights.RequiresFuel;

                for (int i = 0; i < entities.Count; i++)
                {
                    if (ToggleLight(entities[i], active, requiresFuel))
                        yield return CoroutineEx.waitForEndOfFrame;
                }

                isTogglingLights = false;
            }

            private bool ToggleLight(BaseEntity baseEntity, bool active, bool requiresFuel)
            {
                BaseOven baseOven = baseEntity as BaseOven;
                if (baseOven)
                {
                    if (active)
                    {
                        if (!baseOven.IsOn())
                        {
                            if ((requiresFuel && baseOven.FindBurnable() != null) || !requiresFuel)
                                baseOven.SetFlag(BaseEntity.Flags.On, true);
                        }
                    }
                    else
                    {
                        if (baseOven.IsOn())
                            baseOven.StopCooking();
                    }

                    return true;
                }

                SearchLight searchLight = baseEntity as SearchLight;
                if (searchLight)
                {
                    if (active)
                    {
                        if (!searchLight.IsOn())
                            searchLight.SetFlag(BaseEntity.Flags.On, true);
                    }
                    else
                    {
                        if (searchLight.IsOn())
                            searchLight.SetFlag(BaseEntity.Flags.On, false);
                    }

                    return true;
                }

                return false;
            }
            #endregion

            #region Entity Detection            
            private void OnTriggerEnter(Collider col)
            {
                if (!definition.Enabled || !col || !col.gameObject)
                    return;

                BaseEntity baseEntity = col.gameObject.ToBaseEntity();
                if (!baseEntity || !baseEntity.IsValid())
                    return;

                if (baseEntity is BasePlayer { IsNpc: false } player)
                {
                    Instance?.OnPlayerEnterZone(player, this);

                    if (parent)
                        Instance?.UpdateZoneEntityFlags(this);

                    return;
                }

                Instance?.OnEntityEnterZone(baseEntity, this);
            }

            private void OnTriggerExit(Collider col)
            {
                if (!definition.Enabled || !col || !col.gameObject)
                    return;

                BaseEntity baseEntity = col.gameObject.ToBaseEntity();
                if (!baseEntity || !baseEntity.IsValid())
                    return;

                if (baseEntity is BasePlayer { IsNpc: false } player)
                {
                    Instance?.OnPlayerExitZone(player, this);

                    return;
                }

                Instance?.OnEntityExitZone(baseEntity, this);
            }

            public void OnPlayerEnterZone(BasePlayer player)
            {
                if (!players.Contains(player))
                    players.Add(player);

                if (zonedPlayers.TryGetValue(player.userID, out EntityZones entityZone))
                    entityZones[player.userID] = entityZone;
                
                if (safeZone != null)
                    AddToTrigger(safeZone.Trigger, player);

                if (radiation != null)
                    AddToTrigger(radiation.Trigger, player);

                if (comfort != null)
                    AddToTrigger(comfort.Trigger, player);

                if (temperature != null)
                    AddToTrigger(temperature.Trigger, player);
            }            

            public void OnPlayerExitZone(BasePlayer player)
            {
                players.Remove(player);
                entityZones.Remove(player.userID);
                
                if (safeZone != null)
                    RemoveFromTrigger(safeZone.Trigger, player);

                if (radiation != null)
                    RemoveFromTrigger(radiation.Trigger, player);

                if (comfort != null)
                    RemoveFromTrigger(comfort.Trigger, player);

                if (temperature != null)
                    RemoveFromTrigger(temperature.Trigger, player);
            }

            public void OnEntityEnterZone(BaseEntity baseEntity)
            {
                entities.Add(baseEntity);

                if (zonedEntities.TryGetValue(baseEntity.net.ID, out EntityZones entityZone))
                    entityZones[baseEntity.net.ID.Value] = entityZone;

                if (HasFlag(ZoneFlags.NoDecay))
                {
                    DecayEntity decayEntity = baseEntity.GetComponentInParent<DecayEntity>();
                    if (decayEntity)
                    {
                        decayEntity.decay = null;
                    }
                }

                if (HasFlag(ZoneFlags.NoStability))
                {
                    if (baseEntity is StabilityEntity entity)
                    {
                        entity.grounded = true;
                    }
                }

                if (HasFlag(ZoneFlags.NpcFreeze) && baseEntity.IsNpc)
                {
                    if (baseEntity is BaseAnimalNPC animalNpc)
                    {
                        animalNpc.brain.SetEnabled(false);
                        return;
                    }

                    if (baseEntity is global::HumanNPC humanNpc)
                    {
                        humanNpc.Brain.SetEnabled(false);
                        return;
                    }

                    if (baseEntity is ScarecrowNPC scarecrowNpc)
                    {
                        scarecrowNpc.Brain.SetEnabled(false)

Its cut off?

Yeh, it seems to cut it off..

 

change line 250 from

List<ItemAmount> list = block.BuildCost();

 

to

List<ItemAmount> list = block.BuildCost().Items;
2DY5xMAR6pkAWuP.jpg Mortis

Yeh, it seems to cut it off..

 

change line 250 from

List<ItemAmount> list = block.BuildCost();

 

to

List<ItemAmount> list = block.BuildCost().Items;

Thanks!