Better server discovery

This commit is contained in:
Anuken
2019-06-11 13:01:28 -04:00
parent 75a5bbdbb1
commit 16190aa878
3 changed files with 44 additions and 65 deletions
+4
View File
@@ -84,6 +84,10 @@ public class Vars{
}; };
/** default server port */ /** default server port */
public static final int port = 6567; public static final int port = 6567;
/** multicast discovery port.*/
public static final int multicastPort = 20151;
/** multicast group for discovery.*/
public static final String multicastGroup = "227.2.7.7";
/** if true, UI is not drawn */ /** if true, UI is not drawn */
public static boolean disableUI; public static boolean disableUI;
/** if true, game is set up in mobile mode, even on desktop. used for debugging */ /** if true, game is set up in mobile mode, even on desktop. used for debugging */
@@ -2,59 +2,28 @@ package io.anuke.mindustry.net;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.arc.function.Consumer; import io.anuke.arc.function.*;
import io.anuke.arc.net.*; import io.anuke.arc.net.*;
import io.anuke.arc.util.pooling.Pools; import io.anuke.arc.util.pooling.Pools;
import io.anuke.mindustry.net.Net.ClientProvider; import io.anuke.mindustry.net.Net.*;
import io.anuke.mindustry.net.Net.SendMode; import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.net.Packets.Connect; import net.jpountz.lz4.*;
import io.anuke.mindustry.net.Packets.Disconnect;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import java.io.IOException; import java.io.IOException;
import java.net.*; import java.net.*;
import java.nio.*; import java.nio.*;
import java.nio.channels.ClosedSelectorException; import java.nio.channels.ClosedSelectorException;
import static io.anuke.mindustry.Vars.netClient; import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.port;
public class ArcNetClient implements ClientProvider{ public class ArcNetClient implements ClientProvider{
final Client client; final Client client;
final Array<InetAddress> foundAddresses = new Array<>(); final Supplier<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[256], 256);
final ClientDiscoveryHandler handler;
final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
Consumer<Host> lastCallback;
public ArcNetClient(){ public ArcNetClient(){
handler = new ClientDiscoveryHandler(){
@Override
public DatagramPacket newDatagramPacket(){
return new DatagramPacket(new byte[256], 256);
}
@Override
public void discoveredHost(DatagramPacket datagramPacket){
ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData());
Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer);
for(InetAddress address : foundAddresses){
if(address.equals(datagramPacket.getAddress()) || (isLocal(address) && isLocal(datagramPacket.getAddress()))){
return;
}
}
Core.app.post(() -> lastCallback.accept(host));
foundAddresses.add(datagramPacket.getAddress());
}
@Override
public void finish(){
}
};
client = new Client(8192, 4096, new PacketSerializer()); client = new Client(8192, 4096, new PacketSerializer());
client.setDiscoveryHandler(handler); client.setDiscoveryPacket(packetSupplier);
NetListener listener = new NetListener(){ NetListener listener = new NetListener(){
@Override @Override
@@ -172,40 +141,43 @@ public class ArcNetClient implements ClientProvider{
@Override @Override
public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){ public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){
runAsync(() -> { runAsync(() -> {
synchronized(handler){ try{
try{ DatagramSocket socket = new DatagramSocket();
DatagramSocket socket = new DatagramSocket(); socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port));
socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port)); socket.setSoTimeout(2000);
socket.setSoTimeout(2000); DatagramPacket packet = packetSupplier.get();
socket.receive(packet);
lastCallback = valid; ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
DatagramPacket packet = handler.newDatagramPacket(); Core.app.post(() -> valid.accept(host));
}catch(Exception e){
socket.receive(packet); Core.app.post(() -> invalid.accept(e));
ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
Core.app.post(() -> valid.accept(host));
}catch(Exception e){
Core.app.post(() -> invalid.accept(e));
}
} }
}); });
} }
@Override @Override
public void discover(Consumer<Host> callback, Runnable done){ public void discover(Consumer<Host> callback, Runnable done){
runAsync(() -> { Array<InetAddress> foundAddresses = new Array<>();
synchronized(handler){ client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> {
foundAddresses.clear(); Core.app.post(() -> {
lastCallback = callback; try{
client.discoverHosts(port, 3000); if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){
Core.app.post(done); return;
} }
}); ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
callback.accept(host);
foundAddresses.add(packet.getAddress());
}catch(Exception e){
//don't crash when there's an error pinging a a server or parsing data
e.printStackTrace();
}
});
}, () -> Core.app.post(done));
} }
@Override @Override
@@ -19,6 +19,8 @@ import java.nio.channels.ClosedSelectorException;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import static io.anuke.mindustry.Vars.*;
public class ArcNetServer implements ServerProvider{ public class ArcNetServer implements ServerProvider{
final Server server; final Server server;
final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>();
@@ -31,10 +33,11 @@ public class ArcNetServer implements ServerProvider{
public ArcNetServer(){ public ArcNetServer(){
server = new Server(4096 * 2, 4096, new PacketSerializer()); server = new Server(4096 * 2, 4096, new PacketSerializer());
server.setDiscoveryHandler((datagramChannel, fromAddress) -> { server.setMulticast(multicastGroup, multicastPort);
server.setDiscoveryHandler((address, handler) -> {
ByteBuffer buffer = NetworkIO.writeServerData(); ByteBuffer buffer = NetworkIO.writeServerData();
buffer.position(0); buffer.position(0);
datagramChannel.send(buffer, fromAddress); handler.respond(buffer);
}); });
NetListener listener = new NetListener(){ NetListener listener = new NetListener(){