From 90aed50ca805deabde2911899457966d92660b0d Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 3 Sep 2020 14:04:30 -0400 Subject: [PATCH] Many various fixes --- core/src/mindustry/ai/BlockIndexer.java | 10 +- core/src/mindustry/ai/Pathfinder.java | 37 +++-- core/src/mindustry/ai/types/GroundAI.java | 7 +- core/src/mindustry/core/World.java | 2 +- .../mindustry/editor/MapGenerateDialog.java | 3 +- .../mindustry/entities/comp/PayloadComp.java | 3 +- core/src/mindustry/game/EventType.java | 5 +- .../src/mindustry/graphics/BlockRenderer.java | 2 +- .../mindustry/graphics/MinimapRenderer.java | 6 +- core/src/mindustry/logic/LAssembler.java | 3 +- core/src/mindustry/logic/LCanvas.java | 155 +++++++++++------- core/src/mindustry/logic/LExecutor.java | 2 + core/src/mindustry/logic/LogicDialog.java | 3 +- core/src/mindustry/type/UnitType.java | 2 + .../world/blocks/logic/LogicBlock.java | 6 +- 15 files changed, 151 insertions(+), 95 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 26ec43e74b..1d2095ec20 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -37,7 +37,7 @@ public class BlockIndexer{ /** All ores available on this map. */ private ObjectSet allOres = new ObjectSet<>(); /** Stores teams that are present here as tiles. */ - private Seq activeTeams = new Seq<>(); + private Seq activeTeams = new Seq<>(Team.class); /** Maps teams to a map of flagged tiles by flag. */ private TileArray[][] flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; /** Max units by team. */ @@ -52,7 +52,7 @@ public class BlockIndexer{ private Seq breturnArray = new Seq<>(); public BlockIndexer(){ - Events.on(BuildinghangeEvent.class, event -> { + Events.on(TileChangeEvent.class, event -> { if(typeMap.get(event.tile.pos()) != null){ TileIndex index = typeMap.get(event.tile.pos()); for(BlockFlag flag : index.flags){ @@ -73,6 +73,7 @@ public class BlockIndexer{ damagedTiles = new BuildingArray[Team.all.length]; flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; unitCaps = new int[Team.all.length]; + activeTeams = new Seq<>(Team.class); for(int i = 0; i < flagMap.length; i++){ for(int j = 0; j < BlockFlag.all.length; j++){ @@ -220,7 +221,10 @@ public class BlockIndexer{ } public Building findEnemyTile(Team team, float x, float y, float range, Boolf pred){ - for(Team enemy : team.enemies()){ + for(int i = 0; i < activeTeams.size; i++){ + Team enemy = activeTeams.items[i]; + + if(enemy == team) continue; Building entity = indexer.findTile(enemy, x, y, range, pred, true); if(entity != null){ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index 160bf09d35..280106eaa8 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -38,32 +38,35 @@ public class Pathfinder implements Runnable{ costWater = 2; public static final Seq costTypes = Seq.with( + //ground (team, tile) -> (PathTile.team(tile) == team.id || PathTile.team(tile) == 0) && PathTile.solid(tile) ? impassable : 1 + PathTile.health(tile) * 5 + (PathTile.nearSolid(tile) ? 2 : 0) + (PathTile.nearLiquid(tile) ? 6 : 0) + (PathTile.deep(tile) ? 70 : 0), + //legs (team, tile) -> PathTile.legSolid(tile) ? impassable : 1 + (PathTile.solid(tile) ? 5 : 0), - (team, tile) -> PathTile.solid(tile) || !PathTile.liquid(tile) ? impassable : 2 + //TODO cannot go through blocks + //water + (team, tile) -> PathTile.solid(tile) || !PathTile.liquid(tile) ? 200 : 2 + //TODO cannot go through blocks - pathfinding isn't great (PathTile.nearGround(tile) || PathTile.nearSolid(tile) ? 14 : 0) + (PathTile.deep(tile) ? -1 : 0) ); //maps team, cost, type to flow field - private Flowfield[][][] cache; + Flowfield[][][] cache; /** tile data, see PathTileStruct */ - private int[][] tiles; + int[][] tiles; /** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */ - private Seq threadList = new Seq<>(), mainList = new Seq<>(); + Seq threadList = new Seq<>(), mainList = new Seq<>(); /** handles task scheduling on the update thread. */ - private TaskQueue queue = new TaskQueue(); + TaskQueue queue = new TaskQueue(); /** Current pathfinding thread */ - private @Nullable Thread thread; - private IntSeq tmpArray = new IntSeq(); + @Nullable Thread thread; + IntSeq tmpArray = new IntSeq(); public Pathfinder(){ clearCache(); @@ -89,7 +92,7 @@ public class Pathfinder implements Runnable{ Events.on(ResetEvent.class, event -> stop()); - Events.on(BuildinghangeEvent.class, event -> updateTile(event.tile)); + Events.on(TileChangeEvent.class, event -> updateTile(event.tile)); } private void clearCache(){ @@ -115,7 +118,7 @@ public class Pathfinder implements Runnable{ tile.getTeamID(), tile.solid(), tile.floor().isLiquid, - tile.staticDarkness() < 2, + tile.staticDarkness() >= 2, nearLiquid, nearGround, nearSolid, @@ -220,10 +223,6 @@ public class Pathfinder implements Runnable{ } } - //public @Nullable Tile getTargetTile(Tile tile, Team team, Position target){ - // return getTargetTile(tile, team, getTarget(target)); - // } - public Flowfield getField(Team team, int costType, int fieldType){ if(cache[team.id][costType][fieldType] == null){ Flowfield field = fieldTypes.get(fieldType).get(); @@ -277,8 +276,8 @@ public class Pathfinder implements Runnable{ Tile other = world.tile(dx, dy); if(other == null) continue; - if(values[dx][dy] < value && (current == null || values[dx][dy] < tl) && !other.solid() && other.floor().drownTime <= 0 && - !(point.x != 0 && point.y != 0 && (world.solid(tile.x + point.x, tile.y) || world.solid(tile.x, tile.y + point.y)))){ //diagonal corner trap + if(values[dx][dy] < value && (current == null || values[dx][dy] < tl) && path.passable(dx, dy) && + !(point.x != 0 && point.y != 0 && (!path.passable(tile.x + point.x, tile.y) || !path.passable(tile.x, tile.y + point.y)))){ //diagonal corner trap current = other; tl = values[dx][dy]; } @@ -390,10 +389,12 @@ public class Pathfinder implements Runnable{ } if(cost != impassable){ - //TODO this is probably slow. for(Point2 point : Geometry.d4){ int dx = tile.x + point.x, dy = tile.y + point.y; + + if(dx < 0 || dy < 0 || dx >= tiles.length || dy >= tiles[0].length) continue; + int otherCost = path.cost.getCost(path.team, tiles[dx][dy]); if((path.weights[dx][dy] > cost + otherCost || path.searches[dx][dy] < path.search) && otherCost != impassable){ @@ -480,6 +481,10 @@ public class Pathfinder implements Runnable{ this.initialized = true; } + protected boolean passable(int x, int y){ + return cost.getCost(team, pathfinder.tiles[x][y]) != impassable; + } + /** Gets targets to pathfind towards. This must run on the main thread. */ protected abstract void getPositions(IntSeq out); } diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index ff290a6816..eca4d32e62 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -1,5 +1,6 @@ package mindustry.ai.types; +import arc.math.*; import mindustry.ai.*; import mindustry.entities.*; import mindustry.entities.units.*; @@ -33,14 +34,14 @@ public class GroundAI extends AIController{ if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false; } - if(move) moveToCore(FlagTarget.enemyCores); + if(move) moveTo(Pathfinder.fieldCore); } if(command() == UnitCommand.rally){ Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false); if(target != null && !unit.within(target, 70f)){ - moveToCore(FlagTarget.rallyPoints); + moveTo(Pathfinder.fieldRally); } } @@ -82,7 +83,7 @@ public class GroundAI extends AIController{ if(tile == null) return; Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathType)); - if(tile == targetTile) return; + if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return; unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed)); } diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 9dea5f0e35..6f996746a6 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -317,7 +317,7 @@ public class World{ public void notifyChanged(Tile tile){ if(!generating){ - Core.app.post(() -> Events.fire(new BuildinghangeEvent(tile))); + Core.app.post(() -> Events.fire(new TileChangeEvent(tile))); } } diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index c2869a664c..7f540750d9 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -348,6 +348,7 @@ public class MapGenerateDialog extends BaseDialog{ result = executor.submit(() -> { try{ + world.setGenerating(true); generating = true; if(!filters.isEmpty()){ @@ -400,7 +401,7 @@ public class MapGenerateDialog extends BaseDialog{ generating = false; e.printStackTrace(); } - return null; + world.setGenerating(false); }); } diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index b715d4d7c4..6a75086eec 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -70,13 +70,14 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc{ boolean dropUnit(UnitPayload payload){ Unit u = payload.unit; - Fx.unitDrop.at(this); //can't drop ground units if(((tileOn() == null || tileOn().solid()) && u.elevation < 0.1f) || (!floorOn().isLiquid && u instanceof WaterMovec)){ return false; } + Fx.unitDrop.at(this); + //clients do not drop payloads if(Vars.net.client()) return true; diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 531ca72cf2..2239e01911 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -170,11 +170,10 @@ public class EventType{ } } - /** Called from the logic thread. Do not access graphics here! */ - public static class BuildinghangeEvent{ + public static class TileChangeEvent{ public final Tile tile; - public BuildinghangeEvent(Tile tile){ + public TileChangeEvent(Tile tile){ this.tile = tile; } } diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 08b13bf9b8..5bb0b5fbae 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -82,7 +82,7 @@ public class BlockRenderer implements Disposable{ dark.end(); }); - Events.on(BuildinghangeEvent.class, event -> { + Events.on(TileChangeEvent.class, event -> { shadowEvents.add(event.tile); int avgx = (int)(camera.position.x / tilesize); diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index e0cd9c7a50..3b3482e410 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -36,7 +36,11 @@ public class MinimapRenderer implements Disposable{ }); //make sure to call on the graphics thread - Events.on(BuildinghangeEvent.class, event -> Core.app.post(() -> update(event.tile))); + Events.on(TileChangeEvent.class, event -> { + if(!ui.editor.isShown()){ + update(event.tile); + } + }); } public Pixmap getPixmap(){ diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index 8ac7481dd0..3ebda82f02 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -8,7 +8,6 @@ import mindustry.gen.*; import mindustry.logic.LExecutor.*; import mindustry.logic.LStatements.*; import mindustry.type.*; -import mindustry.world.blocks.logic.*; /** "Compiles" a sequence of statements into instructions. */ public class LAssembler{ @@ -66,7 +65,7 @@ public class LAssembler{ } public static Seq read(String data){ - return read(data, LogicBlock.maxInstructions); + return read(data, LExecutor.maxInstructions); } public static Seq read(String data, int max){ diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java index c00a69b887..d626f95388 100644 --- a/core/src/mindustry/logic/LCanvas.java +++ b/core/src/mindustry/logic/LCanvas.java @@ -17,18 +17,20 @@ import arc.util.ArcAnnotate.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.ui.*; -import mindustry.world.blocks.logic.*; public class LCanvas extends Table{ - static Seq postDraw = new Seq<>(); - static Seq postDrawPriority = new Seq<>(); + //ew static variables + static LCanvas canvas; DragLayout statements; StatementElem dragging; ScrollPane pane; + Group jumps; float targetWidth; public LCanvas(){ + canvas = this; + rebuild(); } @@ -45,12 +47,16 @@ public class LCanvas extends Table{ clear(); statements = new DragLayout(); + jumps = new WidgetGroup(); pane = pane(t -> { t.center(); t.add(statements).pad(2f).center().width(targetWidth); + t.addChild(jumps); + + jumps.cullable = false; }).grow().get(); - pane.setClip(false); + //pane.setClip(false); pane.setFlickScroll(false); //load old scroll percent @@ -76,8 +82,10 @@ public class LCanvas extends Table{ } void load(String asm){ + jumps.clear(); + Seq statements = LAssembler.read(asm); - statements.truncate(LogicBlock.maxInstructions); + statements.truncate(LExecutor.maxInstructions); this.statements.clearChildren(); for(LStatement st : statements){ add(st); @@ -104,19 +112,11 @@ public class LCanvas extends Table{ } } - @Override - public void draw(){ - postDraw.clear(); - postDrawPriority.clear(); - super.draw(); - postDraw.each(Runnable::run); - postDrawPriority.each(Runnable::run); - } - public class DragLayout extends WidgetGroup{ float space = Scl.scl(10f), prefWidth, prefHeight; Seq seq = new Seq<>(); int insertPosition = 0; + boolean invalidated; { setTransform(true); @@ -124,6 +124,7 @@ public class LCanvas extends Table{ @Override public void layout(){ + invalidated = true; float cy = 0; seq.clear(); @@ -171,6 +172,10 @@ public class LCanvas extends Table{ } invalidateHierarchy(); + + if(parent != null && parent instanceof Table){ + setCullingArea(parent.getCullingArea()); + } } @Override @@ -196,7 +201,16 @@ public class LCanvas extends Table{ Tex.pane.draw(lastX, lastY - shiftAmount, width, dragging.getHeight()); } + if(invalidated){ + children.each(c -> c.cullable = false); + } + super.draw(); + + if(invalidated){ + children.each(c -> c.cullable = true); + invalidated = false; + } } void finishLayout(){ @@ -338,6 +352,9 @@ public class LCanvas extends Table{ boolean selecting; float mx, my; ClickListener listener; + StatementElem hovered; + + JumpCurve curve; public JumpButton(@NonNull Prov getter, Cons setter){ super(Tex.logicNode, Styles.colori); @@ -383,53 +400,26 @@ public class LCanvas extends Table{ setColor(listener.isOver() ? hoverColor : defaultColor); getStyle().imageUpColor = this.color; }); + + curve = new JumpCurve(this); } @Override - public void draw(){ - super.draw(); + public void act(float delta){ + super.act(delta); - (listener.isOver() ? postDrawPriority : postDraw).add(() -> { - Element hover = to.get() == null && selecting ? hovered() : to.get(); - float tx = 0, ty = 0; - boolean draw = false; - //capture coordinates for use in lambda - float rx = x + translation.x, ry = y + translation.y; + hovered = hovered(); + } - Element p = parent; - while(p != null){ - rx += p.x + p.translation.x; - ry += p.y + p.translation.y; - p = p.parent; - } + @Override + protected void setScene(Scene stage){ + super.setScene(stage); - if(hover != null){ - tx = hover.getX(Align.right) + hover.translation.x; - ty = hover.getY(Align.right) + hover.translation.y; - - Element op = hover.parent; - while(op != null){ - tx += op.x + op.translation.x; - ty += op.y + op.translation.y; - op = op.parent; - } - - draw = true; - }else if(selecting){ - tx = rx + mx; - ty = ry + my; - draw = true; - } - - if(draw){ - drawCurve(rx + width/2f, ry + height/2f, tx, ty); - - float s = width; - Draw.color(color); - Tex.logicNode.draw(tx + s*0.75f, ty - s/2f, -s, s); - Draw.reset(); - } - }); + if(stage == null){ + curve.remove(); + }else{ + canvas.jumps.addChild(curve); + } } StatementElem hovered(){ @@ -442,9 +432,60 @@ public class LCanvas extends Table{ if(e == null || isDescendantOf(e)) return null; return (StatementElem)e; } + } + + public static class JumpCurve extends Element{ + JumpButton button; + + public JumpCurve(JumpButton button){ + this.button = button; + } + + @Override + public void act(float delta){ + super.act(delta); + + if(button.listener.isOver()){ + toFront(); + } + } + + @Override + public void draw(){ + Element hover = button.to.get() == null && button.selecting ? button.hovered : button.to.get(); + boolean draw = false; + Vec2 t = Tmp.v1, r = Tmp.v2; + + Group desc = canvas.pane; + + button.localToAscendantCoordinates(desc, r.set(0, 0)); + + if(hover != null){ + hover.localToAscendantCoordinates(desc, t.set(hover.getWidth(), hover.getHeight()/2f)); + + draw = true; + }else if(button.selecting){ + t.set(r).add(button.mx, button.my); + draw = true; + } + + float offset = canvas.pane.getVisualScrollY() - canvas.pane.getMaxY(); + + t.y += offset; + r.y += offset; + + if(draw){ + drawCurve(r.x + button.getWidth()/2f, r.y + button.getHeight()/2f, t.x, t.y); + + float s = button.getWidth(); + Draw.color(button.color); + Tex.logicNode.draw(t.x + s*0.75f, t.y - s/2f, -s, s); + Draw.reset(); + } + } void drawCurve(float x, float y, float x2, float y2){ - Lines.stroke(4f, color); + Lines.stroke(4f, button.color); Draw.alpha(parentAlpha); float dist = 100f; @@ -454,7 +495,7 @@ public class LCanvas extends Table{ x + dist, y, x2 + dist, y2, x2, y2, - Math.max(20, (int)(Mathf.dst(x, y, x2, y2) / 5)) + Math.max(20, (int)(Mathf.dst(x, y, x2, y2) / 6)) ); } } diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index dc5faff849..5ac84a72ae 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -15,6 +15,8 @@ import mindustry.world.blocks.logic.MessageBlock.*; import static mindustry.Vars.*; public class LExecutor{ + public static final int maxInstructions = 1000; + //special variables public static final int varCounter = 0, diff --git a/core/src/mindustry/logic/LogicDialog.java b/core/src/mindustry/logic/LogicDialog.java index a9f2debfbb..6bd6d45db4 100644 --- a/core/src/mindustry/logic/LogicDialog.java +++ b/core/src/mindustry/logic/LogicDialog.java @@ -7,7 +7,6 @@ import mindustry.gen.*; import mindustry.logic.LStatements.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; -import mindustry.world.blocks.logic.*; import static mindustry.Vars.*; @@ -75,7 +74,7 @@ public class LogicDialog extends BaseDialog{ }); dialog.addCloseButton(); dialog.show(); - }).width(170f).disabled(t -> canvas.statements.getChildren().size >= LogicBlock.maxInstructions); + }).width(170f).disabled(t -> canvas.statements.getChildren().size >= LExecutor.maxInstructions); add(canvas).grow(); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 7693d4ffd6..d268b3ffd5 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -478,6 +478,7 @@ public class UnitType extends UnlockableContent{ } public void drawLegs(T unit){ + applyColor(unit); Leg[] legs = unit.legs(); @@ -570,6 +571,7 @@ public class UnitType extends UnlockableContent{ } public void applyColor(Unit unit){ + Draw.color(); Draw.mixcol(Color.white, unit.hitTime); if(unit.drownTime > 0 && unit.floorOn().isDeep()){ Draw.mixcol(unit.floorOn().mapColor, unit.drownTime * 0.8f); diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index ecf759fade..026a1ca58f 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -25,8 +25,6 @@ import java.util.zip.*; import static mindustry.Vars.*; public class LogicBlock extends Block{ - public static final int maxInstructions = 1500; - public int maxInstructionScale = 5; public int instructionsPerTick = 1; public float range = 8 * 10; @@ -271,7 +269,7 @@ public class LogicBlock extends Block{ try{ //create assembler to store extra variables - LAssembler asm = LAssembler.assemble(str, maxInstructions); + LAssembler asm = LAssembler.assemble(str, LExecutor.maxInstructions); //store connections for(LogicLink link : links){ @@ -316,7 +314,7 @@ public class LogicBlock extends Block{ e.printStackTrace(); //handle malformed code and replace it with nothing - executor.load("", maxInstructions); + executor.load("", LExecutor.maxInstructions); } } }