/** Stop calculating the current path request. * If this Seeker is currently calculating a path it will be canceled. * The callback (usually to a method named OnPathComplete) will soon be called * with a path that has the 'error' field set to true. * * This does not stop the character from moving, it just aborts * the path calculation. * * \param pool If true then the path will be pooled when the pathfinding system is done with it. */ public void CancelCurrentPathRequest(bool pool = true) { if (!IsDone()) { path.FailWithError("Canceled by script (Seeker.CancelCurrentPathRequest)"); if (pool) { // Make sure the path has had its reference count incremented and decremented once. // If this is not done the system will think no pooling is used at all and will not pool the path. // The particular object that is used as the parameter (in this case 'path') doesn't matter at all // it just has to be *some* object. path.Claim(path); path.Release(path); } } }
/// <summary> /// Main pathfinding method. /// This method will calculate the paths in the pathfinding queue. /// /// See: CalculatePathsThreaded /// See: StartPath /// </summary> IEnumerator CalculatePaths(PathHandler pathHandler) { // Max number of ticks before yielding/sleeping long maxTicks = (long)(astar.maxFrameTime * 10000); long targetTick = System.DateTime.UtcNow.Ticks + maxTicks; while (true) { // The path we are currently calculating Path p = null; AstarProfiler.StartProfile("Path Queue"); // Try to get the next path to be calculated bool blockedBefore = false; while (p == null) { try { p = queue.PopNoBlock(blockedBefore); blockedBefore |= p == null; } catch (ThreadControlQueue.QueueTerminationException) { yield break; } if (p == null) { AstarProfiler.EndProfile(); yield return(null); AstarProfiler.StartProfile("Path Queue"); } } AstarProfiler.EndProfile(); AstarProfiler.StartProfile("Path Calc"); IPathInternals ip = (IPathInternals)p; // Max number of ticks we are allowed to continue working in one run // One tick is 1/10000 of a millisecond maxTicks = (long)(astar.maxFrameTime * 10000); ip.PrepareBase(pathHandler); // Now processing the path // Will advance to Processing ip.AdvanceState(PathState.Processing); // Call some callbacks // It needs to be stored in a local variable to avoid race conditions var tmpOnPathPreSearch = OnPathPreSearch; if (tmpOnPathPreSearch != null) { tmpOnPathPreSearch(p); } // Tick for when the path started, used for calculating how long time the calculation took long startTicks = System.DateTime.UtcNow.Ticks; long totalTicks = 0; AstarProfiler.StartFastProfile(8); AstarProfiler.StartFastProfile(0); //Prepare the path AstarProfiler.StartProfile("Path Prepare"); ip.Prepare(); AstarProfiler.EndProfile("Path Prepare"); AstarProfiler.EndFastProfile(0); // Check if the Prepare call caused the path to complete // If this happens the path usually failed if (p.CompleteState == PathCompleteState.NotCalculated) { // For debug uses, we set the last computed path to p, so we can view debug info on it in the editor (scene view). astar.debugPathData = ip.PathHandler; astar.debugPathID = p.pathID; // Initialize the path, now ready to begin search AstarProfiler.StartProfile("Path Initialize"); ip.Initialize(); AstarProfiler.EndProfile(); // The error can turn up in the Init function while (p.CompleteState == PathCompleteState.NotCalculated) { // Do some work on the path calculation. // The function will return when it has taken too much time // or when it has finished calculation AstarProfiler.StartFastProfile(2); AstarProfiler.StartProfile("Path Calc Step"); ip.CalculateStep(targetTick); AstarProfiler.EndFastProfile(2); AstarProfiler.EndProfile(); // If the path has finished calculation, we can break here directly instead of sleeping // Improves latency if (p.CompleteState != PathCompleteState.NotCalculated) { break; } AstarProfiler.EndFastProfile(8); totalTicks += System.DateTime.UtcNow.Ticks - startTicks; // Yield/sleep so other threads can work AstarProfiler.EndProfile(); yield return(null); AstarProfiler.StartProfile("Path Calc"); startTicks = System.DateTime.UtcNow.Ticks; AstarProfiler.StartFastProfile(8); // Cancel function (and thus the thread) if no more paths should be accepted. // This is done when the A* object is about to be destroyed // The path is returned and then this function will be terminated (see similar IF statement higher up in the function) if (queue.IsTerminating) { p.FailWithError("AstarPath object destroyed"); } targetTick = System.DateTime.UtcNow.Ticks + maxTicks; } totalTicks += System.DateTime.UtcNow.Ticks - startTicks; p.duration = totalTicks * 0.0001F; #if ProfileAstar System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted); #endif } // Cleans up node tagging and other things ip.Cleanup(); AstarProfiler.EndFastProfile(8); // Call the immediate callback // It needs to be stored in a local variable to avoid race conditions var tmpImmediateCallback = p.immediateCallback; if (tmpImmediateCallback != null) { tmpImmediateCallback(p); } AstarProfiler.StartFastProfile(13); // It needs to be stored in a local variable to avoid race conditions var tmpOnPathPostSearch = OnPathPostSearch; if (tmpOnPathPostSearch != null) { tmpOnPathPostSearch(p); } AstarProfiler.EndFastProfile(13); // Push the path onto the return stack // It will be detected by the main Unity thread and returned as fast as possible (the next late update) returnQueue.Enqueue(p); ip.AdvanceState(PathState.ReturnQueue); AstarProfiler.EndProfile(); // Wait a bit if we have calculated a lot of paths if (System.DateTime.UtcNow.Ticks > targetTick) { yield return(null); targetTick = System.DateTime.UtcNow.Ticks + maxTicks; } } }
// Token: 0x06002378 RID: 9080 RVA: 0x001997BC File Offset: 0x001979BC private IEnumerator CalculatePaths(PathHandler pathHandler) { long maxTicks = (long)(this.astar.maxFrameTime * 10000f); long targetTick = DateTime.UtcNow.Ticks + maxTicks; for (;;) { Path p = null; bool blockedBefore = false; while (p == null) { try { p = this.queue.PopNoBlock(blockedBefore); blockedBefore |= (p == null); } catch (ThreadControlQueue.QueueTerminationException) { yield break; } if (p == null) { yield return(null); } } IPathInternals ip = p; maxTicks = (long)(this.astar.maxFrameTime * 10000f); ip.PrepareBase(pathHandler); ip.AdvanceState(PathState.Processing); Action <Path> onPathPreSearch = this.OnPathPreSearch; if (onPathPreSearch != null) { onPathPreSearch(p); } long ticks = DateTime.UtcNow.Ticks; long totalTicks = 0L; ip.Prepare(); if (!p.IsDone()) { this.astar.debugPathData = ip.PathHandler; this.astar.debugPathID = p.pathID; ip.Initialize(); while (!p.IsDone()) { ip.CalculateStep(targetTick); if (p.IsDone()) { break; } totalTicks += DateTime.UtcNow.Ticks - ticks; yield return(null); ticks = DateTime.UtcNow.Ticks; if (this.queue.IsTerminating) { p.FailWithError("AstarPath object destroyed"); } targetTick = DateTime.UtcNow.Ticks + maxTicks; } totalTicks += DateTime.UtcNow.Ticks - ticks; p.duration = (float)totalTicks * 0.0001f; } ip.Cleanup(); OnPathDelegate immediateCallback = p.immediateCallback; if (immediateCallback != null) { immediateCallback(p); } Action <Path> onPathPostSearch = this.OnPathPostSearch; if (onPathPostSearch != null) { onPathPostSearch(p); } this.returnQueue.Enqueue(p); ip.AdvanceState(PathState.ReturnQueue); if (DateTime.UtcNow.Ticks > targetTick) { yield return(null); targetTick = DateTime.UtcNow.Ticks + maxTicks; } p = null; ip = null; } yield break; }
/// <summary> /// Main pathfinding method (multithreaded). /// This method will calculate the paths in the pathfinding queue when multithreading is enabled. /// /// See: CalculatePaths /// See: StartPath /// </summary> void CalculatePathsThreaded(PathHandler pathHandler) { #if UNITY_2017_3_OR_NEWER UnityEngine.Profiling.Profiler.BeginThreadProfiling("Pathfinding", "Pathfinding thread #" + (pathHandler.threadID + 1)); #endif #if !ASTAR_FAST_BUT_NO_EXCEPTIONS try { #endif // Max number of ticks we are allowed to continue working in one run. // One tick is 1/10000 of a millisecond. // We need to check once in a while if the thread should be stopped. long maxTicks = (long)(10 * 10000); long targetTick = System.DateTime.UtcNow.Ticks + maxTicks; while (true) { // The path we are currently calculating Path path = queue.Pop(); #if UNITY_2017_3_OR_NEWER profilingSampler.Begin(); #endif // Access the internal implementation methods IPathInternals ipath = (IPathInternals)path; AstarProfiler.StartFastProfile(0); ipath.PrepareBase(pathHandler); // Now processing the path // Will advance to Processing ipath.AdvanceState(PathState.Processing); // Call some callbacks if (OnPathPreSearch != null) { OnPathPreSearch(path); } // Tick for when the path started, used for calculating how long time the calculation took long startTicks = System.DateTime.UtcNow.Ticks; // Prepare the path ipath.Prepare(); AstarProfiler.EndFastProfile(0); if (path.CompleteState == PathCompleteState.NotCalculated) { // For visualization purposes, we set the last computed path to p, so we can view debug info on it in the editor (scene view). astar.debugPathData = ipath.PathHandler; astar.debugPathID = path.pathID; AstarProfiler.StartFastProfile(1); // Initialize the path, now ready to begin search ipath.Initialize(); AstarProfiler.EndFastProfile(1); // Loop while the path has not been fully calculated while (path.CompleteState == PathCompleteState.NotCalculated) { // Do some work on the path calculation. // The function will return when it has taken too much time // or when it has finished calculation AstarProfiler.StartFastProfile(2); ipath.CalculateStep(targetTick); AstarProfiler.EndFastProfile(2); targetTick = System.DateTime.UtcNow.Ticks + maxTicks; // Cancel function (and thus the thread) if no more paths should be accepted. // This is done when the A* object is about to be destroyed // The path is returned and then this function will be terminated if (queue.IsTerminating) { path.FailWithError("AstarPath object destroyed"); } } path.duration = (System.DateTime.UtcNow.Ticks - startTicks) * 0.0001F; #if ProfileAstar System.Threading.Interlocked.Increment(ref AstarPath.PathsCompleted); System.Threading.Interlocked.Add(ref AstarPath.TotalSearchTime, System.DateTime.UtcNow.Ticks - startTicks); #endif } // Cleans up node tagging and other things ipath.Cleanup(); AstarProfiler.StartFastProfile(9); if (path.immediateCallback != null) { path.immediateCallback(path); } if (OnPathPostSearch != null) { OnPathPostSearch(path); } // Push the path onto the return stack // It will be detected by the main Unity thread and returned as fast as possible (the next late update hopefully) returnQueue.Enqueue(path); // Will advance to ReturnQueue ipath.AdvanceState(PathState.ReturnQueue); AstarProfiler.EndFastProfile(9); #if UNITY_2017_3_OR_NEWER profilingSampler.End(); #endif } #if !ASTAR_FAST_BUT_NO_EXCEPTIONS } catch (System.Exception e) { #if !NETFX_CORE if (e is ThreadAbortException || e is ThreadControlQueue.QueueTerminationException) #else if (e is ThreadControlQueue.QueueTerminationException) #endif { if (astar.logPathResults == PathLog.Heavy) { Debug.LogWarning("Shutting down pathfinding thread #" + pathHandler.threadID); } return; } Debug.LogException(e); Debug.LogError("Unhandled exception during pathfinding. Terminating."); // Unhandled exception, kill pathfinding queue.TerminateReceivers(); } finally { #if UNITY_2017_3_OR_NEWER UnityEngine.Profiling.Profiler.EndThreadProfiling(); #endif } #endif Debug.LogError("Error : This part should never be reached."); queue.ReceiverTerminated(); }
// Token: 0x06002377 RID: 9079 RVA: 0x001995EC File Offset: 0x001977EC private void CalculatePathsThreaded(PathHandler pathHandler) { try { long num = 100000L; long targetTick = DateTime.UtcNow.Ticks + num; for (;;) { Path path = this.queue.Pop(); IPathInternals pathInternals = path; pathInternals.PrepareBase(pathHandler); pathInternals.AdvanceState(PathState.Processing); if (this.OnPathPreSearch != null) { this.OnPathPreSearch(path); } long ticks = DateTime.UtcNow.Ticks; pathInternals.Prepare(); if (!path.IsDone()) { this.astar.debugPathData = pathInternals.PathHandler; this.astar.debugPathID = path.pathID; pathInternals.Initialize(); while (!path.IsDone()) { pathInternals.CalculateStep(targetTick); targetTick = DateTime.UtcNow.Ticks + num; if (this.queue.IsTerminating) { path.FailWithError("AstarPath object destroyed"); } } path.duration = (float)(DateTime.UtcNow.Ticks - ticks) * 0.0001f; } pathInternals.Cleanup(); if (path.immediateCallback != null) { path.immediateCallback(path); } if (this.OnPathPostSearch != null) { this.OnPathPostSearch(path); } this.returnQueue.Enqueue(path); pathInternals.AdvanceState(PathState.ReturnQueue); } } catch (Exception ex) { if (ex is ThreadAbortException || ex is ThreadControlQueue.QueueTerminationException) { if (this.astar.logPathResults == PathLog.Heavy) { Debug.LogWarning("Shutting down pathfinding thread #" + pathHandler.threadID); } return; } Debug.LogException(ex); Debug.LogError("Unhandled exception during pathfinding. Terminating."); this.queue.TerminateReceivers(); } Debug.LogError("Error : This part should never be reached."); this.queue.ReceiverTerminated(); }