Exemple #1
0
        protected virtual void OnDonePlanning(IReGoapGoal <T, W> newGoal)
        {
            startedPlanning         = false;
            currentReGoapPlanWorker = default(ReGoapPlanWork <T, W>);
            if (newGoal == null)
            {
                if (currentGoal == null)
                {
                    ReGoapLogger.LogWarning("GoapAgent " + this + " could not find a plan.");
                }
                return;
            }

            if (currentActionState != null)
            {
                currentActionState.Action.Exit(null);
            }
            currentActionState = null;
            currentGoal        = newGoal;
            if (startingPlan != null)
            {
                for (int i = 0; i < startingPlan.Count; i++)
                {
                    startingPlan[i].Action.PlanExit(i > 0 ? startingPlan[i - 1].Action : null, i + 1 < startingPlan.Count ? startingPlan[i + 1].Action : null, startingPlan[i].Settings, currentGoal.GetGoalState());
                }
            }
            startingPlan = currentGoal.GetPlan().ToList();
            ClearPlanValues();
            for (int i = 0; i < startingPlan.Count; i++)
            {
                startingPlan[i].Action.PlanEnter(i > 0 ? startingPlan[i - 1].Action : null, i + 1 < startingPlan.Count ? startingPlan[i + 1].Action : null, startingPlan[i].Settings, currentGoal.GetGoalState());
            }
            currentGoal.Run(WarnGoalEnd);
            PushAction();
        }
Exemple #2
0
        private static double Profile(string description, Action func, int iterations = 100)
        {
            // from: http://stackoverflow.com/questions/1047218/benchmarking-small-code-samples-in-c-can-this-implementation-be-improved
            //Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
            //Thread.CurrentThread.Priority = ThreadPriority.Highest;
            // warm up
            func();

            var watch = new Stopwatch();

            ReGoapLogger.Level = ReGoapLogger.DebugLevel.None;

            // clean up
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            watch.Start();
            for (int i = 0; i < iterations; i++)
            {
                func();
            }
            watch.Stop();

            // clean up
            GC.Collect();

            ReGoapLogger.Level = ReGoapLogger.DebugLevel.Full;

            ReGoapLogger.Log(string.Format("[Profile] {0} took {1}ms (iters: {2} ; avg: {3}ms).", description, watch.Elapsed.TotalMilliseconds, iterations, watch.Elapsed.TotalMilliseconds / iterations));
            return(watch.Elapsed.TotalMilliseconds);
        }
Exemple #3
0
    protected virtual void OnDonePlanning(IReGoapGoal newGoal)
    {
        currentPlanWorker = null;
        if (newGoal == null)
        {
            if (currentGoal == null)
            {
                ReGoapLogger.LogWarning("GoapAgent " + this + " could not find a plan.");
            }
            return;
        }

        if (currentActionState != null)
        {
            currentActionState.Action.Exit(null);
        }
        currentActionState = null;
        currentGoal        = newGoal;
        var plan = currentGoal.GetPlan();

        startingPlan = plan.ToList();
        ClearPlanValues();
        foreach (var actionState in startingPlan)
        {
            actionState.Action.PostPlanCalculations(this);
        }
        currentGoal.Run(WarnGoalEnd);
        PushAction();
    }
Exemple #4
0
    public IReGoapGoal Plan(IReGoapAgent agent, IReGoapGoal blacklistGoal = null, Queue <ReGoapActionState> currentPlan = null, Action <IReGoapGoal> callback = null)
    {
        ReGoapLogger.Log("[ReGoalPlanner] Starting planning calculation for agent: " + agent);
        goapAgent   = agent;
        Calculated  = false;
        currentGoal = null;
        var possibleGoals = new List <IReGoapGoal>();

        foreach (var goal in goapAgent.GetGoalsSet())
        {
            if (goal == blacklistGoal)
            {
                continue;
            }
            goal.Precalculations(this);
            if (goal.IsGoalPossible()) //goal.GetPriority() > bestPriority &&
            {
                possibleGoals.Add(goal);
            }
        }
        possibleGoals.Sort((x, y) => x.GetPriority().CompareTo(y.GetPriority()));

        while (possibleGoals.Count > 0)
        {
            currentGoal = possibleGoals[possibleGoals.Count - 1];
            possibleGoals.RemoveAt(possibleGoals.Count - 1);
            var goalState = currentGoal.GetGoalState();

            var leaf = (BGoapNode)astar.Run(
                new BGoapNode(this, goalState, null, null), goapAgent.GetMemory().GetWorldState(), settings.MaxIterations, settings.PlanningEarlyExit);
            if (leaf == null)
            {
                currentGoal = null;
                continue;
            }
            var path = leaf.CalculatePath();
            if (currentPlan != null && currentPlan == path)
            {
                currentGoal = null;
                break;
            }
            currentGoal.SetPlan(path);
            break;
        }
        Calculated = true;

        if (callback != null)
        {
            callback(currentGoal);
        }
        if (currentGoal != null)
        {
            ReGoapLogger.Log(string.Format("[ReGoapPlanner] Calculated plan for goal '{0}', plan length: {1}", currentGoal, currentGoal.GetPlan().Count));
        }
        else
        {
            ReGoapLogger.LogWarning("[ReGoapPlanner] Error while calculating plan.");
        }
        return(currentGoal);
    }
Exemple #5
0
 public virtual void WarnGoalEnd(IReGoapGoal goal)
 {
     if (goal != currentGoal)
     {
         ReGoapLogger.LogWarning(string.Format("[GoapAgent] Goal {0} warned for end but is not current goal.", goal));
         return;
     }
     CalculateNewGoal();
 }
Exemple #6
0
 public void MainLoop()
 {
     while (isRunning)
     {
         threadEvents.WaitOne();
         try {
             CheckWorkers();
         } catch (Exception e) {
             ReGoapLogger.LogError(e.ToString());
         }
     }
 }
Exemple #7
0
    public INode <T> Run(INode <T> start, T goal, int maxIterations = 100, bool earlyExit = true)
    {
        frontier.Clear();
        stateToNode.Clear();
        explored.Clear();

        frontier.Enqueue(start, start.GetCost());
        var iterations = 0;

        while ((frontier.Count > 0) && (iterations < maxIterations) && (frontier.Count + 1 < frontier.MaxSize))
        {
            iterations++;
            var node = frontier.Dequeue();
            if (node.IsGoal(goal))
            {
                ReGoapLogger.Log("[Astar] Success iterations: " + iterations);
                return(node);
            }
            explored[node.GetState()] = node;
            foreach (var child in node.Expand())
            {
                if (earlyExit && child.IsGoal(goal))
                {
                    ReGoapLogger.Log("[Astar] (early exit) Success iterations: " + iterations);
                    return(child);
                }
                var childCost = child.GetCost();
                var state     = child.GetState();
                if (explored.ContainsKey(state))
                {
                    continue;
                }
                INode <T> similiarNode;
                stateToNode.TryGetValue(state, out similiarNode);
                if (similiarNode != null)
                {
                    if (similiarNode.GetCost() > childCost)
                    {
                        frontier.Remove(similiarNode);
                    }
                    else
                    {
                        break;
                    }
                }
                frontier.Enqueue(child, childCost);
                stateToNode[state] = child;
            }
        }
        ReGoapLogger.LogWarning("[Astar] failed.");
        return(null);
    }
Exemple #8
0
 public virtual void WarnActionFailure(IReGoapAction thisAction)
 {
     if (thisAction != currentActionState.Action)
     {
         ReGoapLogger.LogWarning(string.Format("[GoapAgent] Action {0} warned for failure but is not current action.", thisAction));
         return;
     }
     if (BlackListGoalOnFailure)
     {
         goalBlacklist[currentGoal] = Time.time + currentGoal.GetErrorDelay();
     }
     CalculateNewGoal(true);
 }
Exemple #9
0
 private bool CheckIfStuck()
 {
     if (Time.time > stuckCheckCooldown)
     {
         stuckCheckCooldown = Time.time + StuckCheckDelay;
         if ((lastStuckCheckUpdatePosition - transform.position).magnitude < MaxStuckDistance)
         {
             ReGoapLogger.Log("[SmsGoTo] '" + name + "' is stuck.");
             return(true);
         }
         lastStuckCheckUpdatePosition = transform.position;
     }
     return(false);
 }
Exemple #10
0
    public override void Run(IReGoapAction previous, IReGoapAction next, IReGoapActionSettings settings, ReGoapState goalState, Action <IReGoapAction> done, Action <IReGoapAction> fail)
    {
        base.Run(previous, next, settings, goalState, done, fail);
        var workstation = agent.GetMemory().GetWorldState().Get <Workstation>("nearestWorkstation");

        if (workstation.CraftResource(resourcesBag, recipe))
        {
            ReGoapLogger.Log("[CraftRecipeAction] crafted recipe " + recipe.GetCraftedResource());
            done(this);
        }
        else
        {
            fail(this);
        }
    }
Exemple #11
0
    public override void Run(IReGoapAction <string, object> previous, IReGoapAction <string, object> next, IReGoapActionSettings <string, object> settings, ReGoapState <string, object> goalState, Action <IReGoapAction <string, object> > done, Action <IReGoapAction <string, object> > fail)
    {
        base.Run(previous, next, settings, goalState, done, fail);
        var workstation = agent.GetMemory().GetWorldState().Get("nearestWorkstation") as Workstation;

        if (workstation != null && workstation.CraftResource(resourcesBag, recipe))
        {
            ReGoapLogger.Log("[CraftRecipeAction] crafted recipe " + recipe.GetCraftedResource());
            done(this);
        }
        else
        {
            fail(this);
        }
    }
Exemple #12
0
 public override void Run(IReGoapAction previous, IReGoapAction next, IReGoapActionSettings settings, ReGoapState goalState, Action <IReGoapAction> done, Action <IReGoapAction> fail)
 {
     base.Run(previous, next, settings, goalState, done, fail);
     SetNeededResources(settings);
     if (resource == null || resource.GetCapacity() < ResourcePerAction)
     {
         failCallback(this);
     }
     else
     {
         ReGoapLogger.Log("[GatherResourceAction] acquired " + ResourcePerAction + " " + resource.GetName());
         resource.RemoveResource(ResourcePerAction);
         bag.AddResource(resource.GetName(), ResourcePerAction);
         doneCallback(this);
     }
 }
 protected void Update()
 {
     if (resource == null || resource.GetCapacity() < ResourcePerAction)
     {
         failCallback(this);
         return;
     }
     if (Time.time > gatherCooldown)
     {
         gatherCooldown = float.MaxValue;
         ReGoapLogger.Log("[GatherResourceAction] acquired " + ResourcePerAction + " " + resource.GetName());
         resource.RemoveResource(ResourcePerAction);
         bag.AddResource(resource.GetName(), ResourcePerAction);
         doneCallback(this);
     }
 }
 // called in another thread
 private void OnDonePlan(ReGoapPlannerThread <T, W> plannerThread, ReGoapPlanWork <T, W> work, IReGoapGoal <T, W> newGoal)
 {
     work.NewGoal = newGoal;
     lock (doneWorks)
     {
         doneWorks.Add(work);
     }
     if (work.NewGoal != null && ReGoapLogger.Level == ReGoapLogger.DebugLevel.Full)
     {
         ReGoapLogger.Log("[GoapPlannerManager] Done calculating plan, actions list:");
         var i = 0;
         foreach (var action in work.NewGoal.GetPlan())
         {
             ReGoapLogger.Log(string.Format("{0}: {1}", i++, action.Action));
         }
     }
 }
    // called in another thread
    private void OnDonePlan(GoapPlannerThread plannerThread, PlanWork work, IReGoapGoal newGoal)
    {
        work.NewGoal = newGoal;
        lock (doneWorks)
        {
            doneWorks.Add(work);
#if DEBUG
            if (work.NewGoal != null)
            {
                ReGoapLogger.Log("[GoapPlannerManager] Done calculating plan, actions list:");
                var i = 0;
                foreach (var action in work.NewGoal.GetPlan())
                {
                    ReGoapLogger.Log(string.Format("{0}: {1}", i++, action.Action));
                }
            }
#endif
        }
    }
Exemple #16
0
 protected void Update()
 {
     if (resource == null || resource.GetCapacity() < ResourcePerAction)
     {
         failCallback(this);
         return;
     }
     if (Time.time > gatherCooldown)
     {
         gatherCooldown = float.MaxValue;
         ReGoapLogger.Log("[GatherResourceAction] acquired " + ResourcePerAction + " " + resource.GetName());
         resource.RemoveResource(ResourcePerAction);
         bag.AddResource(resource.GetName(), ResourcePerAction);
         doneCallback(this);
         if (settings.HasKey("resource"))
         {
             ((IResource)settings.Get("resource")).Unreserve(GetHashCode());
         }
     }
 }
        protected virtual void Awake()
        {
            ReGoapNode <T, W> .Warmup(NodeWarmupCount);

            ReGoapState <T, W> .Warmup(StatesWarmupCount);

            ReGoapLogger.Level = LogLevel;
            if (Instance != null)
            {
                Destroy(this);
                var errorString =
                    "[GoapPlannerManager] Trying to instantiate a new manager but there can be only one per scene.";
                ReGoapLogger.LogError(errorString);
                throw new UnityException(errorString);
            }
            Instance = this;

            doneWorks = new List <ReGoapPlanWork <T, W> >();
            ReGoapPlannerThread <T, W> .WorksQueue = new Queue <ReGoapPlanWork <T, W> >();
            planners = new ReGoapPlannerThread <T, W> [ThreadsCount];
            threads  = new Thread[ThreadsCount];

            if (MultiThread)
            {
                ReGoapLogger.Log(String.Format("[GoapPlannerManager] Running in multi-thread mode ({0} threads).", ThreadsCount));
                for (int i = 0; i < ThreadsCount; i++)
                {
                    planners[i] = new ReGoapPlannerThread <T, W>(PlannerSettings, OnDonePlan);
                    var thread = new Thread(planners[i].MainLoop);
                    thread.Start();
                    threads[i] = thread;
                }
            } // no threads run
            else
            {
                ReGoapLogger.Log("[GoapPlannerManager] Running in single-thread mode.");
                planners[0] = new ReGoapPlannerThread <T, W>(PlannerSettings, OnDonePlan);
            }
        }
    protected virtual void Awake()
    {
        if (Instance != null)
        {
            Destroy(this);
            var errorString =
                "[GoapPlannerManager] Trying to instantiate a new manager but there can be only one per scene.";
            ReGoapLogger.LogError(errorString);
            throw new UnityException(errorString);
        }
        Instance = this;

        doneWorks    = new List <PlanWork>();
        worksQueue   = new Queue <PlanWork>();
        planners     = new GoapPlannerThread[ThreadsCount];
        threads      = new Thread[ThreadsCount];
        threadEvents = new AutoResetEvent(false);
        if (ThreadsCount > 1)
        {
            ReGoapLogger.Log("[GoapPlannerManager] Running in multi-thread mode.");
            for (int i = 0; i < ThreadsCount; i++)
            {
                planners[i] = new GoapPlannerThread(threadEvents, PlannerSettings, worksQueue, OnDonePlan);
                var thread = new Thread(planners[i].MainLoop)
                {
                    IsBackground = true
                };
                thread.Start();
                threads[i] = thread;
            }
        } // no threads run
        else
        {
            ReGoapLogger.Log("[GoapPlannerManager] Running in single-thread mode.");
            planners[0] = new GoapPlannerThread(threadEvents, PlannerSettings, worksQueue, OnDonePlan);
        }
    }
Exemple #19
0
    public IReGoapGoal Plan(IReGoapAgent agent, IReGoapGoal blacklistGoal = null, Queue <ReGoapActionState> currentPlan = null, Action <IReGoapGoal> callback = null)
    {
        ReGoapLogger.Log("[ReGoalPlanner] Starting planning calculation for agent: " + agent);
        goapAgent   = agent;
        Calculated  = false;
        currentGoal = null;
        var possibleGoals = new List <IReGoapGoal>();

        foreach (var goal in goapAgent.GetGoalsSet())
        {
            if (goal == blacklistGoal)
            {
                continue;
            }
            goal.Precalculations(this);
            if (goal.IsGoalPossible()) //goal.GetPriority() > bestPriority &&
            {
                possibleGoals.Add(goal);
            }
        }
        possibleGoals.Sort((x, y) => x.GetPriority().CompareTo(y.GetPriority()));

        while (possibleGoals.Count > 0)
        {
            currentGoal = possibleGoals[possibleGoals.Count - 1];
            possibleGoals.RemoveAt(possibleGoals.Count - 1);
            var goalState = currentGoal.GetGoalState();

            // can't work with dynamic actions, of course
            if (!settings.UsingDynamicActions)
            {
                var wantedGoalCheck = currentGoal.GetGoalState();
                // we check if the goal can be archived through actions first, so we don't brute force it with A* if we can't
                foreach (var action in goapAgent.GetActionsSet())
                {
                    action.Precalculations(goapAgent, goalState);
                    if (!action.CheckProceduralCondition(goapAgent, wantedGoalCheck))
                    {
                        continue;
                    }
                    // check if the effects of all actions can archieve currentGoal
                    var previous = wantedGoalCheck;
                    wantedGoalCheck = new ReGoapState();
                    previous.MissingDifference(action.GetEffects(wantedGoalCheck), ref wantedGoalCheck);
                }
                // can't validate goal
                if (wantedGoalCheck.Count > 0)
                {
                    currentGoal = null;
                    continue;
                }
            }

            var leaf = (ReGoapNode)astar.Run(
                new ReGoapNode(this, goalState, null, null), goalState, settings.MaxIterations, settings.PlanningEarlyExit);
            if (leaf == null)
            {
                currentGoal = null;
                continue;
            }
            var path = leaf.CalculatePath();
            if (currentPlan != null && currentPlan == path)
            {
                currentGoal = null;
                break;
            }
            currentGoal.SetPlan(path);
            break;
        }
        Calculated = true;

        if (callback != null)
        {
            callback(currentGoal);
        }
        if (currentGoal != null)
        {
            ReGoapLogger.Log(string.Format("[ReGoapPlanner] Calculated plan for goal '{0}', plan length: {1}", currentGoal, currentGoal.GetPlan().Count));
        }
        else
        {
            ReGoapLogger.LogWarning("[ReGoapPlanner] Error while calculating plan.");
        }
        return(currentGoal);
    }
Exemple #20
0
        public INode <T> Run(INode <T> start, T goal, int maxIterations = 100, bool earlyExit = true, bool clearNodes = true, bool debugPlan = false)
        {
            _debugPlan = debugPlan;

            frontier.Clear();
            stateToNode.Clear();
            explored.Clear();
            if (clearNodes)
            {
                ClearNodes();
                createdNodes.Add(start);
            }

            frontier.Enqueue(start, start.GetCost());

            _DebugPlan(start, null);

            var iterations = 0;

            while ((frontier.Count > 0) && (iterations < maxIterations) && (frontier.Count + 1 < frontier.MaxSize))
            {
                var node = frontier.Dequeue();
                Utilities.ReGoapLogger.Log(string.Format("\n++++Explored action: {0}({3}), state ({1})\n goal ({2})\n effect: ({4})", node.Name, node.GetState(), node.GoalString, node.GetCost(), node.EffectString));
                if (node.IsGoal(goal))
                {
                    ReGoapLogger.Log("[Astar] Success iterations: " + iterations);
                    _EndDebugPlan(node);
                    return(node);
                }
                explored[node.GetState()] = node;


                foreach (var child in node.Expand())
                {
                    iterations++;
                    if (clearNodes)
                    {
                        createdNodes.Add(child);
                    }
                    if (earlyExit && child.IsGoal(goal))
                    {
                        ReGoapLogger.Log("[Astar] (early exit) Success iterations: " + iterations);
                        _EndDebugPlan(child);
                        return(child);
                    }
                    var childCost = child.GetCost();
                    var state     = child.GetState();
                    if (explored.ContainsKey(state))
                    {
                        continue;
                    }
                    INode <T> similiarNode;
                    stateToNode.TryGetValue(state, out similiarNode);
                    if (similiarNode != null)
                    {
                        if (similiarNode.GetCost() > childCost)
                        {
                            frontier.Remove(similiarNode);
                        }
                        else
                        {
                            break;
                        }
                    }

                    _DebugPlan(child, node);

                    Utilities.ReGoapLogger.Log(string.Format("    Enqueue frontier: {0}, cost: {1}", child.Name, childCost));
                    frontier.Enqueue(child, childCost);
                    stateToNode[state] = child;
                }
            }

            string failReason =
                (frontier.Count <= 0 ? "Depleted Search Space. " : "") +
                ((iterations >= maxIterations) ? "Too many iter: " + iterations : "") +
                (frontier.Count + 1 >= frontier.MaxSize ? "FrontierQueue too large: " + frontier.MaxSize : "");

            ReGoapLogger.LogWarning("[Astar] failed. " + failReason);
            _EndDebugPlan(null);
            return(null);
        }
Exemple #21
0
        public IReGoapGoal <T, W> Plan(IReGoapAgent <T, W> agent, IReGoapGoal <T, W> blacklistGoal = null, Queue <ReGoapActionState <T, W> > currentPlan = null, Action <IReGoapGoal <T, W> > callback = null)
        {
            if (ReGoapLogger.Level == ReGoapLogger.DebugLevel.Full)
            {
                ReGoapLogger.Log("[ReGoalPlanner] Starting planning calculation for agent: " + agent);
            }
            goapAgent   = agent;
            Calculated  = false;
            currentGoal = null;
            var possibleGoals = new List <IReGoapGoal <T, W> >();

            foreach (var goal in goapAgent.GetGoalsSet())
            {
                if (goal == blacklistGoal)
                {
                    continue;
                }
                goal.Precalculations(this);
                if (goal.IsGoalPossible())
                {
                    possibleGoals.Add(goal);
                }
            }
            possibleGoals.Sort((x, y) => x.GetPriority().CompareTo(y.GetPriority()));

            while (possibleGoals.Count > 0)
            {
                currentGoal = possibleGoals[possibleGoals.Count - 1];
                possibleGoals.RemoveAt(possibleGoals.Count - 1);
                var goalState = currentGoal.GetGoalState();

                // can't work with dynamic actions, of course
                if (!settings.UsingDynamicActions)
                {
                    var wantedGoalCheck = currentGoal.GetGoalState();
                    // we check if the goal can be archived through actions first, so we don't brute force it with A* if we can't
                    foreach (var action in goapAgent.GetActionsSet())
                    {
                        action.Precalculations(goapAgent, goalState);
                        if (!action.CheckProceduralCondition(goapAgent, wantedGoalCheck))
                        {
                            continue;
                        }
                        // check if the effects of all actions can archieve currentGoal
                        var previous = wantedGoalCheck;
                        wantedGoalCheck = ReGoapState <T, W> .Instantiate();

                        previous.MissingDifference(action.GetEffects(wantedGoalCheck), ref wantedGoalCheck);
                    }
                    // can't validate goal
                    if (wantedGoalCheck.Count > 0)
                    {
                        currentGoal = null;
                        continue;
                    }
                }

                //Utilities.ReGoapLogger.Log(string.Format("**** Goal: {0}, Expected State = ({1})", currentGoal.GetName(), goalState));

                goalState = goalState.Clone();
                var leaf = (ReGoapNode <T, W>)astar.Run(
                    ReGoapNode <T, W> .Instantiate(this, goalState, null, null), goalState, settings.MaxIterations, settings.PlanningEarlyExit, debugPlan: agent.debugPlan);
                if (leaf == null)
                {
                    currentGoal = null;
                    continue;
                }

                var result = leaf.CalculatePath();
                if (currentPlan != null && currentPlan == result)
                {
                    currentGoal = null;
                    break;
                }
                if (result.Count == 0)
                {
                    currentGoal = null;
                    continue;
                }
                currentGoal.SetPlan(result);
                break;
            }
            Calculated = true;

            if (callback != null)
            {
                callback(currentGoal);
            }
            if (currentGoal != null)
            {
                ReGoapLogger.Log(string.Format("[ReGoapPlanner] Calculated plan for goal '{0}', plan length: {1}", currentGoal, currentGoal.GetPlan().Count));
                if (ReGoapLogger.Level == ReGoapLogger.DebugLevel.Full)
                {
                    int i = 0;
                    foreach (var action in currentGoal.GetPlan())
                    {
                        ReGoapLogger.Log(string.Format("[ReGoapPlanner] {0}) {1}", i++, action.Action));
                    }
                }
            }
            else
            {
                ReGoapLogger.LogWarning("[ReGoapPlanner] Error while calculating plan.");
            }
            return(currentGoal);
        }
Exemple #22
0
        public INode <T> Run(INode <T> start, T goal, int maxIterations = 100, bool earlyExit = true, bool clearNodes = true, bool debugPlan = false)
        {
            this.debugPlan = debugPlan;

            frontier.Clear();
            stateToNode.Clear();
            explored.Clear();
            if (clearNodes)
            {
                ClearNodes();
                createdNodes.Add(start);
            }

            frontier.Enqueue(start, start.GetCost());

            DebugPlan(start, null);

            var iterations = 0;

            while ((frontier.Count > 0) && (iterations < maxIterations) && (frontier.Count + 1 < frontier.MaxSize))
            {
                var node = frontier.Dequeue();
                if (node.IsGoal(goal))
                {
                    ReGoapLogger.Log("[Astar] Success iterations: " + iterations);
                    EndDebugPlan(node);
                    return(node);
                }
                explored[node.GetState()] = node;


                foreach (var child in node.Expand())
                {
                    iterations++;
                    if (clearNodes)
                    {
                        createdNodes.Add(child);
                    }
                    if (earlyExit && child.IsGoal(goal))
                    {
                        ReGoapLogger.Log("[Astar] (early exit) Success iterations: " + iterations);
                        EndDebugPlan(child);
                        return(child);
                    }
                    var childCost = child.GetCost();
                    var state     = child.GetState();
                    if (explored.ContainsKey(state))
                    {
                        continue;
                    }
                    INode <T> similiarNode;
                    stateToNode.TryGetValue(state, out similiarNode);
                    if (similiarNode != null)
                    {
                        if (similiarNode.GetCost() > childCost)
                        {
                            frontier.Remove(similiarNode);
                        }
                        else
                        {
                            break;
                        }
                    }

                    DebugPlan(child, node);

                    //Utilities.ReGoapLogger.Log(string.Format("    Enqueue frontier: {0}, cost: {1}", child.Name, childCost));
                    frontier.Enqueue(child, childCost);
                    stateToNode[state] = child;
                }
            }
            ReGoapLogger.LogWarning("[Astar] failed.");
            EndDebugPlan(null);
            return(null);
        }