/** Sets up all needed variables and scans the graphs. * Calls Initialize, starts the ReturnPaths coroutine and scans all graphs. * Also starts threads if using multithreading * \see #OnAwakeSettings */ public void Awake () { //Very important to set this. Ensures the singleton pattern holds active = this; if (FindObjectsOfType (typeof(AstarPath)).Length > 1) { Debug.LogError ("You should NOT have more than one AstarPath component in the scene at any time.\n" + "This can cause serious errors since the AstarPath component builds around a singleton pattern."); } //Disable GUILayout to gain some performance, it is not used in the OnGUI call useGUILayout = false; isEditor = Application.isEditor; if (OnAwakeSettings != null) { OnAwakeSettings (); } //To make sure all graph modifiers have been enabled before scan (to avoid script run order issues) GraphModifier.FindAllModifiers (); RelevantGraphSurface.FindAllGraphSurfaces (); int numThreads = CalculateThreadCount (threadCount); threads = new Thread[numThreads]; //Thread info, will contain at least one item since the coroutine "thread" is thought of as a real thread in this case threadInfos = new PathThreadInfo[System.Math.Max(numThreads,1)]; //Set up path queue with the specified number of receivers pathQueue = new ThreadControlQueue(threadInfos.Length); for (int i=0;i<threadInfos.Length;i++) { threadInfos[i] = new PathThreadInfo(i,this,new PathHandler()); } for (int i=0;i<threads.Length;i++) { threads[i] = new Thread (new ParameterizedThreadStart (CalculatePathsThreaded)); threads[i].Name = "Pathfinding Thread " + i; threads[i].IsBackground = true; } //Start coroutine if not using multithreading if (numThreads == 0) { threadEnumerator = CalculatePaths (threadInfos[0]); } else { threadEnumerator = null; } //Start pathfinding threads for (int i=0;i<threads.Length;i++) { if (logPathResults == PathLog.Heavy) Debug.Log ("Starting pathfinding thread "+i); threads[i].Start (threadInfos[i]); } Thread graphUpdateThread = new Thread (new ParameterizedThreadStart(ProcessGraphUpdatesAsync)); graphUpdateThread.IsBackground = true; graphUpdateThread.Start (this); Initialize (); #if !PhotonImplementation // Flush work items, possibly added in initialize to load graph data FlushWorkItems(); if (scanOnStartup) { if (!astarData.cacheStartup || astarData.data_cachedStartup == null) { Scan (); } } #endif }
/** Replacement for UnityEngine's StartCoroutine */ public void StartCoroutine (IEnumerator update) { if (activeThread != null && activeThread.IsAlive) { Debug.Log ("Can only start one coroutine at a time, please end the current running thread first (activeThread)"); return; } //Execute to the first yield if (!update.MoveNext ()) { return; } activeThread = new Thread (StartCoroutineInternal); activeThread.Start (update); }
/// <param name="path">The path to wait for. The path must be started, otherwise an exception will be thrown.</param> public static void BlockUntilCalculated(Path path) { if (active == null) { throw new System.Exception("Pathfinding is not correctly initialized in this scene (yet?). " + "AstarPath.active is null.\nDo not call this function in Awake"); } if (path == null) { throw new System.ArgumentNullException("Path must not be null"); } if (active.pathProcessor.queue.IsTerminating) { return; } if (path.PipelineState == PathState.Created) { throw new System.Exception("The specified path has not been started yet."); } waitForPathDepth++; if (waitForPathDepth == 5) { Debug.LogError("You are calling the BlockUntilCalculated function recursively (maybe from a path callback). Please don't do this."); } if (path.PipelineState < PathState.ReturnQueue) { if (active.IsUsingMultithreading) { while (path.PipelineState < PathState.ReturnQueue) { if (active.pathProcessor.queue.IsTerminating) { waitForPathDepth--; throw new System.Exception("Pathfinding Threads seem to have crashed."); } // Wait for threads to calculate paths Thread.Sleep(1); active.PerformBlockingActions(true); } } else { while (path.PipelineState < PathState.ReturnQueue) { if (active.pathProcessor.queue.IsEmpty && path.PipelineState != PathState.Processing) { waitForPathDepth--; throw new System.Exception("Critical error. Path Queue is empty but the path state is '" + path.PipelineState + "'"); } // Calculate some paths active.pathProcessor.TickNonMultithreaded(); active.PerformBlockingActions(true); } } } active.pathReturnQueue.ReturnPaths(false); waitForPathDepth--; }