public static IEnumerator <BTStatus> FoodFinder(Animal agent, Func <Animal, BTStatus> noNearbyFoodBehavior, float hungerRestored)
        {
            var             lastPos     = Vector3.Zero;
            Queue <Vector3> foodSources = new Queue <Vector3>();

            while (agent.Hunger > Brain.HungerSatiated)
            {
                foodSources.Clear();
                while (foodSources.Count == 0)
                {
                    if (Vector3.WrappedDistanceSq(lastPos, agent.Position) > 100)
                    {
                        var agentRegion = RouteRegions.GetRegion(agent.Position.WorldPosition3i);
                        foodSources.AddRange(EcoSim.PlantSim.PlantsWithinRange(agent.Position, 10, plant => agent.Species.Eats(plant.Species) &&
                                                                               RouteRegions.GetRegion(plant.Position.WorldPosition3i.Down()) == agentRegion).Shuffle().Select(plant => plant.Position + Vector3.Down));
                        lastPos = agent.Position;
                    }
                    else
                    {
                        yield return(noNearbyFoodBehavior(agent));
                    }
                }

                while (foodSources.Count > 0 && agent.Hunger > Brain.HungerSatiated && Vector3.WrappedDistanceSq(lastPos, agent.Position) < 100)
                {
                    // low-effort search for the first option or any other option visited while trying to hit the first
                    Vector3 targetPlantPosition;
                    PiecewiseLinearFunction route = AIUtilities.GetRouteToAny(agent.Position, foodSources, agent.Species.WanderingSpeed, out targetPlantPosition, 100, 20, agent.Species.HeadDistance);
                    if (route == null)
                    {
                        break;
                    }
                    agent.Target.SetPath(route);
                    agent.Target.LookPos = targetPlantPosition;
                    agent.AnimationState = AnimalAnimationState.LookingForFood;
                    var target = route.EndPosition;

                    // just in case something interrupts the path
                    while (agent.Target.TargetTime > WorldTime.Seconds && agent.Target.TargetPosition == target)
                    {
                        agent.NextTick = agent.Target.TargetTime;
                        yield return(BTStatus.Running);
                    }

                    if (Vector3.WrappedDistanceSq(target, agent.Position) < 4)
                    {
                        agent.AnimationState = AnimalAnimationState.Eating;
                        agent.NextTick       = WorldTime.Seconds + 10;
                        agent.Hunger        -= hungerRestored;
                        agent.Target.LookPos = targetPlantPosition;
                        yield return(BTStatus.Running);
                    }

                    // something interrupted eating, probably need to find new food
                    if (agent.Target.TargetPosition != target)
                    {
                        break;
                    }
                }
            }
        }