diff --git a/core/src/mindustry/entities/units/BuildPlan.java b/core/src/mindustry/entities/units/BuildPlan.java index 236e80aca1..26811b741f 100644 --- a/core/src/mindustry/entities/units/BuildPlan.java +++ b/core/src/mindustry/entities/units/BuildPlan.java @@ -26,7 +26,7 @@ public class BuildPlan implements Position, QuadTreeObject{ /** Last progress.*/ public float progress; /** Whether construction has started for this plan, and other special variables.*/ - public boolean initialized, worldContext = true, stuck; + public boolean initialized, worldContext = true, stuck, cachedValid; /** Visual scale. Used only for rendering.*/ public float animScale = 0f; @@ -81,7 +81,7 @@ public class BuildPlan implements Position, QuadTreeObject{ public static Object pointConfig(Block block, Object config, Cons cons){ if(config instanceof Point2 point){ config = point.cpy(); - cons.get(point); + cons.get((Point2)config); }else if(config instanceof Point2[] points){ Point2[] result = new Point2[points.length]; int i = 0; diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index ca6531f093..03ebd3d80d 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -39,7 +39,7 @@ public class DesktopInput extends InputHandler{ /** Animation scale for line. */ public float selectScale; /** Selected build plan for movement. */ - public @Nullable BuildPlan sreq; + public @Nullable BuildPlan splan; /** Whether player is currently deleting removal plans. */ public boolean deleting = false, shouldShoot = false, panning = false; /** Mouse pan speed. */ @@ -179,41 +179,50 @@ public class DesktopInput extends InputHandler{ int cursorX = tileX(Core.input.mouseX()); int cursorY = tileY(Core.input.mouseY()); - //draw request being moved - if(sreq != null){ - boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq); - if(sreq.block.rotate){ - drawArrow(sreq.block, sreq.x, sreq.y, sreq.rotation, valid); + //draw plan being moved + if(splan != null){ + boolean valid = validPlace(splan.x, splan.y, splan.block, splan.rotation, splan); + if(splan.block.rotate){ + drawArrow(splan.block, splan.x, splan.y, splan.rotation, valid); } - sreq.block.drawPlan(sreq, allPlans(), valid); + splan.block.drawPlan(splan, allPlans(), valid); - drawSelected(sreq.x, sreq.y, sreq.block, getPlan(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent); + drawSelected(splan.x, splan.y, splan.block, getPlan(splan.x, splan.y, splan.block.size, splan) != null ? Pal.remove : Pal.accent); } //draw hover plans if(mode == none && !isPlacing()){ - BuildPlan req = getPlan(cursorX, cursorY); - if(req != null){ - drawSelected(req.x, req.y, req.breaking ? req.tile().block() : req.block, Pal.accent); + var plan = getPlan(cursorX, cursorY); + if(plan != null){ + drawSelected(plan.x, plan.y, plan.breaking ? plan.tile().block() : plan.block, Pal.accent); } } - //draw schematic plans - selectPlans.each(req -> { - req.animScale = 1f; - drawPlan(req); - }); + var items = selectPlans.items; + int size = selectPlans.size; - selectPlans.each(this::drawOverPlan); + //draw schematic plans + for(int i = 0; i < size; i++){ + var plan = items[i]; + plan.animScale = 1f; + drawPlan(plan); + } + + //draw schematic plans - over version, cached results + for(int i = 0; i < size; i++){ + var plan = items[i]; + //use cached value from previous invocation + drawOverPlan(plan, plan.cachedValid); + } if(player.isBuilder()){ //draw things that may be placed soon if(mode == placing && block != null){ for(int i = 0; i < linePlans.size; i++){ - BuildPlan req = linePlans.get(i); - if(i == linePlans.size - 1 && req.block.rotate){ - drawArrow(block, req.x, req.y, req.rotation); + var plan = linePlans.get(i); + if(i == linePlans.size - 1 && plan.block.rotate){ + drawArrow(block, plan.x, plan.y, plan.rotation); } drawPlan(linePlans.get(i)); } @@ -373,8 +382,8 @@ public class DesktopInput extends InputHandler{ if(!Core.input.keyDown(Binding.diagonal_placement) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){ rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4); - if(sreq != null){ - sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4); + if(splan != null){ + splan.rotation = Mathf.mod(splan.rotation + (int)Core.input.axisTap(Binding.rotate), 4); } if(isPlacing() && mode == placing){ @@ -535,12 +544,12 @@ public class DesktopInput extends InputHandler{ } } - if(sreq != null){ - float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f; + if(splan != null){ + float offset = ((splan.block.size + 2) % 2) * tilesize / 2f; float x = Core.input.mouseWorld().x + offset; float y = Core.input.mouseWorld().y + offset; - sreq.x = (int)(x / tilesize); - sreq.y = (int)(y / tilesize); + splan.x = (int)(x / tilesize); + splan.y = (int)(y / tilesize); } if(block == null || mode != placing){ @@ -581,7 +590,7 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ tappedOne = false; - BuildPlan req = getPlan(cursorX, cursorY); + BuildPlan plan = getPlan(cursorX, cursorY); if(Core.input.keyDown(Binding.break_block)){ mode = none; @@ -594,9 +603,9 @@ public class DesktopInput extends InputHandler{ lastLineY = cursorY; mode = placing; updateLine(selectX, selectY); - }else if(req != null && !req.breaking && mode == none && !req.initialized){ - sreq = req; - }else if(req != null && req.breaking){ + }else if(plan != null && !plan.breaking && mode == none && !plan.initialized){ + splan = plan; + }else if(plan != null && plan.breaking){ deleting = true; }else if(commandMode){ commandRect = true; @@ -630,9 +639,9 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){ - BuildPlan req = getPlan(cursorX, cursorY); - if(req != null && req.breaking){ - player.unit().plans().remove(req); + var plan = getPlan(cursorX, cursorY); + if(plan != null && plan.breaking){ + player.unit().plans().remove(plan); } }else{ deleting = false; @@ -671,11 +680,11 @@ public class DesktopInput extends InputHandler{ tryDropItems(selected == null ? null : selected.build, Core.input.mouseWorld().x, Core.input.mouseWorld().y); - if(sreq != null){ - if(getPlan(sreq.x, sreq.y, sreq.block.size, sreq) != null){ - player.unit().plans().remove(sreq, true); + if(splan != null){ + if(getPlan(splan.x, splan.y, splan.block.size, splan) != null){ + player.unit().plans().remove(splan, true); } - sreq = null; + splan = null; } mode = none; @@ -782,7 +791,7 @@ public class DesktopInput extends InputHandler{ droppingItem = false; mode = none; block = null; - sreq = null; + splan = null; selectPlans.clear(); } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index a8aa541da3..ad3e8a8018 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -73,10 +73,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public @Nullable Schematic lastSchematic; public GestureDetector detector; public PlaceLine line = new PlaceLine(); - public BuildPlan resultreq; + public BuildPlan resultplan; public BuildPlan bplan = new BuildPlan(); public Seq linePlans = new Seq<>(); - public Seq selectPlans = new Seq<>(); + public Seq selectPlans = new Seq<>(BuildPlan.class); //for RTS controls public Seq selectedUnits = new Seq<>(); @@ -177,11 +177,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //O(n^2) search here; no way around it outer: while(it.hasNext()){ - BlockPlan req = it.next(); + var plan = it.next(); for(int pos : positions){ - if(req.x == Point2.x(pos) && req.y == Point2.y(pos)){ - req.removed = true; + if(plan.x == Point2.x(pos) && plan.y == Point2.y(pos)){ + plan.removed = true; it.remove(); continue outer; } @@ -758,10 +758,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void rotatePlans(Seq plans, int direction){ int ox = schemOriginX(), oy = schemOriginY(); - plans.each(req -> { - if(req.breaking) return; + plans.each(plan -> { + if(plan.breaking) return; - req.pointConfig(p -> { + plan.pointConfig(p -> { int cx = p.x, cy = p.y; int lx = cx; @@ -776,7 +776,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ }); //rotate actual plan, centered on its multiblock position - float wx = (req.x - ox) * tilesize + req.block.offset, wy = (req.y - oy) * tilesize + req.block.offset; + float wx = (plan.x - ox) * tilesize + plan.block.offset, wy = (plan.y - oy) * tilesize + plan.block.offset; float x = wx; if(direction >= 0){ wx = -wy; @@ -785,40 +785,40 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ wx = wy; wy = -x; } - req.x = World.toTile(wx - req.block.offset) + ox; - req.y = World.toTile(wy - req.block.offset) + oy; - req.rotation = Mathf.mod(req.rotation + direction, 4); + plan.x = World.toTile(wx - plan.block.offset) + ox; + plan.y = World.toTile(wy - plan.block.offset) + oy; + plan.rotation = Mathf.mod(plan.rotation + direction, 4); }); } public void flipPlans(Seq plans, boolean x){ int origin = (x ? schemOriginX() : schemOriginY()) * tilesize; - plans.each(req -> { - if(req.breaking) return; + plans.each(plan -> { + if(plan.breaking) return; - float value = -((x ? req.x : req.y) * tilesize - origin + req.block.offset) + origin; + float value = -((x ? plan.x : plan.y) * tilesize - origin + plan.block.offset) + origin; if(x){ - req.x = (int)((value - req.block.offset) / tilesize); + plan.x = (int)((value - plan.block.offset) / tilesize); }else{ - req.y = (int)((value - req.block.offset) / tilesize); + plan.y = (int)((value - plan.block.offset) / tilesize); } - req.pointConfig(p -> { - int corigin = x ? req.originalWidth/2 : req.originalHeight/2; + plan.pointConfig(p -> { + int corigin = x ? plan.originalWidth/2 : plan.originalHeight/2; int nvalue = -(x ? p.x : p.y); if(x){ - req.originalX = -(req.originalX - corigin) + corigin; + plan.originalX = -(plan.originalX - corigin) + corigin; p.x = nvalue; }else{ - req.originalY = -(req.originalY - corigin) + corigin; + plan.originalY = -(plan.originalY - corigin) + corigin; p.y = nvalue; } }); //flip rotation - req.block.flipRotation(req, x); + plan.block.flipRotation(plan, x); }); } @@ -840,17 +840,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ float offset = ((size + 1) % 2) * tilesize / 2f; r2.setSize(tilesize * size); r2.setCenter(x * tilesize + offset, y * tilesize + offset); - resultreq = null; + resultplan = null; - Boolf test = req -> { - if(req == skip) return false; - Tile other = req.tile(); + Boolf test = plan -> { + if(plan == skip) return false; + Tile other = plan.tile(); if(other == null) return false; - if(!req.breaking){ - r1.setSize(req.block.size * tilesize); - r1.setCenter(other.worldx() + req.block.offset, other.worldy() + req.block.offset); + if(!plan.breaking){ + r1.setSize(plan.block.size * tilesize); + r1.setCenter(other.worldx() + plan.block.offset, other.worldy() + plan.block.offset); }else{ r1.setSize(other.block().size * tilesize); r1.setCenter(other.worldx() + other.block().offset, other.worldy() + other.block().offset); @@ -859,8 +859,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return r2.overlaps(r1); }; - for(BuildPlan req : player.unit().plans()){ - if(test.get(req)) return req; + for(var plan : player.unit().plans()){ + if(test.get(plan)) return plan; } return selectPlans.find(test); @@ -884,24 +884,24 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Draw.color(Pal.remove); Lines.stroke(1f); - for(BuildPlan req : player.unit().plans()){ - if(req.breaking) continue; - if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){ - drawBreaking(req); + for(var plan : player.unit().plans()){ + if(plan.breaking) continue; + if(plan.bounds(Tmp.r2).overlaps(Tmp.r1)){ + drawBreaking(plan); } } - for(BuildPlan req : selectPlans){ - if(req.breaking) continue; - if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){ - drawBreaking(req); + for(var plan : selectPlans){ + if(plan.breaking) continue; + if(plan.bounds(Tmp.r2).overlaps(Tmp.r1)){ + drawBreaking(plan); } } - for(BlockPlan req : player.team().data().blocks){ - Block block = content.block(req.block); - if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ - drawSelected(req.x, req.y, content.block(req.block), Pal.remove); + for(BlockPlan plan : player.team().data().blocks){ + Block block = content.block(plan.block); + if(block.bounds(plan.x, plan.y, Tmp.r2).overlaps(Tmp.r1)){ + drawSelected(plan.x, plan.y, content.block(plan.block), Pal.remove); } } @@ -929,32 +929,34 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } protected void flushSelectPlans(Seq plans){ - for(BuildPlan req : plans){ - if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ - BuildPlan other = getPlan(req.x, req.y, req.block.size, null); + for(BuildPlan plan : plans){ + if(plan.block != null && validPlace(plan.x, plan.y, plan.block, plan.rotation)){ + BuildPlan other = getPlan(plan.x, plan.y, plan.block.size, null); if(other == null){ - selectPlans.add(req.copy()); - }else if(!other.breaking && other.x == req.x && other.y == req.y && other.block.size == req.block.size){ + selectPlans.add(plan.copy()); + }else if(!other.breaking && other.x == plan.x && other.y == plan.y && other.block.size == plan.block.size){ selectPlans.remove(other); - selectPlans.add(req.copy()); + selectPlans.add(plan.copy()); } } } } protected void flushPlans(Seq plans){ - for(BuildPlan req : plans){ - if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ - BuildPlan copy = req.copy(); - req.block.onNewPlan(copy); + for(var plan : plans){ + if(plan.block != null && validPlace(plan.x, plan.y, plan.block, plan.rotation)){ + BuildPlan copy = plan.copy(); + plan.block.onNewPlan(copy); player.unit().addBuild(copy); } } } protected void drawOverPlan(BuildPlan plan){ - boolean valid = validPlace(plan.x, plan.y, plan.block, plan.rotation); + drawOverPlan(plan, validPlace(plan.x, plan.y, plan.block, plan.rotation)); + } + protected void drawOverPlan(BuildPlan plan, boolean valid){ Draw.reset(); Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime, 6f, 0.28f)); Draw.alpha(1f); @@ -963,7 +965,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } protected void drawPlan(BuildPlan plan){ - plan.block.drawPlan(plan, allPlans(), validPlace(plan.x, plan.y, plan.block, plan.rotation)); + drawPlan(plan, plan.cachedValid = validPlace(plan.x, plan.y, plan.block, plan.rotation)); + } + + protected void drawPlan(BuildPlan plan, boolean valid){ + plan.block.drawPlan(plan, allPlans(), valid); } /** Draws a placement icon for a specific block. */ @@ -1013,16 +1019,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Iterator it = player.unit().plans().iterator(); while(it.hasNext()){ - BuildPlan req = it.next(); - if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){ + var plan = it.next(); + if(!plan.breaking && plan.bounds(Tmp.r2).overlaps(Tmp.r1)){ it.remove(); } } it = selectPlans.iterator(); while(it.hasNext()){ - BuildPlan req = it.next(); - if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){ + var plan = it.next(); + if(!plan.breaking && plan.bounds(Tmp.r2).overlaps(Tmp.r1)){ it.remove(); } } @@ -1032,11 +1038,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //remove blocks to rebuild Iterator broken = player.team().data().blocks.iterator(); while(broken.hasNext()){ - BlockPlan req = broken.next(); - Block block = content.block(req.block); - if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ - removed.add(Point2.pack(req.x, req.y)); - req.removed = true; + BlockPlan plan = broken.next(); + Block block = content.block(plan.block); + if(block.bounds(plan.x, plan.y, Tmp.r2).overlaps(Tmp.r1)){ + removed.add(Point2.pack(plan.x, plan.y)); + plan.removed = true; broken.remove(); } } @@ -1051,16 +1057,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ linePlans.clear(); iterateLine(x1, y1, x2, y2, l -> { rotation = l.rotation; - BuildPlan req = new BuildPlan(l.x, l.y, l.rotation, block, block.nextConfig()); - req.animScale = 1f; - linePlans.add(req); + var plan = new BuildPlan(l.x, l.y, l.rotation, block, block.nextConfig()); + plan.animScale = 1f; + linePlans.add(plan); }); if(Core.settings.getBool("blockreplace")){ - linePlans.each(req -> { - Block replace = req.block.getReplacement(req, linePlans); + linePlans.each(plan -> { + Block replace = plan.block.getReplacement(plan, linePlans); if(replace.unlockedNow()){ - req.block = replace; + plan.block = replace; } }); @@ -1369,11 +1375,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ playerPlanTree.intersect(Tmp.r1, plansOut); for(int i = 0; i < plansOut.size; i++){ - var req = plansOut.items[i]; - if(req != ignore - && !req.breaking - && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2)) - && !(type.canReplace(req.block) && Tmp.r1.equals(Tmp.r2))){ + var plan = plansOut.items[i]; + if(plan != ignore + && !plan.breaking + && plan.block.bounds(plan.x, plan.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2)) + && !(type.canReplace(plan.block) && Tmp.r1.equals(Tmp.r2))){ return false; } } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 5cd7daa15e..fbc4bf2f7a 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -113,26 +113,26 @@ public class MobileInput extends InputHandler implements GestureListener{ r2.setSize(block.size * tilesize); r2.setCenter(x * tilesize + block.offset, y * tilesize + block.offset); - for(BuildPlan req : selectPlans){ - Tile other = req.tile(); + for(var plan : selectPlans){ + Tile other = plan.tile(); - if(other == null || req.breaking) continue; + if(other == null || plan.breaking) continue; - r1.setSize(req.block.size * tilesize); - r1.setCenter(other.worldx() + req.block.offset, other.worldy() + req.block.offset); + r1.setSize(plan.block.size * tilesize); + r1.setCenter(other.worldx() + plan.block.offset, other.worldy() + plan.block.offset); if(r2.overlaps(r1)){ return true; } } - for(BuildPlan req : player.unit().plans()){ - Tile other = world.tile(req.x, req.y); + for(var plan : player.unit().plans()){ + Tile other = world.tile(plan.x, plan.y); - if(other == null || req.breaking) continue; + if(other == null || plan.breaking) continue; - r1.setSize(req.block.size * tilesize); - r1.setCenter(other.worldx() + req.block.offset, other.worldy() + req.block.offset); + r1.setSize(plan.block.size * tilesize); + r1.setCenter(other.worldx() + plan.block.offset, other.worldy() + plan.block.offset); if(r2.overlaps(r1)){ return true; @@ -146,21 +146,21 @@ public class MobileInput extends InputHandler implements GestureListener{ r2.setSize(tilesize); r2.setCenter(tile.worldx(), tile.worldy()); - for(BuildPlan req : selectPlans){ - Tile other = req.tile(); + for(var plan : selectPlans){ + Tile other = plan.tile(); if(other == null) continue; - if(!req.breaking){ - r1.setSize(req.block.size * tilesize); - r1.setCenter(other.worldx() + req.block.offset, other.worldy() + req.block.offset); + if(!plan.breaking){ + r1.setSize(plan.block.size * tilesize); + r1.setCenter(other.worldx() + plan.block.offset, other.worldy() + plan.block.offset); }else{ r1.setSize(other.block().size * tilesize); r1.setCenter(other.worldx() + other.block().offset, other.worldy() + other.block().offset); } - if(r2.overlaps(r1)) return req; + if(r2.overlaps(r1)) return plan; } return null; } @@ -822,10 +822,10 @@ public class MobileInput extends InputHandler implements GestureListener{ int shiftedY = (int)(shiftDeltaY / tilesize); if(Math.abs(shiftedX) > 0 || Math.abs(shiftedY) > 0){ - for(BuildPlan req : selectPlans){ - if(req.breaking) continue; //don't shift removal plans - req.x += shiftedX; - req.y += shiftedY; + for(var plan : selectPlans){ + if(plan.breaking) continue; //don't shift removal plans + plan.x += shiftedX; + plan.y += shiftedY; } shiftDeltaX %= tilesize;