more bugfixes
This commit is contained in:
@@ -71,8 +71,9 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
//TODO: very dangerous usage;
|
//TODO: very dangerous usage;
|
||||||
//TODO - it is accessed from the main thread
|
//TODO - it is accessed from the main thread
|
||||||
//TODO - it is written to on the pathfinding thread
|
//TODO - it is written to on the pathfinding thread
|
||||||
//maps position in world in (x + y * width format) to a cache of flow fields
|
//TODO - it does not include
|
||||||
IntMap<FieldCache> fields = new IntMap<>();
|
//maps position in world in (x + y * width format) | type (bitpacked to long) to a cache of flow fields
|
||||||
|
LongMap<FieldCache> fields = new LongMap<>();
|
||||||
//MAIN THREAD ONLY
|
//MAIN THREAD ONLY
|
||||||
Seq<FieldCache> fieldList = new Seq<>(false);
|
Seq<FieldCache> fieldList = new Seq<>(false);
|
||||||
|
|
||||||
@@ -128,22 +129,26 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
|
|
||||||
static class FieldCache{
|
static class FieldCache{
|
||||||
final PathCost cost;
|
final PathCost cost;
|
||||||
|
final int costId;
|
||||||
final int team;
|
final int team;
|
||||||
final int goalPos;
|
final int goalPos;
|
||||||
//frontier for flow fields
|
//frontier for flow fields
|
||||||
final IntQueue frontier = new IntQueue();
|
final IntQueue frontier = new IntQueue();
|
||||||
//maps cluster index to field weights; 0 means uninitialized
|
//maps cluster index to field weights; 0 means uninitialized
|
||||||
final IntMap<int[]> fields = new IntMap<>();
|
final IntMap<int[]> fields = new IntMap<>();
|
||||||
|
final long mapKey;
|
||||||
|
|
||||||
//main thread only!
|
//main thread only!
|
||||||
long lastUpdateId = state.updateId;
|
long lastUpdateId = state.updateId;
|
||||||
|
|
||||||
//TODO: how are the nodes merged? CAN they be merged?
|
//TODO: how are the nodes merged? CAN they be merged?
|
||||||
|
|
||||||
FieldCache(PathCost cost, int team, int goalPos){
|
FieldCache(PathCost cost, int costId, int team, int goalPos){
|
||||||
this.cost = cost;
|
this.cost = cost;
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.goalPos = goalPos;
|
this.goalPos = goalPos;
|
||||||
|
this.costId = costId;
|
||||||
|
this.mapKey = Pack.longInt(goalPos, costId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +167,7 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
|
|
||||||
//TODO: can the pathfinding thread even see these?
|
//TODO: can the pathfinding thread even see these?
|
||||||
unitRequests = new ObjectMap<>();
|
unitRequests = new ObjectMap<>();
|
||||||
fields = new IntMap<>();
|
fields = new LongMap<>();
|
||||||
fieldList = new Seq<>(false);
|
fieldList = new Seq<>(false);
|
||||||
|
|
||||||
clusters = new Cluster[256][][];
|
clusters = new Cluster[256][][];
|
||||||
@@ -213,7 +218,7 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
//skipped N update -> drop it
|
//skipped N update -> drop it
|
||||||
if(field.lastUpdateId <= state.updateId - 30){
|
if(field.lastUpdateId <= state.updateId - 30){
|
||||||
//make sure it's only modified on the main thread...? but what about calling get() on this thread??
|
//make sure it's only modified on the main thread...? but what about calling get() on this thread??
|
||||||
queue.post(() -> fields.remove(field.goalPos));
|
queue.post(() -> fields.remove(field.mapKey));
|
||||||
Core.app.post(() -> fieldList.remove(field));
|
Core.app.post(() -> fieldList.remove(field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +227,7 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
if(debug){
|
if(debug){
|
||||||
Events.run(Trigger.draw, () -> {
|
Events.run(Trigger.draw, () -> {
|
||||||
int team = player.team().id;
|
int team = player.team().id;
|
||||||
int cost = costGround;
|
int cost = 0;
|
||||||
|
|
||||||
Draw.draw(Layer.overlayUI, () -> {
|
Draw.draw(Layer.overlayUI, () -> {
|
||||||
Lines.stroke(1f);
|
Lines.stroke(1f);
|
||||||
@@ -953,13 +958,14 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
|
|
||||||
var nodePath = clusterAstar(request, costId, node, dest);
|
var nodePath = clusterAstar(request, costId, node, dest);
|
||||||
|
|
||||||
FieldCache cache = fields.get(goalPos);
|
FieldCache cache = fields.get(Pack.longInt(goalPos, costId));
|
||||||
//if true, extra values are added on the sides of existing field cells that face new cells.
|
//if true, extra values are added on the sides of existing field cells that face new cells.
|
||||||
boolean addingFrontier = true;
|
boolean addingFrontier = true;
|
||||||
|
|
||||||
//create the cache if it doesn't exist, and initialize it
|
//create the cache if it doesn't exist, and initialize it
|
||||||
if(cache == null){
|
if(cache == null){
|
||||||
fields.put(goalPos, cache = new FieldCache(pcost, team, goalPos));
|
cache = new FieldCache(pcost, costId, team, goalPos);
|
||||||
|
fields.put(cache.mapKey, cache);
|
||||||
FieldCache fcache = cache;
|
FieldCache fcache = cache;
|
||||||
//register field in main thread for iteration
|
//register field in main thread for iteration
|
||||||
Core.app.post(() -> fieldList.add(fcache));
|
Core.app.post(() -> fieldList.add(fcache));
|
||||||
@@ -1038,13 +1044,15 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
|
|
||||||
boolean any = false;
|
boolean any = false;
|
||||||
|
|
||||||
|
long fieldKey = Pack.longInt(destPos, costId);
|
||||||
|
|
||||||
//use existing request if it exists.
|
//use existing request if it exists.
|
||||||
if(request != null && request.destination == destPos){
|
if(request != null && request.destination == destPos){
|
||||||
request.lastUpdateId = state.updateId;
|
request.lastUpdateId = state.updateId;
|
||||||
|
|
||||||
Tile tileOn = unit.tileOn(), initialTileOn = tileOn;
|
Tile tileOn = unit.tileOn(), initialTileOn = tileOn;
|
||||||
//TODO: should fields be accessible from this thread?
|
//TODO: should fields be accessible from this thread?
|
||||||
FieldCache fieldCache = fields.get(destPos);
|
FieldCache fieldCache = fields.get(fieldKey);
|
||||||
|
|
||||||
if(fieldCache != null && tileOn != null){
|
if(fieldCache != null && tileOn != null){
|
||||||
FieldCache old = request.oldCache;
|
FieldCache old = request.oldCache;
|
||||||
@@ -1059,7 +1067,7 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
boolean recalc = false;
|
boolean recalc = false;
|
||||||
unit.hitboxTile(Tmp.r3);
|
unit.hitboxTile(Tmp.r3);
|
||||||
//tile rect size has tile size factored in, since the ray cannot have thickness
|
//tile rect size has tile size factored in, since the ray cannot have thickness
|
||||||
float tileRectSize = tilesize + Tmp.r3.height - 0.1f;
|
float tileRectSize = tilesize + Tmp.r3.height;
|
||||||
|
|
||||||
//TODO last pos can change if the flowfield changes.
|
//TODO last pos can change if the flowfield changes.
|
||||||
if(initialTileOn.pos() != request.lastTile || request.lastTargetTile == null){
|
if(initialTileOn.pos() != request.lastTile || request.lastTargetTile == null){
|
||||||
@@ -1311,7 +1319,8 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
int index = cx + cy * cwidth;
|
int index = cx + cy * cwidth;
|
||||||
|
|
||||||
for(var req : threadPathRequests){
|
for(var req : threadPathRequests){
|
||||||
var field = fields.get(req.destination);
|
long mapKey = Pack.longInt(req.destination, pathCost);
|
||||||
|
var field = fields.get(mapKey);
|
||||||
if((field != null && field.fields.containsKey(index)) || req.notFound){
|
if((field != null && field.fields.containsKey(index)) || req.notFound){
|
||||||
invalidRequests.add(req);
|
invalidRequests.add(req);
|
||||||
}
|
}
|
||||||
@@ -1396,14 +1405,16 @@ public class HierarchyPathFinder implements Runnable{
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var field = fields.get(request.destination);
|
long mapKey = Pack.longInt(request.destination, request.costId);
|
||||||
|
|
||||||
|
var field = fields.get(mapKey);
|
||||||
|
|
||||||
if(field != null){
|
if(field != null){
|
||||||
//it's only worth recalculating a path when the current frontier has finished; otherwise the unit will be following something incomplete.
|
//it's only worth recalculating a path when the current frontier has finished; otherwise the unit will be following something incomplete.
|
||||||
if(field.frontier.isEmpty()){
|
if(field.frontier.isEmpty()){
|
||||||
|
|
||||||
//remove the field, to be recalculated next update one recalculatePath is processed
|
//remove the field, to be recalculated next update one recalculatePath is processed
|
||||||
fields.remove(field.goalPos);
|
fields.remove(field.mapKey);
|
||||||
Core.app.post(() -> fieldList.remove(field));
|
Core.app.post(() -> fieldList.remove(field));
|
||||||
|
|
||||||
//once the field is invalidated, make sure that all the requests that have it stored in their 'old' field, so units don't stutter during recalculations
|
//once the field is invalidated, make sure that all the requests that have it stored in their 'old' field, so units don't stutter during recalculations
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ abstract class HitboxComp implements Posc, Sized, QuadTreeObject{
|
|||||||
|
|
||||||
public void hitboxTile(Rect rect){
|
public void hitboxTile(Rect rect){
|
||||||
//tile hitboxes are never bigger than a tile, otherwise units get stuck
|
//tile hitboxes are never bigger than a tile, otherwise units get stuck
|
||||||
float size = Math.min(hitSize * 0.66f, 7.9f);
|
float size = Math.min(hitSize * 0.66f, 7.8f);
|
||||||
//TODO: better / more accurate version is
|
//TODO: better / more accurate version is
|
||||||
//float size = hitSize * 0.85f;
|
//float size = hitSize * 0.85f;
|
||||||
//- for tanks?
|
//- for tanks?
|
||||||
|
|||||||
Reference in New Issue
Block a user