diff --git a/.gitignore b/.gitignore index 402c10f82a..b86b284e67 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ /core/assets/gifexport/ /core/assets/version.properties /core/assets/locales.json +/ios/src/io/anuke/mindustry/gen/ *.gif version.properties diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 64fc9d218b..b0e4475812 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -21,7 +21,7 @@ android:name="io.anuke.mindustry.AndroidLauncher" android:label="@string/app_name" android:screenOrientation="user" - android:configChanges="keyboard|keyboardHidden|orientation|screenSize"> + android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"> diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index ce1f7d2394..a5fc2e56c9 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -79,7 +79,9 @@ text.server.mismatch=Packet error: possible client/server version mismatch.\nMak text.server.closing=[accent]Closing server... text.server.kicked.kick=You have been kicked from the server! text.server.kicked.fastShoot=You are shooting too quickly. -text.server.kicked.invalidPassword=Invalid password! +text.server.kicked.serverClose=Server closed. +text.server.kicked.sectorComplete=Sector completed. +text.server.kicked.sectorComplete.text=Your mission is complete.\nThe server will now continue at the next sector. text.server.kicked.clientOutdated=Outdated client! Update your game! text.server.kicked.serverOutdated=Outdated server! Ask the host to update! text.server.kicked.banned=You are banned on this server. diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index c3ed9bd45d..999f9452ee 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -149,7 +149,13 @@ public class NetClient extends Module{ public static void onKick(KickReason reason){ netClient.disconnectQuietly(); state.set(State.menu); - if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name()); + if(!reason.quiet){ + if(reason.extraText() != null){ + ui.showText(reason.toString(), reason.extraText()); + }else{ + ui.showText("$text.disconnect", reason.toString()); + } + } ui.loadfrag.hide(); } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index e318a013fc..34cd4111c8 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -363,6 +363,12 @@ public class NetServer extends Module{ admins.clearTraces(); } + public void kickAll(KickReason reason){ + for(NetConnection con : Net.getConnections()){ + kick(con.id, reason); + } + } + public void kick(int connection, KickReason reason){ NetConnection con = Net.getConnection(connection); if(con == null){ diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 13c7870f0b..153d570b26 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -283,6 +283,13 @@ public class UI extends SceneModule{ }}.show(); } + public void showText(String title, String text){ + new Dialog(title, "dialog"){{ + content().margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center); + buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); + }}.show(); + } + public void showConfirm(String title, String text, Runnable confirmed){ FloatingDialog dialog = new FloatingDialog(title); dialog.content().add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center); diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 3a38764218..a2201c2365 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -10,6 +10,8 @@ import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.core.Platform; +import io.anuke.mindustry.gen.Call; +import io.anuke.mindustry.net.Packets.KickReason; import io.anuke.mindustry.net.Packets.StreamBegin; import io.anuke.mindustry.net.Packets.StreamChunk; import io.anuke.mindustry.net.Streamable.StreamBuilder; @@ -88,7 +90,7 @@ public class Net{ } /** - * Host a server at an address + * Host a server at an address. */ public static void host(int port) throws IOException{ serverProvider.host(port); @@ -102,6 +104,10 @@ public class Net{ * Closes the server. */ public static void closeServer(){ + for(NetConnection con : getConnections()){ + Call.onKick(con.id, KickReason.serverClose); + } + serverProvider.close(); server = false; active = false; diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 1e77dce5d8..ab0adf26e1 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -10,6 +10,7 @@ import io.anuke.mindustry.game.Version; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.io.IOUtils; +import io.anuke.ucore.util.Bundles; import io.anuke.ucore.util.Mathf; import java.nio.ByteBuffer; @@ -22,16 +23,27 @@ import static io.anuke.mindustry.Vars.world; public class Packets{ public enum KickReason{ - kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true), recentKick, nameInUse, idInUse, fastShoot, nameEmpty, customClient, sectorComplete(true); + kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick, + nameInUse, idInUse, nameEmpty, customClient, sectorComplete, serverClose; + public final boolean quiet; KickReason(){ - quiet = false; + this(false); } KickReason(boolean quiet){ this.quiet = quiet; } + + @Override + public String toString(){ + return Bundles.get("text.server.kicked." + name()); + } + + public String extraText(){ + return Bundles.getOrNull("text.server.kicked." + name() + ".text"); + } } public enum AdminAction{ diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java index b4dd5b5956..fdac8ab508 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java @@ -8,6 +8,7 @@ import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.type.Item; +import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.consumers.ConsumeLiquid; @@ -233,7 +234,8 @@ public class Drill extends Block{ } protected boolean isValid(Tile tile){ - return tile.floor().drops != null && tile.floor().drops.item.hardness <= tier; + ItemStack drops = tile.floor().drops; + return drops != null && drops.item.hardness <= tier; } public static class DrillEntity extends TileEntity{ diff --git a/core/src/io/anuke/mindustry/world/blocks/units/UnitPad.java b/core/src/io/anuke/mindustry/world/blocks/units/UnitPad.java index cb8f9a4f2e..40c12c42e3 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/UnitPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/UnitPad.java @@ -38,7 +38,7 @@ import java.io.DataOutputStream; import java.io.IOException; public class UnitPad extends Block{ - protected float gracePeriodMultiplier = 22f; + protected float gracePeriodMultiplier = 23f; protected float speedupTime = 60f * 60f * 20; protected float maxSpeedup = 7f; diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index dad2c6a9c0..699fc09f91 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -53,23 +53,25 @@ public class ServerControl extends Module{ Effects.setEffectProvider((a, b, c, d, e, f) -> {}); Sounds.setHeadless(true); - String[] commands = {}; - - if(args.length > 0){ - commands = String.join(" ", args).split(","); - Log.info("&lmFound {0} command-line arguments to parse. {1}", commands.length); - } - registerCommands(); - for(String s : commands){ - Response response = handler.handleMessage(s); - if(response.type != ResponseType.valid){ - Log.err("Invalid command argument sent: '{0}': {1}", s, response.type.name()); - Log.err("Argument usage: &lc , "); - System.exit(1); + Gdx.app.postRunnable(() -> { + String[] commands = {}; + + if(args.length > 0){ + commands = String.join(" ", args).split(","); + Log.info("&lmFound {0} command-line arguments to parse. {1}", commands.length); } - } + + for(String s : commands){ + Response response = handler.handleMessage(s); + if(response.type != ResponseType.valid){ + Log.err("Invalid command argument sent: '{0}': {1}", s, response.type.name()); + Log.err("Argument usage: &lc , "); + System.exit(1); + } + } + }); Thread thread = new Thread(this::readCommands, "Server Controls"); thread.setDaemon(true); @@ -82,33 +84,28 @@ public class ServerControl extends Module{ Events.on(GameOverEvent.class, () -> { info("Game over!"); - - for(NetConnection connection : Net.getConnections()){ - netServer.kick(connection.id, KickReason.gameover); - } + netServer.kickAll(KickReason.gameover); if(mode != ShuffleMode.off){ - if(world.maps().all().size > 0){ - Array maps = mode == ShuffleMode.both ? world.maps().all() : - mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps(); + if(world.getSector() == null){ + if(world.maps().all().size > 0){ + Array maps = mode == ShuffleMode.both ? world.maps().all() : + mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps(); - Map previous = world.getMap(); - Map map = previous; - while(map == previous) map = maps.random(); - - if(map != null){ + Map previous = world.getMap(); + Map map = previous; + if(maps.size > 1){ + while(map == previous) map = maps.random(); + } info("Selected next map to be {0}.", map.name); - state.set(State.playing); logic.reset(); world.loadMap(map); - }else{ - info("Selected a procedural map."); - playSectorMap(); + state.set(State.playing); } }else{ - info("Selected a procedural map."); + info("Re-trying sector map."); playSectorMap(); } }else{ @@ -290,7 +287,7 @@ public class ServerControl extends Module{ } }); - handler.register("debugmode", "", "Disables or enables debug ode", arg -> { + handler.register("debug", "", "Disables or enables debug ode", arg -> { boolean value = arg[0].equalsIgnoreCase("on"); debug = value; info("Debug mode is now {0}.", value ? "on" : "off"); @@ -632,7 +629,7 @@ public class ServerControl extends Module{ info("Core destroyed."); }); - handler.register("debug", "Print debug info", arg -> { + handler.register("debuginfo", "Print debug info", arg -> { info(DebugFragment.debugInfo()); }); @@ -829,7 +826,7 @@ public class ServerControl extends Module{ } private void playSectorMap(){ - world.loadSector(world.sectors().get(0, 0)); + world.loadSector(world.sectors().get(Settings.getInt("sectorid"), 0)); logic.play(); } @@ -842,6 +839,27 @@ public class ServerControl extends Module{ } } + @Override + public void update(){ + + if(state.is(State.playing) && world.getSector() != null){ + //all assigned missions are complete + if(world.getSector().completedMissions >= world.getSector().missions.size){ + world.sectors().completeSector(world.getSector().x, world.getSector().y); + world.sectors().save(); + Settings.putInt("sectorid", world.getSector().x + 1); + Settings.save(); + + netServer.kickAll(KickReason.sectorComplete); + logic.reset(); + playSectorMap(); + }else if(world.getSector().currentMission().isComplete()){ + //increment completed missions, check next index next frame + world.getSector().completedMissions ++; + } + } + } + enum ShuffleMode{ normal, custom, both, off }