From b0086082d03c5c6c5fa9bb8698b5503515cf38ad Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Mar 2018 18:59:11 -0500 Subject: [PATCH] Fixed server crashes, android client error, ping system rewrite --- .../io/anuke/mindustry/AndroidLauncher.java | 19 +++++ build.gradle | 2 +- core/assets/version.properties | 6 +- .../src/io/anuke/mindustry/net/NetworkIO.java | 44 ++++++++++ .../io/anuke/mindustry/net/ServerDebug.java | 17 ++-- .../mindustry/client/WebsocketClient.java | 16 +--- kryonet/src/io/anuke/kryonet/KryoClient.java | 5 +- .../src/io/anuke/kryonet/KryoRegistrator.java | 50 +---------- kryonet/src/io/anuke/kryonet/KryoServer.java | 85 ++++++++++--------- .../anuke/mindustry/server/ServerControl.java | 39 +++++---- 10 files changed, 153 insertions(+), 130 deletions(-) diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index ea6a1443a5..a3a9a3fd41 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -10,12 +10,14 @@ import android.provider.Settings.Secure; import android.telephony.TelephonyManager; import com.badlogic.gdx.backends.android.AndroidApplication; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; +import com.badlogic.gdx.utils.Base64Coder; import io.anuke.kryonet.DefaultThreadImpl; import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoServer; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.mindustry.io.Platform; import io.anuke.mindustry.net.Net; +import io.anuke.ucore.core.Settings; import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.layout.Unit; @@ -24,6 +26,7 @@ import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; +import java.util.Random; public class AndroidLauncher extends AndroidApplication{ boolean doubleScaleTablets = true; @@ -104,6 +107,22 @@ public class AndroidLauncher extends AndroidApplication{ try { String s = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID); + + if(s == null){ + Settings.defaults("uuid", ""); + + String uuid = Settings.getString("uuid"); + if(uuid.isEmpty()){ + byte[] result = new byte[8]; + new Random().nextBytes(result); + uuid = new String(Base64Coder.encode(result)); + Settings.putString("uuid", uuid); + Settings.save(); + return result; + } + return Base64Coder.decode(uuid); + } + int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { diff --git a/build.gradle b/build.gradle index a05ab165c3..70d7e461d8 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' aiVersion = '1.8.1' - uCoreVersion = '80af5ed' + uCoreVersion = '21f04f8' getVersionString = { String buildVersion = getBuildVersion() diff --git a/core/assets/version.properties b/core/assets/version.properties index 5366f4b8d1..d373c22de7 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,7 +1,7 @@ #Autogenerated file. Do not modify. -#Wed Mar 07 15:56:57 EST 2018 +#Thu Mar 08 18:52:47 EST 2018 version=release -androidBuildCode=349 +androidBuildCode=356 name=Mindustry code=3.4 -build=32 +build=33 diff --git a/core/src/io/anuke/mindustry/net/NetworkIO.java b/core/src/io/anuke/mindustry/net/NetworkIO.java index abfd204c0e..912881d26d 100644 --- a/core/src/io/anuke/mindustry/net/NetworkIO.java +++ b/core/src/io/anuke/mindustry/net/NetworkIO.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.utils.ByteArray; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.game.GameMode; +import io.anuke.mindustry.io.Version; import io.anuke.mindustry.resource.Upgrade; import io.anuke.mindustry.resource.Weapon; import io.anuke.mindustry.world.*; @@ -16,6 +17,7 @@ import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.Entities; import java.io.*; +import java.nio.ByteBuffer; import static io.anuke.mindustry.Vars.*; @@ -340,4 +342,46 @@ public class NetworkIO { throw new RuntimeException(e); } } + + public static ByteBuffer writeServerData(){ + int maxlen = 32; + + String host = (headless ? "Server" : player.name); + String map = world.getMap().name; + + host = host.substring(0, Math.min(host.length(), maxlen)); + map = map.substring(0, Math.min(map.length(), maxlen)); + + ByteBuffer buffer = ByteBuffer.allocate(128); + + buffer.put((byte)host.getBytes().length); + buffer.put(host.getBytes()); + + buffer.put((byte)map.getBytes().length); + buffer.put(map.getBytes()); + + buffer.putInt(playerGroup.size()); + buffer.putInt(state.wave); + buffer.putInt(Version.build); + return buffer; + } + + public static Host readServerData(String hostAddress, ByteBuffer buffer){ + byte hlength = buffer.get(); + byte[] hb = new byte[hlength]; + buffer.get(hb); + + byte mlength = buffer.get(); + byte[] mb = new byte[mlength]; + buffer.get(mb); + + String host = new String(hb); + String map = new String(mb); + + int players = buffer.getInt(); + int wave = buffer.getInt(); + int version = buffer.getInt(); + + return new Host(host, hostAddress, map, wave, players, version); + } } diff --git a/core/src/io/anuke/mindustry/net/ServerDebug.java b/core/src/io/anuke/mindustry/net/ServerDebug.java index fc9709a0b9..a34b05e7c1 100644 --- a/core/src/io/anuke/mindustry/net/ServerDebug.java +++ b/core/src/io/anuke/mindustry/net/ServerDebug.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.net.Packets.Disconnect; +import io.anuke.ucore.util.Log; import static io.anuke.mindustry.Vars.playerGroup; @@ -13,12 +14,16 @@ public class ServerDebug { private IntMap, Long>> last = new IntMap<>(); public void handle(int connection, Object packet){ - if(!last.containsKey(connection)) - last.put(connection, new OrderedMap<>()); - if(packet instanceof Disconnect) - last.remove(connection); - else - last.get(connection).put(packet.getClass(), TimeUtils.millis()); + try { + if (!last.containsKey(connection)) + last.put(connection, new OrderedMap<>()); + if (packet instanceof Disconnect) + last.remove(connection); + else + last.get(connection).put(packet.getClass(), TimeUtils.millis()); + }catch (Exception e){ + Log.err(""); + } } public String getOut(){ diff --git a/html/src/io/anuke/mindustry/client/WebsocketClient.java b/html/src/io/anuke/mindustry/client/WebsocketClient.java index 450a85107f..36bd641128 100644 --- a/html/src/io/anuke/mindustry/client/WebsocketClient.java +++ b/html/src/io/anuke/mindustry/client/WebsocketClient.java @@ -7,22 +7,18 @@ import com.badlogic.gdx.utils.reflect.ReflectionException; import com.sksamuel.gwt.websockets.Websocket; import com.sksamuel.gwt.websockets.WebsocketListener; import io.anuke.mindustry.io.Platform; -import io.anuke.mindustry.net.Host; -import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.ClientProvider; import io.anuke.mindustry.net.Net.SendMode; -import io.anuke.mindustry.net.Packet; import io.anuke.mindustry.net.Packets.Connect; import io.anuke.mindustry.net.Packets.Disconnect; -import io.anuke.mindustry.net.Registrator; import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.Consumer; -import io.anuke.ucore.util.Strings; import java.io.IOException; import java.nio.ByteBuffer; -import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.webPort; public class WebsocketClient implements ClientProvider { Websocket socket; @@ -118,11 +114,7 @@ public class WebsocketClient implements ClientProvider { @Override public void onMessage(String msg) { - if (!msg.startsWith("---")) return; - String[] text = msg.substring(3).split("\\|"); - Host host = new Host(text[1], address, text[2], Strings.parseInt(text[3]), - Strings.parseInt(text[0]), - text.length > 4 && Strings.canParsePostiveInt(text[4]) ? Strings.parseInt(text[4]) : 0); + Host host = NetworkIO.readServerData(address, ByteBuffer.wrap(Base64Coder.decode(msg))); valid.accept(host); accepted[0] = true; socket.close(); @@ -130,7 +122,7 @@ public class WebsocketClient implements ClientProvider { @Override public void onOpen() { - socket.send("_ping_"); + socket.send("ping"); } }); socket.open(); diff --git a/kryonet/src/io/anuke/kryonet/KryoClient.java b/kryonet/src/io/anuke/kryonet/KryoClient.java index 77cf87be44..d9f25b830e 100644 --- a/kryonet/src/io/anuke/kryonet/KryoClient.java +++ b/kryonet/src/io/anuke/kryonet/KryoClient.java @@ -10,6 +10,7 @@ import io.anuke.mindustry.net.Host; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net.ClientProvider; import io.anuke.mindustry.net.Net.SendMode; +import io.anuke.mindustry.net.NetworkIO; import io.anuke.mindustry.net.Packets.Connect; import io.anuke.mindustry.net.Packets.Disconnect; import io.anuke.ucore.function.Consumer; @@ -41,7 +42,7 @@ public class KryoClient implements ClientProvider{ @Override public void onDiscoveredHost(DatagramPacket datagramPacket) { ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData()); - Host address = KryoRegistrator.readServerData(datagramPacket.getAddress(), buffer); + Host address = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer); addresses.put(datagramPacket.getAddress(), address); } @@ -156,7 +157,7 @@ public class KryoClient implements ClientProvider{ socket.receive(packet); ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); - Host host = KryoRegistrator.readServerData(packet.getAddress(), buffer); + Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer); if (host != null) { Gdx.app.postRunnable(() -> valid.accept(host)); diff --git a/kryonet/src/io/anuke/kryonet/KryoRegistrator.java b/kryonet/src/io/anuke/kryonet/KryoRegistrator.java index 1f724e898a..5d9590dd27 100644 --- a/kryonet/src/io/anuke/kryonet/KryoRegistrator.java +++ b/kryonet/src/io/anuke/kryonet/KryoRegistrator.java @@ -2,16 +2,12 @@ package io.anuke.kryonet; import com.esotericsoftware.minlog.Log; import com.esotericsoftware.minlog.Log.Logger; -import io.anuke.mindustry.io.Version; -import io.anuke.mindustry.net.Host; import io.anuke.ucore.util.ColorCodes; import java.io.PrintWriter; import java.io.StringWriter; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.headless; public class KryoRegistrator { public static boolean fakeLag = false; @@ -46,48 +42,4 @@ public class KryoRegistrator { } }); } - - public static ByteBuffer writeServerData(){ - int maxlen = 32; - - String host = (headless ? "Server" : player.name); - String map = world.getMap().name; - - host = host.substring(0, Math.min(host.length(), maxlen)); - map = map.substring(0, Math.min(map.length(), maxlen)); - - ByteBuffer buffer = ByteBuffer.allocate(128); - - buffer.put((byte)host.getBytes().length); - buffer.put(host.getBytes()); - - buffer.put((byte)map.getBytes().length); - buffer.put(map.getBytes()); - - buffer.putInt(playerGroup.size()); - buffer.putInt(state.wave); - buffer.putInt(Version.build); - return buffer; - } - - public static Host readServerData(InetAddress ia, ByteBuffer buffer){ - if(buffer.capacity() < 128) return null; //old version address. - - byte hlength = buffer.get(); - byte[] hb = new byte[hlength]; - buffer.get(hb); - - byte mlength = buffer.get(); - byte[] mb = new byte[mlength]; - buffer.get(mb); - - String host = new String(hb); - String map = new String(mb); - - int players = buffer.getInt(); - int wave = buffer.getInt(); - int version = buffer.getInt(); - - return new Host(host, ia.getHostAddress(), map, wave, players, version); - } } diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index c08bd87db2..9e1cd8f27f 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -10,14 +10,10 @@ import com.esotericsoftware.kryonet.Listener.LagListener; import com.esotericsoftware.kryonet.Server; import com.esotericsoftware.kryonet.util.InputStreamSender; import io.anuke.mindustry.Vars; -import io.anuke.mindustry.io.Version; -import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.SendMode; import io.anuke.mindustry.net.Net.ServerProvider; -import io.anuke.mindustry.net.NetConnection; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.net.Registrator; -import io.anuke.mindustry.net.Streamable; import io.anuke.mindustry.net.Streamable.StreamBegin; import io.anuke.mindustry.net.Streamable.StreamChunk; import io.anuke.ucore.UCore; @@ -38,11 +34,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import static io.anuke.mindustry.Vars.headless; -import static io.anuke.mindustry.Vars.state; -import static io.anuke.mindustry.Vars.world; public class KryoServer implements ServerProvider { - final boolean debug = false; final Server server; final ByteSerializer serializer = new ByteSerializer(); final ByteBuffer buffer = ByteBuffer.allocate(4096); @@ -57,7 +50,7 @@ public class KryoServer implements ServerProvider { public KryoServer(){ server = new Server(4096*2, 2048, connection -> new ByteSerializer()); server.setDiscoveryHandler((datagramChannel, fromAddress) -> { - ByteBuffer buffer = KryoRegistrator.writeServerData(); + ByteBuffer buffer = NetworkIO.writeServerData(); buffer.position(0); datagramChannel.send(buffer, fromAddress); return true; @@ -185,19 +178,27 @@ public class KryoServer implements ServerProvider { lastconnection = 0; async(server::close); - async(() -> { - try { - if (webServer != null) webServer.stop(1); - //kill them all - for (Thread worker : Thread.getAllStackTraces().keySet()) { - if (worker.getName().contains("WebSocketWorker")) { - worker.interrupt(); - } - } - }catch (Exception e){ - handleException(e); + + //kill them all + for (Thread worker : Thread.getAllStackTraces().keySet()) { + if (worker.getName().contains("WebSocketWorker")) { + worker.interrupt(); } - }); + } + + try { + if (webServer != null) webServer.stop(1); + }catch (NullPointerException e){ + try { + synchronized (webServer) { + ((Thread) UCore.getPrivate(WebSocketServer.class, webServer, "selectorthread")).join(1); + } + }catch (InterruptedException j){ + handleException(j); + } + }catch (InterruptedException e){ + handleException(e); + } } @Override @@ -343,14 +344,12 @@ public class KryoServer implements ServerProvider { try { synchronized (buffer) { buffer.position(0); - if(debug) Log.info("Sending object with ID {0}", Registrator.getID(object.getClass())); serializer.write(buffer, object); int pos = buffer.position(); buffer.position(0); byte[] out = new byte[pos]; buffer.get(out); String string = new String(Base64Coder.encode(out)); - if(debug) Log.info("Sending string: {0}", string); socket.send(string); } }catch (WebsocketNotConnectedException e){ @@ -405,16 +404,7 @@ public class KryoServer implements ServerProvider { } @Override - public void onOpen(WebSocket conn, ClientHandshake handshake) { - Connect connect = new Connect(); - connect.addressTCP = conn.getRemoteSocketAddress().getAddress().getHostAddress(); - KryoConnection kn = new KryoConnection(lastconnection ++, connect.addressTCP, conn); - - Log.info("&bRecieved web connection: {0} {1}", kn.id, connect.addressTCP); - connections.add(kn); - - Gdx.app.postRunnable(() -> Net.handleServerReceived(kn.id, connect)); - } + public void onOpen(WebSocket conn, ClientHandshake handshake) {} @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { @@ -432,18 +422,31 @@ public class KryoServer implements ServerProvider { @Override public void onMessage(WebSocket conn, String message) { try { - KryoConnection k = getBySocket(conn); - if (k == null) return; - - if(message.equals("_ping_")){ - conn.send("---" + Vars.playerGroup.size() + "|" + (headless ? "Server" : Vars.player.name) - + "|" + world.getMap().name + "|" + state.wave + "|" + Version.build); - connections.remove(k); + if(message.equals("ping")){ + ByteBuffer ping = NetworkIO.writeServerData(); + conn.send(new String(Base64Coder.encode(ping.array()))); }else { + KryoConnection k = getBySocket(conn); + + if (k == null){ + Connect connect = new Connect(); + connect.addressTCP = conn.getRemoteSocketAddress().getAddress().getHostAddress(); + k = new KryoConnection(lastconnection ++, connect.addressTCP, conn); + + Log.info("&bRecieved web connection: {0} {1}", k.id, connect.addressTCP); + connections.add(k); + + int id = k.id; + + Gdx.app.postRunnable(() -> Net.handleServerReceived(id, connect)); + } + + int id = k.id; + byte[] out = Base64Coder.decode(message); ByteBuffer buffer = ByteBuffer.wrap(out); Object o = serializer.read(buffer); - Gdx.app.postRunnable(() -> Net.handleServerReceived(k.id, o)); + Gdx.app.postRunnable(() -> Net.handleServerReceived(id, o)); } }catch (Exception e){ Log.err(e); diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index a125947f5a..0b8da6e4f6 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -9,6 +9,7 @@ import io.anuke.mindustry.game.Difficulty; import io.anuke.mindustry.game.EventType.GameOverEvent; import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.io.SaveIO; +import io.anuke.mindustry.io.Version; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.net.Packets.ChatPacket; @@ -74,27 +75,24 @@ public class ServerControl extends Module { Events.on(GameOverEvent.class, () -> { info("Game over!"); - Timers.runTask(30f, () -> { + Timers.runTask(10f, () -> { state.set(State.menu); Net.closeServer(); - Timers.runTask(30f, () -> { + if (mode != ShuffleMode.off) { + Array maps = mode == ShuffleMode.both ? world.maps().getAllMaps() : + mode == ShuffleMode.normal ? world.maps().getDefaultMaps() : world.maps().getCustomMaps(); - if (mode != ShuffleMode.off) { - Array maps = mode == ShuffleMode.both ? world.maps().getAllMaps() : - mode == ShuffleMode.normal ? world.maps().getDefaultMaps() : world.maps().getCustomMaps(); + Map previous = world.getMap(); + Map map = previous; + while (map == previous || !map.visible) map = maps.random(); - Map previous = world.getMap(); - Map map = previous; - while (map == previous || !map.visible) map = maps.random(); - - info("Selected next map to be {0}.", map.name); - state.set(State.playing); - logic.reset(); - world.loadMap(map); - host(); - } - }); + info("Selected next map to be {0}.", map.name); + state.set(State.playing); + logic.reset(); + world.loadMap(map); + host(); + } }); }); @@ -109,6 +107,10 @@ public class ServerControl extends Module { } }); + handler.register("version", "Displays server version info.", arg -> { + info("&lmVersion: &lyMindustry {0} {1} / {2}", Version.code, Version.type, Version.buildName); + }); + handler.register("exit", "Exit the server application.", arg -> { info("Shutting down server."); Net.dispose(); @@ -496,6 +498,11 @@ public class ServerControl extends Module { }); handler.register("gameover", "Force a game over.", arg -> { + if(state.is(State.menu)){ + info("Not playing a map."); + return; + } + world.removeBlock(world.getCore()); info("Core destroyed."); });