Improved server discovery
This commit is contained in:
@@ -114,7 +114,7 @@ text.hosting=[accent]Opening server...
|
|||||||
text.hosts.refresh=Refresh
|
text.hosts.refresh=Refresh
|
||||||
text.hosts.discovering=Discovering LAN games
|
text.hosts.discovering=Discovering LAN games
|
||||||
text.server.refreshing=Refreshing server
|
text.server.refreshing=Refreshing server
|
||||||
text.hosts.none=[lightgray]No LAN games found!
|
text.hosts.none=[lightgray]No local games found!
|
||||||
text.host.invalid=[scarlet]Can't connect to host.
|
text.host.invalid=[scarlet]Can't connect to host.
|
||||||
text.trace=Trace Player
|
text.trace=Trace Player
|
||||||
text.trace.playername=Player name: [accent]{0}
|
text.trace.playername=Player name: [accent]{0}
|
||||||
|
|||||||
@@ -137,8 +137,8 @@ public class Net{
|
|||||||
* Starts discovering servers on a different thread. Does not work with GWT.
|
* Starts discovering servers on a different thread. Does not work with GWT.
|
||||||
* Callback is run on the main libGDX thread.
|
* Callback is run on the main libGDX thread.
|
||||||
*/
|
*/
|
||||||
public static void discoverServers(Consumer<Array<Host>> cons){
|
public static void discoverServers(Consumer<Host> cons, Runnable done){
|
||||||
clientProvider.discover(cons);
|
clientProvider.discover(cons, done);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,8 +374,9 @@ public class Net{
|
|||||||
/**
|
/**
|
||||||
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
|
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
|
||||||
* Callback should be run on libGDX main thread.
|
* Callback should be run on libGDX main thread.
|
||||||
|
* @param done is the callback that should run after discovery.
|
||||||
*/
|
*/
|
||||||
void discover(Consumer<Array<Host>> callback);
|
void discover(Consumer<Host> callback, Runnable done);
|
||||||
|
|
||||||
/**Ping a host. If an error occured, failed() should be called with the exception.*/
|
/**Ping a host. If an error occured, failed() should be called with the exception.*/
|
||||||
void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed);
|
void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public class JoinDialog extends FloatingDialog{
|
|||||||
Table local = new Table();
|
Table local = new Table();
|
||||||
Table remote = new Table();
|
Table remote = new Table();
|
||||||
Table hosts = new Table();
|
Table hosts = new Table();
|
||||||
|
int totalHosts;
|
||||||
|
|
||||||
public JoinDialog(){
|
public JoinDialog(){
|
||||||
super("$text.joingame");
|
super("$text.joingame");
|
||||||
@@ -185,15 +186,6 @@ public class JoinDialog extends FloatingDialog{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshLocal(){
|
|
||||||
if(!Vars.gwt){
|
|
||||||
local.clear();
|
|
||||||
local.background("button");
|
|
||||||
local.label(() -> "[accent]" + Bundles.get("text.hosts.discovering") + Strings.animated(4, 10f, ".")).pad(10f);
|
|
||||||
Net.discoverServers(this::addLocalHosts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup(){
|
void setup(){
|
||||||
float w = targetWidth();
|
float w = targetWidth();
|
||||||
|
|
||||||
@@ -255,32 +247,50 @@ public class JoinDialog extends FloatingDialog{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLocalHosts(Array<Host> array){
|
void refreshLocal(){
|
||||||
float w = targetWidth();
|
if(!Vars.gwt){
|
||||||
|
totalHosts = 0;
|
||||||
|
|
||||||
local.clear();
|
local.clear();
|
||||||
|
local.background((Drawable)null);
|
||||||
|
local.table("button", t -> {
|
||||||
|
t.label(() -> "[accent]" + Bundles.get("text.hosts.discovering") + Strings.animated(4, 10f, ".")).pad(10f);
|
||||||
|
}).growX();
|
||||||
|
Net.discoverServers(this::addLocalHost, this::finishLocalHosts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(array.size == 0){
|
void finishLocalHosts(){
|
||||||
|
if(totalHosts == 0){
|
||||||
|
local.clear();
|
||||||
|
local.background("button");
|
||||||
local.add("$text.hosts.none").pad(10f);
|
local.add("$text.hosts.none").pad(10f);
|
||||||
local.add().growX();
|
local.add().growX();
|
||||||
local.addImageButton("icon-loading", 16 * 2f, this::refreshLocal).pad(-10f).padLeft(0).padTop(-6).size(70f, 74f);
|
local.addImageButton("icon-loading", 16 * 2f, this::refreshLocal).pad(-10f).padLeft(0).padTop(-6).size(70f, 74f);
|
||||||
}else{
|
}else{
|
||||||
for(Host a : array){
|
local.background((Drawable) null);
|
||||||
TextButton button = local.addButton("[accent]" + a.name, "clear", () -> connect(a.address, port))
|
|
||||||
.width(w).height(80f).pad(4f).get();
|
|
||||||
button.left();
|
|
||||||
button.row();
|
|
||||||
button.add("[lightgray]" + (a.players != 1 ? Bundles.format("text.players", a.players) :
|
|
||||||
Bundles.format("text.players.single", a.players)));
|
|
||||||
button.row();
|
|
||||||
button.add("[lightgray]" + a.address).pad(4).left();
|
|
||||||
|
|
||||||
local.row();
|
|
||||||
local.background((Drawable) null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addLocalHost(Host host){
|
||||||
|
if(totalHosts == 0){
|
||||||
|
local.clear();
|
||||||
|
}
|
||||||
|
totalHosts ++;
|
||||||
|
float w = targetWidth();
|
||||||
|
|
||||||
|
local.row();
|
||||||
|
|
||||||
|
TextButton button = local.addButton("[accent]" + host.name, "clear", () -> connect(host.address, port))
|
||||||
|
.width(w).height(80f).pad(4f).get();
|
||||||
|
button.left();
|
||||||
|
button.row();
|
||||||
|
button.add("[lightgray]" + (host.players != 1 ? Bundles.format("text.players", host.players) :
|
||||||
|
Bundles.format("text.players.single", host.players)));
|
||||||
|
button.row();
|
||||||
|
button.add("[lightgray]" + host.address).pad(4).left();
|
||||||
|
}
|
||||||
|
|
||||||
void connect(String ip, int port){
|
void connect(String ip, int port){
|
||||||
ui.loadfrag.show("$text.connecting");
|
ui.loadfrag.show("$text.connecting");
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package io.anuke.kryonet;
|
|||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.ObjectMap;
|
|
||||||
import com.badlogic.gdx.utils.ObjectSet;
|
|
||||||
import com.esotericsoftware.kryonet.*;
|
import com.esotericsoftware.kryonet.*;
|
||||||
import com.esotericsoftware.minlog.Log;
|
import com.esotericsoftware.minlog.Log;
|
||||||
import io.anuke.mindustry.net.Host;
|
import io.anuke.mindustry.net.Host;
|
||||||
@@ -20,19 +18,17 @@ import net.jpountz.lz4.LZ4Factory;
|
|||||||
import net.jpountz.lz4.LZ4FastDecompressor;
|
import net.jpountz.lz4.LZ4FastDecompressor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramPacket;
|
import java.net.*;
|
||||||
import java.net.DatagramSocket;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.ClosedSelectorException;
|
import java.nio.channels.ClosedSelectorException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
import static io.anuke.mindustry.net.Net.packetPoolLock;
|
import static io.anuke.mindustry.net.Net.packetPoolLock;
|
||||||
|
|
||||||
public class KryoClient implements ClientProvider{
|
public class KryoClient implements ClientProvider{
|
||||||
Client client;
|
Client client;
|
||||||
ObjectMap<InetAddress, Host> addresses = new ObjectMap<>();
|
Consumer<Host> lastCallback;
|
||||||
|
Array<InetAddress> foundAddresses = new Array<>();
|
||||||
ClientDiscoveryHandler handler;
|
ClientDiscoveryHandler handler;
|
||||||
LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
||||||
|
|
||||||
@@ -48,8 +44,14 @@ public class KryoClient implements ClientProvider{
|
|||||||
@Override
|
@Override
|
||||||
public void onDiscoveredHost(DatagramPacket datagramPacket) {
|
public void onDiscoveredHost(DatagramPacket datagramPacket) {
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData());
|
ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData());
|
||||||
Host address = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer);
|
Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer);
|
||||||
addresses.put(datagramPacket.getAddress(), address);
|
for(InetAddress address : foundAddresses){
|
||||||
|
if(address.equals(datagramPacket.getAddress()) || (isLocal(address) && isLocal(datagramPacket.getAddress()))){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Gdx.app.postRunnable(() -> lastCallback.accept(host));
|
||||||
|
foundAddresses.add(datagramPacket.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,6 +110,17 @@ public class KryoClient implements ClientProvider{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isLocal(InetAddress addr) {
|
||||||
|
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return NetworkInterface.getByInetAddress(addr) != null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] decompressSnapshot(byte[] input, int size){
|
public byte[] decompressSnapshot(byte[] input, int size){
|
||||||
byte[] result = new byte[size];
|
byte[] result = new byte[size];
|
||||||
@@ -170,7 +183,7 @@ public class KryoClient implements ClientProvider{
|
|||||||
|
|
||||||
socket.setSoTimeout(2000);
|
socket.setSoTimeout(2000);
|
||||||
|
|
||||||
addresses.clear();
|
lastCallback = valid;
|
||||||
|
|
||||||
DatagramPacket packet = handler.onRequestNewDatagramPacket();
|
DatagramPacket packet = handler.onRequestNewDatagramPacket();
|
||||||
|
|
||||||
@@ -187,23 +200,12 @@ public class KryoClient implements ClientProvider{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void discover(Consumer<Array<Host>> callback){
|
public void discover(Consumer<Host> callback, Runnable done){
|
||||||
runAsync(() -> {
|
runAsync(() -> {
|
||||||
addresses.clear();
|
foundAddresses.clear();
|
||||||
List<InetAddress> list = client.discoverHosts(port, 3000);
|
lastCallback = callback;
|
||||||
ObjectSet<String> hostnames = new ObjectSet<>();
|
client.discoverHosts(port, 3000);
|
||||||
Array<Host> result = new Array<>();
|
Gdx.app.postRunnable(done);
|
||||||
|
|
||||||
for(InetAddress a : list){
|
|
||||||
if(!hostnames.contains(a.getHostName())) {
|
|
||||||
Host address = addresses.get(a);
|
|
||||||
if(address != null) result.add(address);
|
|
||||||
|
|
||||||
}
|
|
||||||
hostnames.add(a.getHostName());
|
|
||||||
}
|
|
||||||
|
|
||||||
Gdx.app.postRunnable(() -> callback.accept(result));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user