Slight improvements to hosting.

Allow a host/client to disconnect and reconnect/make lobby, leave lobby and play the game.

#pair[kre39,hyi25] #story[1047]
This commit is contained in:
Kusal Ekanayake
2017-07-27 12:45:22 +12:00
parent 34704bd93d
commit 870dc07fd2
8 changed files with 64 additions and 28 deletions
+2
View File
@@ -7,6 +7,7 @@ import javafx.scene.Scene;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.stage.Stage; import javafx.stage.Stage;
import seng302.client.ClientPacketParser; import seng302.client.ClientPacketParser;
import seng302.client.ClientState;
import seng302.models.PolarTable; import seng302.models.PolarTable;
import seng302.models.stream.StreamReceiver; import seng302.models.stream.StreamReceiver;
@@ -31,6 +32,7 @@ public class App extends Application {
System.exit(0); System.exit(0);
}); });
ClientState.primaryStage = primaryStage;
} }
public static void main(String[] args) { public static void main(String[] args) {
@@ -2,6 +2,7 @@ package seng302.client;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javafx.stage.Stage;
import seng302.models.Yacht; import seng302.models.Yacht;
/** /**
@@ -17,6 +18,7 @@ public class ClientState {
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>(); private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
private static Boolean boatsUpdated = true; private static Boolean boatsUpdated = true;
private static String clientSourceId = ""; private static String clientSourceId = "";
public static Stage primaryStage;
public static String getHostIp() { public static String getHostIp() {
return hostIp; return hostIp;
@@ -10,6 +10,9 @@ import java.time.LocalDateTime;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; 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.models.stream.packets.StreamPacket;
import seng302.server.messages.BoatActionMessage; import seng302.server.messages.BoatActionMessage;
import seng302.server.messages.Message; import seng302.server.messages.Message;
@@ -42,7 +45,8 @@ public class ClientToServerThread implements Runnable {
* *
* @param ipAddress a string of ip address to be connected to * @param ipAddress a string of ip address to be connected to
* @param portNumber an integer port number * @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); socket = new Socket(ipAddress, portNumber);
@@ -73,7 +77,8 @@ public class ClientToServerThread implements Runnable {
*/ */
static void clientLog(String message, int logLevel) { static void clientLog(String message, int logLevel) {
if (logLevel <= LOG_LEVEL) { if (logLevel <= LOG_LEVEL) {
System.out.println("[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message); System.out.println(
"[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
} }
} }
@@ -111,6 +116,15 @@ public class ClientToServerThread implements Runnable {
} }
} catch (Exception e) { } catch (Exception e) {
closeSocket(); closeSocket();
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); clientLog("Disconnected from server", 1);
return; return;
} }
@@ -122,6 +136,7 @@ public class ClientToServerThread implements Runnable {
/** /**
* Listens for an allocated sourceID and returns it to the server * Listens for an allocated sourceID and returns it to the server
*
* @return the sourceID allocated to us by the server * @return the sourceID allocated to us by the server
*/ */
private Integer threeWayHandshake() { private Integer threeWayHandshake() {
@@ -146,7 +161,6 @@ public class ClientToServerThread implements Runnable {
} }
/** /**
* Send the post-start race course information * Send the post-start race course information
*/ */
@@ -10,6 +10,7 @@ import javafx.scene.Parent;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import seng302.client.ClientPacketParser; import seng302.client.ClientPacketParser;
import seng302.client.ClientState;
import seng302.client.ClientToServerThread; import seng302.client.ClientToServerThread;
import seng302.server.messages.BoatActionMessage; import seng302.server.messages.BoatActionMessage;
import seng302.server.messages.BoatActionType; import seng302.server.messages.BoatActionType;
@@ -22,7 +23,7 @@ public class Controller implements Initializable {
private long lastSendingTime; private long lastSendingTime;
private int KEY_STROKE_SENDING_FREQUENCY = 50; private int KEY_STROKE_SENDING_FREQUENCY = 50;
private Object setContentPane(String jfxUrl) { public Object setContentPane(String jfxUrl) {
try { try {
contentPane.getChildren().removeAll(); contentPane.getChildren().removeAll();
contentPane.getChildren().clear(); contentPane.getChildren().clear();
@@ -41,19 +42,25 @@ public class Controller implements Initializable {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { 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()); contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
StartScreenController startScreenController = (StartScreenController) setContentPane("/views/StartScreenView.fxml"); StartScreenController startScreenController = (StartScreenController) setContentPane("/views/StartScreenView.fxml");
startScreenController.setController(this); startScreenController.setController(this);
ClientPacketParser.boatLocations.clear(); ClientPacketParser.boatLocations.clear();
lastSendingTime = System.currentTimeMillis();
} }
/** Handle the key-pressed event from the text field. */ /** Handle the key-pressed event from the text field. */
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
BoatActionMessage boatActionMessage; BoatActionMessage boatActionMessage;
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY) { if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY && ClientState.isRaceStarted()) {
lastSendingTime = currentTime; lastSendingTime = currentTime;
switch (e.getCode()) { switch (e.getCode()) {
case SPACE: // align with vmg case SPACE: // align with vmg
@@ -85,10 +85,12 @@ public class LobbyController implements Initializable, Observer{
private Boolean switchedPane = false; private Boolean switchedPane = false;
private MainServerThread mainServerThread; private MainServerThread mainServerThread;
private Controller controller;
private void setContentPane(String jfxUrl) { private void setContentPane(String jfxUrl) {
try { try {
AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent(); AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent();
System.out.println(contentPane);
contentPane.getChildren().removeAll(); contentPane.getChildren().removeAll();
contentPane.getChildren().clear(); contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
@@ -200,11 +202,12 @@ public class LobbyController implements Initializable, Observer{
@FXML @FXML
public void leaveLobbyButtonPressed() { public void leaveLobbyButtonPressed() {
// TODO: 10/07/17 wmu16 - Finish function! if (ClientState.isHost()) {
setContentPane("/views/StartScreenView.fxml");
GameState.setCurrentStage(GameStages.CANCELLED); GameState.setCurrentStage(GameStages.CANCELLED);
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game mainServerThread.terminate();
}
ClientState.setConnectedToHost(false); ClientState.setConnectedToHost(false);
controller.setUpStartScreen();
} }
@FXML @FXML
@@ -224,4 +227,8 @@ public class LobbyController implements Initializable, Observer{
public void setMainServerThread(MainServerThread mainServerThread) { public void setMainServerThread(MainServerThread mainServerThread) {
this.mainServerThread = mainServerThread; this.mainServerThread = mainServerThread;
} }
public void setController(Controller controller) {
this.controller = controller;
}
} }
@@ -81,6 +81,7 @@ public class StartScreenController {
controller.setClientToServerThread(clientToServerThread); controller.setClientToServerThread(clientToServerThread);
LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml"); LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml");
lobbyController.setMainServerThread(mainServerThread); lobbyController.setMainServerThread(mainServerThread);
lobbyController.setController(controller);
} catch (Exception e) { } catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR); Alert alert = new Alert(AlertType.ERROR);
alert.setHeaderText("Cannot host"); alert.setHeaderText("Cannot host");
@@ -110,7 +111,8 @@ public class StartScreenController {
ClientState.setConnectedToHost(true); ClientState.setConnectedToHost(true);
controller.setClientToServerThread(clientToServerThread); controller.setClientToServerThread(clientToServerThread);
setContentPane("/views/LobbyView.fxml"); LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml");
lobbyController.setController(controller);
} catch (Exception e) { } catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR); Alert alert = new Alert(AlertType.ERROR);
alert.setHeaderText("Cannot reach the host"); alert.setHeaderText("Cannot reach the host");
@@ -33,10 +33,6 @@ public class GameState implements Runnable {
public GameState(String hostIpAddress) { public GameState(String hostIpAddress) {
windDirection = 180d; windDirection = 180d;
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>();
players = new ArrayList<>();
this.hostIpAddress = hostIpAddress; this.hostIpAddress = hostIpAddress;
players = new ArrayList<>(); players = new ArrayList<>();
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
@@ -25,6 +25,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer CLIENT_UPDATES_PER_SECOND = 10; private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
private static final int LOG_LEVEL = 1; private static final int LOG_LEVEL = 1;
private boolean terminated;
private Thread thread; 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); serverLog("IO error in server thread handler upon trying to make new server socket", 0);
} }
terminated = false;
thread = new Thread(this); thread = new Thread(this);
thread.start(); thread.start();
} }
@@ -54,7 +56,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
serverListenThread.start(); serverListenThread.start();
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app. //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 { try {
Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND); Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -148,4 +150,8 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
} }
}, 0, 500); }, 0, 500);
} }
public void terminate() {
terminated = true;
}
} }