diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 229b0e804c..311df85b8d 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -16,6 +16,9 @@ text.server.connected=A player has joined. text.server.disconnected={0} has disconnected. text.hostserver=Host Server text.host=Host +text.hosts.discovering=Discovering LAN games +text.hosts.none=[lightgray]No hosts found! +text.joingame.byip=Join by IP... text.joingame.title=Join Game text.joingame.ip=IP: text.disconnect=Disconnected. diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 18e607defc..b100dc629b 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -187,6 +187,11 @@ public class Control extends Module{ Settings.defaults("save-" + i + "-name", "untitled"); Settings.defaults("save-" + i + "-data", "empty"); } + + Settings.defaultList( + "ip", "localhost", + "port", Vars.port+"" + ); Settings.loadAll("io.anuke.moment"); diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index fe12ea4369..28461457f8 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -178,29 +178,6 @@ public class UI extends SceneModule{ editor = new MapEditor(); editorDialog = new MapEditorDialog(editor); } - - join = new FloatingDialog("$text.joingame.title"); - join.content().add("$text.joingame.ip").left(); - Mindustry.platforms.addDialog(join.content().addField("localhost", text -> lastip = text).size(180f, 54f).get()); - join.content().row(); - join.content().add("$text.server.port").left(); - Mindustry.platforms.addDialog(join.content() - .addField(Vars.port + "", new DigitsOnlyFilter(), text -> lastport = Strings.parseInt(text)) - .size(180f, 54f).get()); - join.buttons().defaults().size(140f, 60f).pad(4f); - join.buttons().addButton("$text.cancel", join::hide); - join.buttons().addButton("$text.ok", () -> { - showLoading("$text.connecting"); - - Timers.runTask(2f, () -> { - try{ - Net.connect(lastip, lastport); - }catch (IOException e) { - showError(Bundles.format("text.connectfail", Strings.parseException(e, false))); - hideLoading(); - } - }); - }).disabled(b -> lastip.isEmpty() || lastport == Integer.MIN_VALUE); settingserror = new Dialog("Warning", "dialog"); settingserror.content().add("[crimson]Failed to access local storage.\nSettings will not be saved."); @@ -210,6 +187,8 @@ public class UI extends SceneModule{ gameerror = new Dialog("$text.error.crashtitle", "dialog"); gameerror.content().labelWrap("$text.error.crashmessage").width(600f).pad(10f); gameerror.buttons().addButton("#text.ok", gameerror::hide).size(200f, 50); + + join = new JoinDialog(); discord = new Dialog("Discord", "dialog"); discord.content().margin(12f); diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 9645b2d23e..c63addab63 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -55,7 +55,7 @@ public class Net{ /**Starts discovering servers on a different thread. Does not work with GWT. * Callback is run on the main libGDX thread.*/ - public void discoverServers(Consumer> cons){ + public static void discoverServers(Consumer> cons){ executor.submit(() -> { Array
arr = clientProvider.discover(); Gdx.app.postRunnable(() -> { diff --git a/core/src/io/anuke/mindustry/ui/JoinDialog.java b/core/src/io/anuke/mindustry/ui/JoinDialog.java index 0b643ec4e1..f3d34b94df 100644 --- a/core/src/io/anuke/mindustry/ui/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/JoinDialog.java @@ -1,12 +1,103 @@ package io.anuke.mindustry.ui; +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.Mindustry; +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.net.Address; +import io.anuke.mindustry.net.Net; +import io.anuke.ucore.core.Settings; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.scene.style.Drawable; +import io.anuke.ucore.scene.ui.Dialog; +import io.anuke.ucore.scene.ui.TextButton; +import io.anuke.ucore.scene.ui.TextField.TextFieldFilter.DigitsOnlyFilter; +import io.anuke.ucore.scene.ui.layout.Table; +import io.anuke.ucore.util.Bundles; +import io.anuke.ucore.util.Strings; + +import java.io.IOException; + public class JoinDialog extends FloatingDialog { + Dialog join; + Table hosts = new Table(); + float w = 400; public JoinDialog(){ super("$text.joingame"); + + addCloseButton(); + + join = new FloatingDialog("$text.joingame.title"); + join.content().add("$text.joingame.ip").left(); + Mindustry.platforms.addDialog(join.content().addField(Settings.getString("ip"),text ->{ + Settings.putString("ip", text); + Settings.save(); + }).size(180f, 54f).get()); + + 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(180f, 54f).get()); + join.buttons().defaults().size(140f, 60f).pad(4f); + join.buttons().addButton("$text.cancel", join::hide); + join.buttons().addButton("$text.ok", () -> + connect(Settings.getString("port"), Integer.parseInt(Settings.getString("port"))) + ).disabled(b -> Settings.getString("ip").isEmpty() || Integer.parseInt(Settings.getString("port")) == Integer.MIN_VALUE); + + setup(); + + shown(() -> { + hosts.clear(); + hosts.background("button"); + hosts.label(() -> "[accent]" + Bundles.get("text.hosts.discovering") + new String(new char[(int)(Timers.time() / 10) % 4]).replace("\0", ".")).pad(10f); + Net.discoverServers(list -> { + addHosts(list); + }); + }); } void setup(){ + hosts.background("button"); content().clear(); + content().add(hosts).width(w).pad(0); + content().row(); + content().addButton("$text.joingame.byip", "clear", join::show).width(w).height(80f); + } + + void addHosts(Array
array){ + hosts.clear(); + + if(array.size == 0){ + hosts.add("$text.hosts.none").pad(20f); + }else { + for (Address a : array) { + TextButton button = hosts.addButton("[accent]"+a.name, "clear", () -> { + connect(a.address, Vars.port); + }).width(w).height(80f).pad(4f).get(); + button.left(); + button.row(); + button.add("[lightgray]" + a.address + " / " + Vars.port).pad(4).left(); + + hosts.row(); + hosts.background((Drawable) null); + } + } + } + + void connect(String ip, int port){ + Vars.ui.showLoading("$text.connecting"); + + Timers.runTask(2f, () -> { + try{ + Net.connect(ip, port); + }catch (IOException e) { + Vars.ui.showError(Bundles.format("text.connectfail", Strings.parseException(e, false))); + Vars.ui.hideLoading(); + } + }); } } diff --git a/core/src/io/anuke/mindustry/ui/MenuDialog.java b/core/src/io/anuke/mindustry/ui/MenuDialog.java index 26129ea074..9642a55741 100644 --- a/core/src/io/anuke/mindustry/ui/MenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/MenuDialog.java @@ -44,17 +44,15 @@ public class MenuDialog extends FloatingDialog{ ui.showPrefs(); }); - //if(!Vars.gwt){ - content().row(); - content().addButton("$text.savegame", () -> { - save.show(); - }); + content().row(); + content().addButton("$text.savegame", () -> { + save.show(); + }); - content().row(); - content().addButton("$text.loadgame", () -> { - load.show(); - }); - //} + content().row(); + content().addButton("$text.loadgame", () -> { + load.show(); + }); content().row(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java index d1db1965f3..e3df7132c0 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java @@ -39,7 +39,6 @@ public class MenuFragment implements Fragment{ row(); if(!gwt){ - add(new MenuButton("$text.editor", group, ui::showEditor)); row(); } diff --git a/kryonet/build/libs/kryonet-release.jar b/kryonet/build/libs/kryonet-release.jar index 8c4aff25d0..a669518e69 100644 Binary files a/kryonet/build/libs/kryonet-release.jar and b/kryonet/build/libs/kryonet-release.jar differ diff --git a/kryonet/src/io/anuke/kryonet/KryoClient.java b/kryonet/src/io/anuke/kryonet/KryoClient.java index 668570d9ee..8553b3c5d5 100644 --- a/kryonet/src/io/anuke/kryonet/KryoClient.java +++ b/kryonet/src/io/anuke/kryonet/KryoClient.java @@ -2,6 +2,7 @@ package io.anuke.kryonet; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectSet; import com.esotericsoftware.kryonet.Client; import com.esotericsoftware.kryonet.Connection; import com.esotericsoftware.kryonet.FrameworkMessage; @@ -101,10 +102,13 @@ public class KryoClient implements ClientProvider{ @Override public Array
discover(){ List list = client.discoverHosts(Vars.port, 5000); + ObjectSet hostnames = new ObjectSet<>(); Array
result = new Array<>(); for(InetAddress a : list){ - result.add(new Address(a.getHostName(), a.getHostAddress())); + if(!hostnames.contains(a.getHostName())) + result.add(new Address(a.getCanonicalHostName(), a.getHostAddress())); + hostnames.add(a.getHostName()); } return result;