From 41f50ff8eafbac0e5218c6b75ed0d4da2f8ca506 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 14 Feb 2022 10:16:15 -0500 Subject: [PATCH] Pathfinder fallback system --- core/assets/icons/icons.properties | 1 + core/assets/logicids.dat | Bin 4129 -> 4141 bytes core/src/mindustry/ai/ControlPathfinder.java | 46 +++++++++++++++---- core/src/mindustry/ai/Pathfinder.java | 10 ++-- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 07f62b867d..5b38197e9c 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -536,3 +536,4 @@ 63167=disperse|block-disperse-ui 63166=large-shield-projector|block-large-shield-projector-ui 63165=payload-mass-driver|block-payload-mass-driver-ui +63164=world-cell|block-world-cell-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index 57b036c98a702983da1627882c829b7e313680ce..6972dddfdc239ab893fec8a86b3e4ae917b829e2 100644 GIT binary patch delta 28 jcmZ3euvUSI;oe532wrZk^8BKl6y4<1oSe;(yeF6dg*FLv delta 16 XcmZ3huuy@C;qFGJ2;R+UyvLaUFSP}A diff --git a/core/src/mindustry/ai/ControlPathfinder.java b/core/src/mindustry/ai/ControlPathfinder.java index 9044d2ebaf..e2bd74a7d6 100644 --- a/core/src/mindustry/ai/ControlPathfinder.java +++ b/core/src/mindustry/ai/ControlPathfinder.java @@ -21,16 +21,22 @@ public class ControlPathfinder{ private static final long maxUpdate = Time.millisToNanos(20); private static final int updateFPS = 60; private static final int updateInterval = 1000 / updateFPS; + private static final int wallImpassable = -2; public static boolean showDebug = false; public static final Seq costTypes = Seq.with( //ground - (team, tile) -> (PathTile.allDeep(tile) || PathTile.solid(tile)) ? impassable : 1 + + (team, tile) -> + //deep is impassable + PathTile.allDeep(tile) ? impassable : + ((PathTile.team(tile) != team && PathTile.team(tile) != 0) && PathTile.solid(tile)) ? wallImpassable : + PathTile.solid(tile) ? impassable : + 1 + (PathTile.nearSolid(tile) ? 6 : 0) + (PathTile.nearLiquid(tile) ? 8 : 0) + (PathTile.deep(tile) ? 6000 : 0) + - (PathTile.damages(tile) ? 40 : 0), + (PathTile.damages(tile) ? 50 : 0), //legs (team, tile) -> PathTile.legSolid(tile) ? impassable : 1 + @@ -165,6 +171,7 @@ public class ControlPathfinder{ req.pathType = pathType; req.destination.set(destination); req.curId = pathId; + req.team = unit.team.id; req.lastUpdateId = state.updateId; req.lastPos.set(unit); req.lastWorldUpdate = worldUpdateId; @@ -178,6 +185,7 @@ public class ControlPathfinder{ }else{ var req = requests.get(unit); req.lastUpdateId = state.updateId; + req.team = unit.team.id; if(req.curId != req.lastId || req.curId != pathId){ req.pathIndex = 0; req.rayPathIndex = -1; @@ -350,17 +358,21 @@ public class ControlPathfinder{ return Math.abs(x - x2) + Math.abs(y - y2); } + private static int tcost(int team, int type, int tilePos){ + return costTypes.items[type].getCost(team, pathfinder.tiles[tilePos]); + } + private static int cost(int type, int tilePos){ - return costTypes.items[type].getCost(null, pathfinder.tiles[tilePos]); + return costTypes.items[type].getCost(-1, pathfinder.tiles[tilePos]); } private static boolean avoid(int type, int tilePos){ int cost = cost(type, tilePos); - return cost == impassable || cost >= 2; + return cost <= impassable || cost >= 2; } private static boolean solid(int type, int tilePos){ - return cost(type, tilePos) == impassable; + return cost(type, tilePos) <= impassable; } private static float tileCost(int type, int a, int b){ @@ -416,8 +428,10 @@ public class ControlPathfinder{ volatile boolean done = false; volatile boolean foundEnd = false; + volatile boolean fallback = false; volatile Unit unit; volatile int pathType; + volatile int team; volatile int lastWorldUpdate; final Vec2 lastPos = new Vec2(); @@ -485,9 +499,16 @@ public class ControlPathfinder{ if(newx >= wwidth || newy >= wheight || newx < 0 || newy < 0) continue; - if(cost(pathType, next) == impassable) continue; + float passTest = tcost(team, pathType, next); + + //in fallback mode, enemy walls are passable + if((passTest <= impassable) && !(fallback && passTest == wallImpassable)) continue; + + float add = tileCost(pathType, current, next); + + //the cost can include an impassable enemy wall, so handle that and add a base cost + float newCost = costs.get(current) + (add == wallImpassable ? 12 : add); - float newCost = costs.get(current) + tileCost(pathType, current, next); //a cost of 0 means "not set" if(!costs.containsKey(next) || newCost < costs.get(next)){ costs.put(next, newCost); @@ -516,6 +537,7 @@ public class ControlPathfinder{ rayPathIndex = -1; if(foundEnd){ + fallback = false; int cur = goal; while(cur != start){ result.add(cur); @@ -525,11 +547,16 @@ public class ControlPathfinder{ result.reverse(); smoothPath(); + done = true; + }else if(!fallback && pathType != 1){ + clear(true); + //it's not over! + fallback = true; + }else{ + done = true; } //TODO free resources? - - done = true; } void smoothPath(){ @@ -559,6 +586,7 @@ public class ControlPathfinder{ start = world.packArray(unit.tileX(), unit.tileY()); goal = world.packArray(World.toTile(destination.x), World.toTile(destination.y)); + fallback = false; cameFrom.put(start, start); costs.put(start, 0); diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index fa79849286..765b3d69f1 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -42,7 +42,7 @@ public class Pathfinder implements Runnable{ public static final Seq costTypes = Seq.with( //ground - (team, tile) -> (PathTile.allDeep(tile) || (PathTile.team(tile) == team.id || PathTile.team(tile) == 0) && PathTile.solid(tile)) ? impassable : 1 + + (team, tile) -> (PathTile.allDeep(tile) || (PathTile.team(tile) == team || PathTile.team(tile) == 0) && PathTile.solid(tile)) ? impassable : 1 + PathTile.health(tile) * 5 + (PathTile.nearSolid(tile) ? 2 : 0) + (PathTile.nearLiquid(tile) ? 6 : 0) + @@ -306,7 +306,7 @@ public class Pathfinder implements Runnable{ } //update cost of the tile TODO maybe only update the cost when it's not passable - path.weights[packed] = path.cost.getCost(path.team, tiles[packed]); + path.weights[packed] = path.cost.getCost(path.team.id, tiles[packed]); //clear frontier to prevent contamination path.frontier.clear(); @@ -391,7 +391,7 @@ public class Pathfinder implements Runnable{ if(dx < 0 || dy < 0 || dx >= wwidth || dy >= wheight) continue; int newPos = tile + point.x + point.y * wwidth; - int otherCost = path.cost.getCost(path.team, tiles[newPos]); + int otherCost = path.cost.getCost(path.team.id, tiles[newPos]); if((path.weights[newPos] > cost + otherCost || path.searches[newPos] < path.search) && otherCost != impassable){ path.frontier.addFirst(newPos); @@ -485,7 +485,7 @@ public class Pathfinder implements Runnable{ } protected boolean passable(int pos){ - return cost.getCost(team, pathfinder.tiles[pos]) != impassable; + return cost.getCost(team.id, pathfinder.tiles[pos]) != impassable; } /** Gets targets to pathfind towards. This must run on the main thread. */ @@ -493,7 +493,7 @@ public class Pathfinder implements Runnable{ } public interface PathCost{ - int getCost(Team traversing, int tile); + int getCost(int team, int tile); } /** Holds a copy of tile data for a specific tile position. */