示例#1
0
    public IEnumerable <Progress> ScanAsync(NavGraph[] graphsToScan = null)
    {
        if (graphsToScan == null)
        {
            graphsToScan = graphs;
        }

        if (graphsToScan == null)
        {
            yield break;
        }

        if (isScanning)
        {
            throw new System.InvalidOperationException("Another async scan is already running");
        }

        isScanning = true;

        VerifyIntegrity();

        var graphUpdateLock = PausePathfinding();

        // Make sure all paths that are in the queue to be returned
        // are returned immediately
        // Some modifiers (e.g the funnel modifier) rely on
        // the nodes being valid when the path is returned
        pathReturnQueue.ReturnPaths(false);

        if (!Application.isPlaying)
        {
            data.FindGraphTypes();
            GraphModifier.FindAllModifiers();
        }

        int startFrame = Time.frameCount;

        yield return(new Progress(0.05F, "Pre processing graphs"));


        if (Time.frameCount != startFrame)
        {
            throw new System.Exception("Async scanning can only be done in the pro version of the A* Pathfinding Project");
        }

        if (OnPreScan != null)
        {
            OnPreScan(this);
        }

        GraphModifier.TriggerEvent(GraphModifier.EventType.PreScan);

        data.LockGraphStructure();

        var watch = System.Diagnostics.Stopwatch.StartNew();

        // Destroy previous nodes
        for (int i = 0; i < graphsToScan.Length; i++)
        {
            if (graphsToScan[i] != null)
            {
                ((IGraphInternals)graphsToScan[i]).DestroyAllNodes();
            }
        }

        // Loop through all graphs and scan them one by one
        for (int i = 0; i < graphsToScan.Length; i++)
        {
            // Skip null graphs
            if (graphsToScan[i] == null)
            {
                continue;
            }

            // Just used for progress information
            // This graph will advance the progress bar from minp to maxp
            float minp = Mathf.Lerp(0.1F, 0.8F, (float)(i) / (graphsToScan.Length));
            float maxp = Mathf.Lerp(0.1F, 0.8F, (float)(i + 0.95F) / (graphsToScan.Length));

            var progressDescriptionPrefix = "Scanning graph " + (i + 1) + " of " + graphsToScan.Length + " - ";

            // Like a foreach loop but it gets a little complicated because of the exception
            // handling (it is not possible to yield inside try-except clause).
            var coroutine = ScanGraph(graphsToScan[i]).GetEnumerator();
            while (true)
            {
                try {
                    if (!coroutine.MoveNext())
                    {
                        break;
                    }
                } catch {
                    isScanning = false;
                    data.UnlockGraphStructure();
                    graphUpdateLock.Release();
                    throw;
                }
                yield return(coroutine.Current.MapTo(minp, maxp, progressDescriptionPrefix));
            }
        }

        data.UnlockGraphStructure();
        yield return(new Progress(0.8F, "Post processing graphs"));

        if (OnPostScan != null)
        {
            OnPostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.PostScan);

        FlushWorkItems();

        yield return(new Progress(0.9F, "Computing areas"));

        hierarchicalGraph.RecalculateIfNecessary();

        yield return(new Progress(0.95F, "Late post processing"));

        // Signal that we have stopped scanning here
        // Note that no yields can happen after this point
        // since then other parts of the system can start to interfere
        isScanning = false;

        if (OnLatePostScan != null)
        {
            OnLatePostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.LatePostScan);

        euclideanEmbedding.dirty = true;
        euclideanEmbedding.RecalculatePivots();

        // Perform any blocking actions
        FlushWorkItems();
        // Resume pathfinding threads
        graphUpdateLock.Release();

        watch.Stop();
        lastScanTime = (float)watch.Elapsed.TotalSeconds;

        System.GC.Collect();

        if (logPathResults != PathLog.None && logPathResults != PathLog.OnlyErrors)
        {
            Debug.Log("Scanning - Process took " + (lastScanTime * 1000).ToString("0") + " ms to complete");
        }
    }