diff --git a/src/engine/devcmd/cmds/RegionCmd.java b/src/engine/devcmd/cmds/RegionCmd.java index 2f608f95..733bae67 100644 --- a/src/engine/devcmd/cmds/RegionCmd.java +++ b/src/engine/devcmd/cmds/RegionCmd.java @@ -57,6 +57,7 @@ public class RegionCmd extends AbstractDevCmd { output += "Region Height: " + region.lerpY(((AbstractCharacter)target).loc) + newline; output += "is Stairs: " + region.isStairs() + newline; output += "is Outside: " + region.isOutside() + newline; + output += "is Entrance: " + region.isExit() + newline; for(Vector3f point : region.regionPoints) output += point + newline; output += "NavMesh Data" + newline; diff --git a/src/engine/gameManager/BuildingManager.java b/src/engine/gameManager/BuildingManager.java index f9449ea9..882b1261 100644 --- a/src/engine/gameManager/BuildingManager.java +++ b/src/engine/gameManager/BuildingManager.java @@ -20,6 +20,7 @@ import engine.jobs.UpgradeBuildingJob; import engine.math.Bounds; import engine.math.Vector2f; import engine.math.Vector3fImmutable; +import engine.mobileAI.utilities.PathingUtilities; import engine.net.client.ClientConnection; import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ManageCityAssetsMsg; @@ -998,6 +999,29 @@ public enum BuildingManager { meshBound.lineTo(rotatedStart.x,rotatedStart.z); meshBound.closePath(); building.meshes.add(meshBound); + building.parentZone.navObstacles.add(meshBound); + } + //add navNodes to parent zone list + float X = building.getBounds().getHalfExtents().x; + float Y = building.getBounds().getHalfExtents().y; + ArrayList cornersAndFaces = new ArrayList<>(); + cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z - Y)); + cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z + Y)); + cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z - Y)); + cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z + Y)); + cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z)); + cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z)); + cornersAndFaces.add(new Vector2f(building.loc.x,building.loc.z - Y)); + cornersAndFaces.add(new Vector2f(building.loc.x,building.loc.z + Y)); + for(Vector2f point : cornersAndFaces){ + if(!NavigationManager.pointIsBlocked(new Vector3fImmutable(point.x,building.loc.y,point.y))){ + building.parentZone.navNodes.add(new PathingUtilities.Node(point,null,building)); + } + } + + //add region centers to the zones navNodes list + for(Regions region : building.getBounds().getRegions()){ + building.parentZone.navNodes.add(new PathingUtilities.Node(new Vector2f(region.center.x,region.center.z),region,building)); } } } diff --git a/src/engine/gameManager/NavigationManager.java b/src/engine/gameManager/NavigationManager.java index db09c639..68862d99 100644 --- a/src/engine/gameManager/NavigationManager.java +++ b/src/engine/gameManager/NavigationManager.java @@ -2,6 +2,7 @@ package engine.gameManager; import engine.Enum; import engine.math.Vector3fImmutable; +import engine.mobileAI.MobAI; import engine.net.client.msg.MoveToPointMsg; import engine.objects.*; import java.awt.geom.Path2D; @@ -14,31 +15,16 @@ public class NavigationManager { private static final int stepHeight = 2; public static void pathfind(AbstractCharacter character, Vector3fImmutable goal) { + if(!pathBlocked(character.loc,goal)){ + character.destination = goal; + MobAI.directMove((Mob)character,character.combatTarget != null); + } try { ArrayList path = getPath(character.loc, goal);//getOptimizedPath(getPath(character.loc, goal), getPath(goal, character.loc)); if (path.isEmpty()) { - MoveToPointMsg msg = new MoveToPointMsg(); - - msg.setSourceType(Enum.GameObjectType.Mob.ordinal()); - msg.setSourceID(character.getObjectUUID()); - msg.setStartCoord(character.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); - } + MobAI.directMove((Mob)character,character.combatTarget != null); return; //no points to walk to } - - //character.destination = path.get(1); character.navPath = path; } catch (Exception e) { @@ -109,30 +95,43 @@ public class NavigationManager { } } - - - public static float getCost(Vector3fImmutable point, Vector3fImmutable start, Vector3fImmutable goal) { float gCost = start.distanceSquared(point); float hCost = goal.distanceSquared(point); return gCost + hCost; } - public static boolean pointIsBlocked(Vector3fImmutable point) { - - Building building = BuildingManager.getBuildingAtLocation(point); - if(building != null) { - for (Path2D.Float mesh : building.meshes) { - if (mesh.contains(point.x,point.z)) { + public static boolean pathBlocked(Vector3fImmutable start, Vector3fImmutable end){ + Zone zone = ZoneManager.findSmallestZone(start); + if(zone != null) { + for (Path2D.Float obstacle : zone.navObstacles) + if(obstacle.intersects(start.x,start.z,end.x,end.z)) return true; - } - } - for (Regions region : building.getBounds().getRegions()) { - if (region.isPointInPolygon(point)) - if (Math.abs(region.lerpY(point) - point.y) > stepHeight) // get the height distance between current height and target location height - return true; - } } return false; } + public static boolean pointIsBlocked(Vector3fImmutable point) { + Zone zone = ZoneManager.findSmallestZone(point); + if(zone != null){ + for(Path2D.Float obstacle : zone.navObstacles) + if (obstacle.contains(point.x,point.z)) { + return true; + } + } + + //Building building = BuildingManager.getBuildingAtLocation(point); + //if(building != null) { + //for (Path2D.Float mesh : building.meshes) { + //if (mesh.contains(point.x,point.z)) { + //return true; + //} + //} + //for (Regions region : building.getBounds().getRegions()) { + //if (region.isPointInPolygon(point)) + //if (Math.abs(region.lerpY(point) - point.y) > stepHeight) // get the height distance between current height and target location height + //return true; + //} + //} + return false; + } } diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java index 5ec171d4..d1ee4721 100644 --- a/src/engine/mobileAI/MobAI.java +++ b/src/engine/mobileAI/MobAI.java @@ -1345,14 +1345,14 @@ public class MobAI { public static void aiMove(Mob mob, boolean isWalking, float offset) { - if(mob.navPath.isEmpty() || mob.navPath.size() == 1){ - NavigationManager.pathfind(mob,mob.destination); - return; - } if(mob.isMoving()) { return; } + if(mob.navPath.isEmpty()){ + NavigationManager.pathfind(mob,mob.destination); + return; + } Vector3fImmutable PathPoint = mob.navPath.get(0); if(mob.loc.distanceSquared(mob.destination) > mob.loc.distanceSquared2D(mob.destination)) { mob.navPath.remove(0); @@ -1393,6 +1393,46 @@ public class MobAI { + try { + MovementManager.movement(msg, mob); + } catch (MsgSendException e) { + // TODO Figure out how we want to handle the msg send exception + e.printStackTrace(); + } + } + + public static void directMove(Mob mob,boolean isWalking){ + //update our walk/run state. + if (isWalking && !mob.isWalk()) { + mob.setWalkMode(true); + MovementManager.sendRWSSMsg(mob); + } else if (!isWalking && mob.isWalk()) { + mob.setWalkMode(false); + MovementManager.sendRWSSMsg(mob); + } + mob.endLoc = mob.destination; + + MoveToPointMsg msg = new MoveToPointMsg(); + + msg.setSourceType(Enum.GameObjectType.Mob.ordinal()); + msg.setSourceID(mob.getObjectUUID()); + msg.setStartCoord(mob.loc); + msg.setEndCoord(mob.destination); + Regions region = Regions.getRegionAtLocation(mob.destination); + 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) { diff --git a/src/engine/mobileAI/utilities/PathingUtilities.java b/src/engine/mobileAI/utilities/PathingUtilities.java index 4741ab7d..aff1662e 100644 --- a/src/engine/mobileAI/utilities/PathingUtilities.java +++ b/src/engine/mobileAI/utilities/PathingUtilities.java @@ -1,80 +1,22 @@ package engine.mobileAI.utilities; +import engine.math.Vector2f; +import engine.objects.Building; import engine.objects.Regions; -import java.awt.geom.Area; + import java.util.ArrayList; public class PathingUtilities { - public static class Point { - public int x; - public int y; - public Point previous; - - public Point(int x, int y, Point previous) { - this.x = x; - this.y = y; - this.previous = previous; - } - - public Point offset(int ox, int oy) { return new Point(x + ox, y + oy, this); } - } - - public static boolean IsWalkable(Area navMesh, Point point) { - if (navMesh.contains(point.x, point.y)) - return true; - - Regions region = Regions.getRegionAtPoint(point); - if (region != null) { - return !(region.getHeightAtPoint(point) - point.y > 2); + 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; } - return false; } - public static ArrayList FindNeighbors(Area navMesh, Point point) { - ArrayList neighbors = new ArrayList<>(); - Point up = point.offset(0, 1); - Point down = point.offset(0, -1); - Point left = point.offset(-1, 0); - Point right = point.offset(1, 0); - if (IsWalkable(navMesh, up)) neighbors.add(up); - if (IsWalkable(navMesh, down)) neighbors.add(down); - if (IsWalkable(navMesh, left)) neighbors.add(left); - if (IsWalkable(navMesh, right)) neighbors.add(right); - return neighbors; - } - - public static ArrayList FindPath(Area navMesh, Point start, Point end) { - boolean finished = false; - ArrayList used = new ArrayList<>(); - used.add(start); - while (!finished) { - ArrayList newOpen = new ArrayList<>(); - for(int i = 0; i < used.size(); ++i){ - Point point = used.get(i); - for (Point neighbor : FindNeighbors(navMesh, point)) { - if (!used.contains(neighbor) && !newOpen.contains(neighbor)) { - newOpen.add(neighbor); - } - } - } - - for(Point point : newOpen) { - used.add(point); - if (end.equals(point)) { - finished = true; - break; - } - } - - if (!finished && newOpen.isEmpty()) - return null; - } - - ArrayList path = new ArrayList<>(); - Point point = used.get(used.size() - 1); - while(point.previous != null) { - path.add(0, point); - point = point.previous; - } - return path; - } } diff --git a/src/engine/objects/Regions.java b/src/engine/objects/Regions.java index f612815a..934ed932 100644 --- a/src/engine/objects/Regions.java +++ b/src/engine/objects/Regions.java @@ -289,22 +289,6 @@ public class Regions { } return region; } - public static Regions getRegionAtPoint(PathingUtilities.Point point) { - Vector3fImmutable baseLoc = new Vector3fImmutable(point.x,0,point.y); - baseLoc.setY(Terrain.getWorldHeight(baseLoc)); - Building building = BuildingManager.getBuildingAtLocation(baseLoc); - if(building == null) - return null; - for(Regions region : building.getBounds().getRegions()) - if(region.isPointInPolygon(baseLoc)) - return region; - return null; - } - - public float getHeightAtPoint(PathingUtilities.Point point){ - Vector3fImmutable baseLoc = new Vector3fImmutable(point.x,0,point.y); - return this.lerpY(baseLoc); - } public int getRoom() { return room; diff --git a/src/engine/objects/Zone.java b/src/engine/objects/Zone.java index 24ba8266..c9bb018c 100644 --- a/src/engine/objects/Zone.java +++ b/src/engine/objects/Zone.java @@ -17,10 +17,12 @@ import engine.gameManager.ZoneManager; import engine.math.Bounds; import engine.math.Vector2f; import engine.math.Vector3fImmutable; +import engine.mobileAI.utilities.PathingUtilities; import engine.net.ByteBufferWriter; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.awt.*; +import java.awt.geom.Path2D; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -65,8 +67,8 @@ public class Zone extends AbstractWorldObject { public float sea_level; public Terrain terrain = null; - - public Area navMesh; + public ArrayList navObstacles = new ArrayList<>(); + public ArrayList navNodes = new ArrayList<>(); /** * ResultSet Constructor @@ -183,18 +185,6 @@ public class Zone extends AbstractWorldObject { } ZoneManager.populateZoneCollections(this); - - //this.createNavMesh(); - - } - - public void createNavMesh(){ - int xPoint = (int)(this.absX - this.bounds.getHalfExtents().x); - int zPoint = (int) (this.absZ - this.bounds.getHalfExtents().y); - int extentsX = (int) (this.bounds.getHalfExtents().x * 2); - int extentsZ = (int) (this.bounds.getHalfExtents().y * 2); - - this.navMesh = new Area(new Rectangle(xPoint, zPoint, extentsX, extentsZ)); } /* Method sets a default value for player cities * otherwise using values derived from the loadnum