package seng302.gameServer; import java.time.LocalDateTime; import java.util.Observable; import seng302.client.ClientPacketParser; import seng302.models.Player; import seng302.models.stream.PacketBufferDelegate; import seng302.models.stream.packets.StreamPacket; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.PriorityBlockingQueue; import java.util.logging.Logger; /** * A class describing the overall server, which creates and collects server threads for each client * Created by wmu16 on 13/07/17. */ public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{ private static final int PORT = 4942; private static final Integer CLIENT_UPDATES_PER_SECOND = 5; private static final int LOG_LEVEL = 1; private Thread thread; private ServerSocket serverSocket = null; private ArrayList serverToClientThreads = new ArrayList<>(); public MainServerThread() { try { serverSocket = new ServerSocket(PORT); } catch (IOException e) { serverLog("IO error in server thread handler upon trying to make new server socket", 0); } thread = new Thread(this); thread.start(); } public void run() { ServerListenThread serverListenThread; HeartbeatThread heartbeatThread; serverListenThread = new ServerListenThread(serverSocket, this); heartbeatThread = new HeartbeatThread(this); heartbeatThread.start(); serverListenThread.start(); //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app. while (!thread.isInterrupted()) { try { Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND); } catch (InterruptedException e) { e.printStackTrace(); } if (GameState.getCurrentStage() == GameStages.PRE_RACE) { updateClients(); } //RACING if (GameState.getCurrentStage() == GameStages.RACING) { updateClients(); } //FINISHED else if (GameState.getCurrentStage() == GameStages.FINISHED) { } } // TODO: 14/07/17 wmu16 - Send out disconnect packet to clients try { serverSocket.close(); return; } catch (IOException e) { System.out.println("IO error in server thread handler upon closing socket"); } } public void updateClients() { for (ServerToClientThread serverToClientThread : serverToClientThreads) { serverToClientThread.updateClient(); } } static void serverLog(String message, int logLevel){ if(logLevel <= LOG_LEVEL){ System.out.println("[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message); } } /** * A client has tried to connect to the server * @param serverToClientThread The player that connected */ @Override public void clientConnected(ServerToClientThread serverToClientThread) { serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0); serverToClientThreads.add(serverToClientThread); this.addObserver(serverToClientThread); setChanged(); notifyObservers(); } /** * A player has left the game, remove the player from the GameState * @param player The player that left */ @Override public void clientDisconnected(Player player) { try { player.getSocket().close(); } catch (Exception e) { serverLog("Cannot disconnect the socket for the disconnected player.", 0); } serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0); GameState.removeYacht(player.getYacht().getSourceId()); GameState.removePlayer(player); for (ServerToClientThread serverToClientThread : serverToClientThreads) { if (serverToClientThread.getSocket() == player.getSocket()) { this.deleteObserver(serverToClientThread); } } setChanged(); notifyObservers(); } public void startGame() { Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run() { for (ServerToClientThread serverToClientThread : serverToClientThreads) { serverToClientThread.sendRaceStatusMessage(); } } }, 0, 500); } }