diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 5525c4603c..2d2729a960 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -22,6 +22,7 @@ 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.invalidPassword=Invalid password! +text.server.kicked.outdated=Outdated client! Update your game! text.server.connected={0} has joined. text.server.disconnected={0} has disconnected. text.nohost=Can't host server on a custom map! diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index b0260de10f..20fa81eba7 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -477,7 +477,7 @@ public class Control extends Module{ addItem(Item.stone, 40); if(debug){ - Arrays.fill(items, 999900); + Arrays.fill(items, 99999); } } @@ -611,7 +611,7 @@ public class Control extends Module{ } if(Inputs.keyTap(Keys.G)){ - world.pathfinder().benchmark(); + addItem(Item.stone, 1000); } if(Inputs.keyDown(Keys.I)){ @@ -653,8 +653,12 @@ public class Control extends Module{ ui.paused.hide(); GameState.set(State.playing); }else if (!ui.restart.isShown()){ - ui.paused.show(); - GameState.set(State.paused); + if(ui.chatfrag.chatOpen()) { + ui.chatfrag.hide(); + }else{ + ui.paused.show(); + GameState.set(State.paused); + } } } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index f587ea80ff..80d088db1a 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -46,6 +46,11 @@ public class NetServer extends Module{ Net.handleServer(ConnectPacket.class, (id, packet) -> { + if(packet.version != Net.version){ + Net.kickConnection(id, KickReason.outdated); + return; + } + UCore.log("Sending world data to client (ID=" + id + ")"); Player player = new Player(); @@ -83,7 +88,7 @@ public class NetServer extends Module{ Player player = connections.get(packet.id); if (player == null) { - sendMessage("[accent]" + Bundles.format("text.server.disconnected", "")); + Gdx.app.error("Mindustry", "Unknown client has disconnected (ID=" + id + ")"); return; } diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 9c67d82750..4dbba91cfa 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -8,6 +8,7 @@ import com.badlogic.gdx.utils.async.AsyncExecutor; import io.anuke.mindustry.Mindustry; import io.anuke.mindustry.net.Packets.Connect; import io.anuke.mindustry.net.Packets.Disconnect; +import io.anuke.mindustry.net.Packets.KickReason; import io.anuke.mindustry.net.Streamable.StreamBegin; import io.anuke.mindustry.net.Streamable.StreamBuilder; import io.anuke.mindustry.net.Streamable.StreamChunk; @@ -19,6 +20,8 @@ import io.anuke.ucore.function.Consumer; import java.io.IOException; public class Net{ + public static final int version = 9; + private static boolean server; private static boolean active; private static boolean clientLoaded; @@ -79,8 +82,8 @@ public class Net{ } /**Kick a specified connection from the server.*/ - public static void kickConnection(int id){ - serverProvider.kick(id); + public static void kickConnection(int id, KickReason reason){ + serverProvider.kick(id, reason); } /**Returns a list of all connections IDs.*/ @@ -249,7 +252,7 @@ public class Net{ /**Return all connected users.*/ Array getConnections(); /**Kick a certain connection.*/ - void kick(int connection); + void kick(int connection, KickReason reason); /**Returns the ping for a certain connection.*/ int getPingFor(NetConnection connection); /**Register classes to be sent.*/ diff --git a/core/src/io/anuke/mindustry/net/NetworkIO.java b/core/src/io/anuke/mindustry/net/NetworkIO.java index 642ded251e..b22e8f2379 100644 --- a/core/src/io/anuke/mindustry/net/NetworkIO.java +++ b/core/src/io/anuke/mindustry/net/NetworkIO.java @@ -19,14 +19,10 @@ import io.anuke.ucore.entities.Entities; import java.io.*; public class NetworkIO { - private static final int fileVersionID = 16; public static void write(int playerID, ByteArray upgrades, OutputStream os){ try(DataOutputStream stream = new DataOutputStream(os)){ - - //--META-- - stream.writeInt(fileVersionID); //version id stream.writeFloat(Timers.time()); //timer time stream.writeLong(TimeUtils.millis()); //timestamp @@ -151,17 +147,11 @@ public class NetworkIO { public static void load(InputStream is){ try(DataInputStream stream = new DataInputStream(is)){ - - int version = stream.readInt(); float timerTime = stream.readFloat(); long timestamp = stream.readLong(); Timers.resetTime(timerTime + (TimeUtils.timeSinceMillis(timestamp) / 1000f) * 60f); - if(version != fileVersionID){ - throw new RuntimeException("Netcode version mismatch!"); - } - //general state byte mode = stream.readByte(); byte mapid = stream.readByte(); diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 9395474f21..091a5b9659 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -44,11 +44,13 @@ public class Packets { } public static class ConnectPacket implements Packet{ + public int version; public String name; public boolean android; @Override public void write(ByteBuffer buffer) { + buffer.putInt(Net.version); buffer.put((byte)name.getBytes().length); buffer.put(name.getBytes()); buffer.put(android ? (byte)1 : 0); @@ -56,6 +58,7 @@ public class Packets { @Override public void read(ByteBuffer buffer) { + version = buffer.getInt(); byte length = buffer.get(); byte[] bytes = new byte[length]; buffer.get(bytes); @@ -394,7 +397,7 @@ public class Packets { } public enum KickReason{ - kick, invalidPassword + kick, invalidPassword, outdated } public static class UpgradePacket implements Packet{ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java index 7c3f7acca8..ee50f559fb 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java @@ -17,7 +17,7 @@ import io.anuke.ucore.util.Strings; public class JoinDialog extends FloatingDialog { Array servers = new Array<>(); - Dialog join; + Dialog add; Server renaming; Table local = new Table(); Table remote = new Table(); @@ -31,24 +31,18 @@ public class JoinDialog extends FloatingDialog { addCloseButton(); - join = new FloatingDialog("$text.joingame.title"); - join.content().add("$text.joingame.ip").padRight(5f).left(); - Mindustry.platforms.addDialog(join.content().addField(Settings.getString("ip"),text ->{ + add = new FloatingDialog("$text.joingame.title"); + add.content().add("$text.joingame.ip").padRight(5f).left(); + + Mindustry.platforms.addDialog(add.content().addField(Settings.getString("ip"), text ->{ Settings.putString("ip", text); Settings.save(); }).size(340f, 54f).get(), 100); - join.content().row(); - /* - join.content().add("$text.server.port").left(); - Mindustry.platforms.addDialog(join.content() - .addField(Settings.getString("port"), new DigitsOnlyFilter(), text ->{ - Settings.putString("port", text); - Settings.save(); - }).size(240f, 54f).get());*/ - join.buttons().defaults().size(140f, 60f).pad(4f); - join.buttons().addButton("$text.cancel", join::hide); - join.buttons().addButton("$text.ok", () -> { + add.content().row(); + add.buttons().defaults().size(140f, 60f).pad(4f); + add.buttons().addButton("$text.cancel", add::hide); + add.buttons().addButton("$text.ok", () -> { if(renaming == null) { Server server = new Server(Settings.getString("ip"), Strings.parseInt(Settings.getString("port"))); servers.add(server); @@ -62,11 +56,11 @@ public class JoinDialog extends FloatingDialog { setupRemote(); refreshRemote(); } - join.hide(); + add.hide(); }).disabled(b -> Settings.getString("ip").isEmpty() || Net.active()); - join.shown(() -> { - join.getTitleLabel().setText(renaming != null ? "$text.server.edit" : "$text.server.add"); + add.shown(() -> { + add.getTitleLabel().setText(renaming != null ? "$text.server.edit" : "$text.server.add"); }); setup(); @@ -101,7 +95,7 @@ public class JoinDialog extends FloatingDialog { inner.addImageButton("icon-pencil", "empty", 16*2, () -> { renaming = server; - join.show(); + add.show(); }).margin(3f).padTop(6f).top().right(); inner.addImageButton("icon-trash-16", "empty", 16*2, () -> { @@ -182,7 +176,7 @@ public class JoinDialog extends FloatingDialog { content().row(); content().addCenteredImageTextButton("$text.server.add", "icon-add", "clear", 14*3, () -> { renaming = null; - join.show(); + add.show(); }).width(w).height(80f); } @@ -219,7 +213,7 @@ public class JoinDialog extends FloatingDialog { Vars.netClient.beginConnecting(); Net.connect(ip, port); hide(); - join.hide(); + add.hide(); }catch (Exception e) { Throwable t = e; while(t.getCause() != null){ diff --git a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java index 8fb1e67bdc..001a9ed342 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java @@ -49,6 +49,10 @@ public class ChatFragment extends Table implements Fragment{ //TODO put it in input? update(() -> { + if(!Net.active()){ + hide(); + } + if(Net.active() && Inputs.keyTap("chat")){ toggle(); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java index 4d72e44cd1..c7e926256c 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java @@ -5,6 +5,7 @@ import io.anuke.mindustry.core.GameState; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.net.Packets.KickReason; import io.anuke.mindustry.ui.BorderImage; import io.anuke.ucore.core.Draw; import io.anuke.ucore.core.Inputs; @@ -77,7 +78,7 @@ public class PlayerListFragment implements Fragment{ if(Net.server() && !player.isLocal){ button.add().growY(); button.addImageButton("icon-cancel", 14*3, () -> - Net.kickConnection(player.clientid) + Net.kickConnection(player.clientid, KickReason.kick) ).pad(-5).padBottom(-10).size(h+10, h+14); } diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index 7e3ffcf8b9..8a84cb0a09 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -117,11 +117,11 @@ public class KryoServer implements ServerProvider { } @Override - public void kick(int connection) { + public void kick(int connection, KickReason reason) { KryoConnection con = getByID(connection); KickPacket p = new KickPacket(); - p.reason = KickReason.kick; + p.reason = reason; con.send(p, SendMode.tcp); Timers.runTask(1f, con::close); @@ -345,10 +345,16 @@ public class KryoServer implements ServerProvider { connections.remove(this); } }else if (connection != null) { - if (mode == SendMode.tcp) { - connection.sendTCP(object); - } else { - connection.sendUDP(object); + try { + if (mode == SendMode.tcp) { + connection.sendTCP(object); + } else { + connection.sendUDP(object); + } + }catch (Exception e){ + e.printStackTrace(); + UCore.log("Disconnecting invalid client!"); + connection.close(); } } }