Multithreading cleanup

This commit is contained in:
Anuken
2018-10-10 23:43:48 -04:00
parent 67db5e9dfc
commit 52bd079c0a
18 changed files with 50 additions and 359 deletions

View File

@@ -1,267 +0,0 @@
package io.anuke.mindustry.maps.generation.pathfinding;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.BinaryHeap;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Structs;
import io.anuke.ucore.util.Geometry;
//TODO
public class AStarPathFinder extends TilePathfinder{
NodeRecord[] records;
BinaryHeap<NodeRecord> openList;
NodeRecord current;
Predicate<Tile> goal;
private int searchId;
private Tile end;
private static final byte UNVISITED = 0;
private static final byte OPEN = 1;
private static final byte CLOSED = 2;
private static final boolean debug = false;
public AStarPathFinder(Tile[][] tiles) {
super(tiles);
this.records = new NodeRecord[tiles.length * tiles[0].length];
this.openList = new BinaryHeap<>();
}
@Override
public void search(Tile start, Tile end, Array<Tile> out){
}
public void search(Tile start, Tile end, Predicate<Tile> pred, Array<Tile> out){
this.goal = pred;
searchNodePath(start, end, out);
}
public boolean searchNodePath(Tile startNode, Tile endNode, Array<Tile> outPath) {
this.end = endNode;
// Perform AStar
boolean found = search(startNode, endNode);
if (found) {
// Create a path made of nodes
generateNodePath(startNode, outPath);
}
return found;
}
protected boolean search(Tile startNode, Tile endNode) {
initSearch(startNode, endNode);
// Iterate through processing each node
do {
// Retrieve the node with smallest estimated total cost from the open list
current = openList.pop();
current.category = CLOSED;
// Terminate if we reached the goal node
if (current.node == endNode || goal.test(current.node)) return true;
visitChildren(endNode);
} while (openList.size > 0);
// We've run out of nodes without finding the goal, so there's no solution
return false;
}
/*
public boolean search(PathFinderRequest<Tile> request, long timeToRun) {
long lastTime = TimeUtils.nanoTime();
// We have to initialize the search if the status has just changed
if (request.statusChanged) {
initSearch(request.startNode, request.endNode);
request.statusChanged = false;
}
// Iterate through processing each node
do {
// Check the available time
long currentTime = TimeUtils.nanoTime();
timeToRun -= currentTime - lastTime;
if (timeToRun <= PathFinderQueue.TIME_TOLERANCE) return false;
// Retrieve the node with smallest estimated total cost from the open list
current = openList.pop();
current.category = CLOSED;
// Terminate if we reached the goal node; we've found a path.
if (current.node == request.endNode) {
request.pathFound = true;
generateNodePath(request.startNode, request.resultPath);
return true;
}
// Visit current node's children
visitChildren(request.endNode);
// Store the current time
lastTime = currentTime;
} while (openList.size > 0);
// The open list is empty and we've not found a path.
request.pathFound = false;
return true;
}*/
protected void initSearch(Tile startNode, Tile endNode) {
// Increment the search id
if (++searchId < 0) searchId = 1;
// Initialize the open list
openList.clear();
// Initialize the record for the start node and add it to the open list
NodeRecord startRecord = getNodeRecord(startNode);
startRecord.node = startNode;
startRecord.from = null;
startRecord.costSoFar = 0;
addToOpenList(startRecord, estimate(startNode, endNode));
current = null;
}
protected void visitChildren(Tile endNode) {
if(debug) Effects.effect(Fx.spawn, current.node.worldx(), current.node.worldy());
nodes(current.node, node -> {
float addCost = estimate(current.node, node);
float nodeCost = current.costSoFar + addCost;
float nodeHeuristic;
NodeRecord nodeRecord = getNodeRecord(node);
if (nodeRecord.category == CLOSED) { // The node is closed
// If we didn't find a shorter route, skip
if (nodeRecord.costSoFar <= nodeCost){
return;
}
// We can use the node's old cost values to calculate its heuristic
// without calling the possibly expensive heuristic function
nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
} else if (nodeRecord.category == OPEN) { // The node is open
//If our route is no better, then skip
if (nodeRecord.costSoFar <= nodeCost){
return;
}
// Remove it from the open list (it will be re-added with the new cost)
openList.remove(nodeRecord);
// We can use the node's old cost values to calculate its heuristic
// without calling the possibly expensive heuristic function
nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
} else { // the node is unvisited
// We'll need to calculate the heuristic value using the function,
// since we don't have a node record with a previously calculated value
nodeHeuristic = estimate(node, endNode);
}
// Update node record's cost and connection
nodeRecord.costSoFar = nodeCost;
nodeRecord.from = current.node;
// Add it to the open list with the estimated total cost
addToOpenList(nodeRecord, nodeCost + nodeHeuristic);
});
}
protected void nodes(Tile current, Consumer<Tile> cons){
if(obstacle(current)) return;
for(GridPoint2 p : Geometry.d4){
int wx = current.x + p.x, wy = current.y + p.y;
Tile n = Structs.inBounds(wx, wy, tiles) ? tiles[wx][wy] : null;
if(!obstacle(n)) cons.accept(n);
}
}
protected boolean obstacle(Tile tile){
return tile == null || (tile.solid() && end.target() != tile && tile.target() != end) || !tile.block().alwaysReplace;
}
protected float estimate(Tile tile, Tile other){
return goal.test(other) || goal.test(tile) ? Float.MIN_VALUE : Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy());
}
protected void generateNodePath(Tile startNode, Array<Tile> outPath) {
// Work back along the path, accumulating nodes
outPath.clear();
while (current.from != null) {
outPath.add(current.node);
current = records[(indexOf(current.from))];
}
outPath.add(startNode);
// Reverse the path
outPath.reverse();
}
protected void addToOpenList(NodeRecord nodeRecord, float estimatedTotalCost) {
openList.add(nodeRecord, estimatedTotalCost);
nodeRecord.category = OPEN;
}
protected NodeRecord getNodeRecord(Tile node) {
if(records[indexOf(node)] == null){
NodeRecord record = new NodeRecord();
record.node = node;
record.searchId = searchId;
records[indexOf(node)] = record;
return record;
}else{
NodeRecord record = records[indexOf(node)];
if(record.searchId != searchId){
record.category = UNVISITED;
record.searchId = searchId;
}
return record;
}
}
private int indexOf(Tile node){
return node.packedPosition();
}
static class NodeRecord extends BinaryHeap.Node {
Tile node;
Tile from;
float costSoFar;
byte category;
int searchId;
public NodeRecord() {
super(0);
}
public float getEstimatedTotalCost() {
return getValue();
}
}
}