From 49a39d42e7a14c1e5de3b699f7a302be5484a9aa Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 17 Feb 2022 15:15:51 -0500 Subject: [PATCH] Proper pathfinding fixes --- .../annotations/impl/StructProcess.java | 14 +++++-- core/src/mindustry/ai/ControlPathfinder.java | 16 ++++++- core/src/mindustry/ai/Pathfinder.java | 42 +++++++++++++++++-- core/src/mindustry/ai/types/CommandAI.java | 2 +- core/src/mindustry/world/Tile.java | 1 + 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java b/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java index 975e1dceee..bb4540adbd 100644 --- a/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java +++ b/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java @@ -1,6 +1,7 @@ package mindustry.annotations.impl; import arc.struct.*; +import arc.util.*; import com.squareup.javapoet.*; import mindustry.annotations.Annotations.*; import mindustry.annotations.*; @@ -63,23 +64,28 @@ public class StructProcess extends BaseProcessor{ int size = varSize(var); TypeName varType = var.tname(); String varName = var.name(); + boolean isBool = varType == TypeName.BOOLEAN; //add val param to constructor constructor.addParameter(varType, varName); //[get] field(structType) : fieldType - MethodSpec.Builder getter = MethodSpec.methodBuilder(var.name().toString()) + MethodSpec.Builder getter = MethodSpec.methodBuilder(var.name()) .addModifiers(Modifier.STATIC, Modifier.PUBLIC) .returns(varType) .addParameter(structType, structParam); //[set] field(structType, fieldType) : structType - MethodSpec.Builder setter = MethodSpec.methodBuilder(var.name().toString()) + MethodSpec.Builder setter = MethodSpec.methodBuilder(var.name()) .addModifiers(Modifier.STATIC, Modifier.PUBLIC) .returns(structType) .addParameter(structType, structParam).addParameter(varType, "value"); + //field for offset + classBuilder.addField(FieldSpec.builder(structType, "bitMask" + Strings.capitalize(varName), Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer(!isBool ? "($T)($L)" : "($T)(1L << $L)", structType, isBool ? offset : bitString(offset, size, structTotalSize)).build()); + //[getter] - if(varType == TypeName.BOOLEAN){ + if(isBool){ //bools: single bit, is simplified getter.addStatement("return ($L & (1L << $L)) != 0", structParam, offset); }else if(varType == TypeName.FLOAT){ @@ -124,7 +130,7 @@ public class StructProcess extends BaseProcessor{ classBuilder.addJavadoc(doc.toString()); //add constructor final statement + add to class and build - constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3)); + constructor.addStatement("return ($T)($L)", structType, cons.substring(3)); classBuilder.addMethod(constructor.build()); JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer); diff --git a/core/src/mindustry/ai/ControlPathfinder.java b/core/src/mindustry/ai/ControlPathfinder.java index 45f70c163f..39acf0d36a 100644 --- a/core/src/mindustry/ai/ControlPathfinder.java +++ b/core/src/mindustry/ai/ControlPathfinder.java @@ -298,13 +298,27 @@ public class ControlPathfinder{ if(avoid(type, x + y * wwidth)) return true; if(x == x2 && y == y2) return false; - //no diagonals + //TODO no diagonals???? is this a good idea? + /* + //no diagonal ver if(2 * err + dy > dx - 2 * err){ err -= dy; x += sx; }else{ err += dx; y += sy; + }*/ + + //diagonal ver + e2 = 2 * err; + if(e2 > -dy){ + err -= dy; + x += sx; + } + + if(e2 < dx){ + err += dx; + y += sy; } } diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index ebe33bc317..378a052ccd 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -92,7 +92,7 @@ public class Pathfinder implements Runnable{ for(int i = 0; i < tiles.length; i++){ Tile tile = world.tiles.geti(i); - tiles[i] = packTile(tile); + tiles[i] = packTile(tile, 0); } preloadPath(getField(state.rules.waveTeam, costGround, fieldCore)); @@ -108,6 +108,34 @@ public class Pathfinder implements Runnable{ Events.on(ResetEvent.class, event -> stop()); Events.on(TileChangeEvent.class, event -> updateTile(event.tile)); + + //remove nearSolid flag for tiles + Events.on(TilePreChangeEvent.class, event -> { + Tile tile = event.tile; + + if(tile.solid()){ + for(int i = 0; i < 4; i++){ + Tile other = tile.nearby(i); + if(other != null){ + //other tile needs to update its nearSolid to be false if it's not solid and this tile just got un-solidified + if(!other.solid()){ + boolean otherNearSolid = false; + for(int j = 0; j < 4; j++){ + Tile othernear = other.nearby(i); + if(othernear != null && othernear.solid()){ + otherNearSolid = true; + break; + } + } + //the other tile is no longer near solid, remove the solid bit + if(!otherNearSolid){ + tiles[other.array()] &= ~(PathTile.bitMaskNearSolid); + } + } + } + } + } + }); } private void clearCache(){ @@ -115,17 +143,23 @@ public class Pathfinder implements Runnable{ } /** Packs a tile into its internal representation. */ - private int packTile(Tile tile){ + private int packTile(Tile tile, int prev){ boolean nearLiquid = false, nearSolid = false, nearGround = false, solid = tile.solid(), allDeep = tile.floor().isDeep(); for(int i = 0; i < 4; i++){ Tile other = tile.nearby(i); if(other != null){ Floor floor = other.floor(); + boolean osolid = other.solid(); if(floor.isLiquid) nearLiquid = true; - if(other.solid()) nearSolid = true; + if(osolid) nearSolid = true; if(!floor.isLiquid) nearGround = true; if(!floor.isDeep()) allDeep = false; + + //other tile is now near solid + if(solid){ + tiles[other.array()] |= PathTile.bitMaskNearSolid; + } } } @@ -173,7 +207,7 @@ public class Pathfinder implements Runnable{ tile.getLinkedTiles(t -> { int pos = t.array(); if(pos < tiles.length){ - tiles[pos] = packTile(t); + tiles[pos] = packTile(t, tiles[pos]); } }); diff --git a/core/src/mindustry/ai/types/CommandAI.java b/core/src/mindustry/ai/types/CommandAI.java index 0f8fd4b108..20fcaae230 100644 --- a/core/src/mindustry/ai/types/CommandAI.java +++ b/core/src/mindustry/ai/types/CommandAI.java @@ -70,7 +70,7 @@ public class CommandAI extends AIController{ faceTarget(); } - if(attackTarget == null && unit.within(targetPos, Math.max(5f, unit.hitSize) / 2.5f)){ + if(attackTarget == null && unit.within(targetPos, Math.max(5f, unit.hitSize / 2.5f))){ targetPos = null; } }else if(target != null){ diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 783d029554..5f36fdd2ba 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -253,6 +253,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ if(other != null){ if(pass == 0){ //first pass: delete existing blocks - this should automatically trigger removal if overlap exists + //TODO pointless setting air to air? other.setBlock(Blocks.air); }else{ //second pass: assign changed data