public static void Postfix(MapTerrainDataCell cell, ref bool __result) { if (!cell.MapEncounterLayerDataCell.HasBuilding) { CacheManager.WatchCache[cell] = __result; } }
public static void AppendDangerousTerrainText(MoveStatusPreview __instance, AbstractActor actor, Vector3 worldPos) { try { MapTerrainDataCell cell = Combat.EncounterLayerData.GetCellAt(worldPos).relatedTerrainCell; bool isLandingZone = SplatMapInfo.IsDropshipLandingZone(cell.terrainMask), isDangerous = SplatMapInfo.IsDangerousLocation(cell.terrainMask); if (!isLandingZone && !isDangerous) { return; } DesignMaskDef mask = Combat.MapMetaData.GetPriorityDesignMask(cell); if (mask == null) { return; } string title = mask.Description.Name, text = mask.Description.Details; CombatUIConstantsDef desc = Combat.Constants.CombatUIConstants; if (isDangerous) { title += " <#FF0000>(" + desc.DangerousLocationDesc.Name + ")"; text += " <#FF0000>" + desc.DangerousLocationDesc.Details; if (isLandingZone) { text += " " + desc.DrophipLocationDesc.Details; } } else { title += " <#FF0000>(" + desc.DrophipLocationDesc.Name + ")"; text += " <#FF0000>" + desc.DrophipLocationDesc.Details; } CombatHUDInfoSidePanel sidePanel = (CombatHUDInfoSidePanel)SidePanelProp?.GetValue(__instance, null); sidePanel?.ForceShowSingleFrame(new Text(title), new Text(text), null, false); } catch (Exception ex) { Error(ex); } }
// Duplication of HBS code, avoiding prefix=true for now. public static void Postfix(ref BehaviorTreeResults __result, string ___name, BehaviorTree ___tree, AbstractActor ___unit) { Mod.Log.Info?.Write("CJMCN:T - entered"); Mech mech = ___unit as Mech; if (mech != null && mech.WorkingJumpjets > 0) { string stayInsideRegionGUID = RegionUtil.GetStayInsideRegionGUID(___unit); float acceptableHeat = AIUtil.GetAcceptableHeatLevelForMech(mech); float currentHeat = (float)mech.CurrentHeat; Mod.Log.Info?.Write($"CJMCN:T - === actor:{CombatantUtils.Label(mech)} has currentHeat:{currentHeat} and acceptableHeat:{acceptableHeat}"); List <PathNode> sampledPathNodes = ___unit.JumpPathing.GetSampledPathNodes(); Mod.Log.Info?.Write($"CJMCN:T - calculating {sampledPathNodes.Count} nodes"); for (int i = 0; i < sampledPathNodes.Count; i++) { Vector3 candidatePos = sampledPathNodes[i].Position; float distanceBetween2D = AIUtil.Get2DDistanceBetweenVector3s(candidatePos, ___unit.CurrentPosition); float distanceBetween3D = Vector3.Distance(candidatePos, ___unit.CurrentPosition); Mod.Log.Info?.Write($"CJMCN:T - calculated distances 2D:'{distanceBetween2D}' 3D:'{distanceBetween3D} "); if (distanceBetween2D >= 1f) { float magnitude = (candidatePos - ___unit.CurrentPosition).magnitude; float jumpHeat = (float)mech.CalcJumpHeat(magnitude); Mod.Log.Info?.Write($"CJMCN:T - calculated jumpHeat:'{jumpHeat}' from magnitude:'{magnitude}. "); Mod.Log.Info?.Write($"CJMCN:T - comparing heat: [jumpHeat:'{jumpHeat}' + currentHeat:'{currentHeat}'] <= acceptableHeat:'{acceptableHeat}. "); if (jumpHeat + (float)mech.CurrentHeat <= acceptableHeat) { if (stayInsideRegionGUID != null) { MapTerrainDataCell cellAt = ___unit.Combat.MapMetaData.GetCellAt(candidatePos); if (cellAt != null) { MapEncounterLayerDataCell mapEncounterLayerDataCell = cellAt.MapEncounterLayerDataCell; if (mapEncounterLayerDataCell != null && mapEncounterLayerDataCell.regionGuidList != null && !mapEncounterLayerDataCell.regionGuidList.Contains(stayInsideRegionGUID)) { // Skip this loop iteration if Mod.Log.Info?.Write($"CJMCN:T - candidate outside of constraint region, ignoring."); goto CANDIDATE_OUTSIDE_REGION; } } } Mod.Log.Info?.Write($"CJMCN:T - adding candidate position:{candidatePos}"); ___tree.movementCandidateLocations.Add(new MoveDestination(sampledPathNodes[i], MoveType.Jumping)); } } CANDIDATE_OUTSIDE_REGION :; } } // Should already be set by prefix method //__result = BehaviorTreeResults(BehaviorNodeState.Success); }
/// <summary> /// Gets incremental incline data for a point and a neighboring point. /// </summary> /// <param name="mapMetaData">Map meta data.</param> /// <param name="startPoint">Start point, using mapmetadata indices.</param> /// <param name="endPoint">End point, using mapmetadata indices.</param> /// <param name="incline">Incline (out).</param> /// <param name="decline">Decline (out).</param> /// <param name="distance">Distance (out).</param> void getIncrementalInclines(MapMetaData mapMetaData, Point startPoint, Point endPoint, out float incline, out float decline, out float distance) { Vector3 startVector = mapMetaData.getWorldPos(startPoint); Vector3 endVector = mapMetaData.getWorldPos(endPoint); MapTerrainDataCell startCell = mapMetaData.GetCellAt(startPoint); MapTerrainDataCell endCell = mapMetaData.GetCellAt(endPoint); float horzDistance = Mathf.Abs(startVector.x - endVector.x) + Mathf.Abs(startVector.z - endVector.z); distance = horzDistance; float vertDistance = endCell.cachedHeight - startCell.cachedHeight; if (vertDistance > 0) { decline = 0.0f; incline = vertDistance / horzDistance; } else { incline = 0.0f; decline = -(vertDistance / horzDistance); } }
public static bool Prefix(MapTerrainDataCell cell) { if (cell is MapTerrainDataCellEx eCell) { return(!eCell.waterLevelCached); } return(true); }
static bool Prefix(MapMetaData __instance, ref MapTerrainDataCell __result, Point index, MapTerrainDataCell[,] ___mapTerrainDataCells) { try { __result = ___mapTerrainDataCells[index.Z, index.X]; } catch (IndexOutOfRangeException) { __result = InvalidCell; } return(false); }
public static bool Prefix(MapTerrainDataCell cell, ref bool __result) { if (cell is null) { return(true); } return(!CacheManager.WatchCache.TryGetValue(cell, out __result)); }
private bool IsCellImpassableOrDeepWater(MapTerrainDataCell cellData) { TerrainMaskFlags terrainMask = cellData.terrainMask; bool isImpassableOrDeepWater = SplatMapInfo.IsImpassable(terrainMask) || (SplatMapInfo.IsDeepWater(terrainMask) && !cellData.MapEncounterLayerDataCell.HasBuilding); if (isImpassableOrDeepWater) { Main.LogDebug("[PFM.IsCellImpassableOrDeepWater] Tile is impassable or deep water"); return(true); } return(false); }
private bool HasPathImpassableOrDeepWaterTiles(CombatGameState combatState, List <Vector3> path) { if (path == null) { return(true); } for (int i = 0; i < path.Count; i++) { Vector3 position = path[i]; MapTerrainDataCell cellData = combatState.MapMetaData.GetCellAt(position); if (IsCellImpassableOrDeepWater(cellData)) { Main.LogDebug("[PFM.HasPathImpassableOrDeepWaterTiles] Path has impassable or deep water tiles in it"); return(true); } } return(false); }
public bool IsSpawnValid(GameObject spawnGo, Vector3 position, Vector3 validityPosition, UnitType type, string identifier) { CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; MapTerrainDataCell cellData = combatState.MapMetaData.GetCellAt(position); Main.LogDebug($""); Main.LogDebug($"-------- [PFM.IsSpawnValid] [{identifier}] --------"); if (position.IsTooCloseToAnotherSpawn(spawnGo)) { Main.LogDebug($"[PFM] Position '{position}' is too close to another spawn point. Not a valid location."); return(false); } if (cellData.cachedSteepness > MAX_SLOPE_FOR_PATHFINDING) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Spawn point of '{cellData.cachedSteepness}' is too steep (> {MAX_SLOPE_FOR_PATHFINDING}). Not a valid spawn"); return(false); } if (IsCellImpassableOrDeepWater(cellData)) { return(false); } if (!encounterLayerData.IsInEncounterBounds(position)) { return(false); } if (cellData.cachedHeight > (cellData.terrainHeight + 50f)) { return(false); } float pathFindingZoneRadius = 25f; AbstractActor pathfindingActor = GetPathFindingActor(type); SetupPathfindingActor(position, pathfindingActor); PathNode positionPathNode = null; try { PathNodeGrid pathfinderPathGrid = pathfindingActor.Pathing.CurrentGrid; positionPathNode = pathfinderPathGrid.GetValidPathNodeAt(position, pathfindingActor.Pathing.MaxCost); if (positionPathNode == null) { Reset(); return(false); } } catch (Exception e) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Caught error in 'pathfinderPathGrid.GetValidPathNodeAt' chunk. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); WasABadPathfindTest(validityPosition); return(false); } if (positionPathNode == null) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] PositionPathNode not set from 'pathfinderPathGrid.GetValidPathNodeAt'. No valid path found so not a valid spawn."); WasABadPathfindTest(validityPosition); return(false); } List <Vector3> path = null; try { DynamicLongRangePathfinder.PointWithCost pointWithCost = new DynamicLongRangePathfinder.PointWithCost(combatState.HexGrid.GetClosestHexPoint3OnGrid(positionPathNode.Position), 0, (validityPosition - positionPathNode.Position).magnitude); path = DynamicLongRangePathfinder.GetDynamicPathToDestination(new List <DynamicLongRangePathfinder.PointWithCost>() { pointWithCost }, validityPosition, float.MaxValue, pathfindingActor, false, new List <AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); } catch (Exception e) { // TODO: Sometimes this gets triggered in very large amounts. It's usually because the SpawnLogic.GetClosestValidPathFindingHex is increasing // the radius larger and larger and the checks keep going off the map // I need a way to hard abort out of this and either use the original origin of the focus or trigger the rule logic again (random, around a position etc) Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Caught error in 'DynamicLongRangePathfinder' chunk. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); WasABadPathfindTest(validityPosition); return(false); } if (path == null) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path not set from DynamicLongRangePathfinder so not a valid spawn."); WasABadPathfindTest(validityPosition); return(false); } Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); // GUARD: Against deep water and other impassables that have slipped through if (HasPathImpassableOrDeepWaterTiles(combatState, path)) { return(false); } if (path != null && path.Count > 1 && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Last point is '{path[path.Count - 1]}', Validity position is '{validityPosition}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Distance from last path to valdity position is: '{(path[path.Count - 1].DistanceFlat(validityPosition))}' and is it within zone radius? '{(path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has valid long range path finding"); if (HasValidNeighbours(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has at least two valid neighbours"); if (HasValidLocalPathfinding(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has a valid path"); Reset(); Main.LogDebug($"-------- END [PFM.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); return(true); } else { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Does NOT have a valid path"); } } else { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Does not have two valid neighbours"); } } Main.LogDebug($"-------- END [PFM.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); Reset(); return(false); }
public static bool IsLocationSafe(CombatGameState combat, Vector3 point) { MapTerrainDataCell dataCell = combat.MapMetaData.GetCellAt(point); return(!(SplatMapInfo.IsDropshipLandingZone(dataCell.terrainMask) || SplatMapInfo.IsDropPodLandingZone(dataCell.terrainMask) || SplatMapInfo.IsDangerousLocation(dataCell.terrainMask))); }
/// <summary> /// Finds a path from any of start to goal, such that the path has no links that are steeper than the unit's maxGrade. /// </summary> /// <returns>The path.</returns> /// <param name="startPointList">List of PointWithDistances for points to start from</param> /// <param name="snappedGoalPoint">HexPoint3 to go to</param> /// <param name="unit">moving unit</param> /// <param name="moveType">move type - walk, sprint</param> /// <param name="targetRadius">how close to get to the target</param> /// <param name="actorAware">Discard nodes where other actors reside</param> public static List <PointWithCost> FindPath(List <PointWithCost> startPointList, HexPoint3 snappedGoalPoint, AbstractActor unit, MoveType moveType, float targetRadius, bool actorAware) { MapMetaData mapMetaData = unit.Combat.MapMetaData; HexGrid hexGrid = unit.Combat.HexGrid; unit.Pathing.MoveType = moveType; List <AbstractActor> actors = null; bool startedInEncounterBounds = false; BattleTech.Designed.EncounterBoundaryChunkGameLogic boundaryChunk = unit.Combat.EncounterLayerData.encounterBoundaryChunk; for (int spi = 0; spi < startPointList.Count; ++spi) { PointWithCost sp = startPointList[spi]; //Vector3 wp = HexPoint3ToWorldPoint(sp.point, hexGrid); if (boundaryChunk.IsInEncounterBounds(unit.CurrentPosition)) { startedInEncounterBounds = true; break; } } actorAware = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Bool_EnableLongRangePathfindingBeActorAware).BoolVal ? true : actorAware; if (actorAware) { actors = unit.Combat.AllActors; actors.Remove(unit); } List <PointWithCost> path = new List <PointWithCost>(); HeapQueue <PointWithCost> openHeap = new HeapQueue <PointWithCost>(); Dictionary <HexPoint3, float> bestCostDict = new Dictionary <HexPoint3, float>(); Dictionary <HexPoint3, PointWithCost> bestPrevPoint = new Dictionary <HexPoint3, PointWithCost>(); Vector3 worldGoalPoint = HexPoint3ToWorldPoint(snappedGoalPoint, hexGrid); float bestPathCost = float.MaxValue; bool anyPathFound = false; PointWithCost bestGoalPoint = new PointWithCost(new HexPoint3(-4000, -4000), float.MaxValue, float.MaxValue); for (int startIndex = 0; startIndex < startPointList.Count; ++startIndex) { PointWithCost pwd = startPointList[startIndex]; openHeap.Push(pwd); bestCostDict[pwd.point] = pwd.cost; bestPrevPoint[pwd.point] = null; Vector3 wp = HexPoint3ToWorldPoint(pwd.point, hexGrid); if ((pwd.point.Equals(snappedGoalPoint)) || (AIUtil.Get2DDistanceBetweenVector3s(wp, worldGoalPoint) < targetRadius)) { if (pwd.cost < bestPathCost) { anyPathFound = true; bestPathCost = pwd.cost; bestGoalPoint = pwd; } } } while (!openHeap.IsEmpty()) { PointWithCost ptWithCost = openHeap.PopMinimum(); if (ptWithCost.estimatedTotalCost > bestPathCost) { continue; } Vector3 worldPoint = HexPoint3ToWorldPoint(ptWithCost.point, hexGrid); if (actorAware && CheckForOccupiedPoint(actors, worldPoint)) { continue; } if (startedInEncounterBounds && (!boundaryChunk.IsInEncounterBounds(worldPoint))) { continue; } for (int direction = 0; direction < 6; ++direction) { HexPoint3 neighborHexPoint = ptWithCost.point.Step(direction, 1); Vector3 neighborWorldPoint = HexPoint3ToWorldPoint(neighborHexPoint, hexGrid); if ((!mapMetaData.IsWithinBounds(neighborWorldPoint)) || (unit.Pathing.CurrentGrid.FindBlockerReciprocal(worldPoint, neighborWorldPoint))) { continue; } Debug.DrawLine(worldPoint, neighborWorldPoint, Color.yellow, 15.0f); float linkCost = unit.Pathing.CurrentGrid.GetTerrainModifiedCost(worldPoint, neighborWorldPoint); float newCost = ptWithCost.cost + linkCost; if (newCost >= bestPathCost) { continue; } if ((!bestCostDict.ContainsKey(neighborHexPoint)) || (newCost < bestCostDict[neighborHexPoint])) { bestCostDict[neighborHexPoint] = newCost; bestPrevPoint[neighborHexPoint] = ptWithCost; if ((neighborHexPoint.Equals(snappedGoalPoint)) || ((neighborWorldPoint - worldGoalPoint).magnitude < targetRadius)) { if (newCost < bestPathCost) { anyPathFound = true; bestPathCost = newCost; bestGoalPoint = new PointWithCost(neighborHexPoint, newCost, 0.0f); } } else { Vector3 remainingDistance = (worldGoalPoint - neighborWorldPoint); float estRemainingCost = remainingDistance.magnitude; openHeap.Push(new PointWithCost(neighborHexPoint, newCost, newCost + estRemainingCost)); } } } } if (anyPathFound) { PointWithCost p = bestGoalPoint; path.Add(p); while (bestPrevPoint.ContainsKey(p.point)) { PointWithCost prevPoint = bestPrevPoint[p.point]; if ((prevPoint == null) || (path.Contains(prevPoint))) { break; } path.Insert(0, prevPoint); p = prevPoint; } } else { // draw the failed path data const int SIDES = 3; const float RADIUS = 12; foreach (PointWithCost startPoint in startPointList) { Vector3 worldStartPoint = HexPoint3ToWorldPoint(startPoint.point, hexGrid); for (int i = 0; i < SIDES; ++i) { float dx0 = RADIUS * Mathf.Cos(i * Mathf.PI * 2 / SIDES); float dz0 = RADIUS * Mathf.Sin(i * Mathf.PI * 2 / SIDES); float dx1 = RADIUS * Mathf.Cos((i + 1) * Mathf.PI * 2 / SIDES); float dz1 = RADIUS * Mathf.Sin((i + 1) * Mathf.PI * 2 / SIDES); Vector3 wp0 = new Vector3(worldStartPoint.x + dx0, 0, worldStartPoint.z + dz0); Vector3 wp1 = new Vector3(worldStartPoint.x + dx1, 0, worldStartPoint.z + dz1); Debug.DrawLine(wp0, wp1, Color.magenta, 15.0f); } } Vector3 worldEndPoint = HexPoint3ToWorldPoint(snappedGoalPoint, hexGrid); Color orangeColor = new Color(1.0f, 0.5f, 0.0f); for (int i = 0; i < SIDES; ++i) { float dx0 = RADIUS * Mathf.Cos(i * Mathf.PI * 2 / SIDES); float dz0 = RADIUS * Mathf.Sin(i * Mathf.PI * 2 / SIDES); float dx1 = RADIUS * Mathf.Cos((i + 1) * Mathf.PI * 2 / SIDES); float dz1 = RADIUS * Mathf.Sin((i + 1) * Mathf.PI * 2 / SIDES); Vector3 wp0 = new Vector3(worldEndPoint.x + dx0, 0, worldEndPoint.z + dz0); Vector3 wp1 = new Vector3(worldEndPoint.x + dx1, 0, worldEndPoint.z + dz1); Debug.DrawLine(wp0, wp1, orangeColor, 15.0f); } } int removedCount = 0; // Now, check to see if the end of the path is in "danger". If it is, prune until it's not, which might lead to an empty path. while (path.Count > 0) { PointWithCost lastHexPoint = path[path.Count - 1]; Vector3 lastWorldPoint = HexPoint3ToWorldPoint(lastHexPoint.point, hexGrid); MapTerrainDataCell dataCell = unit.Combat.MapMetaData.GetCellAt(lastWorldPoint); if (SplatMapInfo.IsDropshipLandingZone(dataCell.terrainMask) || SplatMapInfo.IsDangerousLocation(dataCell.terrainMask) || SplatMapInfo.IsDropPodLandingZone(dataCell.terrainMask)) { path.RemoveAt(path.Count - 1); ++removedCount; } else { break; } } if (removedCount > 0) { if (path.Count == 0) { BehaviorNode.LogAI(unit, string.Format("DANGER TRIM: removed all {0} points, bracing", removedCount)); } else { BehaviorNode.LogAI(unit, string.Format("DANGER TRIM: removed {0} points, moving to {1}", removedCount, path[path.Count - 1])); } } return(path); }
static void Postfix(LineOfSight __instance, Point p0, float height0, Point p1, float height1, Vector3 unitDelta, string targetGuid, ref float __result, CombatGameState ___Combat) { if (ModState.CurrentTurretForLOS == null) { return; } if (p0.X == p1.X && p0.Z == p1.Z) { __result = 0f; return; } if (!___Combat.MapMetaData.IsWithinBounds(p0) || !___Combat.MapMetaData.IsWithinBounds(p1)) { __result = float.MaxValue; return; } float numCellsX = Mathf.Abs(unitDelta.x) * (float)MapMetaDataExporter.cellSize; float numCellsY = Mathf.Abs(unitDelta.z) * (float)MapMetaDataExporter.cellSize; float lineDeltaX = (float)(p1.X - p0.X); float lineDeltaZ = (float)(p1.Z - p0.Z); float greatestDivisor = Mathf.Max(Mathf.Abs(lineDeltaX), Mathf.Abs(lineDeltaZ)); float stepHeight = (height1 - height0) / greatestDivisor; float sumVisionCost = 0f; Traverse projectedHeightAtT = Traverse.Create(__instance).Method("getProjectedHeightAt", new Type[] { typeof(Point), typeof(float), typeof(Point), typeof(float) }); Traverse visCostOfCellT = Traverse.Create(__instance).Method("visCostOfCell", new Type[] { typeof(MapTerrainDataCell), typeof(float) }); string shellBuildingGUID = ModState.AmbushTurretGUIDtoBuilding[ModState.CurrentTurretForLOS.GUID].GUID; EncounterLayerData encounterLayerData = ___Combat.EncounterLayerData; List <Point> list = BresenhamLineUtil.BresenhamLine(p0, p1); for (int i = 1; i < list.Count; i++) { float stepDelta; if (list[i].X != list[i - 1].X) { stepDelta = numCellsX; } else { stepDelta = numCellsY; } // Increment vision cost only slightly if it's inside our shell building if (encounterLayerData.mapEncounterLayerDataCells[list[i].Z, list[i].X].HasSpecifiedBuilding(shellBuildingGUID)) { Mod.Log.Trace?.Write($" Point x={list[i].X} z={list[i].Z} is inside the shell building, adding vision cost normally."); sumVisionCost += stepDelta; } else { float projectedHeightAt = projectedHeightAtT.GetValue <float>(new object[] { p0, height0, list[i], stepHeight }); MapTerrainDataCell mapTerrainDataCell = ___Combat.MapMetaData.mapTerrainDataCells[list[i].Z, list[i].X]; if (mapTerrainDataCell.cachedHeight > projectedHeightAt) { if (mapTerrainDataCell.MapEncounterLayerDataCell.HasBuilding) { for (int j = 0; j < mapTerrainDataCell.MapEncounterLayerDataCell.buildingList.Count; j++) { if (ObstructionGameLogic.GuidsMatchObjectOrRep(mapTerrainDataCell.MapEncounterLayerDataCell.buildingList[j].buildingGuid, targetGuid)) { __result = sumVisionCost; return; } } } __result = float.MaxValue; return; } sumVisionCost += visCostOfCellT.GetValue <float>(new object[] { mapTerrainDataCell, projectedHeightAt }) * stepDelta; } } __result = sumVisionCost; return; }
public DistCell(float dist, MapTerrainDataCell cell) { this.dist = dist; this.cell = cell; }
public bool IsSpawnValid(Vector3 position, Vector3 validityPosition, UnitType type, string identifier) { CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; MapTerrainDataCell cellData = combatState.MapMetaData.GetCellAt(position); Main.LogDebug($""); Main.LogDebug($"-------- [PathFinderManager.IsSpawnValid] [{identifier}] --------"); if (cellData.cachedSteepness > MAX_SLOPE_FOR_PATHFINDING) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Spawn point of '{cellData.cachedSteepness}' is too steep (> {MAX_SLOPE_FOR_PATHFINDING}). Not a valid spawn"); return(false); } if (IsCellImpassableOrDeepWater(cellData)) { return(false); } if (!encounterLayerData.IsInEncounterBounds(position)) { return(false); } if (cellData.cachedHeight > (cellData.terrainHeight + 50f)) { return(false); } float pathFindingZoneRadius = 25f; AbstractActor pathfindingActor = GetPathFindingActor(type); SetupPathfindingActor(position, pathfindingActor); try { PathNodeGrid pathfinderPathGrid = pathfindingActor.Pathing.CurrentGrid; PathNode positionPathNode = pathfinderPathGrid.GetValidPathNodeAt(position, pathfindingActor.Pathing.MaxCost); if (positionPathNode == null) { Reset(); return(false); } DynamicLongRangePathfinder.PointWithCost pointWithCost = new DynamicLongRangePathfinder.PointWithCost(combatState.HexGrid.GetClosestHexPoint3OnGrid(positionPathNode.Position), 0, (validityPosition - positionPathNode.Position).magnitude) { pathNode = positionPathNode }; List <Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(new List <DynamicLongRangePathfinder.PointWithCost>() { pointWithCost }, validityPosition, float.MaxValue, pathfindingActor, false, new List <AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); // List<Vector3> path = DynamicLongRangePathfinder.GetPathToDestination(position, float.MaxValue, pathfindingActor, true, pathFindingZoneRadius); // List<Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(position, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); // GUARD: Against deep water and other impassables that have slipped through if (HasPathImpassableOrDeepWaterTiles(combatState, path)) { return(false); } if (path != null && path.Count > 1 && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Last point is '{path[path.Count - 1]}', Validity position is '{validityPosition}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Distance from last path to valdity position is: '{(path[path.Count - 1].DistanceFlat(validityPosition))}' and is it within zone radius? '{(path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has valid long range path finding"); if (HasValidNeighbours(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has at least two valid neighbours"); if (HasValidLocalPathfinding(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has a valid path"); Reset(); Main.LogDebug($"-------- END [PathFinderManager.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); return(true); } else { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Does NOT have a valid path"); } } else { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Does not have two valid neighbours"); } } /* // Failed attempt to improve spawn checks * List<Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(validityPosition, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); * if (path != null && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { * if (path.Count > 4) { // very strong pathfinding location * return true; * } else { * Main.Logger.Log($"[PathFinderManager] Spawn point is valid due to proximity but is not strong enough success for pathing. Attempting to confirm."); * CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; * List<Vector3> pointsAroundPosition = combatState.HexGrid.GetGridPointsAroundPointWithinRadius(position, 3, 5); * * foreach (Vector3 point in pointsAroundPosition) { * List<Vector3> secondaryPath = DynamicLongRangePathfinder.GetDynamicPathToDestination(point, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, 2); * if (path != null && path.Count > 2) { * Main.Logger.Log($"[PathFinderManager] Spawn point is valid. It is close to the validation point but can be moved away from. Success."); * return true; * } * } * } * } */ } catch (Exception e) { // TODO: Sometimes this gets triggered in very large amounts. It's usually because the SpawnLogic.GetClosestValidPathFindingHex is increasing // the radius larger and larger and the checks keep going off the map // I need a way to hard abort out of this and either use the original origin of the focus or trigger the rule logic again (random, around a position etc) Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Array out of bounds detected in the path finding code. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); } Main.LogDebug($"-------- END [PathFinderManager.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); Reset(); return(false); }