package net.fourbytes.shadow.network;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
import net.fourbytes.shadow.Shadow;
import net.fourbytes.shadow.mod.ModManager;
import java.io.IOException;
/**
* This class is a server class for networking. It is using KryoNet as underlying implementation.
*/
public class KryoNetServer extends KryoNetStream {
public static int bufferWrite = bufferObject*512;
public Server server;
public ObjectMap<Connection, DataHandshake> connectionMap = new ObjectMap<Connection, DataHandshake>();
public Array<Connection> connections = new Array<Connection>(Connection.class);
public Array<DataHandshake> handshakes = new Array<DataHandshake>(DataHandshake.class);
public Array<String> blacklistNames = new Array<String>(String.class);
public Array<String> blacklistUUIDs = new Array<String>(String.class);
public Array<String> clientSessionIDs = new Array<String>(String.class);
public KryoNetServer() {
super();
server = new Server(bufferWrite, bufferObject);
register(server);
server.addListener(new Listener() {
@Override
public void connected(Connection con) {
KryoNetServer.this.connected(con);
//TODO Mod support
}
@Override
public void disconnected(Connection con) {
KryoNetServer.this.disconnected(con);
//TODO Mod support
}
@Override
public void received(Connection con, Object obj) {
if (!(obj instanceof Data)) {
return;
}
Entry entry = entries.getNext();
entry.key = con;
entry.value = obj;
queueHandle.add(entry);
//handled on main thread in #handle(...)
}
@Override
public void idle(Connection con) {
KryoNetServer.this.idle(con);
//TODO
}
});
}
@Override
public void handle(Data data, Object target) {
if (ModManager.handleServer(data, target)) {
return;
}
if (!(target instanceof Connection)) {
return;
}
Connection c = (Connection) target;
if (data instanceof DataHandshake) {
DataHandshake dh = (DataHandshake) data;
if (!Shadow.gameID.equals(dh.gameID)) {
System.out.println("S: "+dh.clientName+": KICK: version");
c.sendTCP(new DataKick("Version mismatch."));
c.close();
return;
}
if (blacklistNames.contains(dh.clientName, false)) {
System.out.println("S: "+dh.clientName+": KICK: blacklist (name)");
c.sendTCP(new DataKick("Nickname on blacklist."));
c.close();
return;
}
if (blacklistUUIDs.contains(dh.clientUUID, false)) {
System.out.println("S: "+dh.clientName+": KICK: blacklist (UUID)");
c.sendTCP(new DataKick("UUID on blacklist."));
c.close();
return;
}
if (clientSessionIDs.contains(dh.clientSessionID, false)) {
System.out.println("S: "+dh.clientName+": KICK: session");
c.sendTCP(new DataKick("Session ID already used."));
c.close();
return;
}
connectionMap.put(c, dh);
connections.add(c);
handshakes.add(dh);
clientSessionIDs.add(dh.clientSessionID);
server.sendToAllTCP(new DataConnected(dh.clientName, dh.clientName+" joined."));
if (Shadow.level instanceof ServerLevel) {
((ServerLevel)Shadow.level).send(c);
}
}
if (Shadow.level instanceof ServerLevel) {
((ServerLevel)Shadow.level).handle(data, c);
}
//TODO more
}
@Override
public void sendTCP(Data data, Object target) {
if (target != null) {
if (target instanceof Connection) {
((Connection)target).sendTCP(data);
return;
}
}
server.sendToAllTCP(data);
}
@Override
public void sendUDP(Data data, Object target) {
if (target != null) {
if (target instanceof Connection) {
((Connection)target).sendUDP(data);
return;
}
}
server.sendToAllUDP(data);
}
@Override
public void start() {
try {
server.bind(portTCP, portUDP);
} catch (IOException e) {
e.printStackTrace();
}
server.start();
}
@Override
public void connect(String ip) {
}
@Override
public void disconnect() {
server.stop();
}
@Override
public void connected(Connection con) {
//as for now nothing, still awaiting handshake
}
@Override
public void disconnected(Connection con) {
DataHandshake dh = connectionMap.get(con);
if (dh == null) {
return;
}
connectionMap.remove(con);
connections.removeValue(con, false);
handshakes.removeValue(dh, false);
clientSessionIDs.removeValue(dh.clientSessionID, false);
server.sendToAllTCP(new DataDisconnected(dh.clientName, dh.clientName+" left."));
}
@Override
public void idle(Connection con) {
}
}