Pathfinder bugfixes
This commit is contained in:
@@ -19,7 +19,7 @@ import mindustry.world.meta.*;
|
|||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class Pathfinder implements Runnable{
|
public class Pathfinder implements Runnable{
|
||||||
private static final long maxUpdate = Time.millisToNanos(7);
|
private static final long maxUpdate = Time.millisToNanos(8);
|
||||||
private static final int updateFPS = 60;
|
private static final int updateFPS = 60;
|
||||||
private static final int updateInterval = 1000 / updateFPS;
|
private static final int updateInterval = 1000 / updateFPS;
|
||||||
|
|
||||||
@@ -219,8 +219,6 @@ public class Pathfinder implements Runnable{
|
|||||||
public void updateTile(Tile tile){
|
public void updateTile(Tile tile){
|
||||||
if(net.client()) return;
|
if(net.client()) return;
|
||||||
|
|
||||||
int x = tile.x, y = tile.y;
|
|
||||||
|
|
||||||
tile.getLinkedTiles(t -> {
|
tile.getLinkedTiles(t -> {
|
||||||
int pos = t.array();
|
int pos = t.array();
|
||||||
if(pos < tiles.length){
|
if(pos < tiles.length){
|
||||||
@@ -238,9 +236,10 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mark every flow field as dirty, so it updates when it's done
|
||||||
queue.post(() -> {
|
queue.post(() -> {
|
||||||
for(Flowfield data : threadList){
|
for(Flowfield data : threadList){
|
||||||
updateTargets(data, x, y);
|
data.dirty = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -257,6 +256,13 @@ public class Pathfinder implements Runnable{
|
|||||||
|
|
||||||
//each update time (not total!) no longer than maxUpdate
|
//each update time (not total!) no longer than maxUpdate
|
||||||
for(Flowfield data : threadList){
|
for(Flowfield data : threadList){
|
||||||
|
|
||||||
|
//if it's dirty and there is nothing to update, begin updating once more
|
||||||
|
if(data.dirty && data.frontier.size == 0){
|
||||||
|
updateTargets(data);
|
||||||
|
data.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
updateFrontier(data, maxUpdate);
|
updateFrontier(data, maxUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,7 +321,8 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] values = path.weights;
|
//use complete weights if possible; these contain a complete flow field that is not being updated
|
||||||
|
int[] values = path.hasComplete ? path.completeWeights : path.weights;
|
||||||
int apos = tile.array();
|
int apos = tile.array();
|
||||||
int value = values[apos];
|
int value = values[apos];
|
||||||
|
|
||||||
@@ -341,32 +348,6 @@ public class Pathfinder implements Runnable{
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the frontier, increments the search and sets up all flow sources.
|
|
||||||
* This only occurs for active teams.
|
|
||||||
*/
|
|
||||||
private void updateTargets(Flowfield path, int x, int y){
|
|
||||||
int packed = world.packArray(x, y);
|
|
||||||
|
|
||||||
if(packed > path.weights.length) return;
|
|
||||||
|
|
||||||
if(path.weights[packed] == 0){
|
|
||||||
//this was a previous target
|
|
||||||
path.frontier.clear();
|
|
||||||
}else if(!path.frontier.isEmpty()){
|
|
||||||
//skip if this path is processing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//update cost of the tile TODO maybe only update the cost when it's not passable
|
|
||||||
path.weights[packed] = path.cost.getCost(path.team.id, tiles[packed]);
|
|
||||||
|
|
||||||
//clear frontier to prevent contamination
|
|
||||||
path.frontier.clear();
|
|
||||||
|
|
||||||
updateTargets(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Increments the search and sets up flow sources. Does not change the frontier. */
|
/** Increments the search and sets up flow sources. Does not change the frontier. */
|
||||||
private void updateTargets(Flowfield path){
|
private void updateTargets(Flowfield path){
|
||||||
|
|
||||||
@@ -421,6 +402,7 @@ public class Pathfinder implements Runnable{
|
|||||||
|
|
||||||
/** Update the frontier for a path. Pathfinding thread only. */
|
/** Update the frontier for a path. Pathfinding thread only. */
|
||||||
private void updateFrontier(Flowfield path, long nsToRun){
|
private void updateFrontier(Flowfield path, long nsToRun){
|
||||||
|
boolean hadAny = path.frontier.size > 0;
|
||||||
long start = Time.nanos();
|
long start = Time.nanos();
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
@@ -462,6 +444,12 @@ public class Pathfinder implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//there WERE some things in the frontier, but now they are gone, so the path is done; copy over latest data
|
||||||
|
if(hadAny && path.frontier.size == 0){
|
||||||
|
System.arraycopy(path.weights, 0, path.completeWeights, 0, path.weights.length);
|
||||||
|
path.hasComplete = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EnemyCoreField extends Flowfield{
|
public static class EnemyCoreField extends Flowfield{
|
||||||
@@ -505,11 +493,18 @@ public class Pathfinder implements Runnable{
|
|||||||
protected Team team = Team.derelict;
|
protected Team team = Team.derelict;
|
||||||
/** Function for calculating path cost. Set before using. */
|
/** Function for calculating path cost. Set before using. */
|
||||||
protected PathCost cost = costTypes.get(costGround);
|
protected PathCost cost = costTypes.get(costGround);
|
||||||
|
/** If true, this flow field needs updating. This flag is only set to false once the flow field finishes and the weights are copied over. */
|
||||||
|
protected boolean dirty = false;
|
||||||
|
/** Whether there are valid weights in the complete array. */
|
||||||
|
protected volatile boolean hasComplete;
|
||||||
|
|
||||||
/** costs of getting to a specific tile */
|
/** costs of getting to a specific tile */
|
||||||
public int[] weights;
|
public int[] weights;
|
||||||
/** search IDs of each position - the highest, most recent search is prioritized and overwritten */
|
/** search IDs of each position - the highest, most recent search is prioritized and overwritten */
|
||||||
public int[] searches;
|
public int[] searches;
|
||||||
|
/** the last "complete" weights of this tilemap. */
|
||||||
|
public int[] completeWeights;
|
||||||
|
|
||||||
/** search frontier, these are Pos objects */
|
/** search frontier, these are Pos objects */
|
||||||
IntQueue frontier = new IntQueue();
|
IntQueue frontier = new IntQueue();
|
||||||
/** all target positions; these positions have a cost of 0, and must be synchronized on! */
|
/** all target positions; these positions have a cost of 0, and must be synchronized on! */
|
||||||
@@ -524,6 +519,7 @@ public class Pathfinder implements Runnable{
|
|||||||
void setup(int length){
|
void setup(int length){
|
||||||
this.weights = new int[length];
|
this.weights = new int[length];
|
||||||
this.searches = new int[length];
|
this.searches = new int[length];
|
||||||
|
this.completeWeights = new int[length];
|
||||||
this.frontier.ensureCapacity((length) / 4);
|
this.frontier.ensureCapacity((length) / 4);
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class BuilderAI extends AIController{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//follow someone and help them build
|
//follow someone and help them build
|
||||||
if(timer.get(timerTarget2, 60f)){
|
if(timer.get(timerTarget2, 20f)){
|
||||||
found = false;
|
found = false;
|
||||||
|
|
||||||
Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> {
|
Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public enum LAccess{
|
|||||||
all = values(),
|
all = values(),
|
||||||
senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class),
|
senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class),
|
||||||
controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class),
|
controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class),
|
||||||
settable = {x, y, rotation, team, flag, health, totalPower, payloadType}; //TODO
|
settable = {x, y, rotation, team, flag, health, totalPower, payloadType};
|
||||||
|
|
||||||
LAccess(String... params){
|
LAccess(String... params){
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
|||||||
+1
-1
@@ -25,4 +25,4 @@ org.gradle.caching=true
|
|||||||
#used for slow jitpack builds; TODO see if this actually works
|
#used for slow jitpack builds; TODO see if this actually works
|
||||||
org.gradle.internal.http.socketTimeout=100000
|
org.gradle.internal.http.socketTimeout=100000
|
||||||
org.gradle.internal.http.connectionTimeout=100000
|
org.gradle.internal.http.connectionTimeout=100000
|
||||||
archash=a96ce3b267
|
archash=cc9c60d49b
|
||||||
|
|||||||
Reference in New Issue
Block a user