Pathfinding stop calling callback sometimes (random bug)

Althoug sometime (1 at 20 times), the pathfinding is found in the log, but the callback in the path object ( for example OnPathfindComplet(Path ) ) is not called. So I can’t get the path found and everything is freeze.

The only 'unsusal" thing I do is I recalculate the node grid at runtime (my map is randomly generated).

I have the pro version in multithread.

Hi

I can only think of one reason.
You are using a seeker and you are requesting a path, and then before it has been returned, you request another path. That will cancel the first path, and the first path will not be returned (this is expected).

That’s not that. If a path is cancelled that way, there is a message in your log (and according to the log everything is fine).
I’m also asking a new pathfind calculation only if the last one is finished (but still force it if it takes more than 1 seconds).

I tried to debug it, but it happen rarely and each time I’m able to debug, mono crashed after a few click…
It push the path result in the queue but it’s never pop (the bebugger crash each time I try to see why).

But I still can’t let this kind of bug in a commercial game.

Hm… Maybe one of your OnPathComplete methods raised an exception. I think that could potentially cause paths to not be returned… [EDIT] Scrap that, won’t happen.

Try adding some Debug.Log calls in AstarPath.cs -> ReturnPaths method to see which paths are being returned. Logging their pathID is a nice way to separate them from each other.

How exactly are you requesting paths?

I would be very helpful if you can post
#1: Your scripts for this
and #2: A screen shot of your seeker

Generally I find it best to debug this kind of thing by having a Debug.log(Method name) in each method, and when I find an error like this, add more Debug.log’s in the Method until I isolate the issue.

Its a bit ( Brute force, but it works :stuck_out_tongue: )

Hi,
this is the code I use:

Path newPath = m_oSeeker.GetNewPath (m_oMoverGameObject.transform.position, vTargetPosition);
newPath.nnConstraint = NNConstraint.Default;
newPath.nnConstraint.constrainDistance = false;

		// start pathfinding
		m_oSeeker.StartPath( newPath, OnPathComplete, -1);

Sorry WildFactor but I need your whole script if i’m going to be much help :confused:

`
using UnityEngine;
using System.Collections;
using Pathfinding;

public abstract class PathfindingMove : MonoBehaviour {

public GameObject m_oMoverGameObject;

public bool m_bMoving = true;
public float m_fDeltaTimeUpdateMove = 0.02f;

// bool m_bPathFoundSinceEnable = false;

public Seeker m_oSeeker;

[HideInInspector] public Path m_oPath = null;
//int m_iPathMoveId = 0;

float fPreviousTime;

public abstract void OnPathFound();
public abstract void UpdateMove(float fDeltaMove);

bool m_bCalculatingPathFind = false;
float m_fTimeLastPathFindCalculate = 0.0f;
const float F_MAX_PATHFIND_DURATION_CALCULATION = 1.0f;

bool m_bNewTargedtInQueue = false;
Vector3 m_newTargetInQueue;

//
Vector3 m_vLastTarget;
bool m_bHasTarget = false;

protected int m_iCurrentPathGoToId = 0;
int m_iNextPathGotoId = 0;


static int m_sNBPathFindingCalculating = 0;

//bool m_bStopCurrentMove = false;

void Awake()
{
	m_oSeeker.pathCallback += OnPathComplete;
}

public virtual void OnEnable() 
{
	if (m_oPath != null) 
		m_oPath.Release (this);
	
	m_oPath = null;
	
	m_bHasTarget = false;
	//StartCoroutine( RefreshPathfinding() );
	
}

public void OnDisable () 
{
	m_oSeeker.pathCallback -= OnPathComplete;

	m_bNewTargedtInQueue = false;
	m_bCalculatingPathFind  = false;
	m_fTimeLastPathFindCalculate = 0.0f;
	//m_bPathFoundSinceEnable = false;
} 

public void OnDestroy () 
{
	ResetPath();
}

public void SetDefaultPenaltie( int iPenaltie )
{
	for (int i = 0; i < 32; i++ )
	{
		m_oSeeker.tagPenalties[i] = iPenaltie;
	}
}

public void AddTagPenaltie( int iPathfindTag, int iPenaltie )
{
	for (int i = 0; i < 32; i++ )
	{
		if ( ( i & iPathfindTag ) != 0 )
		{
			m_oSeeker.tagPenalties[i] = iPenaltie;
		}
	}
}

public void GoTo( Vector3 vTargetPosition, int iID )
{	
	m_iNextPathGotoId = iID;
	
	GoTo(vTargetPosition);
}

public void GoTo( Vector3 vTargetPosition)
{						
	if ( m_bCalculatingPathFind && ( ( m_fTimeLastPathFindCalculate + F_MAX_PATHFIND_DURATION_CALCULATION ) > Time.time)  )//already searching one pathfind (wait for it's completion)
	{
		m_bNewTargedtInQueue 			  = true;
		m_newTargetInQueue 				  = vTargetPosition;
	}
	else
	{	
		Path newPath = m_oSeeker.GetNewPath (m_oMoverGameObject.transform.position, vTargetPosition);
		newPath.nnConstraint = NNConstraint.Default;
		newPath.nnConstraint.constrainDistance = false;
		
		// start pathfinding
		m_oSeeker.StartPath( newPath, OnPathComplete, -1);
		m_bCalculatingPathFind = true;
		m_fTimeLastPathFindCalculate = Time.time;
			
		m_vLastTarget = vTargetPosition;
		m_bHasTarget = true;
		
		m_sNBPathFindingCalculating++;
	}
}

public void ResetPath()
{
	if (m_oPath != null) 
		m_oPath.Release (this);
	
	m_oPath = null;
}


public void OnPathComplete (Path oPath) 
{		
	m_sNBPathFindingCalculating--;
	
   // Debug.Log ("Yey, we got a path back. Did it have an error? "+p.error);
    if (!oPath.error) 
	{
		//Release the previous path
		if (m_oPath != null) m_oPath.Release (this);
		
		//Claim the new path
		oPath.Claim (this);
		
		//Replace the old path
		m_oPath = oPath;
		
		if ( m_oPath.vectorPath.Count > 0 )
		{
			int iClosestPoint = GetClosestPointIndexFromPosition();
			
			for (int i = 0; i < iClosestPoint + 1; i++ )
			{
				// start the path at the current position
				m_oPath.vectorPath[i] = m_oMoverGameObject.transform.position;
			}

			
			//end position to the end search
			//m_oPath.vectorPath[m_oPath.vectorPath.Count - 1] = ( m_oPath as ABPath ).originalEndPoint;
		}
		
		m_iCurrentPathGoToId = m_iNextPathGotoId;
		
       // m_oPath = oPath;
        OnPathFound();
		//m_iPathMoveId++;
		
		/*if ( gameObject.activeInHierarchy )
		{
			StartCoroutine(Moving(m_iPathMoveId));
		}*/
		
		//Debug.Log("PathCompleted");
    }
	else
	{
		Debug.Log ("Path error " + oPath.error);
	}
	
	m_bCalculatingPathFind = false;
	m_fTimeLastPathFindCalculate = 0.0f;

	//manage on queue
	if ( m_bNewTargedtInQueue  )
	{
		GoTo(m_newTargetInQueue );
		m_bNewTargedtInQueue = false;			
	}
	
}

public virtual void FixedUpdate()
{
	if ( m_bMoving )
	{
		UpdateMove(Time.fixedDeltaTime);
	}
}

public void StopFollowPath()
{
	m_bMoving = false;
}

public void StartFollowPath()
{
	m_bMoving = true;
}


public int GetClosestPointIndexFromPosition()
{
	int iClosestPoint = 0;
	float fSmallestSquareDistance = Vector3.SqrMagnitude( m_oMoverGameObject.transform.position  - m_oPath.vectorPath[0] );
	
	for (int i = 1; i < m_oPath.vectorPath.Count; i++ )
	{
		float fCurrentSquareDistance = Vector3.SqrMagnitude( m_oMoverGameObject.transform.position  - m_oPath.vectorPath[i] );
		if ( fCurrentSquareDistance < fSmallestSquareDistance )
		{
			fSmallestSquareDistance = fCurrentSquareDistance;
			iClosestPoint = i;
		}
	}
	
	return iClosestPoint;
}

public void RefreshPathFindingLastTarget()
{
	if ( !m_bNewTargedtInQueue && m_bHasTarget )
	{			
		GoTo( m_vLastTarget );
	}
}

// start in queue only every second
/*IEnumerator RefreshPathfinding()
{
	while ( true )
	{
		yield return new WaitForSeconds(1.0f);
		
		//manage on queue
		if ( ( m_sNBPathFindingCalculating < 30 ) && m_bNewTargedtInQueue && !m_bCalculatingPathFind  )
		{
			GoTo(m_newTargetInQueue );
			m_bNewTargedtInQueue = false;			
		}
	}
}*/

}`

I’m not sure a screenshot will help you.

And how I generate grid graph:
` public void UpdatePathfind()
{
GridGraph graph = AstarPath.active.graphs[0] as GridGraph;

	graph.aspectRatio = m_fGridWidth / m_fGridHeight;
	graph.nodeSize = m_fGridWidth / m_iNbWidthSubdiv;
	graph.width = m_iNbWidthSubdiv;
	graph.depth = m_iNBHeightSubdiv;
	
	graph.unclampedSize = new Vector2 (graph.width*graph.nodeSize,graph.depth*graph.nodeSize);
	graph.GenerateMatrix ();
	
	
	graph.center = transform.position + new Vector3( m_fGridWidth *0.5f, m_fGridHeight * 0.5f, 0.0f );
		
	AstarPath.active.Scan();
}`

Just from looking at it, I cant see anything you are doing that’s obviously Wrong… Sadly that makes it harder to debug :stuck_out_tongue:

I would try inserting Debug.Log in the proceeding methods returning variable values, this can at least tell you where the error is occurring.

Also try using some other methods (Like seeker startpath VS getnewpath) to see if its a method error~

Sorry that I cant give you a quick fix on this one…

ok, thanks.

I wanted to say that I am also experiencing this bug. What I found is that in the cases where the callback fails, the ReturnPathsHandler seems to never start. If I put some debug text in there, and it spams the console, I’m all good, if not, the callback never occurs (for seemingly obvious reasons). Any reason that coroutine might not actually trigger?
[EDIT] Actually looks like it runs one time then stops.
[EDIT2] Stranger, looks like it sometimes stops, then will randomly start up again, no clear pattern to it.

POSSIBLE FIX: Wildfactor, you might try this and see if it helps you, with some (not yet enough) testing it seems to have fixed it for me. Moving the intial call of
StartCoroutine (ReturnsPathsHandler());

to a Start() function and not having it in Awake() seems to make it reliable. Tried it based on this post:

http://answers.unity3d.com/questions/441262/why-does-coroutine-yield-return-0-sometimes-take-a.html

Thanks Rujuro. I will try it. And if I don’t get the bug anymore during the next week, I will post here.

Of course. That could have caused it.
I really hate that Unity bug.

I didn’t get the bug during the past week. I continue to cross my fingers :slight_smile: