package engine.mobileAI.utilities; import engine.Enum; import engine.exception.MsgSendException; import engine.gameManager.BuildingManager; import engine.gameManager.MovementManager; import engine.gameManager.ZoneManager; import engine.math.Vector2f; import engine.math.Vector3fImmutable; import engine.mobileAI.MobAI; import engine.net.client.msg.MoveToPointMsg; import engine.objects.AbstractCharacter; import engine.objects.Building; import engine.objects.Regions; import engine.objects.Zone; import org.pmw.tinylog.Logger; import java.awt.geom.Path2D; import java.util.ArrayList; public class PathingUtilities { public static class Node { public Vector2f location; public ArrayList neighbors; public Regions region; public Building parentBuilding; public Node(Vector2f loc, Regions reg, Building parent){ this.location = loc; this.region = reg; this.parentBuilding = parent; this.neighbors = new ArrayList<>(); } public ArrayList getNeighbors(){ if(neighbors.size() == 0){ Zone zone = ZoneManager.findSmallestZone(new Vector3fImmutable(this.location.x,0,this.location.y)); if(zone == null) return null; for(Node potentialNeighbor : zone.navNodes){ for (Path2D.Float obstacle : zone.navObstacles) { if (!this.equals(potentialNeighbor) && !obstacle.intersects(this.location.x, this.location.y, potentialNeighbor.location.x, potentialNeighbor.location.y) && this.location.distance(potentialNeighbor.location) < 65) { this.neighbors.add(potentialNeighbor); } } } } return this.neighbors; } } public static Node getClosestNode(Vector3fImmutable loc){ Zone zone = ZoneManager.findSmallestZone(loc); Regions region = Regions.getRegionAtLocation(loc); if(region != null){ for(Node node : zone.navNodes){ if(node.location == new Vector2f(region.center.x,region.center.z)) return node; } } float disSq = 10000000; Node closest = null; for(Node node : zone.navNodes){ if(node.location.distanceSquared(new Vector2f(loc.x,loc.z)) < disSq) closest = node; } return closest; } public static ArrayList getPath(Vector3fImmutable start, Vector3fImmutable goal){ ArrayList path = new ArrayList<>(); Node startNode = getClosestNode(start); Node goalNode = getClosestNode(goal); Node currentNode = startNode; path.add(startNode); int attempts = 0; while(!currentNode.equals(goalNode) && attempts < 250){ attempts ++; currentNode = getCheapestNeighbor(currentNode,new Vector2f(goal.x,goal.z)); path.add(currentNode); } return path; } public static Node getCheapestNeighbor(Node node, Vector2f goal){ Node cheapest = null; for(Node neighbor : node.getNeighbors()){ if(cheapest == null) { cheapest = neighbor; continue; } if(getCost(cheapest.location,node.location,goal) > getCost(neighbor.location,node.location,goal)){ cheapest = neighbor; } } return cheapest; } public static float getCost(Vector2f point, Vector2f start, Vector2f goal) { float gCost = start.distanceSquared(point); float hCost = goal.distanceSquared(point); return gCost + hCost; } public static void followPath(AbstractCharacter character, ArrayList path){ character.isPathing = true; while(new Vector2f(character.loc.x,character.loc.z).distanceSquared(path.get(path.size() - 1).location) > 9 && path.size() > 0){ if( character.isMoving()) continue; if(character.combatTarget != null){ //need ot adjust new path for a moving combat target if(character.combatTarget.loc.distanceSquared2D(new Vector3fImmutable(path.get(path.size() - 1).location.x,0,path.get(path.size() - 1).location.y)) > 625){ character.isPathing = false; break; } } move(character,new Vector3fImmutable(path.get(0).location.x,0,path.get(0).location.y)); path.remove(0); } } public static void move(AbstractCharacter mob, Vector3fImmutable goal) { mob.destination = goal; if (mob.getObjectType().equals(Enum.GameObjectType.Mob)) { mob.setWalkMode(!(mob.combatTarget == null)); MovementManager.sendRWSSMsg(mob); } mob.endLoc = goal; MoveToPointMsg msg = new MoveToPointMsg(); msg.setSourceType(Enum.GameObjectType.Mob.ordinal()); msg.setSourceID(mob.getObjectUUID()); msg.setStartCoord(mob.loc); msg.setEndCoord(goal); Regions region = Regions.getRegionAtLocation(goal); if (region != null) { msg.setInBuildingFloor(region.room); msg.setInBuilding(region.level); msg.setStartLocType(0); msg.setInBuildingUUID(region.parentBuildingID); } else { msg.setInBuildingFloor(-1); msg.setInBuilding(-1); msg.setStartLocType(0); msg.setInBuildingUUID(0); } try { MovementManager.movement(msg, mob); } catch (MsgSendException e) { // TODO Figure out how we want to handle the msg send exception e.printStackTrace(); } } }