package rts.core.network;
import java.io.IOException;
import java.util.ArrayList;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
import rts.core.engine.Player;
import rts.core.network.ig_tcp_container.CreateEntityState;
import rts.core.network.ig_tcp_container.DeleteAllEntityState;
import rts.core.network.ig_tcp_container.DeleteEntityState;
import rts.core.network.ig_udp_containers.EntitiesStatePacket;
import rts.core.network.ig_udp_containers.EntityState;
import rts.core.network.menu_tcp_containers.AllClientState;
import rts.core.network.menu_tcp_containers.CRMessageState;
import rts.core.network.menu_tcp_containers.ClientState;
import rts.core.network.menu_tcp_containers.LoadGameMessage;
import rts.core.network.menu_tcp_containers.MessageState;
import rts.core.network.menu_tcp_containers.ServerState;
import rts.core.network.menu_tcp_containers.SwitchToGameMessage;
import rts.utils.Configuration;
public class ServerManager {
private int networkIdPool;
private NetworkManager manager;
private Server server;
private ArrayList<ClientState> clients;
private ClientPosition[] position;
public ServerManager(NetworkManager manager) {
this.manager = manager;
this.server = new Server();
this.server.addListener(new ServerListener());
this.clients = new ArrayList<ClientState>();
this.position = new ClientPosition[8];
for (int i = 0; i < position.length; i++)
position[i] = new ClientPosition(i);
}
public void launch() throws IOException {
ClassRegister.register(server.getKryo());
server.start();
server.bind(Configuration.getTcpPort(), Configuration.getUdpPort());
}
public void launchGame() {
boolean allReady = true;
for (int i = 0; i < clients.size(); i++) {
if (!clients.get(i).isReady) {
MessageState ms = new MessageState();
ms.name = "[Server]";
ms.message = "Can't launch the game because " + clients.get(i).name + " is not ready...";
server.sendToAllTCP(ms);
allReady = false;
}
}
// Check not all in the same team
if (allReady) {
// On n'accepte plus d'autres joueurs
manager.getServerState().state = ServerState.IN_GAME;
refreshServerState();
// On demande aux joueurs de charger le jeu
LoadGameMessage lms = new LoadGameMessage();
lms.state = manager.getServerState();
server.sendToAllTCP(lms);
}
}
public void stop() {
server.stop();
}
public void refreshClientStates() {
AllClientState acs = new AllClientState();
acs.clientStates = clients;
server.sendToAllTCP(acs);
}
public void refreshServerState() {
// Check the logic of server state
manager.getServerState().update();
server.sendToAllTCP(manager.getServerState());
}
public void cancelPlayerReady(String reason) {
for (int i = 0; i < clients.size(); i++) {
clients.get(i).isReady = false;
}
CRMessageState crm = new CRMessageState();
crm.reason = reason;
server.sendToAllTCP(crm);
}
public int getNextId() {
if (networkIdPool + 1 == Integer.MAX_VALUE) {
networkIdPool = 0;
} else
networkIdPool++;
return networkIdPool;
}
private class ClientPosition {
private int connectionId;
private int position;
public ClientPosition(int position) {
connectionId = -1;
this.position = position;
}
}
private class ServerListener extends Listener {
@Override
public void connected(Connection connection) {
super.connected(connection);
manager.getServerState().nbPlayer++;
refreshServerState();
}
@Override
public void disconnected(Connection connection) {
super.disconnected(connection);
if (manager.isInGame()) {
for (int i = 0; i < clients.size(); i++) {
if (clients.get(i).connectionId == connection.getID()) {
DeleteAllEntityState dellAll = new DeleteAllEntityState();
dellAll.playerId = clients.get(i).position;
server.sendToAllTCP(dellAll);
MessageState ms = new MessageState();
ms.color = "";
ms.name = "[Server]";
ms.message = clients.get(i).name + " is gone !";
server.sendToAllTCP(ms);
clients.remove(i);
break;
}
}
} else {
manager.getServerState().nbPlayer--;
refreshServerState();
synchronized (clients) {
for (int i = 0; i < clients.size(); i++) {
if (clients.get(i).connectionId == connection.getID()) {
for (int j = 0; j < position.length; j++) {
if (position[j].connectionId == connection.getID()) {
position[j].connectionId = -1;
break;
}
}
clients.remove(i);
break;
}
}
}
refreshClientStates();
}
}
@Override
public void received(Connection connection, Object object) {
super.received(connection, object);
if (manager.isInGame()) {
receiveInGameMessage(connection, object);
} else {
if (object instanceof ClientState) {
ClientState cs = null;
for (int i = 0; i < clients.size(); i++) {
if (clients.get(i).connectionId == connection.getID()) {
cs = clients.get(i);
break;
}
}
if (cs != null) {
cs.transfer((ClientState) object);
// Check all load and ready to play
boolean allLoad = true;
for (int i = 0; i < clients.size(); i++) {
if (!clients.get(i).isLoad) {
allLoad = false;
break;
}
}
if (allLoad) {
// THE GAME IS LOAD AND LAUNCH
server.sendToAllTCP(new SwitchToGameMessage());
manager.setInGame(true);
if (manager.getMenuListener() != null) {
manager.getMenuListener().switchToGame();
}
} else {
refreshClientStates();
}
} else {
// First time client connected wait and send
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ClientState clientState = (ClientState) object;
int pos = 0;
for (int i = 0; i < position.length; i++) {
if (position[i].connectionId == -1) {
// find one
pos = position[i].position;
position[i].connectionId = clientState.connectionId;
break;
}
}
clientState.position = pos;
clients.add(clientState);
// Send infos about all client to client
refreshClientStates();
}
}
}
if (object instanceof MessageState) {
server.sendToAllExceptTCP(connection.getID(), object);
}
}
private void receiveInGameMessage(Connection connection, Object object) {
if (object instanceof Player || object instanceof EntitiesStatePacket) {
server.sendToAllExceptUDP(connection.getID(), object);
} else {
if (object instanceof CreateEntityState) {
CreateEntityState ces = (CreateEntityState) object;
ces.networkId = getNextId();
server.sendToAllTCP(ces);
} else {
if (object instanceof DeleteEntityState) {
server.sendToAllExceptTCP(connection.getID(), object);
} else {
if (object instanceof EntityState) {
server.sendToAllExceptTCP(connection.getID(), object);
}
}
}
}
}
}
}