Ejemplo n.º 1
0
        /** Creates a mesh of the surfaces of the navmesh for use in OnDrawGizmos in the editor */
        public static void CreateNavmeshSurfaceVisualization(this NavmeshBase navmeshBase, NavmeshTile tile, GraphGizmoHelper helper)
        {
            // Vertex array might be a bit larger than necessary, but that's ok
            var vertices = PF.ArrayPool <Vector3> .Claim(tile.nodes.Length *3);

            var colors = PF.ArrayPool <Color> .Claim(tile.nodes.Length *3);

            for (int j = 0; j < tile.nodes.Length; j++)
            {
                var  node = tile.nodes[j];
                Int3 v0, v1, v2;
                node.GetVertices(out v0, out v1, out v2);
                vertices[j * 3 + 0] = (Vector3)v0;
                vertices[j * 3 + 1] = (Vector3)v1;
                vertices[j * 3 + 2] = (Vector3)v2;

                var color = helper.NodeColor(node);
                colors[j * 3 + 0] = colors[j * 3 + 1] = colors[j * 3 + 2] = color;
            }

            if (navmeshBase.showMeshSurface)
            {
                helper.DrawTriangles(vertices, colors, tile.nodes.Length);
            }
            if (navmeshBase.showMeshOutline)
            {
                helper.DrawWireTriangles(vertices, colors, tile.nodes.Length);
            }

            // Return lists to the pool
            PF.ArrayPool <Vector3> .Release(ref vertices);

            PF.ArrayPool <Color> .Release(ref colors);
        }
Ejemplo n.º 2
0
        // Token: 0x06002696 RID: 9878 RVA: 0x001A8890 File Offset: 0x001A6A90
        public void OnDrawGizmosSelected()
        {
            List <List <Vector3> > list = ListPool <List <Vector3> > .Claim();

            this.GetContour(list);
            Color color = Color.Lerp(NavmeshCut.GizmoColor, Color.white, 0.5f);

            color.a     *= 0.5f;
            Gizmos.color = color;
            NavmeshBase    navmeshBase    = (AstarPath.active != null) ? (AstarPath.active.data.recastGraph ?? AstarPath.active.data.navmesh) : null;
            GraphTransform graphTransform = (navmeshBase != null) ? navmeshBase.transform : GraphTransform.identityTransform;
            float          y  = this.GetY(graphTransform);
            float          y2 = y - this.height * 0.5f;
            float          y3 = y + this.height * 0.5f;

            for (int i = 0; i < list.Count; i++)
            {
                List <Vector3> list2 = list[i];
                for (int j = 0; j < list2.Count; j++)
                {
                    Vector3 vector  = graphTransform.InverseTransform(list2[j]);
                    Vector3 vector2 = graphTransform.InverseTransform(list2[(j + 1) % list2.Count]);
                    Vector3 point   = vector;
                    Vector3 point2  = vector2;
                    Vector3 point3  = vector;
                    Vector3 point4  = vector2;
                    point.y  = (point2.y = y2);
                    point3.y = (point4.y = y3);
                    Gizmos.DrawLine(graphTransform.Transform(point), graphTransform.Transform(point2));
                    Gizmos.DrawLine(graphTransform.Transform(point3), graphTransform.Transform(point4));
                    Gizmos.DrawLine(graphTransform.Transform(point), graphTransform.Transform(point3));
                }
            }
            ListPool <List <Vector3> > .Release(ref list);
        }
Ejemplo n.º 3
0
 internal void Destroy()
 {
     if (this.nodes.Length > 0)
     {
         int  tileIndex  = NavmeshBase.GetTileIndex(this.nodes[0].GetVertexIndex(0));
         uint graphIndex = this.nodes[0].GraphIndex;
         for (int i = 0; i < this.nodes.Length; i++)
         {
             TriangleMeshNode triangleMeshNode = this.nodes[i];
             if (triangleMeshNode.connections != null)
             {
                 for (int j = 0; j < triangleMeshNode.connections.Length; j++)
                 {
                     TriangleMeshNode triangleMeshNode2 = triangleMeshNode.connections[j].node as TriangleMeshNode;
                     if (triangleMeshNode2 != null && triangleMeshNode2.GraphIndex == graphIndex && NavmeshBase.GetTileIndex(triangleMeshNode2.GetVertexIndex(0)) == tileIndex)
                     {
                         triangleMeshNode.connections[j].node = null;
                     }
                 }
             }
         }
         for (int k = 0; k < this.nodes.Length; k++)
         {
             this.nodes[k].Destroy();
         }
     }
     this.nodes = null;
     ObjectPool <BBTree> .Release(ref this.bbTree);
 }
Ejemplo n.º 4
0
        public RichFunnel()
        {
            left = Pathfinding.Util.ListPool <Vector3> .Claim();

            right = Pathfinding.Util.ListPool <Vector3> .Claim();

            nodes      = new List <TriangleMeshNode>();
            this.graph = null;
        }
Ejemplo n.º 5
0
 public override void OnEnterPool()
 {
     left.Clear();
     right.Clear();
     nodes.Clear();
     graph       = null;
     currentNode = 0;
     checkForDestroyedNodesCounter = 0;
 }
Ejemplo n.º 6
0
        /** Returns a rect containing the indices of all tiles touching the specified bounds.
         * \param rect Graph space rectangle (in graph space all tiles are on the XZ plane regardless of graph rotation and other transformations, the first tile has a corner at the origin)
         */
        public static IntRect GetTouchingTilesInGraphSpace(this NavmeshBase self, Rect rect)
        {
            // Calculate world bounds of all affected tiles
            var r = new IntRect(Mathf.FloorToInt(rect.xMin / self.TileWorldSizeX), Mathf.FloorToInt(rect.yMin / self.TileWorldSizeZ), Mathf.FloorToInt(rect.xMax / self.TileWorldSizeX), Mathf.FloorToInt(rect.yMax / self.TileWorldSizeZ));

            // Clamp to bounds
            r = IntRect.Intersection(r, new IntRect(0, 0, self.tileXCount - 1, self.tileZCount - 1));
            return(r);
        }
Ejemplo n.º 7
0
 public static void DrawUnwalkableNodes(this NavmeshBase navmeshBase, float size)
 {
     Gizmos.color = AstarColor.UnwalkableNode;
     navmeshBase.GetNodes(node => {
         if (!node.Walkable)
         {
             Gizmos.DrawCube((Vector3)node.position, Vector3.one * size);
         }
     });
 }
Ejemplo n.º 8
0
        /** Returns an XZ bounds object with the bounds of a group of tiles in graph space */
        public static Bounds GetTileBoundsInGraphSpace(this NavmeshBase navmeshBase, int x, int z, int width = 1, int depth = 1)
        {
            var b = new Bounds();

            b.SetMinMax(
                new Vector3(x * navmeshBase.TileWorldSizeX, 0, z * navmeshBase.TileWorldSizeZ),
                new Vector3((x + width) * navmeshBase.TileWorldSizeX, navmeshBase.forcedBoundsSize.y, (z + depth) * navmeshBase.TileWorldSizeZ)
                );
            return(b);
        }
Ejemplo n.º 9
0
 // Token: 0x060026A7 RID: 9895 RVA: 0x001A8E50 File Offset: 0x001A7050
 private void OnDisable()
 {
     if (this.handler != null)
     {
         NavmeshClipper.RemoveEnableCallback(new Action <NavmeshClipper>(this.HandleOnEnableCallback), new Action <NavmeshClipper>(this.HandleOnDisableCallback));
         this.forcedReloadRects.Clear();
         NavmeshBase graph = this.handler.graph;
         graph.OnRecalculatedTiles = (Action <NavmeshTile[]>)Delegate.Remove(graph.OnRecalculatedTiles, new Action <NavmeshTile[]>(this.OnRecalculatedTiles));
     }
 }
Ejemplo n.º 10
0
 private NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z, int threadIndex)
 {
     if (mesh.tris == null)
     {
         throw new ArgumentNullException("mesh.tris");
     }
     if (mesh.verts == null)
     {
         throw new ArgumentNullException("mesh.verts");
     }
     if (mesh.tris.Length % 3 != 0)
     {
         throw new ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
     }
     if (mesh.verts.Length >= 4095)
     {
         if (this.tileXCount * this.tileZCount == 1)
         {
             throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\n<b>Try enabling tiling in the recast graph settings.</b>\n");
         }
         throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\n<b>Try reducing tile size or enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector</b>");
     }
     else
     {
         NavmeshTile navmeshTile = new NavmeshTile
         {
             x      = x,
             z      = z,
             w      = 1,
             d      = 1,
             tris   = mesh.tris,
             bbTree = new BBTree()
         };
         navmeshTile.vertsInGraphSpace = Utility.RemoveDuplicateVertices(mesh.verts, navmeshTile.tris);
         navmeshTile.verts             = (Int3[])navmeshTile.vertsInGraphSpace.Clone();
         this.transform.Transform(navmeshTile.verts);
         uint num = (uint)(this.active.data.graphs.Length + threadIndex);
         if (num > 255u)
         {
             throw new Exception("Graph limit reached. Multithreaded recast calculations cannot be done because a few scratch graph indices are required.");
         }
         int num2 = x + z * this.tileXCount;
         num2 <<= 12;
         TriangleMeshNode.SetNavmeshHolder((int)num, navmeshTile);
         object active = this.active;
         lock (active)
         {
             navmeshTile.nodes = base.CreateNodes(navmeshTile.tris, num2, num);
         }
         navmeshTile.bbTree.RebuildFrom(navmeshTile.nodes);
         NavmeshBase.CreateNodeConnections(navmeshTile.nodes);
         TriangleMeshNode.SetNavmeshHolder((int)num, null);
         return(navmeshTile);
     }
 }
Ejemplo n.º 11
0
        /** Returns a rect containing the indices of all tiles touching the specified bounds */
        public static IntRect GetTouchingTiles(this NavmeshBase self, Bounds bounds)
        {
            bounds = self.transform.InverseTransform(bounds);

            // Calculate world bounds of all affected tiles
            var r = new IntRect(Mathf.FloorToInt(bounds.min.x / self.TileWorldSizeX), Mathf.FloorToInt(bounds.min.z / self.TileWorldSizeZ), Mathf.FloorToInt(bounds.max.x / self.TileWorldSizeX), Mathf.FloorToInt(bounds.max.z / self.TileWorldSizeZ));

            // Clamp to bounds
            r = IntRect.Intersection(r, new IntRect(0, 0, self.tileXCount - 1, self.tileZCount - 1));
            return(r);
        }
Ejemplo n.º 12
0
 private void FindGraph()
 {
     if (AstarPath.active != null)
     {
         NavmeshBase navmeshBase = AstarPath.active.data.recastGraph ?? AstarPath.active.data.navmesh;
         if (navmeshBase != null)
         {
             this.UseSpecifiedHandler(new TileHandler(navmeshBase));
             this.handler.CreateTileTypesFromGraph();
         }
     }
 }
Ejemplo n.º 13
0
 // Token: 0x060026AA RID: 9898 RVA: 0x001A8F48 File Offset: 0x001A7148
 private void FindGraph()
 {
     if (AstarPath.active != null)
     {
         NavmeshBase navmeshBase = AstarPath.active.data.FindGraphWhichInheritsFrom(typeof(NavmeshBase)) as NavmeshBase;
         if (navmeshBase != null)
         {
             this.UseSpecifiedHandler(new TileHandler(navmeshBase));
             this.handler.CreateTileTypesFromGraph();
         }
     }
 }
Ejemplo n.º 14
0
 // Token: 0x060021A0 RID: 8608 RVA: 0x0018F05E File Offset: 0x0018D25E
 public RichFunnel Initialize(RichPath path, NavmeshBase graph)
 {
     if (graph == null)
     {
         throw new ArgumentNullException("graph");
     }
     if (this.graph != null)
     {
         throw new InvalidOperationException("Trying to initialize an already initialized object. " + graph);
     }
     this.graph = graph;
     this.path  = path;
     return(this);
 }
Ejemplo n.º 15
0
 public TileHandler(NavmeshBase graph)
 {
     if (graph == null)
     {
         throw new ArgumentNullException("graph");
     }
     if (graph.GetTiles() == null)
     {
         Debug.LogWarning("Creating a TileHandler for a graph with no tiles. Please scan the graph before creating a TileHandler");
     }
     this.tileXCount          = graph.tileXCount;
     this.tileZCount          = graph.tileZCount;
     this.activeTileTypes     = new TileHandler.TileType[this.tileXCount * this.tileZCount];
     this.activeTileRotations = new int[this.activeTileTypes.Length];
     this.activeTileOffsets   = new int[this.activeTileTypes.Length];
     this.reloadedInBatch     = new bool[this.activeTileTypes.Length];
     this.cuts  = new GridLookup <NavmeshClipper>(new Int2(this.tileXCount, this.tileZCount));
     this.graph = graph;
 }
Ejemplo n.º 16
0
 // Token: 0x060026A5 RID: 9893 RVA: 0x001A8D18 File Offset: 0x001A6F18
 public void UseSpecifiedHandler(TileHandler newHandler)
 {
     if (!base.enabled)
     {
         throw new InvalidOperationException("TileHandlerHelper is disabled");
     }
     if (this.handler != null)
     {
         NavmeshClipper.RemoveEnableCallback(new Action <NavmeshClipper>(this.HandleOnEnableCallback), new Action <NavmeshClipper>(this.HandleOnDisableCallback));
         NavmeshBase graph = this.handler.graph;
         graph.OnRecalculatedTiles = (Action <NavmeshTile[]>)Delegate.Remove(graph.OnRecalculatedTiles, new Action <NavmeshTile[]>(this.OnRecalculatedTiles));
     }
     this.handler = newHandler;
     if (this.handler != null)
     {
         NavmeshClipper.AddEnableCallback(new Action <NavmeshClipper>(this.HandleOnEnableCallback), new Action <NavmeshClipper>(this.HandleOnDisableCallback));
         NavmeshBase graph2 = this.handler.graph;
         graph2.OnRecalculatedTiles = (Action <NavmeshTile[]>)Delegate.Combine(graph2.OnRecalculatedTiles, new Action <NavmeshTile[]>(this.OnRecalculatedTiles));
     }
 }
Ejemplo n.º 17
0
        internal void Destroy()
        {
            if (nodes.Length > 0)
            {
                // Get this tile's index from the first node
                var tileIndex  = NavmeshBase.GetTileIndex(nodes[0].GetVertexIndex(0));
                var graphIndex = nodes[0].GraphIndex;

                // Destroy the nodes
                // To avoid removing connections one by one, which is very inefficient
                // we set all connections to other nodes in the same tile to null since
                // we already know that their connections will be destroyed as well.
                // This reduces the time it takes to destroy the nodes by approximately 50%
                for (int i = 0; i < nodes.Length; i++)
                {
                    var node = nodes[i];
                    if (node.connections != null)
                    {
                        for (int j = 0; j < node.connections.Length; j++)
                        {
                            var otherMesh = node.connections[j].node as TriangleMeshNode;
                            // Check if the nodes are in the same graph and the same tile
                            if (otherMesh != null && otherMesh.GraphIndex == graphIndex && NavmeshBase.GetTileIndex(otherMesh.GetVertexIndex(0)) == tileIndex)
                            {
                                node.connections[j].node = null;
                            }
                        }
                    }
                }

                // This will also remove old connections
                for (int i = 0; i < nodes.Length; i++)
                {
                    nodes[i].Destroy();
                }
            }

            nodes = null;
            graph = null;
            ObjectPool <BBTree> .Release(ref bbTree);
        }
Ejemplo n.º 18
0
 /** Returns a bounds object with the bounding box of a group of tiles.
  * The bounding box is defined in world space.
  */
 public static Bounds GetTileBounds(this NavmeshBase navmeshBase, int x, int z, int width = 1, int depth = 1)
 {
     return(navmeshBase.transform.Transform(navmeshBase.GetTileBoundsInGraphSpace(x, z, width, depth)));
 }
Ejemplo n.º 19
0
 public NavmeshUpdateSettings(NavmeshBase graph)
 {
     this.graph = graph;
 }
Ejemplo n.º 20
0
        // Token: 0x06002140 RID: 8512 RVA: 0x001890A0 File Offset: 0x001872A0
        public void Initialize(Seeker seeker, Path path, bool mergePartEndpoints, bool simplificationMode)
        {
            if (path.error)
            {
                throw new ArgumentException("Path has an error");
            }
            List <GraphNode> path2 = path.path;

            if (path2.Count == 0)
            {
                throw new ArgumentException("Path traverses no nodes");
            }
            this.seeker = seeker;
            for (int i = 0; i < this.parts.Count; i++)
            {
                RichFunnel  richFunnel  = this.parts[i] as RichFunnel;
                RichSpecial richSpecial = this.parts[i] as RichSpecial;
                if (richFunnel != null)
                {
                    ObjectPool <RichFunnel> .Release(ref richFunnel);
                }
                else if (richSpecial != null)
                {
                    ObjectPool <RichSpecial> .Release(ref richSpecial);
                }
            }
            this.Clear();
            this.Endpoint = path.vectorPath[path.vectorPath.Count - 1];
            for (int j = 0; j < path2.Count; j++)
            {
                if (path2[j] is TriangleMeshNode)
                {
                    NavmeshBase navmeshBase = AstarData.GetGraph(path2[j]) as NavmeshBase;
                    if (navmeshBase == null)
                    {
                        throw new Exception("Found a TriangleMeshNode that was not in a NavmeshBase graph");
                    }
                    RichFunnel richFunnel2 = ObjectPool <RichFunnel> .Claim().Initialize(this, navmeshBase);

                    richFunnel2.funnelSimplification = simplificationMode;
                    int  num        = j;
                    uint graphIndex = path2[num].GraphIndex;
                    while (j < path2.Count && (path2[j].GraphIndex == graphIndex || path2[j] is NodeLink3Node))
                    {
                        j++;
                    }
                    j--;
                    if (num == 0)
                    {
                        richFunnel2.exactStart = path.vectorPath[0];
                    }
                    else
                    {
                        richFunnel2.exactStart = (Vector3)path2[mergePartEndpoints ? (num - 1) : num].position;
                    }
                    if (j == path2.Count - 1)
                    {
                        richFunnel2.exactEnd = path.vectorPath[path.vectorPath.Count - 1];
                    }
                    else
                    {
                        richFunnel2.exactEnd = (Vector3)path2[mergePartEndpoints ? (j + 1) : j].position;
                    }
                    richFunnel2.BuildFunnelCorridor(path2, num, j);
                    this.parts.Add(richFunnel2);
                }
                else if (NodeLink2.GetNodeLink(path2[j]) != null)
                {
                    NodeLink2 nodeLink    = NodeLink2.GetNodeLink(path2[j]);
                    int       num2        = j;
                    uint      graphIndex2 = path2[num2].GraphIndex;
                    j++;
                    while (j < path2.Count && path2[j].GraphIndex == graphIndex2)
                    {
                        j++;
                    }
                    j--;
                    if (j - num2 > 1)
                    {
                        throw new Exception("NodeLink2 path length greater than two (2) nodes. " + (j - num2));
                    }
                    if (j - num2 != 0)
                    {
                        RichSpecial item = ObjectPool <RichSpecial> .Claim().Initialize(nodeLink, path2[num2]);

                        this.parts.Add(item);
                    }
                }
            }
        }
Ejemplo n.º 21
0
 public NavmeshUpdateSettings(NavmeshBase graph)
 {
 }
Ejemplo n.º 22
0
 public static Bounds GetTileBoundsInGraphSpace(this NavmeshBase navmeshBase, IntRect rect)
 {
     return(navmeshBase.GetTileBoundsInGraphSpace(rect.xmin, rect.ymin, rect.Width, rect.Height));
 }
Ejemplo n.º 23
0
        public static void OnDrawGizmos(this NavmeshBase navmeshBase, Pathfinding.Util.RetainedGizmos gizmos, bool drawNodes)
        {
            if (!drawNodes)
            {
                return;
            }

            using (var helper = gizmos.GetSingleFrameGizmoHelper()) {
                var bounds = new Bounds();
                bounds.SetMinMax(Vector3.zero, navmeshBase.forcedBoundsSize);
                // Draw a write cube using the latest transform
                // (this makes the bounds update immediately if some field is changed in the editor)
                helper.builder.DrawWireCube(navmeshBase.CalculateTransform(), bounds, Color.white);
            }

            if (navmeshBase.tiles != null)
            {
                // Update navmesh vizualizations for
                // the tiles that have been changed
                for (int i = 0; i < navmeshBase.tiles.Length; i++)
                {
                    // This may happen if an exception has been thrown when the graph was scanned.
                    // We don't want the gizmo code to start to throw exceptions as well then as
                    // that would obscure the actual source of the error.
                    if (navmeshBase.tiles[i] == null)
                    {
                        continue;
                    }

                    // Calculate a hash of the tile
                    var hasher = new RetainedGizmos.Hasher(AstarPath.active);
                    hasher.AddHash(navmeshBase.showMeshOutline ? 1 : 0);
                    hasher.AddHash(navmeshBase.showMeshSurface ? 1 : 0);
                    hasher.AddHash(navmeshBase.showNodeConnections ? 1 : 0);

                    var nodes = navmeshBase.tiles[i].nodes;
                    for (int j = 0; j < nodes.Length; j++)
                    {
                        hasher.HashNode(nodes[j]);
                    }

                    if (!gizmos.Draw(hasher))
                    {
                        using (var helper = gizmos.GetGizmoHelper(hasher)) {
                            if (navmeshBase.showMeshSurface || navmeshBase.showMeshOutline)
                            {
                                navmeshBase.CreateNavmeshSurfaceVisualization(navmeshBase.tiles[i], helper);
                            }
                            if (navmeshBase.showMeshSurface || navmeshBase.showMeshOutline)
                            {
                                CreateNavmeshOutlineVisualization(navmeshBase.tiles[i], helper);
                            }

                            if (navmeshBase.showNodeConnections)
                            {
                                for (int j = 0; j < nodes.Length; j++)
                                {
                                    helper.DrawConnections(nodes[j]);
                                }
                            }
                        }
                    }

                    gizmos.Draw(hasher);
                }
            }

            if (AstarPath.active.showUnwalkableNodes)
            {
                navmeshBase.DrawUnwalkableNodes(AstarPath.active.unwalkableNodeDebugSize);
            }
        }
Ejemplo n.º 24
0
        /** Create a tile at tile index \a x, \a z from the mesh.
         * \version Since version 3.7.6 the implementation is thread safe
         */
        public static NavmeshTile CreateTile(this RecastGraph self, Voxelize vox, VoxelMesh mesh, int x, int z, int threadIndex)
        {
            if (mesh.tris == null)
            {
                throw new System.ArgumentNullException("mesh.tris");
            }
            if (mesh.verts == null)
            {
                throw new System.ArgumentNullException("mesh.verts");
            }
            if (mesh.tris.Length % 3 != 0)
            {
                throw new System.ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
            }
            if (mesh.verts.Length >= NavmeshBase.VertexIndexMask)
            {
                if (self.tileXCount * self.tileZCount == 1)
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + NavmeshBase.VertexIndexMask + ")." +
                                                       "\n<b>Try enabling tiling in the recast graph settings.</b>\n");
                }
                else
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + NavmeshBase.VertexIndexMask + ")." +
                                                       "\n<b>Try reducing tile size or enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector</b>");
                }
            }

            // Create a new navmesh tile and assign its settings
            var tile = new NavmeshTile {
                x      = x,
                z      = z,
                w      = 1,
                d      = 1,
                tris   = mesh.tris,
                bbTree = new BBTree(),
                graph  = self,
            };

            tile.vertsInGraphSpace = Utility.RemoveDuplicateVertices(mesh.verts, tile.tris);
            tile.verts             = (Int3[])tile.vertsInGraphSpace.Clone();
            self.transform.Transform(tile.verts);

            // Here we are faking a new graph
            // The tile is not added to any graphs yet, but to get the position queries from the nodes
            // to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
            // and direct the position queries directly to the tile
            // The thread index is added to make sure that if multiple threads are calculating tiles at the same time
            // they will not use the same temporary graph index
            uint temporaryGraphIndex = (uint)(AstarPath.active.data.graphs.Length + threadIndex);

            if (temporaryGraphIndex > GraphNode.MaxGraphIndex)
            {
                // Multithreaded tile calculations use fake graph indices, see above.
                throw new System.Exception("Graph limit reached. Multithreaded recast calculations cannot be done because a few scratch graph indices are required.");
            }

            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, tile);
            // We need to lock here because creating nodes is not thread safe
            // and we may be doing this from multiple threads at the same time
            tile.nodes = new TriangleMeshNode[tile.tris.Length / 3];
            lock (AstarPath.active) {
                self.CreateNodes(tile.nodes, tile.tris, x + z * self.tileXCount, temporaryGraphIndex);
            }

            tile.bbTree.RebuildFrom(tile.nodes);
            NavmeshBase.CreateNodeConnections(tile.nodes);
            // Remove the fake graph
            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, null);

            return(tile);
        }