Пример #1
0
 protected override void Awake()
 {
     base.Awake();
     AstarPath.active = this;
     if (UnityEngine.Object.FindObjectsOfType(typeof(AstarPath)).Length > 1)
     {
         UnityEngine.Debug.LogError("You should NOT have more than one AstarPath component in the scene at any time.\nThis can cause serious errors since the AstarPath component builds around a singleton pattern.");
     }
     base.useGUILayout = false;
     if (!Application.isPlaying)
     {
         return;
     }
     if (AstarPath.OnAwakeSettings != null)
     {
         AstarPath.OnAwakeSettings();
     }
     GraphModifier.FindAllModifiers();
     RelevantGraphSurface.FindAllGraphSurfaces();
     this.InitializePathProcessor();
     this.InitializeProfiler();
     this.ConfigureReferencesInternal();
     this.InitializeAstarData();
     this.FlushWorkItems();
     this.euclideanEmbedding.dirty = true;
     if (this.scanOnStartup && (!this.data.cacheStartup || this.data.file_cachedStartup == null))
     {
         this.Scan(null);
     }
 }
Пример #2
0
        // Token: 0x060005EB RID: 1515 RVA: 0x00037D0C File Offset: 0x0003610C
        public void LoadTile(TileHandler.TileType tile, int x, int z, int rotation, int yoffset)
        {
            if (tile == null)
            {
                throw new ArgumentNullException("tile");
            }
            if (AstarPath.active == null)
            {
                return;
            }
            int index = x + z * this.graph.tileXCount;

            rotation %= 4;
            if (this.isBatching && this.reloadedInBatch[index] && this.activeTileOffsets[index] == yoffset && this.activeTileRotations[index] == rotation && this.activeTileTypes[index] == tile)
            {
                return;
            }
            if (this.isBatching)
            {
                this.reloadedInBatch[index] = true;
            }
            this.activeTileOffsets[index]   = yoffset;
            this.activeTileRotations[index] = rotation;
            this.activeTileTypes[index]     = tile;
            AstarPath.active.AddWorkItem(new AstarPath.AstarWorkItem(delegate(bool force)
            {
                if (this.activeTileOffsets[index] != yoffset || this.activeTileRotations[index] != rotation || this.activeTileTypes[index] != tile)
                {
                    return(true);
                }
                GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate);
                Int3[] verts;
                int[] tris;
                tile.Load(out verts, out tris, rotation, yoffset);
                Bounds tileBounds = this.graph.GetTileBounds(x, z, tile.Width, tile.Depth);
                Int3 @int         = (Int3)tileBounds.min;
                @int         = -@int;
                Int3[] array = null;
                int[] array2 = null;
                int num;
                int num2;
                this.CutPoly(verts, tris, ref array, ref array2, out num, out num2, null, @int, tileBounds, (TileHandler.CutMode) 3, 0);
                this.DelaunayRefinement(array, array2, ref num, ref num2, true, false, -@int);
                if (num2 != array2.Length)
                {
                    array2 = TileHandler.ShrinkArray <int>(array2, num2);
                }
                if (num != array.Length)
                {
                    array = TileHandler.ShrinkArray <Int3>(array, num);
                }
                int w = (rotation % 2 != 0) ? tile.Depth : tile.Width;
                int d = (rotation % 2 != 0) ? tile.Width : tile.Depth;
                this.graph.ReplaceTile(x, z, w, d, array, array2, false);
                GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);
                AstarPath.active.QueueWorkItemFloodFill();
                return(true);
            }));
        }
Пример #3
0
        static public void Initialize()
        {
            cache    = new CacheCore();
            modifier = new GraphModifier();
            hacker   = new RespHacker();

            _AppendToFiddler();
        }
Пример #4
0
        public void LoadTile(List <NavmeshCut> navmeshCuts, MyTileHandler.TileType tile, int x, int z, int rotation, int yoffset)
        {
            if (tile == null)
            {
                throw new ArgumentNullException("tile");
            }
            int num = x + z * this.graph.tileXCount;

            rotation %= 4;
            if (this.isBatching && this.reloadedInBatch[num] && this.activeTileOffsets[num] == yoffset && this.activeTileRotations[num] == rotation && this.activeTileTypes[num] == tile)
            {
                return;
            }
            if (this.isBatching)
            {
                this.reloadedInBatch[num] = true;
            }
            this.activeTileOffsets[num]   = yoffset;
            this.activeTileRotations[num] = rotation;
            this.activeTileTypes[num]     = tile;
            if (this.activeTileOffsets[num] != yoffset || this.activeTileRotations[num] != rotation || this.activeTileTypes[num] != tile)
            {
                return;
            }
            GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate);
            Int3[] verts;
            int[]  tris;
            tile.Load(out verts, out tris, rotation, yoffset);
            Bounds tileBounds = this.graph.GetTileBounds(x, z, tile.Width, tile.Depth);
            Int3   vInt       = (Int3)tileBounds.min;

            vInt = -vInt;
            Int3[] array  = null;
            int[]  array2 = null;
            int    num2;
            int    num3;

            this.CutPoly(navmeshCuts, verts, tris, ref array, ref array2, out num2, out num3, null, vInt, tileBounds, (MyTileHandler.CutMode) 3, 0);
            this.DelaunayRefinement(array, array2, ref num2, ref num3, true, false, -vInt);
            if (num3 != array2.Length)
            {
                array2 = MyTileHandler.ShrinkArray <int>(array2, num3);
            }
            if (num2 != array.Length)
            {
                array = MyTileHandler.ShrinkArray <Int3>(array, num2);
            }
            int w = (rotation % 2 != 0) ? tile.Depth : tile.Width;
            int d = (rotation % 2 != 0) ? tile.Width : tile.Depth;

            this.graph.ReplaceTile(x, z, w, d, array, array2, false);
            GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);
        }
Пример #5
0
        // Token: 0x060029BC RID: 10684 RVA: 0x001C4000 File Offset: 0x001C2200
        public void LoadTile(TileHandler.TileType tile, int x, int z, int rotation, int yoffset)
        {
            if (tile == null)
            {
                throw new ArgumentNullException("tile");
            }
            if (AstarPath.active == null)
            {
                return;
            }
            int index = x + z * this.tileXCount;

            rotation %= 4;
            if (this.isBatching && this.reloadedInBatch[index] && this.activeTileOffsets[index] == yoffset && this.activeTileRotations[index] == rotation && this.activeTileTypes[index] == tile)
            {
                return;
            }
            this.reloadedInBatch[index]    |= this.isBatching;
            this.activeTileOffsets[index]   = yoffset;
            this.activeTileRotations[index] = rotation;
            this.activeTileTypes[index]     = tile;
            AstarPath.active.AddWorkItem(new AstarWorkItem(delegate(IWorkItemContext context, bool force)
            {
                if (this.activeTileOffsets[index] != yoffset || this.activeTileRotations[index] != rotation || this.activeTileTypes[index] != tile)
                {
                    return(true);
                }
                GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate);
                Int3[] verts;
                int[] tris;
                tile.Load(out verts, out tris, rotation, yoffset);
                TileHandler.CuttingResult cuttingResult = this.CutPoly(verts, tris, null, this.graph.transform, new IntRect(x, z, x + tile.Width - 1, z + tile.Depth - 1), TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual, -1);
                int num = cuttingResult.tris.Length;
                this.DelaunayRefinement(cuttingResult.verts, cuttingResult.tris, ref num, true, false);
                if (num != cuttingResult.tris.Length)
                {
                    cuttingResult.tris = Memory.ShrinkArray <int>(cuttingResult.tris, num);
                }
                int num2 = (rotation % 2 == 0) ? tile.Width : tile.Depth;
                int num3 = (rotation % 2 == 0) ? tile.Depth : tile.Width;
                if (num2 != 1 || num3 != 1)
                {
                    throw new Exception("Only tiles of width = depth = 1 are supported at this time");
                }
                this.graph.ReplaceTile(x, z, cuttingResult.verts, cuttingResult.tris);
                if (!this.isBatching)
                {
                    GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);
                }
                context.QueueFloodFill();
                return(true);
            }));
        }
Пример #6
0
    /// <summary>
    /// 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: <see cref="OnAwakeSettings"/>
    /// </summary>
    protected override void Awake()
    {
        base.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;

        // This class uses the [ExecuteInEditMode] attribute
        // So Awake is called even when not playing
        // Don't do anything when not in play mode
        if (!Application.isPlaying)
        {
            return;
        }

        if (OnAwakeSettings != null)
        {
            OnAwakeSettings();
        }

        // To make sure all graph modifiers have been enabled before scan (to avoid script execution order issues)
        GraphModifier.FindAllModifiers();
        RelevantGraphSurface.FindAllGraphSurfaces();

        InitializePathProcessor();
        InitializeProfiler();
        ConfigureReferencesInternal();
        InitializeAstarData();

        // Flush work items, possibly added in InitializeAstarData to load graph data
        FlushWorkItems();

        euclideanEmbedding.dirty = true;

        navmeshUpdates.OnEnable();

        if (scanOnStartup && (!data.cacheStartup || data.file_cachedStartup == null))
        {
            Scan();
        }
    }
Пример #7
0
 // Token: 0x060029AE RID: 10670 RVA: 0x001C2A8C File Offset: 0x001C0C8C
 public void EndBatchLoad()
 {
     if (!this.isBatching)
     {
         throw new Exception("Ending batching when batching has not been started");
     }
     for (int i = 0; i < this.reloadedInBatch.Length; i++)
     {
         this.reloadedInBatch[i] = false;
     }
     this.isBatching = false;
     AstarPath.active.AddWorkItem(new AstarWorkItem(delegate(bool force)
     {
         this.graph.EndBatchTileUpdate();
         GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);
         return(true);
     }));
 }
Пример #8
0
 public void ClearTile(int x, int z)
 {
     if (AstarPath.active == null)
     {
         return;
     }
     if (x < 0 || z < 0 || x >= this.tileXCount || z >= this.tileZCount)
     {
         return;
     }
     AstarPath.active.AddWorkItem(new AstarWorkItem(delegate(IWorkItemContext context, bool force)
     {
         this.graph.ReplaceTile(x, z, new Int3[0], new int[0]);
         this.activeTileTypes[x + z * this.tileXCount] = null;
         GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);
         context.QueueFloodFill();
         return(true);
     }));
 }
Пример #9
0
    public IEnumerable <Progress> ScanAsync(NavGraph[] graphsToScan = null)
    {
        if (graphsToScan == null)
        {
            graphsToScan = this.graphs;
        }
        if (graphsToScan == null)
        {
            yield break;
        }
        if (this.isScanning)
        {
            throw new InvalidOperationException("Another async scan is already running");
        }
        this.isScanning = true;
        this.VerifyIntegrity();
        PathProcessor.GraphUpdateLock graphUpdateLock = this.PausePathfinding();
        this.pathReturnQueue.ReturnPaths(false);
        if (!Application.isPlaying)
        {
            this.data.FindGraphTypes();
            GraphModifier.FindAllModifiers();
        }
        yield return(new Progress(0.05f, "Pre processing graphs"));

        if (AstarPath.OnPreScan != null)
        {
            AstarPath.OnPreScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.PreScan);
        this.data.LockGraphStructure(false);
        Stopwatch watch = Stopwatch.StartNew();

        for (int j = 0; j < graphsToScan.Length; j++)
        {
            if (graphsToScan[j] != null)
            {
                graphsToScan[j].DestroyAllNodesInternal();
            }
        }
        int num;

        for (int i = 0; i < graphsToScan.Length; i = num + 1)
        {
            if (graphsToScan[i] != null)
            {
                float  minp = Mathf.Lerp(0.1f, 0.8f, (float)i / (float)graphsToScan.Length);
                float  maxp = Mathf.Lerp(0.1f, 0.8f, ((float)i + 0.95f) / (float)graphsToScan.Length);
                string progressDescriptionPrefix = string.Concat(new object[]
                {
                    "Scanning graph ",
                    i + 1,
                    " of ",
                    graphsToScan.Length,
                    " - "
                });
                IEnumerator <Progress> coroutine = this.ScanGraph(graphsToScan[i]).GetEnumerator();
                for (;;)
                {
                    try
                    {
                        if (!coroutine.MoveNext())
                        {
                            break;
                        }
                    }
                    catch
                    {
                        this.isScanning = false;
                        this.data.UnlockGraphStructure();
                        graphUpdateLock.Release();
                        throw;
                    }
                    yield return(new Progress(Mathf.Lerp(minp, maxp, coroutine.Current.progress), progressDescriptionPrefix + coroutine.Current.description));
                }
                progressDescriptionPrefix = null;
                coroutine = null;
            }
            num = i;
        }
        this.data.UnlockGraphStructure();
        yield return(new Progress(0.8f, "Post processing graphs"));

        if (AstarPath.OnPostScan != null)
        {
            AstarPath.OnPostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.PostScan);
        this.FlushWorkItems();
        yield return(new Progress(0.9f, "Computing areas"));

        this.FloodFill();
        yield return(new Progress(0.95f, "Late post processing"));

        this.isScanning = false;
        if (AstarPath.OnLatePostScan != null)
        {
            AstarPath.OnLatePostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.LatePostScan);
        this.euclideanEmbedding.dirty = true;
        this.euclideanEmbedding.RecalculatePivots();
        this.FlushWorkItems();
        graphUpdateLock.Release();
        watch.Stop();
        this.lastScanTime = (float)watch.Elapsed.TotalSeconds;
        GC.Collect();
        this.Log("Scanning - Process took " + (this.lastScanTime * 1000f).ToString("0") + " ms to complete");
        yield break;
        yield break;
    }
Пример #10
0
    /** 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
     */
    void Awake()
    {
        //Very important to set this. Ensures the singleton pattern holds
        active = this;

        if (FindObjectsOfType(typeof(AstarPath)).Length > 1)
        {
            EB.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;

        // This class uses the [ExecuteInEditMode] attribute
        // So Awake is called even when not playing
        // Don't do anything when not in play mode
        if (!Application.isPlaying)
        {
            return;
        }

        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(i, threadInfos.Length));
        }

        //Start coroutine if not using multithreading
        if (numThreads == 0)
        {
            threadEnumerator = CalculatePaths(threadInfos[0]);
        }
        else
        {
            threadEnumerator = null;
        }

#if !UNITY_WEBGL
        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 pathfinding threads
        for (int i = 0; i < threads.Length; i++)
        {
            if (logPathResults == PathLog.Heavy)
            {
                EB.Debug.Log("Starting pathfinding thread {0}", i);
            }
            threads[i].Start(threadInfos[i]);
        }

        if (numThreads != 0)
        {
            graphUpdateThread = new Thread(new ParameterizedThreadStart(ProcessGraphUpdatesAsync));
            graphUpdateThread.IsBackground = true;

            // Set the thread priority for graph updates
            // Unless compiling for windows store or windows phone which does not support it
#if !UNITY_WINRT
            graphUpdateThread.Priority = System.Threading.ThreadPriority.Lowest;
#endif
            graphUpdateThread.Start(this);
        }
#endif

        Initialize();

        // Flush work items, possibly added in initialize to load graph data
        FlushWorkItems();

        euclideanEmbedding.dirty = true;

#if BNICKSON_UPDATED
        // added !AStarPathfindingUtils.WillNavMeshBeBuiltFromInputMeshOnLevelBegin()
        if (scanOnStartup && !AStarPathfindingUtils.WillNavMeshBeBuiltFromInputMeshOnLevelBegin())
#else
        if (scanOnStartup)
#endif
        {
            if (!astarData.cacheStartup || astarData.file_cachedStartup == null)
            {
                Scan();

#if BNICKSON_UPDATED
                EventManager.instance.Raise(new NavMeshScanEvent());
#endif
            }
        }
    }
Пример #11
0
    public IEnumerable <Progress> ScanAsync()
    {
        if (this.graphs == null)
        {
            yield break;
        }
        this.isScanning = true;
        this.euclideanEmbedding.dirty = false;
        this.VerifyIntegrity();
        this.BlockUntilPathQueueBlocked();
        this.pathReturnQueue.ReturnPaths(false);
        this.BlockUntilPathQueueBlocked();
        if (!Application.isPlaying)
        {
            GraphModifier.FindAllModifiers();
            RelevantGraphSurface.FindAllGraphSurfaces();
        }
        RelevantGraphSurface.UpdateAllPositions();
        this.astarData.UpdateShortcuts();
        yield return(new Progress(0.05f, "Pre processing graphs"));

        if (AstarPath.OnPreScan != null)
        {
            AstarPath.OnPreScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.PreScan);
        Stopwatch watch = Stopwatch.StartNew();

        for (int j = 0; j < this.graphs.Length; j++)
        {
            if (this.graphs[j] != null)
            {
                this.graphs[j].GetNodes(delegate(GraphNode node)
                {
                    node.Destroy();
                    return(true);
                });
            }
        }
        for (int i = 0; i < this.graphs.Length; i++)
        {
            if (this.graphs[i] != null)
            {
                float  minp = Mathf.Lerp(0.1f, 0.8f, (float)i / (float)this.graphs.Length);
                float  maxp = Mathf.Lerp(0.1f, 0.8f, ((float)i + 0.95f) / (float)this.graphs.Length);
                string progressDescriptionPrefix = string.Concat(new object[]
                {
                    "Scanning graph ",
                    i + 1,
                    " of ",
                    this.graphs.Length,
                    " - "
                });
                foreach (Progress progress in this.ScanGraph(this.graphs[i]))
                {
                    yield return(new Progress(Mathf.Lerp(minp, maxp, progress.progress), progressDescriptionPrefix + progress.description));
                }
            }
        }
        yield return(new Progress(0.8f, "Post processing graphs"));

        if (AstarPath.OnPostScan != null)
        {
            AstarPath.OnPostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.PostScan);
        try
        {
            this.FlushWorkItemsInternal(false);
        }
        catch (Exception exception)
        {
            UnityEngine.Debug.LogException(exception);
        }
        yield return(new Progress(0.9f, "Computing areas"));

        this.FloodFill();
        this.VerifyIntegrity();
        yield return(new Progress(0.95f, "Late post processing"));

        this.isScanning = false;
        if (AstarPath.OnLatePostScan != null)
        {
            AstarPath.OnLatePostScan(this);
        }
        GraphModifier.TriggerEvent(GraphModifier.EventType.LatePostScan);
        this.euclideanEmbedding.dirty = true;
        this.euclideanEmbedding.RecalculatePivots();
        this.PerformBlockingActions(true, true);
        watch.Stop();
        this.lastScanTime = (float)watch.Elapsed.TotalSeconds;
        GC.Collect();
        this.Log("Scanning - Process took " + (this.lastScanTime * 1000f).ToString("0") + " ms to complete");
        yield break;
    }
Пример #12
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");
        }
    }
Пример #13
0
        /** Load a tile at tile coordinate \a x, \a z.
         *
         * \param tile Tile type to load
         * \param x Tile x coordinate (first tile is at (0,0), second at (1,0) etc.. ).
         * \param z Tile z coordinate.
         * \param rotation Rotate tile by 90 degrees * value.
         * \param yoffset Offset Y coordinates by this amount. In Int3 space, so if you have a world space
         * offset, multiply by Int3.Precision and round to the nearest integer before calling this function.
         */
        public void LoadTile(TileType tile, int x, int z, int rotation, int yoffset)
        {
            if (tile == null)
            {
                throw new ArgumentNullException("tile");
            }

            if (AstarPath.active == null)
            {
                return;
            }

            int index = x + z * graph.tileXCount;

            rotation = rotation % 4;

            // If loaded during this batch with the same settings, skip it
            if (isBatching && reloadedInBatch[index] && activeTileOffsets[index] == yoffset && activeTileRotations[index] == rotation && activeTileTypes[index] == tile)
            {
                return;
            }

            reloadedInBatch[index] |= isBatching;

            activeTileOffsets[index]   = yoffset;
            activeTileRotations[index] = rotation;
            activeTileTypes[index]     = tile;

            //Add a work item
            //This will pause pathfinding as soon as possible
            //and call the delegate when it is safe to update graphs
            AstarPath.active.AddWorkItem(new AstarPath.AstarWorkItem(delegate(bool force) {
                // If this was not the correct settings to load with, ignore
                if (!(activeTileOffsets[index] == yoffset && activeTileRotations[index] == rotation && activeTileTypes[index] == tile))
                {
                    return(true);
                }

                GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate);

                Int3[] verts;
                int[] tris;

                tile.Load(out verts, out tris, rotation, yoffset);

                //Calculate tile bounds so that the correct cutting offset can be used
                //The tile will be cut in local space (i.e it is at the world origin) so cuts need to be translated
                //to that point from their world space coordinates
                Bounds r      = graph.GetTileBounds(x, z, tile.Width, tile.Depth);
                var cutOffset = (Int3)r.min;
                cutOffset     = -cutOffset;

                Int3[] outVerts = null;
                int[] outTris   = null;
                int vCount, tCount;

                //Cut the polygon
                CutPoly(verts, tris, ref outVerts, ref outTris, out vCount, out tCount, null, cutOffset, r);

                //Refine to remove bad triangles
                DelaunayRefinement(outVerts, outTris, ref vCount, ref tCount, true, false, -cutOffset);

                if (tCount != outTris.Length)
                {
                    outTris = ShrinkArray(outTris, tCount);
                }
                if (vCount != outVerts.Length)
                {
                    outVerts = ShrinkArray(outVerts, vCount);
                }

                // Rotate the mask correctly
                // and update width and depth to match rotation
                // (width and depth will swap if rotated 90 or 270 degrees )
                int newWidth = rotation % 2 == 0 ? tile.Width : tile.Depth;
                int newDepth = rotation % 2 == 0 ? tile.Depth : tile.Width;

                //Replace the tile using the final vertices and triangles
                //The vertices are still in local space
                graph.ReplaceTile(x, z, newWidth, newDepth, outVerts, outTris, false);

                //Trigger post update event
                //This can trigger for example recalculation of navmesh links
                GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate);

#if BNICKSON_UPDATED
                AStarPathfindingAbilityBridge.NavMeshHasBeenUpdated();
#endif

                //Flood fill everything to make sure graph areas are still valid
                //This tends to take more than 50% of the calculation time
                AstarPath.active.QueueWorkItemFloodFill();

                return(true);
            }));
        }