diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 6a9dca0998..78ee87ed73 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -37,9 +37,7 @@ import static io.anuke.mindustry.Vars.*; * This class is not created in the headless server. */ public class Control extends Module{ - /** - * Minimum period of time between the same sound being played. - */ + /** Minimum period of time between the same sound being played.*/ private static final long minSoundPeriod = 100; private boolean hiscore = false; diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 059d58f5c3..5df0526caa 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -34,6 +34,7 @@ import java.util.Locale; import static io.anuke.mindustry.Vars.control; import static io.anuke.mindustry.Vars.players; +import static io.anuke.mindustry.Vars.threads; import static io.anuke.ucore.scene.actions.Actions.*; public class UI extends SceneModule{ @@ -231,6 +232,16 @@ public class UI extends SceneModule{ }); } + public void loadLogic(Callable call){ + loadfrag.show(); + Timers.runTask(7f, () -> { + threads.run(() -> { + call.run(); + threads.runGraphics(loadfrag::hide); + }); + }); + } + public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer confirmed){ new Dialog(title, "dialog"){{ content().margin(30).add(text).padRight(6f); diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 4094aa118f..4fc313a31c 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -33,20 +33,17 @@ import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.scene.Group; import io.anuke.ucore.scene.builders.imagebutton; import io.anuke.ucore.scene.builders.table; +import io.anuke.ucore.scene.event.Touchable; import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.input.PlaceMode.*; public class MobileInput extends InputHandler implements GestureListener{ - /** - * Maximum speed the player can pan. - */ + /** Maximum speed the player can pan. */ private static final float maxPanSpeed = 1.3f; private static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); - /** - * Distance to edge of screen to start panning. - */ + /** Distance to edge of screen to start panning. */ private final float edgePan = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(60f); //gesture data @@ -54,53 +51,31 @@ public class MobileInput extends InputHandler implements GestureListener{ private Vector2 vector = new Vector2(); private float initzoom = -1; private boolean zoomed = false; - /** - * Set of completed guides. - */ + /** Set of completed guides. */ private ObjectSet guides = new ObjectSet<>(); - /** - * Position where the player started dragging a line. - */ + /** Position where the player started dragging a line. */ private int lineStartX, lineStartY; - /** - * Animation scale for line. - */ + /** Animation scale for line. */ private float lineScale; - /** - * Animation data for crosshair. - */ + /** Animation data for crosshair. */ private float crosshairScale; private TargetTrait lastTarget; - /** - * List of currently selected tiles to place. - */ + /** List of currently selected tiles to place. */ private Array selection = new Array<>(); - /** - * Place requests to be removed. - */ + /** Place requests to be removed. */ private Array removals = new Array<>(); - /** - * Whether or not the player is currently shifting all placed tiles. - */ + /** Whether or not the player is currently shifting all placed tiles. */ private boolean selecting; - /** - * Whether the player is currently in line-place mode. - */ + /** Whether the player is currently in line-place mode. */ private boolean lineMode; - /** - * Current place mode. - */ + /** Current place mode. */ private PlaceMode mode = none; - /** - * Whether no recipe was available when switching to break mode. - */ + /** Whether no recipe was available when switching to break mode. */ private Recipe lastRecipe; - /** - * Last placed request. Used for drawing block overlay. - */ + /** Last placed request. Used for drawing block overlay. */ private PlaceRequest lastPlaced; public MobileInput(Player player){ @@ -110,9 +85,7 @@ public class MobileInput extends InputHandler implements GestureListener{ //region utility methods - /** - * Check and assign targets for a specific position. - */ + /** Check and assign targets for a specific position. */ void checkTargets(float x, float y){ synchronized(Entities.entityLock){ Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true); @@ -130,16 +103,12 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - /** - * Returns whether this tile is in the list of requests, or at least colliding with one. - */ + /** Returns whether this tile is in the list of requests, or at least colliding with one. */ boolean hasRequest(Tile tile){ return getRequest(tile) != null; } - /** - * Returns whether this block overlaps any selection requests. - */ + /** Returns whether this block overlaps any selection requests. */ boolean checkOverlapPlacement(int x, int y, Block block){ r2.setSize(block.size * tilesize); r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset()); @@ -159,9 +128,7 @@ public class MobileInput extends InputHandler implements GestureListener{ return false; } - /** - * Returns the selection request that overlaps this tile, or null. - */ + /** Returns the selection request that overlaps this tile, or null. */ PlaceRequest getRequest(Tile tile){ r2.setSize(tilesize); r2.setCenter(tile.worldx(), tile.worldy()); @@ -250,6 +217,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a cancel button new imagebutton("icon-cancel", 16 * 2f, () -> { mode = none; @@ -297,6 +266,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a break button. new imagebutton("icon-break", "toggle", 16 * 2f, () -> { mode = mode == breaking ? recipe == null ? none : placing : breaking; @@ -311,6 +282,8 @@ public class MobileInput extends InputHandler implements GestureListener{ margin(5); defaults().size(60f); + touchable(Touchable.enabled); + //Add a 'cancel building' button. new imagebutton("icon-cancel", 16 * 2f, player::clearBuilding); @@ -806,4 +779,4 @@ public class MobileInput extends InputHandler implements GestureListener{ return world.tileWorld(x - (recipe == null ? 0 : recipe.result.offset()), y - (recipe == null ? 0 : recipe.result.offset())); } } -} +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index dfd21820c5..bfe652c384 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -134,6 +134,8 @@ public class SaveIO{ FileHandle backup = file.sibling(file.name() + "-backup." + file.extension()); if(backup.exists()){ load(new InflaterInputStream(backup.read())); + }else{ + throw new RuntimeException(e); } } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java index 7730850513..03fb0ffdee 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java @@ -166,21 +166,18 @@ public class LoadDialog extends FloatingDialog{ } public void runLoadSave(SaveSlot slot){ - ui.loadfrag.show(); + hide(); + ui.paused.hide(); - Timers.runTask(3f, () -> { - ui.loadfrag.hide(); - hide(); + ui.loadLogic(() -> { try{ slot.load(); state.set(State.playing); - ui.paused.hide(); }catch(Exception e){ Log.err(e); - ui.paused.hide(); state.set(State.menu); logic.reset(); - ui.showError("$text.save.corrupted"); + threads.runGraphics(() -> ui.showError("$text.save.corrupted")); } }); } diff --git a/core/src/io/anuke/mindustry/world/Edges.java b/core/src/io/anuke/mindustry/world/Edges.java index 6c0bbbdc94..8565b5a50d 100644 --- a/core/src/io/anuke/mindustry/world/Edges.java +++ b/core/src/io/anuke/mindustry/world/Edges.java @@ -52,6 +52,7 @@ public class Edges{ } public static Tile getFacingEdge(Tile tile, Tile other){ + if(!tile.block().isMultiblock()) return tile; int size = tile.block().size; return world.tile(tile.x + Mathf.clamp(other.x - tile.x, -(size - 1) / 2, (size / 2)), tile.y + Mathf.clamp(other.y - tile.y, -(size - 1) / 2, (size / 2))); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java index db4ecebd58..6fde022a52 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java @@ -1,7 +1,9 @@ package io.anuke.mindustry.world.blocks.distribution; import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Mathf; public class OverflowGate extends Splitter{ @@ -9,22 +11,35 @@ public class OverflowGate extends Splitter{ public OverflowGate(String name){ super(name); hasItems = true; + speed = 1f; } @Override - Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ - int dir = source.relativeTo(dest.x, dest.y); - if(dir == -1) return null; - Tile to = dest.getNearby(dir); + public void update(Tile tile){ + SplitterEntity entity = tile.entity(); + if(entity.lastItem != null){ + entity.time += 1f/speed * Timers.delta(); + Tile target = getTileTarget(tile, entity.lastItem, entity.lastInput, false); - if((!to.block().acceptItem(item, to, dest) || - (to.block().instantTransfer && source.block().instantTransfer))){ - Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); - Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); - boolean ac = !(a.block().instantTransfer && source.block().instantTransfer) && - a.block().acceptItem(item, a, dest); - boolean bc = !(b.block().instantTransfer && source.block().instantTransfer) && - b.block().acceptItem(item, b, dest); + if(target != null && (entity.time >= 1f)){ + getTileTarget(tile, entity.lastItem, entity.lastInput, true); + target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + entity.items.remove(entity.lastItem, 1); + entity.lastItem = null; + } + } + } + + Tile getTileTarget(Tile tile, Item item, int from, boolean flip){ + if(from == -1) return null; + Tile to = tile.getNearby((from + 2) % 4); + Tile edge = Edges.getFacingEdge(tile, to); + + if(!to.block().acceptItem(item, to, edge) || (to.block() instanceof OverflowGate)){ + Tile a = tile.getNearby(Mathf.mod(from - 1, 4)); + Tile b = tile.getNearby(Mathf.mod(from + 1, 4)); + boolean ac = a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate); + boolean bc = b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate); if(!ac && !bc){ return null; @@ -35,14 +50,12 @@ public class OverflowGate extends Splitter{ }else if(bc && !ac){ to = b; }else{ - if(dest.getDump() == 0){ + if(tile.getDump() == 0){ to = a; - if(flip) - dest.setDump((byte) 1); + if(flip) tile.setDump((byte) 1); }else{ to = b; - if(flip) - dest.setDump((byte) 0); + if(flip) tile.setDump((byte) 0); } } } diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java index f0d4d84022..462f28da1d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Splitter.java @@ -1,22 +1,24 @@ package io.anuke.mindustry.world.blocks.distribution; import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.meta.BlockGroup; +import io.anuke.ucore.core.Timers; public class Splitter extends Block{ - protected float speed = 30f; + protected float speed = 9f; public Splitter(String name){ super(name); solid = true; - instantTransfer = true; update = true; - hasItems = false; + hasItems = true; + itemCapacity = 1; group = BlockGroup.transportation; } @@ -28,29 +30,68 @@ public class Splitter extends Block{ } @Override - public boolean acceptItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, false); + public void update(Tile tile){ + SplitterEntity entity = tile.entity(); + if(entity.lastItem != null){ + entity.time += 1f/speed * Timers.delta(); + Tile target = getTileTarget(tile, entity.lastItem, entity.lastInput); - return to != null; + if(target != null && (entity.time >= 1f)){ + target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); + entity.items.remove(entity.lastItem, 1); + entity.lastItem = null; + } + } + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + SplitterEntity entity = tile.entity(); + + return entity.lastItem == null; } @Override public void handleItem(Item item, Tile tile, Tile source){ - Tile to = getTileTarget(item, tile, source, true); - to.block().handleItem(item, to, Edges.getFacingEdge(tile, to)); + SplitterEntity entity = tile.entity(); + entity.items.add(item, 1); + entity.lastItem = item; + entity.time = 0f; + entity.lastInput = tile.relativeTo(source.x, source.y); } - Tile getTileTarget(Item item, Tile tile, Tile source, boolean flip){ + Tile getTileTarget(Tile tile, Item item, int from){ Array proximity = tile.entity.proximity(); int counter = tile.getDump(); for(int i = 0; i < proximity.size; i++){ Tile other = proximity.get((i + counter) % proximity.size); - if(flip) tile.setDump((byte) ((tile.getDump() + 1) % proximity.size)); - if(other != source && !(source.block().instantTransfer && other.block().instantTransfer) && !(other.block() instanceof Splitter) && - other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){ + if(tile.relativeTo(other.x, other.y) == from) continue; + tile.setDump((byte) ((tile.getDump() + 1) % proximity.size)); + if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){ return other; } } return null; } + + @Override + public int removeStack(Tile tile, Item item, int amount){ + SplitterEntity entity = tile.entity(); + int result = super.removeStack(tile, item, amount); + if(result != 0 && item == entity.lastItem){ + entity.lastItem = null; + } + return result; + } + + @Override + public TileEntity getEntity(){ + return new SplitterEntity(); + } + + public class SplitterEntity extends TileEntity{ + Item lastItem; + int lastInput; + float time; + } }