diff --git a/core/src/mindustry/ai/ControlPathfinder.java b/core/src/mindustry/ai/ControlPathfinder.java index feeca983d9..60def58dd4 100644 --- a/core/src/mindustry/ai/ControlPathfinder.java +++ b/core/src/mindustry/ai/ControlPathfinder.java @@ -164,6 +164,7 @@ public class ControlPathfinder implements Runnable{ //main thread only! long lastUpdateId = state.updateId; + long lastRecomputeTime; //both threads volatile boolean notFound = false; @@ -1192,7 +1193,9 @@ public class ControlPathfinder implements Runnable{ long fieldKey = FieldIndex.get(destPos, costId, team); //use existing request if it exists. - if(request != null && request.destination == destPos){ + if(request != null && (request.destination == destPos || + //can only recompute path only twice a second, unless it's far away + (Time.timeSinceMillis(request.lastRecomputeTime) < 1000 && Mathf.dst(destX, destY, request.destination % wwidth, request.destination / wwidth) <= 4f))){ request.lastUpdateId = state.updateId; Tile initialTileOn = tileOn; @@ -1313,6 +1316,7 @@ public class ControlPathfinder implements Runnable{ unitRequests.put(unit, request = new PathRequest(unit, team, costId, destPos)); PathRequest f = request; + request.lastRecomputeTime = Time.millis(); //on the pathfinding thread: initialize the request queue.post(() -> { diff --git a/core/src/mindustry/ai/types/CommandAI.java b/core/src/mindustry/ai/types/CommandAI.java index 637ade5f29..3d955a5b6e 100644 --- a/core/src/mindustry/ai/types/CommandAI.java +++ b/core/src/mindustry/ai/types/CommandAI.java @@ -259,7 +259,8 @@ public class CommandAI extends AIController{ targetPos = new Vec2(); lastTargetPos = targetPos; } - targetPos.set(attackTarget); + //don't target where target dummies are right now, target their block + targetPos.set(attackTarget instanceof TargetDummyUnit t && t.building != null ? t.building : attackTarget); if(unit.isGrounded() && attackTarget instanceof Building build && build.tile.solid() && unit.type.pathCostId != ControlPathfinder.costIdLegs && !ramming){ Tile best = build.findClosestEdge(unit, Tile::solid); diff --git a/core/src/mindustry/world/blocks/defense/TargetDummy.java b/core/src/mindustry/world/blocks/defense/TargetDummy.java index 851d988e88..93e89fdb57 100644 --- a/core/src/mindustry/world/blocks/defense/TargetDummy.java +++ b/core/src/mindustry/world/blocks/defense/TargetDummy.java @@ -22,6 +22,8 @@ import mindustry.world.meta.*; import static mindustry.Vars.*; public class TargetDummy extends Block{ + static final float maxDummySize = 30f; + public final int dpsUpdateTime = timers++; public UnitType unitType = UnitTypes.dummy; public float pullScale = 0.33f; @@ -39,7 +41,6 @@ public class TargetDummy extends Block{ targetable = false; allowedInPayloads = false; canOverdrive = false; - saveConfig = true; config(int[].class, (TargetDummyBuild tile, int[] config) -> { @@ -47,9 +48,10 @@ public class TargetDummy extends Block{ tile.unitTeam = tile.team; if(config[0] == 1) tile.unitTeam = Team.get(tile.dummyTeam()); tile.boosting = config[1] == 1; - tile.unitArmor = config[2]; + tile.unitArmor = Mathf.clamp(config[2], 0, 100_000); tile.resetTime = config[3]; - tile.dummySize = Float.intBitsToFloat(config[4]); + tile.dummySize = Mathf.clamp(Float.intBitsToFloat(config[4]), 0.1f, maxDummySize * tilesize); + if(Float.isNaN(tile.dummySize) || Float.isInfinite(tile.dummySize)) tile.dummySize = 8f; }); } @@ -251,7 +253,7 @@ public class TargetDummy extends Block{ t.field("" + (dummySize/tilesize), TextFieldFilter.floatsOnly, s -> configureInt(4, Float.floatToIntBits(Strings.parseFloat(s) * tilesize))) .valid(val -> { float parsed = Strings.parseFloat(val, Float.MAX_VALUE); - return parsed >= 0.1f && parsed <= 50f; + return parsed >= 0.1f && parsed <= maxDummySize; }).padLeft(8f).growX(); t.add(StatUnit.blocks.localized()).padLeft(8f); }).top().grow().margin(8f);