From f0bee7f19fddeedc4c9159044beb79eb384833e9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 8 Jun 2024 12:55:04 -0400 Subject: [PATCH] Pathfinder bugfixes --- core/src/mindustry/ai/ControlPathfinder.java | 43 +++++++++++++++++--- core/src/mindustry/ai/UnitGroup.java | 4 +- gradle.properties | 2 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/core/src/mindustry/ai/ControlPathfinder.java b/core/src/mindustry/ai/ControlPathfinder.java index b3b647dcee..261d1073b2 100644 --- a/core/src/mindustry/ai/ControlPathfinder.java +++ b/core/src/mindustry/ai/ControlPathfinder.java @@ -1099,6 +1099,7 @@ public class ControlPathfinder implements Runnable{ destY = World.toTile(mainDestination.y), actualDestX = World.toTile(destination.x), actualDestY = World.toTile(destination.y), + actualDestPos = actualDestX + actualDestY * wwidth, destPos = destX + destY * wwidth; PathRequest request = unitRequests.get(unit); @@ -1156,8 +1157,10 @@ public class ControlPathfinder implements Runnable{ int i = 0; boolean recalc = false; + if(packedPos == actualDestPos){ + request.lastTargetTile = tileOn; //TODO last pos can change if the flowfield changes. - if(initialTileOn.pos() != request.lastTile || request.lastTargetTile == null){ + }else if(initialTileOn.pos() != request.lastTile || request.lastTargetTile == null){ boolean anyNearSolid = false; //find the next tile until one near a solid block is discovered @@ -1181,9 +1184,13 @@ public class ControlPathfinder implements Runnable{ anyNearSolid = true; } - if((value == 0 || otherCost < value) && otherCost != impassable && (otherCost != 0 || packed == destPos) && (current == null || otherCost < minCost) && passable(unit.team.id, cost, packed)){ + if((value == 0 || otherCost < value) && otherCost != impassable && ((otherCost != 0 && (current == null || otherCost < minCost)) || packed == actualDestPos || packed == destPos) && passable(unit.team.id, cost, packed)){ current = other; minCost = otherCost; + //no need to keep searching. + if(packed == destPos || packed == actualDestPos){ + break; + } } } @@ -1205,7 +1212,9 @@ public class ControlPathfinder implements Runnable{ tileOn = current; any = true; - if(current.array() == destPos){ + int a = current.array(); + + if(a == destPos || a == actualDestPos){ break; } } @@ -1216,13 +1225,13 @@ public class ControlPathfinder implements Runnable{ } request.lastTargetTile = any ? tileOn : null; - if(showDebug && tileOn != null){ + if(showDebug && tileOn != null && Core.graphics.getFrameId() % 30 == 0){ Fx.placeBlock.at(tileOn.worldx(), tileOn.worldy(), 1); } } if(request.lastTargetTile != null){ - if(showDebug){ + if(showDebug && Core.graphics.getFrameId() % 30 == 0){ Fx.breakBlock.at(request.lastTargetTile.worldx(), request.lastTargetTile.worldy(), 1); } out.set(request.lastTargetTile); @@ -1325,6 +1334,30 @@ public class ControlPathfinder implements Runnable{ return 0; } + /** @return 0 if nothing was hit, otherwise the packed coordinates. This is an internal function and will likely be moved - do not use!*/ + public static int raycastFastAvoid(int team, PathCost type, int x1, int y1, int x2, int y2){ + int ww = world.width(), wh = world.height(); + int x = x1, dx = Math.abs(x2 - x), sx = x < x2 ? 1 : -1; + int y = y1, dy = Math.abs(y2 - y), sy = y < y2 ? 1 : -1; + int err = dx - dy; + + while(x >= 0 && y >= 0 && x < ww && y < wh){ + if(avoid(team, type, x + y * wwidth)) return Point2.pack(x, y); + if(x == x2 && y == y2) return 0; + + //no diagonals + if(2 * err + dy > dx - 2 * err){ + err -= dy; + x += sx; + }else{ + err += dx; + y += sy; + } + } + + return 0; + } + private static boolean overlap(int team, PathCost type, int x, int y, float startX, float startY, float endX, float endY, float rectSize){ if(x < 0 || y < 0 || x >= wwidth || y >= wheight) return false; if(!nearPassable(team, type, x + y * wwidth)){ diff --git a/core/src/mindustry/ai/UnitGroup.java b/core/src/mindustry/ai/UnitGroup.java index c712885846..8973c3e2fb 100644 --- a/core/src/mindustry/ai/UnitGroup.java +++ b/core/src/mindustry/ai/UnitGroup.java @@ -168,9 +168,9 @@ public class UnitGroup{ Unit unit = units.get(index); PathCost cost = unit.type.pathCost; - int res = ControlPathfinder.raycastFast(unit.team.id, cost, World.toTile(dest.x), World.toTile(dest.y), World.toTile(x), World.toTile(y)); + int res = ControlPathfinder.raycastFastAvoid(unit.team.id, cost, World.toTile(dest.x), World.toTile(dest.y), World.toTile(x), World.toTile(y)); - //collision found, make th destination the point right before the collision + //collision found, make the destination the point right before the collision if(res != 0){ v1.set(Point2.x(res) * Vars.tilesize - dest.x, Point2.y(res) * Vars.tilesize - dest.y); v1.setLength(Math.max(v1.len() - Vars.tilesize - 4f, 0)); diff --git a/gradle.properties b/gradle.properties index 5736b39a3e..585e33f06e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=true #used for slow jitpack builds; TODO see if this actually works org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 -archash=2126b31154 +archash=7138ef8769