public override bool ShouldExecute()
        {
            if (entity.World.Rand.NextDouble() < 0.005)
            {
                return(false);
            }
            if (cooldownUntilMs > entity.World.ElapsedMilliseconds)
            {
                return(false);
            }
            if (cooldownUntilTotalHours > entity.World.Calendar.TotalHours)
            {
                return(false);
            }
            if (whenInEmotionState != null && !entity.HasEmotionState(whenInEmotionState))
            {
                return(false);
            }
            if (whenNotInEmotionState != null && entity.HasEmotionState(whenNotInEmotionState))
            {
                return(false);
            }

            EntityBehaviorMultiply bh = entity.GetBehavior <EntityBehaviorMultiply>();

            if (bh != null && !bh.ShouldEat)
            {
                return(false);
            }

            IPointOfInterest nearestPoi = porregistry.GetNearestPoi(entity.ServerPos.XYZ, 32, (poi) =>
            {
                if (poi.Type != "food")
                {
                    return(false);
                }

                if ((target = poi as IAnimalFoodSource)?.IsSuitableFor(entity) == true)
                {
                    FailedAttempt attempt;
                    failedSeekTargets.TryGetValue(target, out attempt);
                    doOnce = true;
                    if (attempt == null || (attempt.Count < 4 || attempt.LastTryMs < world.ElapsedMilliseconds - 60000))
                    {
                        return(true);
                    }
                }

                return(false);
            });


            return(nearestPoi != null);
        }
        public override bool ShouldExecute()
        {
            EntityBehaviorProgram prog = entity.GetBehavior <EntityBehaviorProgram>();

            if (prog == null || prog.dormant)
            {
                return(false);
            }
            if (failureTime > entity.World.ElapsedMilliseconds || cooldownUntilMs > entity.World.ElapsedMilliseconds || !prog.CheckArea() || entity.LeftHandItemSlot.Itemstack?.Collectible?.Tool == null)
            {
                return(false);
            }

            targetPoi = porregistry.GetNearestPoi((prog.workArea.End + prog.workArea.Start) / 2, (float)(prog.workArea.Length + prog.workArea.Height + prog.workArea.Width), (poi) =>
            {
                if (poi.Type != "food" || !prog.workArea.ContainsOrTouches(poi.Position))
                {
                    return(false);
                }
                IAnimalFoodSource foodPoi;

                if ((poi is BlockEntityBerryBush || poi is BlockEntityBeehive) && (foodPoi = poi as IAnimalFoodSource)?.IsSuitableFor(entity) == true)
                {
                    return(true);
                }

                if (poi is BlockEntityFarmland)
                {
                    Block harvest = world.BlockAccessor.GetBlock(poi.Position.AsBlockPos);
                    int stage;
                    int.TryParse(harvest.LastCodePart(), out stage);

                    if ((lumber && (harvest?.Code.Path.Contains("log") == true || harvest?.Code.Path.Contains("bamboo-grown") == true) &&
                         (!harvest.Code.Path.Contains("resin") || !harvest.Code.Path.Contains("resinharvested")) && entity.LeftHandItemSlot.Itemstack.Collectible.Tool == EnumTool.Axe) ||
                        FindMatchCode(harvest.Code) || stage == harvest.CropProps?.GrowthStages || harvest?.GetBehavior <BlockBehaviorHarvestable>() != null)
                    {
                        return(true);
                    }
                }

                return(false);
            }) as IAnimalFoodSource;

            return(targetPoi != null);
        }
        public void SeekFoodSources(float dt)
        {
            shouldSeek = true;
            nearestPoi = porregistry.GetNearestPoi(entity.ServerPos.XYZ, 32, (poi) =>
            {
                if (poi.Type != "food")
                {
                    return(false);
                }

                if ((target = poi as IAnimalFoodSource)?.IsSuitableFor(entity) == true)
                {
                    FailedAttempt attempt;
                    failedSeekTargets.TryGetValue(target, out attempt);
                    doOnce = true;
                    if (attempt == null || (attempt.Count < 4 || attempt.LastTryMs < world.ElapsedMilliseconds - 60000))
                    {
                        return(true);
                    }
                }

                return(false);
            });
        }
        public override bool ShouldExecute()
        {
            if (entity.World.Rand.NextDouble() < 0.005)
            {
                return(false);
            }
            // Don't search more often than every 15 seconds
            if (lastPOISearchTotalMs + 15000 > entity.World.ElapsedMilliseconds)
            {
                return(false);
            }
            if (cooldownUntilMs > entity.World.ElapsedMilliseconds)
            {
                return(false);
            }
            if (cooldownUntilTotalHours > entity.World.Calendar.TotalHours)
            {
                return(false);
            }
            if (whenInEmotionState != null && !entity.HasEmotionState(whenInEmotionState))
            {
                return(false);
            }
            if (whenNotInEmotionState != null && entity.HasEmotionState(whenNotInEmotionState))
            {
                return(false);
            }

            EntityBehaviorMultiply bh = entity.GetBehavior <EntityBehaviorMultiply>();

            if (bh != null && !bh.ShouldEat && entity.World.Rand.NextDouble() < 0.996)
            {
                return(false);                                                                       // 0.4% chance go to the food source anyway just because (without eating anything).
            }
            targetPoi            = null;
            extraTargetDist      = 0;
            lastPOISearchTotalMs = entity.World.ElapsedMilliseconds;

            entity.World.Api.ModLoader.GetModSystem <EntityPartitioning>().WalkEntities(entity.ServerPos.XYZ, 10, (e) =>
            {
                if (e is EntityItem)
                {
                    EntityItem ei        = (EntityItem)e;
                    EnumFoodCategory?cat = ei.Itemstack?.Collectible?.NutritionProps?.FoodCategory;
                    if (cat != null && eatItemCategories.Contains((EnumFoodCategory)cat))
                    {
                        targetPoi = new LooseItemFoodSource(ei);
                        return(false);
                    }

                    AssetLocation code = ei.Itemstack?.Collectible?.Code;
                    if (code != null && eatItemCodes.Contains(code))
                    {
                        targetPoi = new LooseItemFoodSource(ei);
                        return(false);
                    }
                }

                if (searchPlayerInv && e is EntityPlayer eplr)
                {
                    if (eplr.Player.InventoryManager.Find(slot => slot.Inventory is InventoryBasePlayer && !slot.Empty && eatItemCodes.Contains(slot.Itemstack.Collectible.Code)))
                    {
                        targetPoi = new PlayerPoi(eplr);
                    }
                }

                return(true);
            });

            if (targetPoi == null)
            {
                targetPoi = porregistry.GetNearestPoi(entity.ServerPos.XYZ, 48, (poi) =>
                {
                    if (poi.Type != "food")
                    {
                        return(false);
                    }
                    IAnimalFoodSource foodPoi;

                    if ((foodPoi = poi as IAnimalFoodSource)?.IsSuitableFor(entity) == true)
                    {
                        FailedAttempt attempt;
                        failedSeekTargets.TryGetValue(foodPoi, out attempt);
                        if (attempt == null || (attempt.Count < 4 || attempt.LastTryMs < world.ElapsedMilliseconds - 60000))
                        {
                            return(true);
                        }
                    }

                    return(false);
                }) as IAnimalFoodSource;
            }

            /*if (targetPoi != null)
             * {
             *  if (targetPoi is BlockEntity || targetPoi is Block)
             *  {
             *      Block block = entity.World.BlockAccessor.GetBlock(targetPoi.Position.AsBlockPos);
             *      Cuboidf[] collboxes = block.GetCollisionBoxes(entity.World.BlockAccessor, targetPoi.Position.AsBlockPos);
             *      if (collboxes != null && collboxes.Length != 0 && collboxes[0].Y2 > 0.3f)
             *      {
             *          extraTargetDist = 0.15f;
             *      }
             *  }
             * }*/

            return(targetPoi != null);
        }