diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 7fe7aea771..f8547cb800 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -104,7 +104,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ if(current.breaking){ entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); }else{ - if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier)){ + if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){ if(current.hasConfig){ Call.onTileConfig(null, tile, current.config); } @@ -267,18 +267,26 @@ public interface BuilderTrait extends Entity, TeamTrait{ /** Class for storing build requests. Can be either a place or remove request. */ class BuildRequest{ + /** Position and rotation of this request. */ public int x, y, rotation; + /** Block being placed. If null, this is a breaking request.*/ public @Nullable Block block; + /** Whether this is a break request.*/ public boolean breaking; + /** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/ public boolean hasConfig; + /** Config int. Not used unless hasConfig is true.*/ public int config; + /** Original position, only used in schematics.*/ + public int originalX, originalY; + /** Last progress.*/ public float progress; + /** Whether construction has started for this request.*/ public boolean initialized; - //animation variables + /** Visual scale. Used only for rendering.*/ public float animScale = 0f; - public float animInvalid; /** This creates a build request. */ public BuildRequest(int x, int y, int rotation, Block block){ @@ -302,6 +310,29 @@ public interface BuilderTrait extends Entity, TeamTrait{ } + public BuildRequest copy(){ + BuildRequest copy = new BuildRequest(); + copy.x = x; + copy.y = y; + copy.rotation = rotation; + copy.block = block; + copy.breaking = breaking; + copy.hasConfig = hasConfig; + copy.config = config; + copy.originalX = originalX; + copy.originalY = originalY; + copy.progress = progress; + copy.initialized = initialized; + copy.animScale = animScale; + return copy; + } + + public BuildRequest original(int x, int y){ + originalX = x; + originalY = y; + return this; + } + public Rectangle bounds(Rectangle rect){ if(breaking){ return rect.set(-100f, -100f, 0f, 0f); diff --git a/core/src/io/anuke/mindustry/entities/type/BaseEntity.java b/core/src/io/anuke/mindustry/entities/type/BaseEntity.java index ee938afd39..97de965cfe 100755 --- a/core/src/io/anuke/mindustry/entities/type/BaseEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseEntity.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.entities.type; +import io.anuke.mindustry.*; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.traits.Entity; @@ -14,6 +15,14 @@ public abstract class BaseEntity implements Entity{ id = lastid++; } + public int tileX(){ + return Vars.world.toTile(x); + } + + public int tileY(){ + return Vars.world.toTile(y); + } + @Override public int getID(){ return id; diff --git a/core/src/io/anuke/mindustry/entities/type/TileEntity.java b/core/src/io/anuke/mindustry/entities/type/TileEntity.java index 177b2b6c34..5fa2ea9aae 100644 --- a/core/src/io/anuke/mindustry/entities/type/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/TileEntity.java @@ -236,11 +236,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ return 0; } - /** @return whether the config is a position that should be translated.*/ - public boolean posConfig(){ - return false; - } - @Override public void removed(){ if(sound != null){ diff --git a/core/src/io/anuke/mindustry/game/Schematics.java b/core/src/io/anuke/mindustry/game/Schematics.java index 831fead321..a73045e966 100644 --- a/core/src/io/anuke/mindustry/game/Schematics.java +++ b/core/src/io/anuke/mindustry/game/Schematics.java @@ -145,7 +145,7 @@ public class Schematics implements Loadable{ /** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */ public Array toRequests(Schematic schem, int x, int y){ - return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).configure(t.config)); + return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y).configure(t.config)); } /** Adds a schematic to the list, also copying it into the files.*/ @@ -209,7 +209,7 @@ public class Schematics implements Loadable{ if(tile != null && tile.entity != null){ int config = tile.entity.config(); - if(tile.entity.posConfig()){ + if(tile.block().posConfig){ config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY); } @@ -240,7 +240,11 @@ public class Schematics implements Loadable{ //region IO methods public static Schematic read(FileHandle file) throws IOException{ - return read(new DataInputStream(file.read(1024))); + Schematic s = read(new DataInputStream(file.read(1024))); + if(!s.tags.containsKey("name")){ + s.tags.put("name", file.nameWithoutExtension()); + } + return s; } public static Schematic read(InputStream input) throws IOException{ @@ -271,8 +275,6 @@ public class Schematics implements Loadable{ blocks.put(i, block == null ? Blocks.air : block); } - Log.info(blocks); - int total = stream.readInt(); Array tiles = new Array<>(total); for(int i = 0; i < total; i++){ diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 141b4ca586..47bcda5892 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -3,7 +3,6 @@ package io.anuke.mindustry.input; import io.anuke.arc.*; import io.anuke.arc.Graphics.*; import io.anuke.arc.Graphics.Cursor.*; -import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; import io.anuke.arc.math.*; @@ -14,7 +13,6 @@ import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.game.Schematics.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.ui.*; @@ -30,7 +28,7 @@ public class DesktopInput extends InputHandler{ /** Position where the player started dragging a line. */ private int selectX, selectY, schemX, schemY; /** Last known line positions.*/ - private int lastLineX, lastLineY; + private int lastLineX, lastLineY, schematicX, schematicY; /** Whether selecting mode is active. */ private PlaceMode mode; /** Animation scale for line. */ @@ -40,8 +38,6 @@ public class DesktopInput extends InputHandler{ /** Whether player is currently deleting removal requests. */ private boolean deleting = false; - private Schematic __REMOVE__; - @Override public void buildUI(Group group){ group.fill(t -> { @@ -89,6 +85,12 @@ public class DesktopInput extends InputHandler{ } } + //draw schematic requests + for(BuildRequest request : selectRequests){ + request.animScale = 1f; + drawRequest(request); + } + if(sreq != null){ boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq); if(sreq.block.rotate){ @@ -108,13 +110,6 @@ public class DesktopInput extends InputHandler{ } Draw.reset(); - - if(__REMOVE__ != null){ - Texture tex = schematics.getPreview(__REMOVE__, PreviewRes.low); - Draw.blend(Blending.disabled); - Draw.rect(Draw.wrap(tex), Core.camera.position.x, Core.camera.position.y, tex.getWidth() / 4f, tex.getHeight() / 4f); - Draw.blend(); - } } @Override @@ -154,6 +149,10 @@ public class DesktopInput extends InputHandler{ mode = none; } + if(mode != none){ + selectRequests.clear(); + } + if(player.isShooting && !canShoot()){ player.isShooting = false; } @@ -182,7 +181,7 @@ public class DesktopInput extends InputHandler{ cursorType = cursor.block().getCursor(cursor); - if(isPlacing()){ + if(isPlacing() || !selectRequests.isEmpty()){ cursorType = SystemCursor.hand; } @@ -210,6 +209,16 @@ public class DesktopInput extends InputHandler{ cursorType = SystemCursor.arrow; } + @Override + public void useSchematic(Schematic schem){ + block = null; + schematicX = tileX(getMouseX()); + schematicY = tileY(getMouseY()); + + selectRequests.addAll(schematics.toRequests(schem, schematicX, schematicY)); + mode = none; + } + @Override public boolean isBreaking(){ return mode == breaking; @@ -221,6 +230,18 @@ public class DesktopInput extends InputHandler{ int cursorY = tileY(Core.input.mouseY()); int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y); + if(!selectRequests.isEmpty()){ + int shiftX = rawCursorX - schematicX, shiftY = rawCursorY - schematicY; + + selectRequests.each(s -> { + s.x += shiftX; + s.y += shiftY; + }); + + schematicX += shiftX; + schematicY += shiftY; + } + if(Core.input.keyTap(Binding.deselect)){ player.setMineTile(null); } @@ -236,12 +257,12 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyRelease(Binding.schematic)){ Schematic schem = schematics.create(schemX, schemY, rawCursorX, rawCursorY); - __REMOVE__ = schem; schematics.add(schem); + useSchematic(schem); } //TODO remove - if(Core.input.keyTap(KeyCode.T)){ + if(Core.input.keyTap(KeyCode.V)){ ui.schematics.show(); } @@ -270,7 +291,10 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ BuildRequest req = getRequest(cursorX, cursorY); - if(isPlacing()){ + if(!selectRequests.isEmpty()){ + flushRequests(selectRequests); + //selectRequests.clear(); + }else if(isPlacing()){ selectX = cursorX; selectY = cursorY; lastLineX = cursorX; @@ -366,6 +390,7 @@ public class DesktopInput extends InputHandler{ mode = none; block = null; sreq = null; + selectRequests.clear(); } } } diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 4e7650e8ca..6a19c12d70 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -19,6 +19,7 @@ import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Teams.*; import io.anuke.mindustry.gen.*; @@ -219,6 +220,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ drawSelected(x, y, block, Pal.remove); } + public void useSchematic(Schematic schem){ + selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y))); + } + /** Returns the selection request that overlaps this position, or null. */ protected BuildRequest getRequest(int x, int y){ return getRequest(x, y, 1, null); @@ -310,7 +315,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ protected void flushSelectRequests(Array requests){ for(BuildRequest req : requests){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ - selectRequests.add(req); + selectRequests.add(req.copy()); } } } @@ -318,7 +323,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ protected void flushRequests(Array requests){ for(BuildRequest req : requests){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ - player.addBuildRequest(req); + BuildRequest copy = req.copy(); + if(copy.hasConfig && copy.block.posConfig){ + copy.config = Pos.get(Pos.x(copy.config) + copy.x - copy.originalX, Pos.y(copy.config) + copy.y - copy.originalY); + } + player.addBuildRequest(copy); } } } diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 89c683c89b..02787ed86a 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -243,7 +243,6 @@ public class MobileInput extends InputHandler implements GestureListener{ if(tile == null) continue; request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f); - request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f); if(request.breaking){ drawSelected(request.x, request.y, tile.block(), Pal.remove); @@ -263,10 +262,8 @@ public class MobileInput extends InputHandler implements GestureListener{ if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation)) || (request.breaking && validBreak(tile.x, tile.y))){ request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f); - request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f); }else{ request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f); - request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f); } Tmp.c1.set(Draw.getMixColor()); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java index 3beb7a2974..338176e1c5 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java @@ -8,7 +8,7 @@ import io.anuke.mindustry.game.Schematics.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.ui.*; -import static io.anuke.mindustry.Vars.schematics; +import static io.anuke.mindustry.Vars.*; public class SchematicsDialog extends FloatingDialog{ @@ -40,7 +40,8 @@ public class SchematicsDialog extends FloatingDialog{ } }.setScaling(Scaling.fit).setName("border")); }, () -> { - + control.input.useSchematic(s); + hide(); }).size(200f, 230f).pad(2).style(Styles.clearPartiali).get(); BorderImage image = sel.find("border"); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index dd056d84ac..7e5e915171 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -87,6 +87,8 @@ public class Block extends BlockStorage{ public boolean configurable; /** Whether this block consumes touchDown events when tapped. */ public boolean consumesTap; + /** Whether the config is positional and needs to be shifted. */ + public boolean posConfig; /** * The color of this block when displayed on the minimap or map preview. * Do not set manually! This is overriden when loading for most blocks. diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 37c3ccc6fa..1f76ed527a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -56,7 +56,7 @@ public class BuildBlock extends Block{ } @Remote(called = Loc.server) - public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team){ + public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){ if(tile == null) return; float healthf = tile.entity == null ? 1f : tile.entity.healthf(); world.setBlock(tile, block, team, rotation); @@ -70,7 +70,9 @@ public class BuildBlock extends Block{ if(!headless && builderID == player.id){ //this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish() //event first before they can recieve the placed() event modification results - Core.app.post(() -> tile.block().playerPlaced(tile)); + if(!skipConfig){ + Core.app.post(() -> tile.block().playerPlaced(tile)); + } } Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false))); Sounds.place.at(tile, Mathf.random(0.7f, 1.4f)); @@ -185,7 +187,7 @@ public class BuildBlock extends Block{ private float[] accumulator; private float[] totalAccumulator; - public boolean construct(Unit builder, @Nullable TileEntity core, float amount){ + public boolean construct(Unit builder, @Nullable TileEntity core, float amount, boolean configured){ if(cblock == null){ kill(); return false; @@ -208,7 +210,7 @@ public class BuildBlock extends Block{ } if(progress >= 1f || state.rules.infiniteResources){ - Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam()); + Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam(), configured); return true; } return false; diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java index 4988a524bb..3c11b5903f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java @@ -37,6 +37,7 @@ public class ItemBridge extends Block{ layer = Layer.power; expanded = true; itemCapacity = 10; + posConfig = true; configurable = true; hasItems = true; unloadable = false; @@ -385,11 +386,6 @@ public class ItemBridge extends Block{ return link; } - @Override - public boolean posConfig(){ - return true; - } - @Override public void write(DataOutput stream) throws IOException{ super.write(stream); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java index a9d8c008c6..04a8af5b9b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java @@ -36,6 +36,7 @@ public class MassDriver extends Block{ super(name); update = true; solid = true; + posConfig = true; configurable = true; hasItems = true; layer = Layer.turret; @@ -319,11 +320,6 @@ public class MassDriver extends Block{ return link; } - @Override - public boolean posConfig(){ - return true; - } - @Override public void write(DataOutput stream) throws IOException{ super.write(stream); diff --git a/gradle.properties b/gradle.properties index ea7e5bc1fe..4626fe4261 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=7f4239e462c07fb3d76a18262cff91dd877df5cc +archash=795ded7ccae9aeb15ee480e3b9f6d6af57148ea0