diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index e9cdddaae0..0e6fb54998 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -77,7 +77,6 @@ text.unlocked = New Block Unlocked\! text.unlocked.plural = New Blocks Unlocked\! text.players = {0} players online text.players.single = {0} player online -text.server.mismatch = Packet error\: possible client/server version mismatch.\nMake sure you and the host have the\nlatest version of Mindustry\! text.server.closing = [accent]Closing server... text.server.kicked.kick = You have been kicked from the server\! text.server.kicked.serverClose = Server closed. @@ -137,7 +136,6 @@ text.disconnect = Disconnected. text.disconnect.data = Failed to load world data\! text.connecting = [accent]Connecting... text.connecting.data = [accent]Loading world data... -text.connectfail = [crimson]Failed to connect to server\: [orange]{0} text.server.port = Port\: text.server.addressinuse = Address already in use\! text.server.invalidport = Invalid port number\! @@ -262,6 +260,14 @@ text.tutorial = Tutorial text.editor = Editor text.mapeditor = Map Editor text.donate = Donate + +text.connectfail = [crimson]Failed to connect to server\:\n\n[accent]{0} +text.error.unreachable = Server unreachable. +text.error.invalidaddress = Invalid address. +text.error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! +text.error.mismatch = Packet error:\npossible client/server version mismatch.\nMake sure you and the host have the latest version of Mindustry! +text.error.any = Unkown network error. + text.settings.language = Language text.settings.reset = Reset to Defaults text.settings.rebind = Rebind diff --git a/core/src/io/anuke/mindustry/entities/units/types/Drone.java b/core/src/io/anuke/mindustry/entities/units/types/Drone.java index 85c9b9705a..244f5ef455 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Drone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Drone.java @@ -269,10 +269,9 @@ public class Drone extends FlyingUnit implements BuilderTrait{ } private void notifyPlaced(BuildEntity entity, boolean isBreaking){ - float timeToBuild = entity.buildCost; float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0); - if(!state.is(build) && dist / type.maxVelocity < timeToBuild * 0.9f){ + if(!state.is(build) && dist / type.maxVelocity < entity.buildCost * 0.9f){ target = entity; this.isBreaking = isBreaking; setState(build); diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 5a1b6133c8..2750d868a8 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -17,13 +17,14 @@ import io.anuke.mindustry.net.Streamable.StreamBuilder; import io.anuke.ucore.core.Timers; import io.anuke.ucore.function.BiConsumer; import io.anuke.ucore.function.Consumer; +import io.anuke.ucore.util.Bundles; import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Pooling; +import io.anuke.ucore.util.Threads; import java.io.IOException; -import static io.anuke.mindustry.Vars.headless; -import static io.anuke.mindustry.Vars.ui; +import static io.anuke.mindustry.Vars.*; public class Net{ private static boolean server; @@ -46,15 +47,41 @@ public class Net{ return serverProvider != null; } - /** - * Display a network error. - */ - public static void showError(String text){ + /**Display a network error. Call on the graphics thread.*/ + public static void showError(Throwable e){ + if(!headless){ - ui.showError(text); - }else{ - Log.err(text); + Threads.assertGraphics(); + + Throwable t = e; + while(t.getCause() != null){ + t = t.getCause(); + } + + String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); + String type = error.getClass().toString().toLowerCase(); + + if(error.equals("mismatch")){ + error = Bundles.get("text.error.mismatch"); + }else if(error.contains("port out of range") || error.contains("invalid argument") || (error.contains("invalid") && error.contains("address"))){ + error = Bundles.get("text.error.invalidaddress"); + }else if(error.contains("connection refused") || error.contains("route to host") || type.contains("unknownhost")){ + error = Bundles.get("text.error.unreachable"); + }else if(type.contains("timeout")){ + error = Bundles.get("text.error.timeout"); + }else if(!error.isEmpty()){ + error = Bundles.get("text.error.any"); + } + + ui.showText("", Bundles.format("text.connectfail", error)); + ui.loadfrag.hide(); + + if(Net.client()){ + netClient.disconnectQuietly(); + } } + + Log.err(e); } /** @@ -77,14 +104,18 @@ public class Net{ /** * Connect to an address. */ - public static void connect(String ip, int port) throws IOException{ - lastIP = ip + ":" + port; - if(!active){ - clientProvider.connect(ip, port); - active = true; - server = false; - }else{ - throw new IOException("Already connected!"); + public static void connect(String ip, int port, Runnable success){ + try{ + lastIP = ip + ":" + port; + if(!active){ + clientProvider.connect(ip, port, success); + active = true; + server = false; + }else{ + throw new IOException("Already connected!"); + } + }catch(IOException e){ + showError(e); } } @@ -346,7 +377,7 @@ public class Net{ /**Client implementation.*/ public interface ClientProvider{ /**Connect to a server.*/ - void connect(String ip, int port) throws IOException; + void connect(String ip, int port, Runnable success) throws IOException; /**Send an object to the server.*/ void send(Object object, SendMode mode); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java index edbd6133c2..540691927b 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java @@ -18,7 +18,6 @@ import io.anuke.ucore.scene.ui.layout.Cell; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.utils.UIUtils; import io.anuke.ucore.util.Bundles; -import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Strings; import static io.anuke.mindustry.Vars.*; @@ -300,34 +299,11 @@ public class JoinDialog extends FloatingDialog{ }); Timers.runTask(2f, () -> { - try{ - Vars.netClient.beginConnecting(); - Net.connect(ip, port); + Vars.netClient.beginConnecting(); + Net.connect(ip, port, () -> { hide(); add.hide(); - }catch(Exception e){ - Throwable t = e; - while(t.getCause() != null){ - t = t.getCause(); - } - //TODO localize - String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); - if(error.contains("connection refused")){ - error = "connection refused"; - }else if(error.contains("port out of range")){ - error = "invalid port!"; - }else if(error.contains("invalid argument")){ - error = "invalid IP or port!"; - }else if(t.getClass().toString().toLowerCase().contains("sockettimeout")){ - error = "timed out!\nmake sure the host has port forwarding set up,\nand that the address is correct!"; - }else{ - error = Strings.parseException(e, false); - } - ui.showError(Bundles.format("text.connectfail", error)); - ui.loadfrag.hide(); - - Log.err(e); - } + }); }); } diff --git a/kryonet/src/io/anuke/kryonet/KryoClient.java b/kryonet/src/io/anuke/kryonet/KryoClient.java index 2719df75a4..d0f6783fe6 100644 --- a/kryonet/src/io/anuke/kryonet/KryoClient.java +++ b/kryonet/src/io/anuke/kryonet/KryoClient.java @@ -3,7 +3,6 @@ package io.anuke.kryonet; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Array; import com.esotericsoftware.kryonet.*; -import com.esotericsoftware.minlog.Log; import io.anuke.mindustry.net.Host; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net.ClientProvider; @@ -13,12 +12,14 @@ import io.anuke.mindustry.net.Packets.Connect; import io.anuke.mindustry.net.Packets.Disconnect; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.util.Pooling; -import io.anuke.ucore.util.Strings; import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4FastDecompressor; import java.io.IOException; -import java.net.*; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.nio.channels.ClosedSelectorException; @@ -75,10 +76,12 @@ public class KryoClient implements ClientProvider{ @Override public void disconnected (Connection connection) { - Disconnect c = new Disconnect(); + if(connection.getLastProtocolError() != null){ + netClient.setQuiet(); + } + Disconnect c = new Disconnect(); threads.runDelay(() -> Net.handleClientReceived(c)); - if(connection.getLastProtocolError() != null) Log.error("\n\n\n\nProtocol error: " + connection.getLastProtocolError() + "\n\n\n\n"); } @Override @@ -89,13 +92,7 @@ public class KryoClient implements ClientProvider{ try{ Net.handleClientReceived(object); }catch (Exception e){ - e.printStackTrace(); - if(e instanceof KryoNetException && e.getMessage() != null && e.getMessage().toLowerCase().contains("incorrect")) { - Net.showError("$text.server.mismatch"); - netClient.disconnectQuietly(); - }else{ - throw new RuntimeException(e); - } + handleException(e); } }); @@ -128,21 +125,28 @@ public class KryoClient implements ClientProvider{ } @Override - public void connect(String ip, int port) throws IOException { - //just in case - client.stop(); - - Thread updateThread = new Thread(() -> { + public void connect(String ip, int port, Runnable success){ + runAsync(() -> { try{ - client.run(); - }catch (Exception e){ - if(!(e instanceof ClosedSelectorException)) handleException(e); - } - }, "Kryonet Client"); - updateThread.setDaemon(true); - updateThread.start(); + //just in case + client.stop(); - client.connect(5000, ip, port, port); + Thread updateThread = new Thread(() -> { + try{ + client.run(); + }catch(Exception e){ + if(!(e instanceof ClosedSelectorException)) handleException(e); + } + }, "Kryonet Client"); + updateThread.setDaemon(true); + updateThread.start(); + + client.connect(5000, ip, port, port); + success.run(); + }catch(Exception e){ + handleException(e); + } + }); } @Override @@ -222,12 +226,10 @@ public class KryoClient implements ClientProvider{ } private void handleException(Exception e){ - e.printStackTrace(); if(e instanceof KryoNetException){ - Gdx.app.postRunnable(() -> Net.showError("$text.server.mismatch")); + Gdx.app.postRunnable(() -> Net.showError(new IOException("mismatch"))); }else{ - Net.showError(Strings.parseException(e, true)); - disconnect(); + Gdx.app.postRunnable(() -> Net.showError(e)); } }