public static void Run( IEnumerable <IntVec3> startingNodes, Func <IntVec3, IEnumerable <IntVec3> > neighborsGetter, Func <IntVec3, IntVec3, float> distanceGetter, List <KeyValuePair <IntVec3, float> > outDistances, Dictionary <IntVec3, IntVec3> outParents = null) { outDistances.Clear(); //distances.Clear(); Dictionary <IntVec3, float> distances = new Dictionary <IntVec3, float>(); //queue.Clear(); FastPriorityQueue <KeyValuePair <IntVec3, float> > queue = new FastPriorityQueue <KeyValuePair <IntVec3, float> >((IComparer <KeyValuePair <IntVec3, float> >) new DistanceComparer()); outParents?.Clear(); if (startingNodes is IList <IntVec3> objList) { for (int index = 0; index < objList.Count; ++index) { IntVec3 key; try { key = objList[index]; } catch (ArgumentOutOfRangeException) { break; } if (!distances.ContainsKey(key)) { distances.Add(key, 0.0f); queue.Push(new KeyValuePair <IntVec3, float>(key, 0.0f)); } } } else { foreach (IntVec3 startingNode in startingNodes) { if (!distances.ContainsKey(startingNode)) { distances.Add(startingNode, 0.0f); queue.Push(new KeyValuePair <IntVec3, float>(startingNode, 0.0f)); } } } while (queue.Count > 0) { KeyValuePair <IntVec3, float> node = queue.Pop(); { IntVec3 nodeKey = node.Key; // NEED TO FIX HACK (contains key) if (distances.ContainsKey(nodeKey)) { float distance = distances[nodeKey]; if ((double)node.Value == (double)distance) { IEnumerable <IntVec3> objs = neighborsGetter(node.Key); if (objs != null) { if (objs is IList <IntVec3> objList2) { for (int index = 0; index < objList2.Count; ++index) { HandleNeighbor2(distances, queue, objList2[index], distance, node, distanceGetter, outParents); } } else { foreach (IntVec3 n in objs) { HandleNeighbor2(distances, queue, n, distance, node, distanceGetter, outParents); } } } } } } } foreach (KeyValuePair <IntVec3, float> distance in distances) { outDistances.Add(distance); } distances.Clear(); }
public WorldPath FindPath(int startTile, int destTile, Caravan caravan, Func <float, bool> terminator = null) { if (startTile < 0) { Log.Error("Tried to FindPath with invalid start tile " + startTile + ", caravan= " + caravan); return(WorldPath.NotFound); } if (destTile < 0) { Log.Error("Tried to FindPath with invalid dest tile " + destTile + ", caravan= " + caravan); return(WorldPath.NotFound); } if (caravan != null) { if (!caravan.CanReach(destTile)) { return(WorldPath.NotFound); } } else if (!Find.WorldReachability.CanReach(startTile, destTile)) { return(WorldPath.NotFound); } World world = Find.World; WorldGrid grid = world.grid; List <int> tileIDToNeighbors_offsets = grid.tileIDToNeighbors_offsets; List <int> tileIDToNeighbors_values = grid.tileIDToNeighbors_values; Vector3 normalized = grid.GetTileCenter(destTile).normalized; float[] movementDifficulty = world.pathGrid.movementDifficulty; int num = 0; int num2 = caravan?.TicksPerMove ?? 3300; int num3 = CalculateHeuristicStrength(startTile, destTile); statusOpenValue += 2; statusClosedValue += 2; if (statusClosedValue >= 65435) { ResetStatuses(); } calcGrid[startTile].knownCost = 0; calcGrid[startTile].heuristicCost = 0; calcGrid[startTile].costNodeCost = 0; calcGrid[startTile].parentTile = startTile; calcGrid[startTile].status = statusOpenValue; openList.Clear(); openList.Push(new CostNode(startTile, 0)); while (true) { if (openList.Count <= 0) { Log.Warning(caravan + " pathing from " + startTile + " to " + destTile + " ran out of tiles to process."); return(WorldPath.NotFound); } CostNode costNode = openList.Pop(); if (costNode.cost != calcGrid[costNode.tile].costNodeCost) { continue; } int tile = costNode.tile; if (calcGrid[tile].status == statusClosedValue) { continue; } if (tile == destTile) { return(FinalizedPath(tile)); } if (num > 500000) { Log.Warning(caravan + " pathing from " + startTile + " to " + destTile + " hit search limit of " + 500000 + " tiles."); return(WorldPath.NotFound); } int num4 = (tile + 1 < tileIDToNeighbors_offsets.Count) ? tileIDToNeighbors_offsets[tile + 1] : tileIDToNeighbors_values.Count; for (int i = tileIDToNeighbors_offsets[tile]; i < num4; i++) { int num5 = tileIDToNeighbors_values[i]; if (calcGrid[num5].status == statusClosedValue || world.Impassable(num5)) { continue; } int num6 = (int)((float)num2 * movementDifficulty[num5] * grid.GetRoadMovementDifficultyMultiplier(tile, num5)) + calcGrid[tile].knownCost; ushort status = calcGrid[num5].status; if ((status != statusClosedValue && status != statusOpenValue) || calcGrid[num5].knownCost > num6) { Vector3 tileCenter = grid.GetTileCenter(num5); if (status != statusClosedValue && status != statusOpenValue) { float num7 = grid.ApproxDistanceInTiles(GenMath.SphericalDistance(tileCenter.normalized, normalized)); calcGrid[num5].heuristicCost = Mathf.RoundToInt((float)num2 * num7 * (float)num3 * 0.5f); } int num8 = num6 + calcGrid[num5].heuristicCost; calcGrid[num5].parentTile = tile; calcGrid[num5].knownCost = num6; calcGrid[num5].status = statusOpenValue; calcGrid[num5].costNodeCost = num8; openList.Push(new CostNode(num5, num8)); } } num++; calcGrid[tile].status = statusClosedValue; if (terminator != null && terminator(calcGrid[tile].costNodeCost)) { break; } } return(WorldPath.NotFound); }
//public static FastPriorityQueue<CostNode2> openList = new FastPriorityQueue<CostNode2>(new CostNodeComparer2()); //public static PathFinderNodeFast[] calcGrid = new PathFinderNodeFast[40000]; //public static ushort statusOpenValue = 1; //public static ushort statusClosedValue = 2; public static bool FindPath(PathFinder __instance, ref PawnPath __result, IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { FastPriorityQueue <CostNode2> openList = getOpenList(); ushort statusOpenValue = getOpenValue(); ushort statusClosedValue = getClosedValue(); PathFinderNodeFast[] calcGrid = getCalcGrid(__instance); RegionCostCalculatorWrapper regionCostCalculator = getRegionCostCalculatorWrapper(__instance); if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } Pawn pawn = traverseParms.pawn; if (pawn != null && pawn.Map != mapField(__instance)) { Log.Error(string.Concat("Tried to FindPath for pawn which is spawned in another map. His map PathFinder should have been used, not this one. pawn=", pawn, " pawn.Map=", pawn.Map, " map=", mapField(__instance))); __result = PawnPath.NotFound; return(false); } if (!start.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid start ", start, ", pawn= ", pawn)); __result = PawnPath.NotFound; return(false); } if (!dest.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn)); __result = PawnPath.NotFound; return(false); } if (traverseParms.mode == TraverseMode.ByPawn) { if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBash, traverseParms.mode)) { __result = PawnPath.NotFound; return(false); } } else if (!mapField(__instance).reachability.CanReach(start, dest, peMode, traverseParms)) { __result = PawnPath.NotFound; return(false); } PfProfilerBeginSample(string.Concat("FindPath for ", pawn, " from ", start, " to ", dest, dest.HasThing ? (" at " + dest.Cell) : "")); cellIndicesField(__instance) = mapField(__instance).cellIndices; pathGridField(__instance) = mapField(__instance).pathGrid; edificeGridField(__instance) = mapField(__instance).edificeGrid.InnerArray; blueprintGridField(__instance) = mapField(__instance).blueprintGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int curIndex = cellIndicesField(__instance).CellToIndex(start); int num = cellIndicesField(__instance).CellToIndex(dest.Cell); ByteGrid byteGrid = pawn?.GetAvoidGrid(); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect destinationRect = CalculateDestinationRect(dest, peMode); bool flag4 = destinationRect.Width == 1 && destinationRect.Height == 1; int[] array = mapField(__instance).pathGrid.pathGrid; TerrainDef[] topGrid = mapField(__instance).terrainGrid.topGrid; EdificeGrid edificeGrid = mapField(__instance).edificeGrid; int num2 = 0; int num3 = 0; Area allowedArea = GetAllowedArea(pawn); bool flag5 = pawn != null && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = !flag && start.GetRegion(mapField(__instance)) != null && flag2; bool flag7 = !flag || !flag3; bool flag8 = false; bool flag9 = pawn?.Drafted ?? false; int num4 = (pawn?.IsColonist ?? false) ? 100000 : 2000; int num5 = 0; int num6 = 0; float num7 = DetermineHeuristicStrength(pawn, start, dest); int num8; int num9; if (pawn != null) { num8 = pawn.TicksPerMoveCardinal; num9 = pawn.TicksPerMoveDiagonal; } else { num8 = 13; num9 = 18; } CalculateAndAddDisallowedCorners2(disallowedCornerIndicesField(__instance), mapField(__instance), peMode, destinationRect); InitStatusesAndPushStartNode3(ref curIndex, start, cellIndicesField(__instance), calcGrid, ref statusOpenValue, ref statusClosedValue); openList.Clear(); openList.Push(new CostNode2(curIndex, 0)); while (true) { PfProfilerBeginSample("Open cell"); if (openList.Count <= 0) { string text = (pawn != null && pawn.CurJob != null) ? pawn.CurJob.ToString() : "null"; string text2 = (pawn != null && pawn.Faction != null) ? pawn.Faction.ToString() : "null"; Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2)); DebugDrawRichData(); PfProfilerEndSample(); PfProfilerEndSample(); __result = PawnPath.NotFound; return(false); } num5 += openList.Count; num6++; CostNode2 costNode = openList.Pop(); curIndex = costNode.index; if (costNode.cost != calcGrid[curIndex].costNodeCost) { PfProfilerEndSample(); continue; } if (calcGrid[curIndex].status == statusClosedValue) { PfProfilerEndSample(); continue; } IntVec3 c = cellIndicesField(__instance).IndexToCell(curIndex); int x2 = c.x; int z2 = c.z; if (flag4) { if (curIndex == num) { PfProfilerEndSample(); PawnPath result = FinalizedPath2(curIndex, flag8, cellIndicesField(__instance), calcGrid); PfProfilerEndSample(); __result = result; return(false); } } else if (destinationRect.Contains(c) && !disallowedCornerIndicesField(__instance).Contains(curIndex)) { PfProfilerEndSample(); PawnPath result2 = FinalizedPath2(curIndex, flag8, cellIndicesField(__instance), calcGrid); PfProfilerEndSample(); __result = result2; return(false); } if (num2 > 160000) { break; } PfProfilerEndSample(); PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num10 = (uint)(x2 + Directions[i]); uint num11 = (uint)(z2 + Directions[i + 8]); if (num10 >= mapSizeXField(__instance) || num11 >= mapSizeZField(__instance)) { continue; } int num12 = (int)num10; int num13 = (int)num11; int num14 = cellIndicesField(__instance).CellToIndex(num12, num13); if (calcGrid[num14].status == statusClosedValue && !flag8) { continue; } int num15 = 0; bool flag10 = false; if (!flag2 && new IntVec3(num12, 0, num13).GetTerrain(mapField(__instance)).HasTag("Water")) { continue; } if (!pathGridField(__instance).WalkableFast(num14)) { if (!flag) { continue; } flag10 = true; num15 += 70; Building building = edificeGrid[num14]; if (building == null || !PathFinder.IsDestroyable(building)) { continue; } num15 += (int)(building.HitPoints * 0.2f); } switch (i) { case 4: if (PathFinder.BlocksDiagonalMovement(curIndex - mapSizeXField(__instance), mapField(__instance))) { if (flag7) { continue; } num15 += 70; } if (PathFinder.BlocksDiagonalMovement(curIndex + 1, mapField(__instance))) { if (flag7) { continue; } num15 += 70; } break; case 5: if (PathFinder.BlocksDiagonalMovement(curIndex + mapSizeXField(__instance), mapField(__instance))) { if (flag7) { continue; } num15 += 70; } if (PathFinder.BlocksDiagonalMovement(curIndex + 1, mapField(__instance))) { if (flag7) { continue; } num15 += 70; } break; case 6: if (PathFinder.BlocksDiagonalMovement(curIndex + mapSizeXField(__instance), mapField(__instance))) { if (flag7) { continue; } num15 += 70; } if (PathFinder.BlocksDiagonalMovement(curIndex - 1, mapField(__instance))) { if (flag7) { continue; } num15 += 70; } break; case 7: if (PathFinder.BlocksDiagonalMovement(curIndex - mapSizeXField(__instance), mapField(__instance))) { if (flag7) { continue; } num15 += 70; } if (PathFinder.BlocksDiagonalMovement(curIndex - 1, mapField(__instance))) { if (flag7) { continue; } num15 += 70; } break; } int num16 = (i > 3) ? num9 : num8; num16 += num15; if (!flag10) { num16 += array[num14]; num16 = ((!flag9) ? (num16 + topGrid[num14].extraNonDraftedPerceivedPathCost) : (num16 + topGrid[num14].extraDraftedPerceivedPathCost)); } if (byteGrid != null) { num16 += byteGrid[num14] * 8; } if (allowedArea != null && !allowedArea[num14]) { num16 += 600; } if (flag5 && PawnUtility.AnyPawnBlockingPathAt(new IntVec3(num12, 0, num13), pawn, actAsIfHadCollideWithPawnsJob: false, collideOnlyWithStandingPawns: false, forPathFinder: true)) { num16 += 175; } Building building2 = edificeGridField(__instance)[num14]; if (building2 != null) { PfProfilerBeginSample("Edifices"); int buildingCost = PathFinder.GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == int.MaxValue) { PfProfilerEndSample(); continue; } num16 += buildingCost; PfProfilerEndSample(); } List <Blueprint> list = blueprintGridField(__instance)[num14]; if (list != null) { PfProfilerBeginSample("Blueprints"); int num17 = 0; for (int j = 0; j < list.Count; j++) { num17 = Mathf.Max(num17, PathFinder.GetBlueprintCost(list[j], pawn)); } if (num17 == int.MaxValue) { PfProfilerEndSample(); continue; } num16 += num17; PfProfilerEndSample(); } int num18 = num16 + calcGrid[curIndex].knownCost; ushort status = calcGrid[num14].status; if (status == statusClosedValue || status == statusOpenValue) { int num19 = 0; if (status == statusClosedValue) { num19 = num8; } if (calcGrid[num14].knownCost <= num18 + num19) { continue; } } if (flag8) { calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)regionCostCalculator.GetPathCostFromDestToRegion(num14) * RegionHeuristicWeightByNodesOpened.Evaluate(num3)); if (calcGrid[num14].heuristicCost < 0) { Log.ErrorOnce(string.Concat("Heuristic cost overflow for ", pawn.ToStringSafe(), " pathing from ", start, " to ", dest, "."), pawn.GetHashCode() ^ 0xB8DC389); calcGrid[num14].heuristicCost = 0; } } else if (status != statusClosedValue && status != statusOpenValue) { int dx = Math.Abs(num12 - x); int dz = Math.Abs(num13 - z); int num20 = GenMath.OctileDistance(dx, dz, num8, num9); calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)num20 * num7); } int num21 = num18 + calcGrid[num14].heuristicCost; if (num21 < 0) { Log.ErrorOnce(string.Concat("Node cost overflow for ", pawn.ToStringSafe(), " pathing from ", start, " to ", dest, "."), pawn.GetHashCode() ^ 0x53CB9DE); num21 = 0; } calcGrid[num14].parentIndex = curIndex; calcGrid[num14].knownCost = num18; calcGrid[num14].status = statusOpenValue; calcGrid[num14].costNodeCost = num21; num3++; openList.Push(new CostNode2(num14, num21)); } PfProfilerEndSample(); num2++; calcGrid[curIndex].status = statusClosedValue; if (num3 >= num4 && flag6 && !flag8) { flag8 = true; regionCostCalculator.Init(destinationRect, traverseParms, num8, num9, byteGrid, allowedArea, flag9, disallowedCornerIndicesField(__instance)); InitStatusesAndPushStartNode3(ref curIndex, start, cellIndicesField(__instance), calcGrid, ref statusOpenValue, ref statusClosedValue); openList.Clear(); openList.Push(new CostNode2(curIndex, 0)); num3 = 0; num2 = 0; } } Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " hit search limit of ", 160000, " cells.")); DebugDrawRichData(); PfProfilerEndSample(); PfProfilerEndSample(); __result = PawnPath.NotFound; return(false); }
public int GetRegionDistance(Region region, out RegionLink minLink) { if (regionMinLink.TryGetValue(region.id, out minLink)) { return(distances[minLink]); } while (queue.Count != 0) { var vertex = queue.Pop(); nodes_popped++; int knownBest = distances[vertex.Link]; if (vertex.Cost == knownBest) { var destRegion = GetLinkOtherRegion(vertex.FromRegion, vertex.Link); //I've never encountered this during testing, but users reported issues resolved by this check. if (destRegion?.valid != true) { continue; } int portalCost = 0; if (destRegion.portal != null) { //Not using Region.Allows because it is not entirely consistent with the pathfinder logic, //resulting in errors when a door is within range of 22 turrets (avoidGrid=255) portalCost = NewPathFinder.GetPathCostForBuilding(destRegion.portal, traverseParms); if (portalCost < 0) { continue; } portalCost = portalCost + OctileDistance(1, 0); } var minPathCost = RegionMedianPathCost(destRegion); foreach (var current2 in destRegion.links) { if (current2 == vertex.Link) { continue; } var addedCost = destRegion.portal != null ? portalCost : RegionLinkDistance(vertex.Link, current2, minPathCost); addedCost = Math.Max(addedCost, 1); //Handle mods with negative path costs int newCost = knownBest + addedCost; int pathCost = MinimumRegionLinkDistance(targetCell, current2) + newCost; int oldCost; if (distances.TryGetValue(current2, out oldCost)) { if (newCost < oldCost) { distances[current2] = newCost; queue.Push(new RegionLinkQueueEntry(destRegion, current2, newCost, pathCost)); } } else { distances.Add(current2, newCost); queue.Push(new RegionLinkQueueEntry(destRegion, current2, newCost, pathCost)); } } //if this is the first vertex popped for the region, we've found the shortest path to that region if (!regionMinLink.ContainsKey(destRegion.id)) { //if (DebugViewSettings.drawPaths && !NewPathFinder.disableDebugFlash) //{ // //NewPathFinder.disableDebugFlash = true; // //var tempPath = debugPathfinder?.FindPathInner(this.rootCell, new LocalTargetInfo(RegionLinkCenter(vertex.Link)), this.traverseParms, Verse.AI.PathEndMode.OnCell); // //NewPathFinder.disableDebugFlash = false; // //var actualCost = tempPath.TotalCost; // //tempPath.Dispose(); // if (regionMinLink.TryGetValue(vertex.FromRegion.id, out minLink)) // NewPathFinder.DebugLine(this.map, RegionLinkCenter(vertex.Link), RegionLinkCenter(minLink)); // NewPathFinder.DebugFlash(this.map, RegionLinkCenter(vertex.Link), knownBest / 1500f, $"{knownBest}\n{nodes_popped}" /*+ "\n(" + actualCost + ")"*/); // //if (actualCost < knownBest) { Log.Warning(vertex.Link + " has actual cost " + actualCost + "with heuristic " + knownBest); } //} regionMinLink[destRegion.id] = vertex.Link; if (destRegion.id == region.id) { minLink = vertex.Link; return(vertex.Cost); } } } } return(100000); }
public PawnPath FindPath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } Pawn pawn = traverseParms.pawn; if (pawn != null && pawn.Map != map) { Log.Warning(String.Format("Map object was rebuilt, but new pather was not assigned to new map (new {0}) (old {1})", pawn.Map.uniqueID, map.uniqueID)); Log.Error("Tried to FindPath for pawn which is spawned in another map. His map PathFinder should have been used, not this one. pawn=" + pawn + " pawn.Map=" + pawn.Map + " map=" + map); return(PawnPath.NotFound); } if (!start.IsValid) { Log.Error("Tried to FindPath with invalid start " + start + ", pawn= " + pawn); return(PawnPath.NotFound); } if (!dest.IsValid) { Log.Error("Tried to FindPath with invalid dest " + dest + ", pawn= " + pawn); return(PawnPath.NotFound); } if (traverseParms.mode == TraverseMode.ByPawn) { if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBash, traverseParms.mode)) { return(PawnPath.NotFound); } } else if (!map.reachability.CanReach(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound); } PfProfilerBeginSample("FindPath for " + pawn + " from " + start + " to " + dest + (dest.HasThing ? (" at " + dest.Cell) : "")); cellIndices = map.cellIndices; pathGrid = map.pathGrid; this.edificeGrid = map.edificeGrid.InnerArray; blueprintGrid = map.blueprintGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int curIndex = cellIndices.CellToIndex(start); int num = cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = pawn?.GetAvoidGrid(); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect cellRect = CalculateDestinationRect(dest, peMode); bool flag4 = cellRect.Width == 1 && cellRect.Height == 1; int[] array = map.pathGrid.pathGrid; TerrainDef[] topGrid = map.terrainGrid.topGrid; EdificeGrid edificeGrid = map.edificeGrid; int num2 = 0; int num3 = 0; Area allowedArea = GetAllowedArea(pawn); bool flag5 = pawn != null && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = (!flag && start.GetRegion(map) != null) & flag2; bool flag7 = !flag || !flag3; bool flag8 = false; bool flag9 = pawn?.Drafted ?? false; int num4 = (pawn?.IsColonist ?? false) ? 100000 : 2000; int num5 = 0; int num6 = 0; float num7 = DetermineHeuristicStrength(pawn, start, dest); // BEGIN CHANGED SECTION // In case pawn is null int num8 = 13; int num9 = 18; Dictionary <TerrainDef, int> pawnTerrainCacheCardinal = new Dictionary <TerrainDef, int>(); Dictionary <TerrainDef, int> pawnTerrainCacheDiagonal = new Dictionary <TerrainDef, int>(); Dictionary <TerrainDef, bool> pawnSpecialMovementCache = new Dictionary <TerrainDef, bool>(); Dictionary <TerrainDef, bool> pawnImpassibleMovementCache = new Dictionary <TerrainDef, bool>(); Dictionary <TerrainDef, int> pawnTerrainMovementCache = new Dictionary <TerrainDef, int>(); // END CHANGED SECTION CalculateAndAddDisallowedCorners(traverseParms, peMode, cellRect); InitStatusesAndPushStartNode(ref curIndex, start); while (true) { PfProfilerBeginSample("Open cell"); if (openList.Count <= 0) { string text = (pawn != null && pawn.CurJob != null) ? pawn.CurJob.ToString() : "null"; string text2 = (pawn != null && pawn.Faction != null) ? pawn.Faction.ToString() : "null"; Log.Warning(pawn + " pathing from " + start + " to " + dest + " ran out of cells to process.\nJob:" + text + "\nFaction: " + text2); DebugDrawRichData(); PfProfilerEndSample(); PfProfilerEndSample(); return(PawnPath.NotFound); } num5 += openList.Count; num6++; CostNode costNode = openList.Pop(); curIndex = costNode.index; if (costNode.cost != calcGrid[curIndex].costNodeCost) { PfProfilerEndSample(); continue; } if (calcGrid[curIndex].status == statusClosedValue) { PfProfilerEndSample(); continue; } IntVec3 c = cellIndices.IndexToCell(curIndex); int x2 = c.x; int z2 = c.z; if (flag4) { if (curIndex == num) { PfProfilerEndSample(); PawnPath result = FinalizedPath(curIndex, flag8); PfProfilerEndSample(); return(result); } } else if (cellRect.Contains(c) && !disallowedCornerIndices.Contains(curIndex)) { PfProfilerEndSample(); PawnPath result2 = FinalizedPath(curIndex, flag8); PfProfilerEndSample(); return(result2); } if (num2 > 160000) { break; } PfProfilerEndSample(); PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num10 = (uint)(x2 + Directions[i]); uint num11 = (uint)(z2 + Directions[i + 8]); if (num10 >= mapSizeX || num11 >= mapSizeZ) { continue; } int num12 = (int)num10; int num13 = (int)num11; int num14 = cellIndices.CellToIndex(num12, num13); if (calcGrid[num14].status == statusClosedValue && !flag8) { continue; } // BEGIN CHANGED SECTION IntVec3 targetCell = new IntVec3(num12, 0, num13); TerrainDef targetTerrain = topGrid[num14]; if (pawn != null) { // Use cache of terrain movement indicators to avoid a lot of repeated computation if (!pawnImpassibleMovementCache.TryGetValue(targetTerrain, out bool impassible)) { impassible = pawn.kindDef.UnreachableTerrainCheck(targetTerrain); pawnImpassibleMovementCache[targetTerrain] = impassible; } if (impassible) { // Skip this cell for pathing calculations calcGrid[num14].status = statusClosedValue; continue; } // Overwrite directional move costs if (!pawnTerrainCacheCardinal.TryGetValue(targetTerrain, out num8)) { num8 = pawn.TerrainAwareTicksPerMoveCardinal(targetTerrain); pawnTerrainCacheCardinal[targetTerrain] = num8; } if (!pawnTerrainCacheDiagonal.TryGetValue(targetTerrain, out num9)) { num9 = pawn.TerrainAwareTicksPerMoveDiagonal(targetTerrain); pawnTerrainCacheDiagonal[targetTerrain] = num9; } } // END CHANGED SECTION int num15 = 0; bool flag10 = false; //if (!flag2 && new IntVec3(num12, 0, num13).GetTerrain(map).HasTag("Water")) if (!flag2 && targetTerrain.HasTag("Water")) { continue; } if (!pathGrid.WalkableFast(num14)) { if (!flag) { continue; } flag10 = true; num15 += 70; Building building = edificeGrid[num14]; if (building == null || !IsDestroyable(building)) { continue; } num15 += (int)((float)building.HitPoints * 0.2f); } switch (i) { case 4: if (BlocksDiagonalMovement(curIndex - mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (BlocksDiagonalMovement(curIndex + 1)) { if (flag7) { continue; } num15 += 70; } break; case 5: if (BlocksDiagonalMovement(curIndex + mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (BlocksDiagonalMovement(curIndex + 1)) { if (flag7) { continue; } num15 += 70; } break; case 6: if (BlocksDiagonalMovement(curIndex + mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (BlocksDiagonalMovement(curIndex - 1)) { if (flag7) { continue; } num15 += 70; } break; case 7: if (BlocksDiagonalMovement(curIndex - mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (BlocksDiagonalMovement(curIndex - 1)) { if (flag7) { continue; } num15 += 70; } break; } int num16 = (i > 3) ? num9 : num8; num16 += num15; if (!flag10) { // BEGIN CHANGED SECTION //num16 += array[num14]; //num16 = ((!flag9) ? (num16 + topGrid[num14].extraNonDraftedPerceivedPathCost) : (num16 + topGrid[num14].extraDraftedPerceivedPathCost)); if (pawn == null) { num16 += array[num14]; if (flag9) { num16 += targetTerrain.extraDraftedPerceivedPathCost; } else { num16 += targetTerrain.extraNonDraftedPerceivedPathCost; } } else { // Use cache of terrain perceived cost instead of fixed pathCost grid to avoid a lot of repeated computation while maintaining accuracy if (!pawnTerrainMovementCache.TryGetValue(targetTerrain, out int terrainMoveCost)) { terrainMoveCost = pawn.TerrainMoveCost(targetTerrain); pawnTerrainMovementCache[targetTerrain] = terrainMoveCost; } // This was really really expensive, so we opted to mod this pre-calced value //num16 += pathGrid.TerrainCalculatedCostAt(map, pawn, targetCell, true, IntVec3.Invalid, terrainMoveCost); num16 += pathGrid.ApplyTerrainModToCalculatedCost(targetTerrain, array[num14], terrainMoveCost); // Use cache of terrain movement indicators to avoid a lot of repeated computation if (!pawnSpecialMovementCache.TryGetValue(targetTerrain, out bool specialMovement)) { specialMovement = pawn.TerrainMoveStat(targetTerrain) != StatDefOf.MoveSpeed; pawnSpecialMovementCache[targetTerrain] = specialMovement; } // Skip applying the PerceivedPathCost hack if we've got a specialized speed stat for this terrain if (!specialMovement) { if (flag9) { num16 += targetTerrain.extraDraftedPerceivedPathCost; } else { num16 += targetTerrain.extraNonDraftedPerceivedPathCost; } } } // END CHANGED SECTION } if (byteGrid != null) { num16 += byteGrid[num14] * 8; } if (allowedArea != null && !allowedArea[num14]) { num16 += 600; } //new IntVec3(num12, 0, num13) -> targetCell if (flag5 && PawnUtility.AnyPawnBlockingPathAt(targetCell, pawn, actAsIfHadCollideWithPawnsJob: false, collideOnlyWithStandingPawns: false, forPathFinder: true)) { num16 += 175; } Building building2 = this.edificeGrid[num14]; if (building2 != null) { PfProfilerBeginSample("Edifices"); int buildingCost = GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == int.MaxValue) { PfProfilerEndSample(); continue; } num16 += buildingCost; PfProfilerEndSample(); } List <Blueprint> list = blueprintGrid[num14]; if (list != null) { PfProfilerBeginSample("Blueprints"); int num17 = 0; for (int j = 0; j < list.Count; j++) { num17 = Mathf.Max(num17, GetBlueprintCost(list[j], pawn)); } if (num17 == int.MaxValue) { PfProfilerEndSample(); continue; } num16 += num17; PfProfilerEndSample(); } int num18 = num16 + calcGrid[curIndex].knownCost; ushort status = calcGrid[num14].status; if (status == statusClosedValue || status == statusOpenValue) { int num19 = 0; if (status == statusClosedValue) { num19 = num8; } if (calcGrid[num14].knownCost <= num18 + num19) { continue; } } if (flag8) { calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)regionCostCalculator.GetPathCostFromDestToRegion(num14) * RegionHeuristicWeightByNodesOpened.Evaluate(num3)); if (calcGrid[num14].heuristicCost < 0) { Log.ErrorOnce("Heuristic cost overflow for " + pawn.ToStringSafe() + " pathing from " + start + " to " + dest + ".", pawn.GetHashCode() ^ 0xB8DC389); calcGrid[num14].heuristicCost = 0; } } else if (status != statusClosedValue && status != statusOpenValue) { int dx = Math.Abs(num12 - x); int dz = Math.Abs(num13 - z); int num20 = GenMath.OctileDistance(dx, dz, num8, num9); calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)num20 * num7); } int num21 = num18 + calcGrid[num14].heuristicCost; if (num21 < 0) { Log.ErrorOnce("Node cost overflow for " + pawn.ToStringSafe() + " pathing from " + start + " to " + dest + ".", pawn.GetHashCode() ^ 0x53CB9DE); num21 = 0; } calcGrid[num14].parentIndex = curIndex; calcGrid[num14].knownCost = num18; calcGrid[num14].status = statusOpenValue; calcGrid[num14].costNodeCost = num21; num3++; openList.Push(new CostNode(num14, num21)); } PfProfilerEndSample(); num2++; calcGrid[curIndex].status = statusClosedValue; if (num3 >= num4 && flag6 && !flag8) { flag8 = true; regionCostCalculator.Init(cellRect, traverseParms, num8, num9, byteGrid, allowedArea, flag9, disallowedCornerIndices); InitStatusesAndPushStartNode(ref curIndex, start); num3 = 0; num2 = 0; } } Log.Warning(pawn + " pathing from " + start + " to " + dest + " hit search limit of " + 160000 + " cells."); DebugDrawRichData(); PfProfilerEndSample(); PfProfilerEndSample(); return(PawnPath.NotFound); }
public static void Run(IEnumerable <T> startingNodes, Func <T, IEnumerable <T> > neighborsGetter, Func <T, T, float> distanceGetter, List <KeyValuePair <T, float> > outDistances, Dictionary <T, T> outParents = null) { outDistances.Clear(); distances.Clear(); queue.Clear(); outParents?.Clear(); IList <T> list = startingNodes as IList <T>; if (list != null) { for (int i = 0; i < list.Count; i++) { T key = list[i]; if (!distances.ContainsKey(key)) { distances.Add(key, 0f); queue.Push(new KeyValuePair <T, float>(key, 0f)); } } } else { foreach (T startingNode in startingNodes) { if (!distances.ContainsKey(startingNode)) { distances.Add(startingNode, 0f); queue.Push(new KeyValuePair <T, float>(startingNode, 0f)); } } } while (queue.Count != 0) { KeyValuePair <T, float> node = queue.Pop(); float num = distances[node.Key]; if (node.Value != num) { continue; } IEnumerable <T> enumerable = neighborsGetter(node.Key); if (enumerable == null) { continue; } IList <T> list2 = enumerable as IList <T>; if (list2 != null) { for (int j = 0; j < list2.Count; j++) { HandleNeighbor(list2[j], num, node, distanceGetter, outParents); } continue; } foreach (T item in enumerable) { HandleNeighbor(item, num, node, distanceGetter, outParents); } } foreach (KeyValuePair <T, float> distance in distances) { outDistances.Add(distance); } distances.Clear(); }
public int GetRegionDistance(Region region, out RegionLink minLink) { if (regionMinLink.TryGetValue(region.id, out minLink)) { return(distances[minLink]); } while (queue.Count != 0) { RegionLinkQueueEntry regionLinkQueueEntry = queue.Pop(); int num = distances[regionLinkQueueEntry.Link]; if (regionLinkQueueEntry.Cost != num) { continue; } Region otherRegion = regionLinkQueueEntry.Link.GetOtherRegion(regionLinkQueueEntry.From); if (otherRegion == null || !otherRegion.valid) { continue; } int num2 = 0; if (otherRegion.door != null) { num2 = PathFinder.GetBuildingCost(otherRegion.door, traverseParms, traverseParms.pawn); if (num2 == int.MaxValue) { continue; } num2 += OctileDistance(1, 0); } int minPathCost = RegionMedianPathCost(otherRegion); for (int i = 0; i < otherRegion.links.Count; i++) { RegionLink regionLink = otherRegion.links[i]; if (regionLink == regionLinkQueueEntry.Link || !regionLink.GetOtherRegion(otherRegion).type.Passable()) { continue; } int val = (otherRegion.door != null) ? num2 : RegionLinkDistance(regionLinkQueueEntry.Link, regionLink, minPathCost); val = Math.Max(val, 1); int num3 = num + val; int estimatedPathCost = MinimumRegionLinkDistance(destinationCell, regionLink) + num3; if (distances.TryGetValue(regionLink, out int value)) { if (num3 < value) { distances[regionLink] = num3; queue.Push(new RegionLinkQueueEntry(otherRegion, regionLink, num3, estimatedPathCost)); } } else { distances.Add(regionLink, num3); queue.Push(new RegionLinkQueueEntry(otherRegion, regionLink, num3, estimatedPathCost)); } } if (!regionMinLink.ContainsKey(otherRegion.id)) { regionMinLink.Add(otherRegion.id, regionLinkQueueEntry.Link); if (otherRegion == region) { minLink = regionLinkQueueEntry.Link; return(regionLinkQueueEntry.Cost); } } } return(10000); }
public PawnPath FindPath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } Pawn pawn = traverseParms.pawn; if (pawn != null && pawn.Map != map) { Log.Error("Tried to FindPath for pawn which is spawned in another map. His map PathFinder should have been used, not this one. pawn=" + pawn + " pawn.Map=" + pawn.Map + " map=" + map); return(PawnPath.NotFound); } if (!start.IsValid) { Log.Error("Tried to FindPath with invalid start " + start + ", pawn= " + pawn); return(PawnPath.NotFound); } if (!dest.IsValid) { Log.Error("Tried to FindPath with invalid dest " + dest + ", pawn= " + pawn); return(PawnPath.NotFound); } if (traverseParms.mode == TraverseMode.ByPawn) { if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBash, traverseParms.mode)) { return(PawnPath.NotFound); } } else if (!map.reachability.CanReach(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound); } PfProfilerBeginSample("FindPath for " + pawn + " from " + start + " to " + dest + ((!dest.HasThing) ? string.Empty : (" at " + dest.Cell))); cellIndices = map.cellIndices; pathGrid = map.pathGrid; this.edificeGrid = map.edificeGrid.InnerArray; blueprintGrid = map.blueprintGrid.InnerArray; IntVec3 cell = dest.Cell; int x = cell.x; IntVec3 cell2 = dest.Cell; int z = cell2.z; int curIndex = cellIndices.CellToIndex(start); int num = cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = pawn?.GetAvoidGrid(); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect cellRect = CalculateDestinationRect(dest, peMode); bool flag4 = cellRect.Width == 1 && cellRect.Height == 1; int[] array = map.pathGrid.pathGrid; TerrainDef[] topGrid = map.terrainGrid.topGrid; EdificeGrid edificeGrid = map.edificeGrid; int num2 = 0; int num3 = 0; Area allowedArea = GetAllowedArea(pawn); bool flag5 = pawn != null && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = true && DebugViewSettings.drawPaths; bool flag7 = !flag && start.GetRegion(map) != null && flag2; bool flag8 = !flag || !flag3; bool flag9 = false; bool flag10 = pawn?.Drafted ?? false; int num4 = (!(pawn?.IsColonist ?? false)) ? 2000 : 100000; int num5 = 0; int num6 = 0; float num7 = DetermineHeuristicStrength(pawn, start, dest); int num8; int num9; if (pawn != null) { num8 = pawn.TicksPerMoveCardinal; num9 = pawn.TicksPerMoveDiagonal; } else { num8 = 13; num9 = 18; } CalculateAndAddDisallowedCorners(traverseParms, peMode, cellRect); InitStatusesAndPushStartNode(ref curIndex, start); while (true) { PfProfilerBeginSample("Open cell"); if (openList.Count <= 0) { string text = (pawn == null || pawn.CurJob == null) ? "null" : pawn.CurJob.ToString(); string text2 = (pawn == null || pawn.Faction == null) ? "null" : pawn.Faction.ToString(); Log.Warning(pawn + " pathing from " + start + " to " + dest + " ran out of cells to process.\nJob:" + text + "\nFaction: " + text2); DebugDrawRichData(); PfProfilerEndSample(); return(PawnPath.NotFound); } num5 += openList.Count; num6++; CostNode costNode = openList.Pop(); curIndex = costNode.index; if (costNode.cost != calcGrid[curIndex].costNodeCost) { PfProfilerEndSample(); } else if (calcGrid[curIndex].status == statusClosedValue) { PfProfilerEndSample(); } else { IntVec3 c = cellIndices.IndexToCell(curIndex); int x2 = c.x; int z2 = c.z; if (flag6) { DebugFlash(c, (float)calcGrid[curIndex].knownCost / 1500f, calcGrid[curIndex].knownCost.ToString()); } if (flag4) { if (curIndex == num) { PfProfilerEndSample(); PawnPath result = FinalizedPath(curIndex, flag9); PfProfilerEndSample(); return(result); } } else if (cellRect.Contains(c) && !disallowedCornerIndices.Contains(curIndex)) { PfProfilerEndSample(); PawnPath result2 = FinalizedPath(curIndex, flag9); PfProfilerEndSample(); return(result2); } if (num2 > 160000) { break; } PfProfilerEndSample(); PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num10 = (uint)(x2 + Directions[i]); uint num11 = (uint)(z2 + Directions[i + 8]); if (num10 < mapSizeX && num11 < mapSizeZ) { int num12 = (int)num10; int num13 = (int)num11; int num14 = cellIndices.CellToIndex(num12, num13); if (calcGrid[num14].status != statusClosedValue || flag9) { int num15 = 0; bool flag11 = false; if (flag2 || !new IntVec3(num12, 0, num13).GetTerrain(map).HasTag("Water")) { if (!pathGrid.WalkableFast(num14)) { if (!flag) { if (flag6) { DebugFlash(new IntVec3(num12, 0, num13), 0.22f, "walk"); } continue; } flag11 = true; num15 += 70; Building building = edificeGrid[num14]; if (building == null || !IsDestroyable(building)) { continue; } num15 += (int)((float)building.HitPoints * 0.2f); } switch (i) { case 4: if (BlocksDiagonalMovement(curIndex - mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "corn"); } break; } num15 += 70; } if (BlocksDiagonalMovement(curIndex + 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "corn"); } break; } num15 += 70; } goto default; case 5: if (BlocksDiagonalMovement(curIndex + mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "corn"); } break; } num15 += 70; } if (BlocksDiagonalMovement(curIndex + 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "corn"); } break; } num15 += 70; } goto default; case 6: if (BlocksDiagonalMovement(curIndex + mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "corn"); } break; } num15 += 70; } if (BlocksDiagonalMovement(curIndex - 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "corn"); } break; } num15 += 70; } goto default; case 7: if (BlocksDiagonalMovement(curIndex - mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "corn"); } break; } num15 += 70; } if (BlocksDiagonalMovement(curIndex - 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "corn"); } break; } num15 += 70; } goto default; default: { int num16 = (i <= 3) ? num8 : num9; num16 += num15; if (!flag11) { num16 += array[num14]; num16 = ((!flag10) ? (num16 + topGrid[num14].extraNonDraftedPerceivedPathCost) : (num16 + topGrid[num14].extraDraftedPerceivedPathCost)); } if (byteGrid != null) { num16 += byteGrid[num14] * 8; } if (allowedArea != null && !allowedArea[num14]) { num16 += 600; } if (flag5 && PawnUtility.AnyPawnBlockingPathAt(new IntVec3(num12, 0, num13), pawn, actAsIfHadCollideWithPawnsJob: false, collideOnlyWithStandingPawns: false, forPathFinder: true)) { num16 += 175; } Building building2 = this.edificeGrid[num14]; if (building2 != null) { PfProfilerBeginSample("Edifices"); int buildingCost = GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == 2147483647) { PfProfilerEndSample(); break; } num16 += buildingCost; PfProfilerEndSample(); } List <Blueprint> list = blueprintGrid[num14]; if (list != null) { PfProfilerBeginSample("Blueprints"); int num17 = 0; for (int j = 0; j < list.Count; j++) { num17 = Mathf.Max(num17, GetBlueprintCost(list[j], pawn)); } if (num17 == 2147483647) { PfProfilerEndSample(); break; } num16 += num17; PfProfilerEndSample(); } int num18 = num16 + calcGrid[curIndex].knownCost; ushort status = calcGrid[num14].status; if (status == statusClosedValue || status == statusOpenValue) { int num19 = 0; if (status == statusClosedValue) { num19 = num8; } if (calcGrid[num14].knownCost <= num18 + num19) { break; } } if (flag9) { calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)regionCostCalculator.GetPathCostFromDestToRegion(num14) * RegionHeuristicWeightByNodesOpened.Evaluate((float)num3)); if (calcGrid[num14].heuristicCost < 0) { Log.ErrorOnce("Heuristic cost overflow for " + pawn.ToStringSafe() + " pathing from " + start + " to " + dest + ".", pawn.GetHashCode() ^ 0xB8DC389); calcGrid[num14].heuristicCost = 0; } } else if (status != statusClosedValue && status != statusOpenValue) { int dx = Math.Abs(num12 - x); int dz = Math.Abs(num13 - z); int num20 = GenMath.OctileDistance(dx, dz, num8, num9); calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)num20 * num7); } int num21 = num18 + calcGrid[num14].heuristicCost; if (num21 < 0) { Log.ErrorOnce("Node cost overflow for " + pawn.ToStringSafe() + " pathing from " + start + " to " + dest + ".", pawn.GetHashCode() ^ 0x53CB9DE); num21 = 0; } calcGrid[num14].parentIndex = curIndex; calcGrid[num14].knownCost = num18; calcGrid[num14].status = statusOpenValue; calcGrid[num14].costNodeCost = num21; num3++; openList.Push(new CostNode(num14, num21)); break; } } } } } } PfProfilerEndSample(); num2++; calcGrid[curIndex].status = statusClosedValue; if (num3 >= num4 && flag7 && !flag9) { flag9 = true; regionCostCalculator.Init(cellRect, traverseParms, num8, num9, byteGrid, allowedArea, flag10, disallowedCornerIndices); InitStatusesAndPushStartNode(ref curIndex, start); num3 = 0; num2 = 0; } } } Log.Warning(pawn + " pathing from " + start + " to " + dest + " hit search limit of " + 160000 + " cells."); DebugDrawRichData(); PfProfilerEndSample(); return(PawnPath.NotFound); }