Inheritance: GraphNode
		/** Utility method used by Linecast.
		 * Required since LevelGridNode does not inherit from GridNode.
		 * Lots of ugly casting but it was better than massive code duplication.
		 *
		 * Returns null if the node has no connection in that direction
		 */
		protected override GridNodeBase GetNeighbourAlongDirection (GridNodeBase node, int direction) {
			var levelGridNode = node as LevelGridNode;
			if (levelGridNode.GetConnection(direction)) {
				return nodes[levelGridNode.NodeInGridIndex+neighbourOffsets[direction] + width*depth*levelGridNode.GetConnectionValue(direction)];
			}
			return null;
		}
Exemple #2
0
		/** Utility method used by Linecast.
		 * Required since LevelGridNode does not inherit from GridNode.
		 * Lots of ugly casting but it was better than massive code duplication.
		 *
		 * Returns null if the node has no connection in that direction.
		 */
		protected virtual GridNodeBase GetNeighbourAlongDirection (GridNodeBase node, int direction) {
			var gridNode = node as GridNode;
			if (gridNode.GetConnectionInternal(direction)) {
				return nodes[gridNode.NodeInGridIndex+neighbourOffsets[direction]];
			}
			return null;
		}
        // Token: 0x0600229C RID: 8860 RVA: 0x00190EDC File Offset: 0x0018F0DC
        public static void GetContours(GridGraph grid, Action <Vector3[]> callback, float yMergeThreshold, GridNodeBase[] nodes = null)
        {
            HashSet <GridNodeBase> hashSet = (nodes != null) ? new HashSet <GridNodeBase>(nodes) : null;

            if (grid is LayerGridGraph)
            {
                GridNodeBase[] array;
                if ((array = nodes) == null)
                {
                    GridNodeBase[] nodes2 = (grid as LayerGridGraph).nodes;
                    array = nodes2;
                }
                nodes = array;
            }
            GridNodeBase[] array2;
            if ((array2 = nodes) == null)
            {
                GridNodeBase[] nodes2 = grid.nodes;
                array2 = nodes2;
            }
            nodes = array2;
            int[] neighbourXOffsets = grid.neighbourXOffsets;
            int[] neighbourZOffsets = grid.neighbourZOffsets;
            int[] array3;
            if (grid.neighbours != NumNeighbours.Six)
            {
                RuntimeHelpers.InitializeArray(array3 = new int[4], fieldof(< PrivateImplementationDetails > .02E4414E7DFA0F3AA2387EE8EA7AB31431CB406A).FieldHandle);
            }
            else
            {
                array3 = GridGraph.hexagonNeighbourIndices;
            }
            int[] array4 = array3;
            float num    = (grid.neighbours == NumNeighbours.Six) ? 0.33333334f : 0.5f;

            if (nodes != null)
            {
                List <Vector3> list = ListPool <Vector3> .Claim();

                HashSet <int> hashSet2 = new HashSet <int>();
                foreach (GridNodeBase gridNodeBase in nodes)
                {
                    if (gridNodeBase != null && gridNodeBase.Walkable && (!gridNodeBase.HasConnectionsToAllEightNeighbours || hashSet != null))
                    {
                        for (int j = 0; j < array4.Length; j++)
                        {
                            int          num2 = gridNodeBase.NodeIndex << 4 | j;
                            GridNodeBase neighbourAlongDirection = gridNodeBase.GetNeighbourAlongDirection(array4[j]);
                            if ((neighbourAlongDirection == null || (hashSet != null && !hashSet.Contains(neighbourAlongDirection))) && !hashSet2.Contains(num2))
                            {
                                list.ClearFast <Vector3>();
                                int          num3          = j;
                                GridNodeBase gridNodeBase2 = gridNodeBase;
                                for (;;)
                                {
                                    int num4 = gridNodeBase2.NodeIndex << 4 | num3;
                                    if (num4 == num2 && list.Count > 0)
                                    {
                                        break;
                                    }
                                    hashSet2.Add(num4);
                                    GridNodeBase neighbourAlongDirection2 = gridNodeBase2.GetNeighbourAlongDirection(array4[num3]);
                                    if (neighbourAlongDirection2 == null || (hashSet != null && !hashSet.Contains(neighbourAlongDirection2)))
                                    {
                                        int num5 = array4[num3];
                                        num3 = (num3 + 1) % array4.Length;
                                        int     num6   = array4[num3];
                                        Vector3 vector = new Vector3((float)gridNodeBase2.XCoordinateInGrid + 0.5f, 0f, (float)gridNodeBase2.ZCoordinateInGrid + 0.5f);
                                        vector.x += (float)(neighbourXOffsets[num5] + neighbourXOffsets[num6]) * num;
                                        vector.z += (float)(neighbourZOffsets[num5] + neighbourZOffsets[num6]) * num;
                                        vector.y  = grid.transform.InverseTransform((Vector3)gridNodeBase2.position).y;
                                        if (list.Count >= 2)
                                        {
                                            Vector3 b       = list[list.Count - 2];
                                            Vector3 vector2 = list[list.Count - 1] - b;
                                            Vector3 vector3 = vector - b;
                                            if (((Mathf.Abs(vector2.x) > 0.01f || Mathf.Abs(vector3.x) > 0.01f) && (Mathf.Abs(vector2.z) > 0.01f || Mathf.Abs(vector3.z) > 0.01f)) || Mathf.Abs(vector2.y) > yMergeThreshold || Mathf.Abs(vector3.y) > yMergeThreshold)
                                            {
                                                list.Add(vector);
                                            }
                                            else
                                            {
                                                list[list.Count - 1] = vector;
                                            }
                                        }
                                        else
                                        {
                                            list.Add(vector);
                                        }
                                    }
                                    else
                                    {
                                        gridNodeBase2 = neighbourAlongDirection2;
                                        num3          = (num3 + array4.Length / 2 + 1) % array4.Length;
                                    }
                                }
                                Vector3[] array5 = list.ToArray();
                                grid.transform.Transform(array5);
                                callback(array5);
                            }
                        }
                    }
                }
                ListPool <Vector3> .Release(ref list);
            }
        }
Exemple #4
0
        /// <summary>
        /// Executes a straight jump search.
        /// See: http://en.wikipedia.org/wiki/Jump_point_search
        /// </summary>
        static GridNodeBase JPSJumpStraight(GridNode node, Path path, PathHandler handler, int parentDir, int depth = 0)
        {
            GridGraph gg = GetGridGraph(node.GraphIndex);

            int[] neighbourOffsets = gg.neighbourOffsets;
            var   nodes            = gg.nodes;

            var origin = node;
            // Indexing into the cache arrays from multiple threads like this should cause
            // a lot of false sharing and cache trashing, but after profiling it seems
            // that this is not a major concern
            int threadID     = handler.threadID;
            int threadOffset = 8 * handler.threadID;

            int cyclicParentDir = JPSCyclic[parentDir];

            GridNodeBase result = null;

            // Rotate 180 degrees
            const int forwardDir    = 4;
            int       forwardOffset = neighbourOffsets[JPSInverseCyclic[(forwardDir + cyclicParentDir) % 8]];

            // Move forwards in the same direction
            // until a node is encountered which we either
            // * know the result for (memoization)
            // * is a special node (flag2 set)
            // * has custom connections
            // * the node has a forced neighbour
            // Then break out of the loop
            // and start another loop which goes through the same nodes and sets the
            // memoization caches to avoid expensive calls in the future
            while (true)
            {
                // This is needed to make sure different threads don't overwrite each others results
                // It doesn't matter if we throw away some caching done by other threads as this will only
                // happen during the first few path requests
                if (node.JPSLastCacheID == null || node.JPSLastCacheID.Length < handler.totalThreadCount)
                {
                    lock (node) {
                        // Check again in case another thread has already created the array
                        if (node.JPSLastCacheID == null || node.JPSLastCacheID.Length < handler.totalThreadCount)
                        {
                            node.JPSCache       = new GridNode[8 * handler.totalThreadCount];
                            node.JPSDead        = new byte[handler.totalThreadCount];
                            node.JPSLastCacheID = new ushort[handler.totalThreadCount];
                        }
                    }
                }
                if (node.JPSLastCacheID[threadID] != path.pathID)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        node.JPSCache[i + threadOffset] = null;
                    }
                    node.JPSLastCacheID[threadID] = path.pathID;
                    node.JPSDead[threadID]        = 0;
                }

                // Cache earlier results, major optimization
                // It is important to read from it once and then return the same result,
                // if we read from it twice, we might get different results due to other threads clearing the array sometimes
                var cachedResult = node.JPSCache[parentDir + threadOffset];
                if (cachedResult != null)
                {
                    result = cachedResult;
                    break;
                }

                if (((node.JPSDead[threadID] >> parentDir) & 1) != 0)
                {
                    return(null);
                }

                // Special node (e.g end node), take care of
                if (handler.GetPathNode(node).flag2)
                {
                    //Debug.Log ("Found end Node!");
                    //Debug.DrawRay ((Vector3)position, Vector3.up*2, Color.green);
                    result = node;
                    break;
                }

#if !ASTAR_GRID_NO_CUSTOM_CONNECTIONS
                // Special node which has custom connections, take care of
                if (node.connections != null && node.connections.Length > 0)
                {
                    result = node;
                    break;
                }
#endif


                // These are the nodes this node is connected to, one bit for each of the 8 directions
                int noncyclic = node.gridFlags;                //We don't actually need to & with this because we don't use the other bits. & 0xFF;
                int cyclic    = 0;
                for (int i = 0; i < 8; i++)
                {
                    cyclic |= ((noncyclic >> i) & 0x1) << JPSCyclic[i];
                }


                int forced = 0;
                // Loop around to be able to assume -X is where we came from
                cyclic = ((cyclic >> cyclicParentDir) | ((cyclic << 8) >> cyclicParentDir)) & 0xFF;

                //for ( int i = 0; i < 8; i++ ) if ( ((cyclic >> i)&1) == 0 ) forced |= JPSForced[i];
                if ((cyclic & (1 << 2)) == 0)
                {
                    forced |= (1 << 3);
                }
                if ((cyclic & (1 << 6)) == 0)
                {
                    forced |= (1 << 5);
                }

                int natural = JPSNaturalStraightNeighbours;

                // Check if there are any forced neighbours which we can reach that are not natural neighbours
                //if ( ((forced & cyclic) & (~(natural & cyclic))) != 0 ) {
                if ((forced & (~natural) & cyclic) != 0)
                {
                    // Some of the neighbour nodes are forced
                    result = node;
                    break;
                }

                // Make sure we can reach the next node
                if ((cyclic & (1 << forwardDir)) != 0)
                {
                    node = nodes[node.nodeInGridIndex + forwardOffset] as GridNode;

                    //Debug.DrawLine ( (Vector3)position + Vector3.up*0.2f*(depth), (Vector3)other.position + Vector3.up*0.2f*(depth+1), Color.magenta);
                }
                else
                {
                    result = null;
                    break;
                }
            }

            if (result == null)
            {
                while (origin != node)
                {
                    origin.JPSDead[threadID] |= (byte)(1 << parentDir);
                    origin = nodes[origin.nodeInGridIndex + forwardOffset] as GridNode;
                }
            }
            else
            {
                while (origin != node)
                {
                    origin.JPSCache[parentDir + threadOffset] = result;
                    origin = nodes[origin.nodeInGridIndex + forwardOffset] as GridNode;
                }
            }

            return(result);
        }