/** 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; }
/** 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); } }
/// <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); }