From af9f1417f1d4891542eeb0eb8c9e27e64beb6dfe Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 26 Jul 2017 16:01:41 +1200 Subject: [PATCH 1/3] Documented client packet parser, client state, client state querying runnable, client to server thread and replaced e.printStackTrace() with client log messages. --- .../seng302/client/ClientPacketParser.java | 17 ++++-- src/main/java/seng302/client/ClientState.java | 13 ++--- .../client/ClientStateQueryingRunnable.java | 13 ++++- .../seng302/client/ClientToServerThread.java | 55 +++++++++++-------- 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/main/java/seng302/client/ClientPacketParser.java b/src/main/java/seng302/client/ClientPacketParser.java index 4198dc55..578344fa 100644 --- a/src/main/java/seng302/client/ClientPacketParser.java +++ b/src/main/java/seng302/client/ClientPacketParser.java @@ -59,6 +59,7 @@ public class ClientPacketParser { */ public ClientPacketParser() { } + /** * Looks at the type of the packet then sends it to the appropriate parser to extract the * specific data associated with that packet type @@ -108,7 +109,7 @@ public class ClientPacketParser { } } catch (NullPointerException e) { System.out.println("Error parsing packet"); - e.printStackTrace(); +// e.printStackTrace(); } } @@ -185,7 +186,6 @@ public class ClientPacketParser { int noBoats = payload[22]; int raceType = payload[23]; - clientStateBoats = ClientState.getBoats(); for (int i = 0; i < noBoats; i++) { long boatStatusSourceID = bytesToLong( Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); @@ -206,7 +206,9 @@ public class ClientPacketParser { boat.setEstimateTimeAtNextMark(estTimeAtNextMark); boat.setEstimateTimeAtFinish(estTimeAtFinish); - Yacht clientBoat = clientStateBoats.get((int) boatStatusSourceID); + // Update Client State boats when receive race status packet. + // Potentially could replace boats in ClientPacketParser. + Yacht clientBoat = ClientState.getBoats().get((int) boatStatusSourceID); clientBoat.setBoatStatus((boatStatus)); setBoatLegPosition(clientBoat, boatLegNumber); clientBoat.setPenaltiesAwarded(boatPenaltyAwarded); @@ -215,9 +217,12 @@ public class ClientPacketParser { clientBoat.setEstimateTimeAtFinish(estTimeAtFinish); } - // 3 is race started + // 3 is race started. + // ClientState race started flag will be set to true if race started, else set false. if (raceStatus == 3) { ClientState.setRaceStarted(true); + } else { + ClientState.setRaceStarted(false); } } @@ -286,8 +291,10 @@ public class ClientPacketParser { xmlObject.constructXML(doc, messageType); if (messageType == 7) { //7 is the boat XML boats = xmlObject.getBoatXML().getCompetingBoats(); + // Set/Update the ClientState boats after receiving new boat xml. + // Flag boatsUpdated in ClientState to true. ClientState.setBoats(xmlObject.getBoatXML().getCompetingBoats()); - ClientState.setDirtyState(true); + ClientState.setBoatsUpdated(true); } if (messageType == 6) { //6 is race info xml newRaceXmlReceived = true; diff --git a/src/main/java/seng302/client/ClientState.java b/src/main/java/seng302/client/ClientState.java index 64512a1b..c96be561 100644 --- a/src/main/java/seng302/client/ClientState.java +++ b/src/main/java/seng302/client/ClientState.java @@ -1,8 +1,5 @@ package seng302.client; -import com.sun.org.apache.xpath.internal.operations.Bool; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import seng302.models.Yacht; @@ -17,7 +14,7 @@ public class ClientState { private static Boolean raceStarted = false; private static Boolean connectedToHost = false; private static Map boats = new ConcurrentHashMap<>(); - private static Boolean dirtyState = true; + private static Boolean boatsUpdated = true; private static String clientSourceId = ""; public static String getHostIp() { @@ -56,12 +53,12 @@ public class ClientState { return boats; } - public static Boolean isDirtyState() { - return dirtyState; + public static Boolean isBoatsUpdated() { + return boatsUpdated; } - public static void setDirtyState(Boolean dirtyState) { - ClientState.dirtyState = dirtyState; + public static void setBoatsUpdated(Boolean boatsUpdated) { + ClientState.boatsUpdated = boatsUpdated; } public static String getClientSourceId() { diff --git a/src/main/java/seng302/client/ClientStateQueryingRunnable.java b/src/main/java/seng302/client/ClientStateQueryingRunnable.java index 67cf1dbf..576d7b24 100644 --- a/src/main/java/seng302/client/ClientStateQueryingRunnable.java +++ b/src/main/java/seng302/client/ClientStateQueryingRunnable.java @@ -12,6 +12,10 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable public ClientStateQueryingRunnable() {} + /** + * Notifies observers "game started" if ClientState raceStarted flag is true and terminates itself. + * Notifies observers "update players" if ClientState boatsUpdated flag is true and resets the flag to false; + */ @Override public void run() { while(!terminate) { @@ -29,14 +33,19 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable terminate(); } - if (ClientState.isDirtyState()) { + if (ClientState.isBoatsUpdated()) { setChanged(); notifyObservers("update players"); - ClientState.setDirtyState(false); + ClientState.setBoatsUpdated(false); } } } + /** + * Used to terminate the thread. + * + * Currently called by the main while loop when game started is detected. + */ public void terminate() { terminate = true; } diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index 1e76bd07..1a8156b7 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -15,7 +15,8 @@ import seng302.server.messages.BoatActionMessage; import seng302.server.messages.Message; /** - * Created by kre39 on 13/07/17. + * A class describing a single connection to a Server for the purposes of sending and receiving on + * its own thread. */ public class ClientToServerThread implements Runnable { @@ -30,8 +31,19 @@ public class ClientToServerThread implements Runnable { private OutputStream os; private Boolean updateClient = true; - private ByteArrayOutputStream crcBuffer; + private ByteArrayOutputStream crcBuffer; + /** + * Constructor for ClientToServerThread which takes in ipAddress and portNumber and attempts to + * connect to the specified ipAddress and port. + * + * Upon successful socket connection, threeWayHandshake will be preformed and the instance will + * be put on a thread and run immediately. + * + * @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 + */ public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{ socket = new Socket(ipAddress, portNumber); is = socket.getInputStream(); @@ -40,7 +52,7 @@ public class ClientToServerThread implements Runnable { Integer allocatedID = threeWayHandshake(); if (allocatedID != null) { ourID = allocatedID; - clientLog("Successful handshake. Allocated ID: " + ourID, 1); + clientLog("Successful handshake. Allocated ID: " + ourID, 0); ClientState.setClientSourceId(String.valueOf(ourID)); } else { clientLog("Unsuccessful handshake", 1); @@ -50,31 +62,30 @@ public class ClientToServerThread implements Runnable { thread = new Thread(this); thread.start(); - } + /** + * Prints out log message and time happened. + * Only perform task if log level is below LOG_LEVEL variable. + * + * @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); } } + /** + * Perform the thread loop. Will exit loop if ClientState connected to host variable is false. + */ public void run() { int sync1; int sync2; // TODO: 14/07/17 wmu16 - Work out how to fix this while loop while(ClientState.isConnectedToHost()) { try { - //Perform a write if it is time to as delegated by the MainServerThread - if (updateClient) { - // TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream -// try { -// GameState.outputState(os); -// } catch (IOException e) { -// System.out.println("IO error in server thread upon writing to output stream"); -// } - updateClient = false; - } crcBuffer = new ByteArrayOutputStream(); sync1 = readByte(); sync2 = readByte(); @@ -101,7 +112,7 @@ public class ClientToServerThread implements Runnable { } } catch (Exception e) { closeSocket(); - e.printStackTrace(); + clientLog("Disconnected from server", 1); return; } } @@ -111,7 +122,7 @@ public class ClientToServerThread implements Runnable { /** - * Listens for an allocated sourceID and returns it to the server if recieved + * Listens for an allocated sourceID and returns it to the server if received * @return the sourceID allocated to us by the server */ private Integer threeWayHandshake() { @@ -120,14 +131,15 @@ public class ClientToServerThread implements Runnable { try { ourSourceID = is.read(); } catch (IOException e) { - e.printStackTrace(); + clientLog("Three way handshake failed", 1); + } if (ourSourceID != null) { try { os.write(ourSourceID); return ourSourceID; } catch (IOException e) { - e.printStackTrace(); + clientLog("Three way handshake failed", 1); return null; } } @@ -143,8 +155,7 @@ public class ClientToServerThread implements Runnable { try { os.write(boatActionMessage.getBuffer()); } catch (IOException e) { - clientLog("COULD NOT WRITE TO SERVER", 0); - e.printStackTrace(); + clientLog("Could not write to server", 1); } } @@ -153,7 +164,7 @@ public class ClientToServerThread implements Runnable { try { socket.close(); } catch (IOException e) { - clientLog("Failed to close the socket", 0); + clientLog("Failed to close the socket", 1); } } @@ -164,7 +175,7 @@ public class ClientToServerThread implements Runnable { currentByte = is.read(); crcBuffer.write(currentByte); } catch (IOException e) { - e.printStackTrace(); + clientLog("Read byte failed", 1); } if (currentByte == -1){ throw new Exception(); From 6e9535d78fb40a059ea93c7ec4d24e3469bf7183 Mon Sep 17 00:00:00 2001 From: Michael Rausch Date: Wed, 26 Jul 2017 19:35:59 +1200 Subject: [PATCH 2/3] Fixed race timer & Added boats to team position list - Race status messages are sent at regular intervals instead of once at race start - Boat positions are initialised on the Team Position list - Timer counts up from when host clicks ready Tags: #story[377] --- .../seng302/client/ClientPacketParser.java | 9 ++++++--- .../controllers/RaceViewController.java | 16 ++++++++++++++-- .../java/seng302/gameServer/GameState.java | 13 ++++++++++++- .../seng302/gameServer/MainServerThread.java | 17 ++++++++++++++--- .../gameServer/ServerToClientThread.java | 5 ++--- src/main/resources/views/RaceView.fxml | 18 +++++++++--------- 6 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/main/java/seng302/client/ClientPacketParser.java b/src/main/java/seng302/client/ClientPacketParser.java index 4198dc55..c6eb89a3 100644 --- a/src/main/java/seng302/client/ClientPacketParser.java +++ b/src/main/java/seng302/client/ClientPacketParser.java @@ -223,18 +223,21 @@ public class ClientPacketParser { private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){ Integer placing = 1; - if (leg != updatingBoat.getLegNumber() && (raceStarted || raceFinished)) { + + if (/* TODO implement when we are getting this data /TODO leg != updatingBoat.getLegNumber() && */(raceStarted || raceFinished)) { for (Yacht boat : boats.values()) { + placing = boat.getSourceId(); + /* See above to-do if (boat.getLegNumber() != null && leg <= boat.getLegNumber()){ placing += 1; - } + }*/ } updatingBoat.setPosition(placing.toString()); updatingBoat.setLegNumber(leg); boatsPos.putIfAbsent(placing, updatingBoat); boatsPos.replace(placing, updatingBoat); } else if(updatingBoat.getLegNumber() == null){ - updatingBoat.setPosition("1"); + updatingBoat.setPosition("-"); updatingBoat.setLegNumber(leg); } } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 436da210..9bbc0f06 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -287,6 +287,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel updateWindDirection(); // updateOrder(); updateBoatSelectionComboBox(); + updateOrder(); }) ); @@ -383,9 +384,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } if (ClientPacketParser.isRaceStarted()) { + /* for (Yacht boat : ClientPacketParser.getBoatsPos().values()) { - if (participantIDs.contains(boat.getSourceId())) { // check if the boat is racing - if (boat.getBoatStatus() == 3) { // 3 is finish status + System.out.println("Hi tjere" + boat.getBoatName()); + if (participantIDs.contains(boat.getSourceId()) || true + ) { // check if the boat is racing + if (boat.getBoatStatus() == 69) { // 3 is finish status Text textToAdd = new Text(boat.getPosition() + ". " + boat.getShortName() + " (Finished)"); textToAdd.setFill(Paint.valueOf("#d3d3d3")); @@ -397,9 +401,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setStyle(""); positionVbox.getChildren().add(textToAdd); + System.out.println("Adding " + textToAdd.getText()); } } } + */ + for (Yacht boat : ClientPacketParser.getBoats().values()){ + Text textToAdd = new Text(boat.getSourceId() + ". " + boat.getShortName() + " "); + textToAdd.setFill(Paint.valueOf("#d3d3d3")); + textToAdd.setStyle(""); + positionVbox.getChildren().add(textToAdd); + } } else { for (Yacht boat : ClientPacketParser.getBoats().values()) { if (participantIDs.contains(boat.getSourceId())) { // check if the boat is racing diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index abd46b51..ff92f6a5 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -25,7 +25,10 @@ public class GameState implements Runnable { private static Map yachts; private static Boolean isRaceStarted; private static GameStages currentStage; - + + private static long startTime = System.currentTimeMillis(); + + public GameState(String hostIpAddress) { windDirection = 170d; windSpeed = 10000d; @@ -79,9 +82,17 @@ public class GameState implements Runnable { } public static void setCurrentStage(GameStages currentStage) { + if (currentStage == GameStages.RACING){ + startTime = System.currentTimeMillis(); + } + GameState.currentStage = currentStage; } + public static long getStartTime(){ + return startTime; + } + public static Double getWindDirection() { return windDirection; } diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index a5021985..85d5c698 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -11,7 +11,10 @@ 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 @@ -133,8 +136,16 @@ public class MainServerThread extends Observable implements Runnable, ClientConn } public void startGame() { - for (ServerToClientThread serverToClientThread : serverToClientThreads) { - serverToClientThread.sendRaceStatusMessage(); - } + Timer t = new Timer(); + + t.schedule(new TimerTask() { + @Override + public void run() { + + for (ServerToClientThread serverToClientThread : serverToClientThreads) { + serverToClientThread.sendRaceStatusMessage(); + } + } + }, 0, 500); } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 6bb2b596..7411310d 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -340,8 +340,7 @@ public class ServerToClientThread implements Runnable, Observer { public void sendRaceStatusMessage() { // variables taken from GameServerThread - int TIME_TILL_RACE_START = 20 * 1000; - long startTime = System.currentTimeMillis() + TIME_TILL_RACE_START; + List boatSubMessages = new ArrayList<>(); BoatStatus boatStatus; @@ -369,7 +368,7 @@ public class ServerToClientThread implements Runnable, Observer { raceStatus = RaceStatus.WARNING; } - sendMessage(new RaceStatusMessage(1, raceStatus, startTime, GameState.getWindDirection(), + sendMessage(new RaceStatusMessage(1, raceStatus, GameState.getStartTime(), GameState.getWindDirection(), GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(), RaceType.MATCH_RACE, 1, boatSubMessages)); } diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index ea453f32..cbe3b2dd 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -20,12 +20,12 @@ -