public static void AddAllowedAdjacentRegions(LocalTargetInfo dest, TraverseParms traverseParams, Map map, List <VehicleRegion> regions) { GenAdj.GetAdjacentCorners(dest, out IntVec3 bl, out IntVec3 tl, out IntVec3 tr, out IntVec3 br); if (!dest.HasThing || (dest.Thing.def.size.x == 1 && dest.Thing.def.size.z == 1)) { IntVec3 cell = dest.Cell; for (int i = 0; i < 8; i++) { IntVec3 intVec = GenAdj.AdjacentCells[i] + cell; if (intVec.InBoundsShip(map) && !TouchPathEndModeUtility.IsAdjacentCornerAndNotAllowed(intVec, bl, tl, tr, br, map)) { VehicleRegion region = VehicleGridsUtility.GetRegion(intVec, map, RegionType.Set_Passable); if (region != null && region.Allows(traverseParams, true)) { regions.Add(region); } } } } else { List <IntVec3> list = GenAdjFast.AdjacentCells8Way(dest); for (int j = 0; j < list.Count; j++) { if (list[j].InBoundsShip(map) && !TouchPathEndModeUtility.IsAdjacentCornerAndNotAllowed(list[j], bl, tl, tr, br, map)) { VehicleRegion region2 = VehicleGridsUtility.GetRegion(list[j], map, RegionType.Set_Passable); if (region2 != null && region2.Allows(traverseParams, true)) { regions.Add(region2); } } } } }
public bool CanReachUnfogged(IntVec3 c, TraverseParms traverseParms) { if (traverseParms.pawn != null) { if (!traverseParms.pawn.Spawned) { return(false); } if (traverseParms.pawn.Map != map) { Log.Error(string.Concat(new object[] { "Called CanReachUnfogged() with a pawn spawned not on this map. This means that we can't check his reachability here. Pawn's current map should have been used instead of this one. pawn=", traverseParms.pawn, " pawn.Map=", traverseParms.pawn.Map, " map=", map })); return(false); } } if (!c.InBoundsShip(map)) { return(false); } if (!c.Fogged(map)) { return(true); } VehicleRegion region = VehicleGridsUtility.GetRegion(c, map, RegionType.Set_Passable); if (region == null) { return(false); } bool entryCondition(VehicleRegion from, VehicleRegion r) => r.Allows(traverseParms, false); bool foundReg = false; bool regionProcessor(VehicleRegion r) { if (!r.AnyCell.Fogged(map)) { foundReg = true; return(true); } return(false); } WaterRegionTraverser.BreadthFirstTraverse(region, entryCondition, regionProcessor, 9999, RegionType.Set_Passable); return(foundReg); }
public void Init(CellRect end, TraverseParms traverseParms, int moveTicksCardinal, int moveTicksDiagonal, ByteGrid avoidGrid, Area allowedArea, bool drafted, List <int> disallowedCorners) { this.moveTicksCardinal = moveTicksCardinal; this.moveTicksDiagonal = moveTicksDiagonal; endCell = end.CenterCell; cachedRegion = null; cachedBestLink = null; cachedSecondBestLink = null; cachedBestLinkCost = 0; cachedSecondBestLinkCost = 0; cachedRegionIsDestination = false; regionGrid = map.GetCachedMapComponent <VehicleMapping>().VehicleRegionGrid.DirectGrid; destRegions.Clear(); if (end.Width == 1 && end.Height == 1) { VehicleRegion region = VehicleGridsUtility.GetRegion(endCell, map, RegionType.Set_Passable); if (region != null) { destRegions.Add(region); } } else { foreach (IntVec3 intVec in end) { if (intVec.InBoundsShip(map) && !disallowedCorners.Contains(map.cellIndices.CellToIndex(intVec))) { VehicleRegion region2 = VehicleGridsUtility.GetRegion(intVec, map, RegionType.Set_Passable); if (region2 != null) { if (region2.Allows(traverseParms, true)) { destRegions.Add(region2); } } } } } if (destRegions.Count == 0) { Log.Error("Couldn't find any destination regions. This shouldn't ever happen because we've checked reachability."); } vehicleRegionCostCalculator.Init(end, destRegions, traverseParms, moveTicksCardinal, moveTicksDiagonal, avoidGrid, allowedArea, drafted); }
public (PawnPath path, bool found) FindVehiclePath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, CancellationToken token, PathEndMode peMode = PathEndMode.OnCell, bool waterPathing = false) { if (report) { Debug.Message($"{VehicleHarmony.LogLabel} MainPath for {traverseParms.pawn.LabelShort} - ThreadId: [{Thread.CurrentThread.ManagedThreadId}] TaskId: [{Task.CurrentId}]"); } postCalculatedCells.Clear(); VehicleMapping VehicleMapping = map.GetCachedMapComponent <VehicleMapping>(); if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } VehiclePawn pawn = traverseParms.pawn as VehiclePawn; if (!pawn.IsBoat() && waterPathing) { Log.Error($"Set to waterPathing but {pawn.LabelShort} is not registered as a Boat. Self Correcting..."); waterPathing = false; } if (!(pawn is null) && pawn.Map != map) { Log.Error(string.Concat(new object[] { "Tried to FindVehiclePath for pawn which is spawned in another map. Their map PathFinder should have been used, not this one. " + "pawn=", pawn, " pawn.Map=", pawn.Map, " map=", map })); return(PawnPath.NotFound, false); } if (!start.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindShipPath with invalid start ", start, ", pawn=", pawn })); return(PawnPath.NotFound, false); } if (!dest.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn })); return(PawnPath.NotFound, false); } if (traverseParms.mode == TraverseMode.ByPawn) { if (waterPathing) { if (!ShipReachabilityUtility.CanReachShip(pawn, dest, peMode, Danger.Deadly, false, traverseParms.mode)) { return(PawnPath.NotFound, false); } } else { if (!ReachabilityUtility.CanReach(pawn, dest, peMode, Danger.Deadly, false, traverseParms.mode)) { return(PawnPath.NotFound, false); } } } else { if (waterPathing) { if (!VehicleMapping.VehicleReachability.CanReachShip(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound, false); } } else { if (!map.reachability.CanReach(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound, false); } } } cellIndices = map.cellIndices; VehiclePathGrid = VehicleMapping.VehiclePathGrid; pathGrid = map.pathGrid; this.edificeGrid = map.edificeGrid.InnerArray; blueprintGrid = map.blueprintGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int num = cellIndices.CellToIndex(start); int num2 = cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = (pawn is null) ? null : pawn.GetAvoidGrid(true); 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[] boatsArray = VehiclePathGrid.pathGrid; int[] vehicleArray = pathGrid.pathGrid; TerrainDef[] topGrid = map.terrainGrid.topGrid; EdificeGrid edificeGrid = map.edificeGrid; int num3 = 0; int num4 = 0; Area allowedArea = GetAllowedArea(pawn); bool flag5 = !(pawn is null) && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = true && DebugViewSettings.drawPaths; bool flag7 = !flag && !(VehicleGridsUtility.GetRegion(start, map, RegionType.Set_Passable) is null) && flag2; bool flag8 = !flag || !flag3; bool flag9 = false; bool flag10 = !(pawn is null) && pawn.Drafted; bool flag11 = !(pawn is null) && !(pawn is null); int num5 = (!flag11) ? NodesToOpenBeforeRegionbasedPathing_NonShip : NodesToOpenBeforeRegionBasedPathing_Ship; int num6 = 0; int num7 = 0; float num8 = DetermineHeuristicStrength(pawn, start, dest); int num9 = !(pawn is null) ? pawn.TicksPerMoveCardinal : DefaultMoveTicksCardinal; int num10 = !(pawn is null) ? pawn.TicksPerMoveDiagonal : DefaultMoveTicksDiagonal; CalculateAndAddDisallowedCorners(traverseParms, peMode, cellRect); InitStatusesAndPushStartNode(ref num, start); Rot8 rot = pawn.FullRotation; int iterations = 0; for (;;) { if (token.IsCancellationRequested) { return(PawnPath.NotFound, false); } iterations++; if (openList.Count <= 0) { break; } num6 += openList.Count; num7++; CostNode costNode = openList.Pop(); num = costNode.index; if (costNode.cost == calcGrid[num].costNodeCost && calcGrid[num].status != statusClosedValue) { IntVec3 c = cellIndices.IndexToCell(num); IntVec3 prevCell = c; int x2 = c.x; int z2 = c.z; if (flag6) { DebugFlash(c, calcGrid[num].knownCost / 1500f, calcGrid[num].knownCost.ToString()); } if (flag4) { if (num == num2) { goto Block_32; } } else if (cellRect.Contains(c) && !disallowedCornerIndices.Contains(num)) { goto Block_32; } if (num3 > SearchLimit) { goto Block_33; } List <IntVec3> fullRectCells = CellRect.CenteredOn(c, pawn.def.size.x, pawn.def.size.z).Where(cl2 => cl2 != c).ToList(); for (int i = 0; i < 8; i++) { uint num11 = (uint)(x2 + Directions[i]); //x uint num12 = (uint)(z2 + Directions[i + 8]); //y if (num11 < ((ulong)mapSizeX) && num12 < (ulong)(mapSizeZ)) { int num13 = (int)num11; int num14 = (int)num12; int num15 = cellIndices.CellToIndex(num13, num14); IntVec3 cellToCheck = cellIndices.IndexToCell(num15); if (VehicleMod.settings.main.fullVehiclePathing && pawn.LocationRestrictedBySize(cellToCheck)) { goto EndPathing; } if (calcGrid[num15].status != statusClosedValue || flag9) { int num16 = 0; bool flag12 = false; //Extra cost for traversing water if (flag2 || !new IntVec3(num13, 0, num14).GetTerrain(map).HasTag("Water")) { if (waterPathing) { if (!pawn.DrivableFast(num15)) { if (!flag) { if (flag6) { DebugFlash(new IntVec3(num13, 0, num14), 0.22f, "walk"); } goto EndPathing; } num16 += 70; Building building = edificeGrid[num15]; if (building is null) { goto EndPathing; } if (!IsDestroyable(building)) { goto EndPathing; } num16 += (int)(building.HitPoints * 0.2f); } } else { if (!pawn.DrivableFast(num15)) { if (!flag) { if (flag6) { DebugFlash(new IntVec3(num13, 0, num14), 0.22f, "walk"); } goto EndPathing; } flag12 = true; num16 += 70; Building building = edificeGrid[num15]; if (building is null) { goto EndPathing; } if (!IsDestroyable(building)) { goto EndPathing; } num16 += (int)(building.HitPoints * 0.2f); } } if (i > 3) { switch (i) { case 4: if (BlocksDiagonalMovement(pawn, num - mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } if (BlocksDiagonalMovement(pawn, num + 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } break; case 5: if (BlocksDiagonalMovement(pawn, num + mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } if (BlocksDiagonalMovement(pawn, num + 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } break; case 6: if (BlocksDiagonalMovement(pawn, num + mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } if (BlocksDiagonalMovement(pawn, num - 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } break; case 7: if (BlocksDiagonalMovement(pawn, num - mapSizeX)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } if (BlocksDiagonalMovement(pawn, num - 1)) { if (flag8) { if (flag6) { DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "ships"); } goto EndPathing; } num16 += 70; } break; } } int num17 = (i <= 3) ? num9 : num10; num17 += num16; //if (Rot8.DirectionFromCells(prevCell, cellToCheck) != rot) //{ // Log.Message("Additional Cost"); // num17 += ChangeDirectionAdditionalCost; //} if (!flag12 && !waterPathing) { //Extra Terrain costs if (pawn.VehicleDef.properties.customTerrainCosts?.NotNullAndAny() ?? false) { TerrainDef currentTerrain = map.terrainGrid.TerrainAt(num15); if (pawn.VehicleDef.properties.customTerrainCosts.ContainsKey(currentTerrain)) { int customCost = pawn.VehicleDef.properties.customTerrainCosts[currentTerrain]; if (customCost < 0) { goto EndPathing; } num17 += customCost; } else { num17 += vehicleArray[num15]; } } else { num17 += vehicleArray[num15]; } num17 += flag10 ? topGrid[num15].extraDraftedPerceivedPathCost : topGrid[num15].extraNonDraftedPerceivedPathCost; } if (byteGrid != null) { num17 += (byteGrid[num15] * 8); } //Allowed area cost? if (flag5 && MultithreadHelper.AnyVehicleBlockingPathAt(new IntVec3(num13, 0, num14), pawn, false, false, true) != null) { num17 += Cost_PawnCollision; } Building building2 = edificeGrid[num15]; if (!(building2 is null)) { //Building Costs Here } if (blueprintGrid[num15] != null) { List <Blueprint> list = new List <Blueprint>(blueprintGrid[num15]); if (!list.NullOrEmpty()) { int num18 = 0; foreach (Blueprint bp in list) { num18 = Mathf.Max(num18, GetBlueprintCost(bp, pawn)); } if (num18 == int.MaxValue) { goto EndPathing; } num17 += num18; } } int num19 = num17 + calcGrid[num].knownCost; ushort status = calcGrid[num15].status; //if(pawn.Props.useFullHitboxPathing) //{ // foreach(IntVec3 fullRect in fullRectCells) // { // if(fullRect != cellToCheck) // { // num19 += calcGrid[cellIndices.CellToIndex(fullRect)].knownCost; // Log.Message($"Cell: {fullRect} Cost: {num19}"); // if(postCalculatedCells.ContainsKey(fullRect)) // { // postCalculatedCells[fullRect] = num19; // } // else // { // postCalculatedCells.Add(fullRect, num19); // } // } // } //} //Only generate path costs for linear non-reverse pathing check if (report) { if (postCalculatedCells.ContainsKey(cellToCheck)) { postCalculatedCells[cellToCheck] = num19; } else { postCalculatedCells.Add(cellToCheck, num19); } } if (waterPathing && !map.terrainGrid.TerrainAt(num15).IsWater) { num19 += 10000; } if (status == statusClosedValue || status == statusOpenValue) { int num20 = 0; if (status == statusClosedValue) { num20 = num9; } if (calcGrid[num15].knownCost <= num19 + num20) { goto EndPathing; } } if (flag9) { calcGrid[num15].heuristicCost = waterPathing ? Mathf.RoundToInt(regionCostCalculatorSea.GetPathCostFromDestToRegion(num15) * RegionheuristicWeighByNodesOpened.Evaluate(num4)) : Mathf.RoundToInt(regionCostCalculatorLand.GetPathCostFromDestToRegion(num15) * RegionheuristicWeighByNodesOpened.Evaluate(num4)); if (calcGrid[num15].heuristicCost < 0) { Log.ErrorOnce(string.Concat(new object[] { "Heuristic cost overflow for vehicle ", pawn.ToStringSafe <Pawn>(), " pathing from ", start, " to ", dest, "." }), pawn.GetHashCode() ^ 193840009); calcGrid[num15].heuristicCost = 0; } } else if (status != statusClosedValue && status != statusOpenValue) { int dx = Math.Abs(num13 - x); int dz = Math.Abs(num14 - z); int num21 = GenMath.OctileDistance(dx, dz, num9, num10); calcGrid[num15].heuristicCost = Mathf.RoundToInt((float)num21 * num8); } int num22 = num19 + calcGrid[num15].heuristicCost; if (num22 < 0) { Log.ErrorOnce(string.Concat(new object[] { "Node cost overflow for ship ", pawn.ToStringSafe <Pawn>(), " pathing from ", start, " to ", dest, "." }), pawn.GetHashCode() ^ 87865822); num22 = 0; } calcGrid[num15].parentIndex = num; calcGrid[num15].knownCost = num19; calcGrid[num15].status = statusOpenValue; calcGrid[num15].costNodeCost = num22; num4++; rot = Rot8.DirectionFromCells(prevCell, cellToCheck); openList.Push(new CostNode(num15, num22)); } } } EndPathing :; } num3++; calcGrid[num].status = statusClosedValue; if (num4 >= num5 && flag7 && !flag9) { flag9 = true; if (waterPathing) { regionCostCalculatorSea.Init(cellRect, traverseParms, num9, num10, byteGrid, allowedArea, flag10, disallowedCornerIndices); } else { regionCostCalculatorLand.Init(cellRect, traverseParms, num9, num10, byteGrid, allowedArea, flag10, disallowedCornerIndices); } InitStatusesAndPushStartNode(ref num, start); num4 = 0; num3 = 0; } } } string text = ((pawn is null) || pawn.CurJob is null) ? "null" : pawn.CurJob.ToString(); string text2 = ((pawn is null) || pawn.Faction is null) ? "null" : pawn.Faction.ToString(); if (report) { Log.Warning(string.Concat(new object[] { "ship pawn: ", pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2, "\niterations: ", iterations })); } DebugDrawRichData(); return(PawnPath.NotFound, false); Block_32: PawnPath result = PawnPath.NotFound; if (report) { result = FinalizedPath(num, flag9); } DebugDrawPathCost(); return(result, true); Block_33: Log.Warning(string.Concat(new object[] { "Ship ", pawn, " pathing from ", start, " to ", dest, " hit search limit of ", SearchLimit, " cells." })); DebugDrawRichData(); return(PawnPath.NotFound, false); }
public bool CanReachShip(IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParms) { if (working) { Log.ErrorOnce("Called CanReach() while working for Ships. This should never happen. Suppressing further errors.", 7312233); return(false); } if (!map.terrainGrid.TerrainAt(dest.Cell).IsWater) { return(false); } if (!(traverseParms.pawn is null)) { if (!traverseParms.pawn.Spawned) { return(false); } if (traverseParms.pawn.Map != map) { Log.Error(string.Concat(new object[] { "Called CanReach() with a ship spawned not on this map. This means that we can't check its reachability here. Pawn's" + "current map should have been used instead of this one. pawn=", traverseParms.pawn, " pawn.Map=", traverseParms.pawn.Map, " map=", map })); return(false); } } if (!dest.IsValid) { return(false); } if (dest.HasThing && dest.Thing.Map != map) { return(false); } if (!start.InBoundsShip(map) || !dest.Cell.InBoundsShip(map)) { return(false); } if ((peMode == PathEndMode.OnCell || peMode == PathEndMode.Touch || peMode == PathEndMode.ClosestTouch) && traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater) { VehicleRoom room = VehicleRegionAndRoomQuery.RoomAtFast(start, map, RegionType.Set_Passable); if (!(room is null) && room == VehicleRegionAndRoomQuery.RoomAtFast(dest.Cell, map, RegionType.Set_Passable)) { return(true); } } if (traverseParms.mode == TraverseMode.PassAllDestroyableThings) { TraverseParms traverseParms2 = traverseParms; traverseParms.mode = TraverseMode.PassDoors; if (CanReachShip(start, dest, peMode, traverseParms2)) { return(true); } } dest = (LocalTargetInfo)GenPathVehicles.ResolvePathMode(traverseParms.pawn, dest.ToTargetInfo(map), ref peMode); working = true; bool result; try { pathGrid = map.GetCachedMapComponent <VehicleMapping>().VehiclePathGrid; regionGrid = map.GetCachedMapComponent <VehicleMapping>().VehicleRegionGrid; reachedIndex += 1u; destRegions.Clear(); if (peMode == PathEndMode.OnCell) { VehicleRegion region = VehicleGridsUtility.GetRegion(dest.Cell, map, RegionType.Set_Passable); if (!(region is null) && region.Allows(traverseParms, true)) { destRegions.Add(region); } } else if (peMode == PathEndMode.Touch) { TouchPathEndModeUtilityVehicles.AddAllowedAdjacentRegions(dest, traverseParms, map, destRegions); } if (destRegions.Count == 0 && traverseParms.mode != TraverseMode.PassAllDestroyableThings && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater) { FinalizeCheck(); result = false; } else { destRegions.RemoveDuplicates(); openQueue.Clear(); numRegionsOpened = 0; DetermineStartRegions(start); if (openQueue.Count == 0 && traverseParms.mode != TraverseMode.PassAllDestroyableThings && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater) { FinalizeCheck(); result = false; } else { if (startingRegions.Any() && destRegions.Any() && CanUseCache(traverseParms.mode)) { BoolUnknown cachedResult = GetCachedResult(traverseParms); if (cachedResult == BoolUnknown.True) { FinalizeCheck(); return(true); } if (cachedResult == BoolUnknown.False) { FinalizeCheck(); return(false); } } if (traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater || traverseParms.mode == TraverseMode.NoPassClosedDoorsOrWater) { bool flag = CheckCellBasedReachability(start, dest, peMode, traverseParms); FinalizeCheck(); result = flag; } else { bool flag2 = CheckRegionBasedReachability(traverseParms); //bool flag2 = CheckCellBasedReachability(start, dest, peMode, traverseParms); //REDO? FinalizeCheck(); result = flag2; } } } } finally { working = false; } return(result); }