LobbyView now can change to RaceView upon race start packet received.

Added port number text field in start screen controller.
Created a client state.

#story[1055] #pair[hyi25, zyt10]
This commit is contained in:
Zhi You Tan
2017-07-21 16:14:45 +12:00
parent d37cbd263e
commit e891ed8a64
12 changed files with 157 additions and 47 deletions
@@ -36,8 +36,6 @@ public class ClientPacketParser {
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markLocations = new ConcurrentHashMap<>(); public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markLocations = new ConcurrentHashMap<>();
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatLocations = new ConcurrentHashMap<>(); public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatLocations = new ConcurrentHashMap<>();
private String threadName;
private Thread t;
private static boolean newRaceXmlReceived = false; private static boolean newRaceXmlReceived = false;
private static boolean raceStarted = false; private static boolean raceStarted = false;
private static XMLParser xmlObject; private static XMLParser xmlObject;
@@ -48,11 +46,10 @@ public class ClientPacketParser {
private static Map<Integer, Yacht> boatsPos = new ConcurrentSkipListMap<>(); private static Map<Integer, Yacht> boatsPos = new ConcurrentSkipListMap<>();
private static double windDirection = 0; private static double windDirection = 0;
private static Double windSpeed = 0d; private static Double windSpeed = 0d;
private static Long currentTimeLong; private static Long currentTimeLong;
private static String currentTimeString; private static String currentTimeString;
private static boolean appRunning; private static boolean appRunning;
//CONVERSION CONSTANTS //CONVERSION CONSTANTS
private static final Double MS_TO_KNOTS = 1.94384; private static final Double MS_TO_KNOTS = 1.94384;
@@ -121,7 +118,7 @@ public class ClientPacketParser {
*/ */
private static void extractHeartBeat(StreamPacket packet) { private static void extractHeartBeat(StreamPacket packet) {
long heartbeat = bytesToLong(packet.getPayload()); long heartbeat = bytesToLong(packet.getPayload());
System.out.println("heartbeat = " + heartbeat); System.out.println("[CLIENT] Received heartbeat = " + heartbeat);
} }
private static String getTimeZoneString() { private static String getTimeZoneString() {
@@ -200,6 +197,9 @@ public class ClientPacketParser {
Long estTimeAtFinish = bytesToLong( Long estTimeAtFinish = bytesToLong(
Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20))); Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20)));
boat.setEstimateTimeAtFinish(estTimeAtFinish); boat.setEstimateTimeAtFinish(estTimeAtFinish);
// FOR DEBUGGING:
// boatsPos.put(estTimeAtFinish, boat); // boatsPos.put(estTimeAtFinish, boat);
// String boatStatus = "SourceID: " + boatStatusSourceID; // String boatStatus = "SourceID: " + boatStatusSourceID;
// boatStatus += "\nBoat Status: " + (int)payload[28 + (i * 20)]; // boatStatus += "\nBoat Status: " + (int)payload[28 + (i * 20)];
@@ -0,0 +1,46 @@
package seng302.client;
import com.sun.org.apache.xpath.internal.operations.Bool;
/**
* Created by zyt10 on 21/07/17.
*/
public class ClientState {
private static String hostIp = "";
private static Boolean isHost = false;
private static Boolean raceStarted = false;
private static Boolean connectedToHost = false;
public static String getHostIp() {
return hostIp;
}
public static void setHostIp(String hostIp) {
ClientState.hostIp = hostIp;
}
public static Boolean isHost() {
return isHost;
}
public static void setHost(Boolean isHost) {
ClientState.isHost = isHost;
}
public static Boolean isRaceStarted() {
return raceStarted;
}
public static void setRaceStarted(Boolean raceStarted) {
ClientState.raceStarted = raceStarted;
}
public static Boolean isConnectedToHost() {
return connectedToHost;
}
public static void setConnectedToHost(Boolean connectedToHost) {
ClientState.connectedToHost = connectedToHost;
}
}
@@ -0,0 +1,28 @@
package seng302.client;
import java.util.List;
import java.util.Observable;
/**
* Created by zyt10 on 21/07/17.
*/
public class ClientStateQueryingRunnable extends Observable implements Runnable {
private Boolean terminate = false;
public ClientStateQueryingRunnable() {}
@Override
public void run() {
while(!terminate) {
if (ClientState.isRaceStarted() && ClientState.isConnectedToHost()) {
setChanged();
notifyObservers();
}
}
}
public void terminate() {
terminate = true;
}
}
@@ -5,6 +5,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
@@ -25,14 +26,10 @@ public class ClientToServerThread extends Thread {
private Boolean updateClient = true; private Boolean updateClient = true;
private ByteArrayOutputStream crcBuffer; private ByteArrayOutputStream crcBuffer;
public ClientToServerThread(String ipAddress, Integer portNumber){ public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{
try {
socket = new Socket(ipAddress, portNumber); socket = new Socket(ipAddress, portNumber);
is = socket.getInputStream(); is = socket.getInputStream();
os = socket.getOutputStream(); os = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
} }
@@ -46,7 +43,7 @@ public class ClientToServerThread extends Thread {
int sync1; int sync1;
int sync2; int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop // TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while(true) { while(ClientState.isConnectedToHost()) {
try { try {
//Perform a write if it is time to as delegated by the MainServerThread //Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) { if (updateClient) {
@@ -6,7 +6,10 @@ import java.net.InetAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.net.URL; import java.net.URL;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@@ -17,6 +20,7 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import seng302.client.ClientStateQueryingRunnable;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
@@ -24,7 +28,7 @@ import seng302.gameServer.GameState;
* A class describing the actions of the lobby screen * A class describing the actions of the lobby screen
* Created by wmu16 on 10/07/17. * Created by wmu16 on 10/07/17.
*/ */
public class LobbyController implements Initializable{ public class LobbyController implements Initializable, Observer{
@FXML @FXML
private ListView competitorsListView; private ListView competitorsListView;
@@ -34,6 +38,7 @@ public class LobbyController implements Initializable{
private Text lobbyIpText; private Text lobbyIpText;
private static ObservableList competitors; private static ObservableList competitors;
private ClientStateQueryingRunnable clientStateQueryingRunnable;
private void setContentPane(String jfxUrl) { private void setContentPane(String jfxUrl) {
try { try {
@@ -53,11 +58,27 @@ public class LobbyController implements Initializable{
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
lobbyIpText.setText("Lobby Host IP: " + getLocalHostIp()); lobbyIpText.setText("Lobby Host IP: " + getLocalHostIp());
}
public void initialize() {
competitors = FXCollections.observableArrayList(); competitors = FXCollections.observableArrayList();
competitorsListView.setItems(competitors); competitorsListView.setItems(competitors);
// set up client state query thread, so that when it receives the race-started packet
// it can switch to the race view
ClientStateQueryingRunnable clientStateQueryingRunnable = new ClientStateQueryingRunnable();
clientStateQueryingRunnable.addObserver(this);
Thread clientStateQueryingThread = new Thread(clientStateQueryingRunnable, "Client State querying thread");
clientStateQueryingThread.setDaemon(true);
clientStateQueryingThread.start();
}
@Override
public void update(Observable o, Object arg) {
Platform.runLater(new Runnable() {
@Override
public void run() {
switchToRaceView();
clientStateQueryingRunnable.terminate();
}
});
} }
private String getLocalHostIp() { private String getLocalHostIp() {
@@ -94,16 +115,16 @@ public class LobbyController implements Initializable{
public void leaveLobbyButtonPressed() { public void leaveLobbyButtonPressed() {
// TODO: 10/07/17 wmu16 - Finish function! // TODO: 10/07/17 wmu16 - Finish function!
setContentPane("/views/StartScreenView.fxml"); setContentPane("/views/StartScreenView.fxml");
System.out.println("Leaving lobby!");
GameState.setCurrentStage(GameStages.CANCELLED); GameState.setCurrentStage(GameStages.CANCELLED);
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game // TODO: 20/07/17 wmu16 - Implement some way of terminating the game
} }
@FXML @FXML
public void readyButtonPressed() { public void readyButtonPressed() {
GameState.setCurrentStage(GameStages.RACING); GameState.setCurrentStage(GameStages.RACING);
setContentPane("/views/RaceView.fxml"); }
private void switchToRaceView() {
setContentPane("/views/RaceView.fxml");
} }
} }
@@ -96,12 +96,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
startingBoats = new ArrayList<>(ClientPacketParser.getBoats().values()); startingBoats = new ArrayList<>(ClientPacketParser.getBoats().values());
includedCanvasController.setup(this); includedCanvasController.setup(this);
includedCanvasController.initializeCanvas(); // includedCanvasController.initializeCanvas();
initializeUpdateTimer(); initializeUpdateTimer();
initialiseFPSCheckBox(); initialiseFPSCheckBox();
initialiseAnnotationSlider(); initialiseAnnotationSlider();
initialiseBoatSelectionComboBox(); initialiseBoatSelectionComboBox();
includedCanvasController.timer.start(); // includedCanvasController.timer.start();
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
} }
@@ -283,7 +283,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
event -> { event -> {
updateRaceTime(); updateRaceTime();
updateWindDirection(); updateWindDirection();
updateOrder(); // updateOrder();
updateBoatSelectionComboBox(); updateBoatSelectionComboBox();
}) })
); );
@@ -2,10 +2,13 @@ package seng302.controllers;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import seng302.client.ClientState;
import seng302.client.ClientToServerThread; import seng302.client.ClientToServerThread;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
@@ -23,6 +26,8 @@ public class StartScreenController {
@FXML @FXML
private TextField ipTextField; private TextField ipTextField;
@FXML @FXML
private TextField portTextField;
@FXML
private GridPane startScreen2; private GridPane startScreen2;
private Controller controller; private Controller controller;
@@ -68,26 +73,32 @@ public class StartScreenController {
// new GameServerThread("Fuck you"); // new GameServerThread("Fuck you");
// get the lobby controller so that we can pass the game server thread to it // get the lobby controller so that we can pass the game server thread to it
setContentPane("/views/LobbyView.fxml"); setContentPane("/views/LobbyView.fxml");
} catch (Exception e) {
} catch (UnknownHostException e) { Alert alert = new Alert(AlertType.ERROR);
System.err.println("COULD NOT FIND YOUR IP ADDRESS!"); alert.setHeaderText("Cannot host");
alert.setContentText("Oops, failed to host, try to restart.");
alert.showAndWait();
e.printStackTrace(); e.printStackTrace();
} }
} }
@FXML @FXML
public void connectButtonPressed() { public void connectButtonPressed() {
// TODO: 10/07/17 wmu16 - Finish function // TODO: 10/07/17 wmu16 - Finish function
String ipAddress = ipTextField.getText().trim().toLowerCase();
try { try {
ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, 4950); String ipAddress = ipTextField.getText().trim().toLowerCase();
Integer port = Integer.valueOf(portTextField.getText().trim());
ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, port);
controller.setClientToServerThread(clientToServerThread); controller.setClientToServerThread(clientToServerThread);
clientToServerThread.start(); clientToServerThread.start();
ClientState.setConnectedToHost(true);
setContentPane("/views/LobbyView.fxml"); setContentPane("/views/LobbyView.fxml");
} catch (Exception e){ } catch (Exception e) {
e.printStackTrace(); Alert alert = new Alert(AlertType.ERROR);
alert.setHeaderText("Cannot reach the host");
alert.setContentText("Please check your host IP address.");
alert.showAndWait();
} }
} }
@@ -1,5 +1,6 @@
package seng302.gameServer; package seng302.gameServer;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -28,6 +29,7 @@ public class GameState {
public GameState(String hostIpAddress) { public GameState(String hostIpAddress) {
GameState.hostIpAddress = hostIpAddress; GameState.hostIpAddress = hostIpAddress;
players = new ArrayList<>(); players = new ArrayList<>();
yachts = new HashMap<>();
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
//set this when game stage changes to prerace //set this when game stage changes to prerace
@@ -32,7 +32,7 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl
try { try {
serverSocket = new ServerSocket(PORT); serverSocket = new ServerSocket(PORT);
} catch (IOException e) { } catch (IOException e) {
System.out.println("IO error in server thread handler upon trying to make new server socket"); serverLog("IO error in server thread handler upon trying to make new server socket", 0);
} }
packetBuffer = new PriorityBlockingQueue<>(); packetBuffer = new PriorityBlockingQueue<>();
@@ -73,7 +73,6 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl
updateClients(); updateClients();
while (!packetBuffer.isEmpty()){ while (!packetBuffer.isEmpty()){
System.out.println("WHATUPPP");
try { try {
StreamPacket packet = packetBuffer.take(); StreamPacket packet = packetBuffer.take();
ClientPacketParser.parsePacket(packet); ClientPacketParser.parsePacket(packet);
@@ -83,9 +82,6 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl
} }
} }
System.out.println("WHOOPSIES");
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients // TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
try { try {
serverSocket.close(); serverSocket.close();
@@ -111,7 +107,6 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl
@Override @Override
public boolean addToBuffer(StreamPacket streamPacket) { public boolean addToBuffer(StreamPacket streamPacket) {
System.out.println("HEY HI");
return packetBuffer.add(streamPacket); return packetBuffer.add(streamPacket);
} }
@@ -50,7 +50,7 @@ public class ServerToClientThread extends Thread {
GameState.addPlayer(new Player(socket)); GameState.addPlayer(new Player(socket));
Random rand = new Random(); Random rand = new Random();
sourceId = rand.nextInt(100000); sourceId = rand.nextInt(100000);
GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); // GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0));
} }
public void run() { public void run() {
@@ -58,14 +58,13 @@ public class ServerToClientThread extends Thread {
int sync2; int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop // TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while(true) { while(true) {
//System.out.print(".");
try { try {
//Perform a write if it is time to as delegated by the MainServerThread //Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) { if (updateClient) {
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream // TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Hello, it's me"); //ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Chatter message");
sendMessage(chatterMessage); //sendMessage(chatterMessage);
// try { // try {
// GameState.outputState(os); // GameState.outputState(os);
+2 -2
View File
@@ -55,9 +55,9 @@
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1"> <AnchorPane focusTraversable="true" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
<children> <children>
<ListView fx:id="competitorsListView" layoutX="154.0" layoutY="59.0" prefHeight="266.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> <ListView fx:id="competitorsListView" focusTraversable="false" layoutX="154.0" layoutY="59.0" prefHeight="266.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children> </children>
</AnchorPane> </AnchorPane>
</children> </children>
+16 -5
View File
@@ -15,8 +15,8 @@
<GridPane fx:id="startScreen2" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.StartScreenController"> <GridPane fx:id="startScreen2" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.StartScreenController">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="442.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="358.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
@@ -33,10 +33,13 @@
</font> </font>
</Label> </Label>
<Button mnemonicParsing="false" onAction="#hostButtonPressed" prefHeight="25.0" prefWidth="175.0" text="Host" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" /> <Button mnemonicParsing="false" onAction="#hostButtonPressed" prefHeight="25.0" prefWidth="175.0" text="Host" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<Button mnemonicParsing="false" onAction="#connectButtonPressed" prefHeight="25.0" prefWidth="147.0" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4" /> <Button mnemonicParsing="false" onAction="#connectButtonPressed" prefHeight="25.0" prefWidth="147.0" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4">
<TextField fx:id="ipTextField" maxWidth="-Infinity" prefHeight="25.0" prefWidth="200.0" text="localhost" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> <Insets left="5.0" right="5.0" />
</GridPane.margin></Button>
<TextField fx:id="ipTextField" alignment="CENTER" maxWidth="-Infinity" prefHeight="25.0" prefWidth="148.0" promptText="Host IP" text="127.0.0.1" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
</GridPane.margin> </GridPane.margin>
</TextField> </TextField>
<Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="OR" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="3"> <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="OR" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="3">
@@ -44,5 +47,13 @@
<Font size="21.0" /> <Font size="21.0" />
</font> </font>
</Text> </Text>
<TextField fx:id="portTextField" alignment="CENTER" maxWidth="75.0" prefHeight="25.0" prefWidth="55.0" promptText="Port" text="4950" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
<opaqueInsets>
<Insets />
</opaqueInsets>
<GridPane.margin>
<Insets left="5.0" right="5.0" />
</GridPane.margin>
</TextField>
</children> </children>
</GridPane> </GridPane>