diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 7069d719..c3b0e7ed 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -7,6 +7,7 @@ import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; import seng302.client.ClientPacketParser; +import seng302.client.ClientState; import seng302.models.PolarTable; import seng302.models.stream.StreamReceiver; @@ -31,6 +32,7 @@ public class App extends Application { System.exit(0); }); + ClientState.primaryStage = primaryStage; } public static void main(String[] args) { diff --git a/src/main/java/seng302/client/ClientState.java b/src/main/java/seng302/client/ClientState.java index 053bc56f..40656dbe 100644 --- a/src/main/java/seng302/client/ClientState.java +++ b/src/main/java/seng302/client/ClientState.java @@ -2,6 +2,7 @@ package seng302.client; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javafx.stage.Stage; import seng302.models.Yacht; /** @@ -17,6 +18,7 @@ public class ClientState { private static Map boats = new ConcurrentHashMap<>(); private static Boolean boatsUpdated = true; private static String clientSourceId = ""; + public static Stage primaryStage; public static String getHostIp() { return hostIp; diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index 92a755b2..27dbcd1f 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -10,6 +10,9 @@ import java.time.LocalDateTime; import java.util.zip.CRC32; import java.util.zip.Checksum; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; import seng302.models.stream.packets.StreamPacket; import seng302.server.messages.BoatActionMessage; import seng302.server.messages.Message; @@ -42,9 +45,10 @@ public class ClientToServerThread implements Runnable { * * @param ipAddress a string of ip address to be connected to * @param portNumber an integer port number - * @throws Exception SocketConnection if fail to connect to ip address and port number combination + * @throws Exception SocketConnection if fail to connect to ip address and port number + * combination */ - public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{ + public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception { socket = new Socket(ipAddress, portNumber); is = socket.getInputStream(); os = socket.getOutputStream(); @@ -71,9 +75,10 @@ public class ClientToServerThread implements Runnable { * @param message a string of message to be printed out * @param logLevel an int for log level */ - static void clientLog(String message, int logLevel){ - if(logLevel <= LOG_LEVEL){ - System.out.println("[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message); + static void clientLog(String message, int logLevel) { + if (logLevel <= LOG_LEVEL) { + System.out.println( + "[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message); } } @@ -85,13 +90,13 @@ public class ClientToServerThread implements Runnable { int sync1; int sync2; // TODO: 14/07/17 wmu16 - Work out how to fix this while loop - while(ClientState.isConnectedToHost()) { + while (ClientState.isConnectedToHost()) { try { crcBuffer = new ByteArrayOutputStream(); sync1 = readByte(); sync2 = readByte(); //checking if it is the start of the packet - if(sync1 == 0x47 && sync2 == 0x83) { + if (sync1 == 0x47 && sync2 == 0x83) { int type = readByte(); //No. of milliseconds since Jan 1st 1970 long timeStamp = Message.bytesToLong(getBytes(6)); @@ -111,7 +116,16 @@ public class ClientToServerThread implements Runnable { } } catch (Exception e) { closeSocket(); - clientLog("Disconnected from server", 1); + Platform.runLater(new Runnable() { + @Override + public void run() { + Alert alert = new Alert(AlertType.ERROR); + alert.setHeaderText("Host has disconnected"); + alert.setContentText("Cannot find Server"); + alert.showAndWait(); + } + }); + clientLog("Disconnected from server", 1); return; } } @@ -122,6 +136,7 @@ public class ClientToServerThread implements Runnable { /** * Listens for an allocated sourceID and returns it to the server + * * @return the sourceID allocated to us by the server */ private Integer threeWayHandshake() { @@ -146,7 +161,6 @@ public class ClientToServerThread implements Runnable { } - /** * Send the post-start race course information */ @@ -176,22 +190,22 @@ public class ClientToServerThread implements Runnable { } catch (IOException e) { clientLog("Read byte failed", 1); } - if (currentByte == -1){ + if (currentByte == -1) { throw new Exception(); } return currentByte; } - private byte[] getBytes(int n) throws Exception{ + private byte[] getBytes(int n) throws Exception { byte[] bytes = new byte[n]; - for (int i = 0; i < n; i++){ + for (int i = 0; i < n; i++) { bytes[i] = (byte) readByte(); } return bytes; } - private void skipBytes(long n) throws Exception{ - for (int i=0; i < n; i++){ + private void skipBytes(long n) throws Exception { + for (int i = 0; i < n; i++) { readByte(); } } diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 550f6f81..f1871192 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -10,6 +10,7 @@ import javafx.scene.Parent; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; import seng302.client.ClientPacketParser; +import seng302.client.ClientState; import seng302.client.ClientToServerThread; import seng302.server.messages.BoatActionMessage; import seng302.server.messages.BoatActionType; @@ -22,7 +23,7 @@ public class Controller implements Initializable { private long lastSendingTime; private int KEY_STROKE_SENDING_FREQUENCY = 50; - private Object setContentPane(String jfxUrl) { + public Object setContentPane(String jfxUrl) { try { contentPane.getChildren().removeAll(); contentPane.getChildren().clear(); @@ -41,19 +42,25 @@ public class Controller implements Initializable { @Override public void initialize(URL location, ResourceBundle resources) { + setUpStartScreen(); + lastSendingTime = System.currentTimeMillis(); + } + + void setUpStartScreen() { + contentPane.getChildren().removeAll(); + contentPane.getChildren().clear(); contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); StartScreenController startScreenController = (StartScreenController) setContentPane("/views/StartScreenView.fxml"); startScreenController.setController(this); ClientPacketParser.boatLocations.clear(); - - lastSendingTime = System.currentTimeMillis(); } + /** Handle the key-pressed event from the text field. */ public void keyPressed(KeyEvent e) { BoatActionMessage boatActionMessage; long currentTime = System.currentTimeMillis(); - if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY) { + if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY && ClientState.isRaceStarted()) { lastSendingTime = currentTime; switch (e.getCode()) { case SPACE: // align with vmg diff --git a/src/main/java/seng302/controllers/LobbyController.java b/src/main/java/seng302/controllers/LobbyController.java index b5f4f791..178f591a 100644 --- a/src/main/java/seng302/controllers/LobbyController.java +++ b/src/main/java/seng302/controllers/LobbyController.java @@ -85,10 +85,12 @@ public class LobbyController implements Initializable, Observer{ private Boolean switchedPane = false; private MainServerThread mainServerThread; + private Controller controller; private void setContentPane(String jfxUrl) { try { AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent(); + System.out.println(contentPane); contentPane.getChildren().removeAll(); contentPane.getChildren().clear(); contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); @@ -200,11 +202,12 @@ public class LobbyController implements Initializable, Observer{ @FXML public void leaveLobbyButtonPressed() { - // TODO: 10/07/17 wmu16 - Finish function! - setContentPane("/views/StartScreenView.fxml"); - GameState.setCurrentStage(GameStages.CANCELLED); - // TODO: 20/07/17 wmu16 - Implement some way of terminating the game + if (ClientState.isHost()) { + GameState.setCurrentStage(GameStages.CANCELLED); + mainServerThread.terminate(); + } ClientState.setConnectedToHost(false); + controller.setUpStartScreen(); } @FXML @@ -224,4 +227,8 @@ public class LobbyController implements Initializable, Observer{ public void setMainServerThread(MainServerThread mainServerThread) { this.mainServerThread = mainServerThread; } + + public void setController(Controller controller) { + this.controller = controller; + } } diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index b2503027..f5a9b102 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -81,6 +81,7 @@ public class StartScreenController { controller.setClientToServerThread(clientToServerThread); LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml"); lobbyController.setMainServerThread(mainServerThread); + lobbyController.setController(controller); } catch (Exception e) { Alert alert = new Alert(AlertType.ERROR); alert.setHeaderText("Cannot host"); @@ -110,7 +111,8 @@ public class StartScreenController { ClientState.setConnectedToHost(true); controller.setClientToServerThread(clientToServerThread); - setContentPane("/views/LobbyView.fxml"); + LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml"); + lobbyController.setController(controller); } catch (Exception e) { Alert alert = new Alert(AlertType.ERROR); alert.setHeaderText("Cannot reach the host"); diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index f4ec9c7c..9dba128c 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -33,10 +33,6 @@ public class GameState implements Runnable { public GameState(String hostIpAddress) { windDirection = 180d; windSpeed = 10000d; - yachts = new HashMap<>(); - players = new ArrayList<>(); - - this.hostIpAddress = hostIpAddress; players = new ArrayList<>(); currentStage = GameStages.LOBBYING; diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index f72b17fd..08688143 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -25,6 +25,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn private static final int PORT = 4942; private static final Integer CLIENT_UPDATES_PER_SECOND = 10; private static final int LOG_LEVEL = 1; + private boolean terminated; private Thread thread; @@ -38,6 +39,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn serverLog("IO error in server thread handler upon trying to make new server socket", 0); } + terminated = false; thread = new Thread(this); thread.start(); } @@ -54,7 +56,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn 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()) { + while (!terminated) { try { Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND); } catch (InterruptedException e) { @@ -148,4 +150,8 @@ public class MainServerThread extends Observable implements Runnable, ClientConn } }, 0, 500); } + + public void terminate() { + terminated = true; + } }