more bugfixes

This commit is contained in:
Anuken
2024-04-17 23:13:10 -04:00
parent 95e4be7186
commit 5e22b093e6
2 changed files with 25 additions and 14 deletions

View File

@@ -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

View File

@@ -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?