From 6cae338c1e7d23c636bc15803ea61103a3a6793f Mon Sep 17 00:00:00 2001 From: Calum Date: Sun, 30 Jul 2017 20:12:19 +1200 Subject: [PATCH] Began fixing bugs with caused by asynchronous listener calls. #bug --- src/main/java/seng302/App.java | 8 +- .../seng302/client/ClientPacketParser.java | 1269 ++++++++--------- src/main/java/seng302/client/ClientState.java | 148 +- .../seng302/controllers/LobbyController.java | 470 +++--- .../java/seng302/gameServer/GameState.java | 9 +- .../seng302/gameServer/HeartbeatThread.java | 7 +- .../seng302/gameServer/MainServerThread.java | 13 +- .../gameServer/ServerToClientThread.java | 6 +- src/main/java/seng302/model/Corner.java | 2 - src/main/java/seng302/model/Yacht.java | 56 +- .../model/stream/PacketBufferDelegate.java | 7 - .../seng302/model/stream/StreamReceiver.java | 130 -- .../model/stream/parser/MarkRoundingData.java | 2 +- .../stream/parser/PositionUpdateData.java | 2 +- .../model/stream/parser/RaceStartData.java | 2 +- .../model/stream/parser/RaceStatusData.java | 6 +- .../model/stream/xml/parser/RaceXMLData.java | 2 +- .../stream/xml/parser/RegattaXMLData.java | 2 +- .../server/messages/BoatActionMessage.java | 4 - .../server/messages/BoatLocationMessage.java | 3 - .../java/seng302/server/messages/Header.java | 3 - .../seng302/server/messages/Heartbeat.java | 3 - .../server/messages/MarkRoundingMessage.java | 3 - .../java/seng302/server/messages/Message.java | 2 - .../messages/RaceStartStatusMessage.java | 3 - .../server/messages/RaceStatusMessage.java | 2 - .../seng302/server/messages/XMLMessage.java | 3 - .../seng302/server/simulator/Simulator.java | 7 +- .../server/simulator/parsers/BoatsParser.java | 1 - .../simulator/parsers/CourseParser.java | 9 +- .../server/simulator/parsers/FileParser.java | 9 +- .../server/simulator/parsers/RaceParser.java | 5 +- .../parser => utilities}/StreamParser.java | 22 +- .../generator => utilities}/XMLGenerator.java | 10 +- .../xml/parser => utilities}/XMLParser.java | 7 +- .../visualiser/ClientSocketListener.java | 11 - .../visualiser/ClientToServerThread.java | 91 +- .../java/seng302/visualiser/GameClient.java | 145 +- .../java/seng302/visualiser/GameView.java | 59 +- .../FinishScreenViewController.java | 1 - .../controllers/LobbyController.java | 26 +- .../controllers/RaceViewController.java | 27 +- .../controllers/StartScreenController.java | 10 +- .../ImportantAnnotationController.java | 5 +- .../visualiser/fxObjects/BoatObject.java | 61 +- .../{model => visualiser}/map/Boundary.java | 6 +- .../{model => visualiser}/map/CanvasMap.java | 13 +- .../map/MercatorProjection.java | 4 +- .../map/TestMapController.java | 7 +- .../resources/views/FinishScreenView.fxml | 16 +- src/main/resources/views/HostLobbyView.fxml | 12 +- src/main/resources/views/LobbyView.fxml | 16 +- src/main/resources/views/RaceView.fxml | 28 +- src/main/resources/views/StartScreenView.fxml | 16 +- src/main/resources/views/TestMapView.fxml | 9 +- .../views/importantAnnotationSelectView.fxml | 11 +- src/test/java/seng302/ColorsTest.java | 3 - src/test/java/seng302/TestGeoUtils.java | 5 +- src/test/java/seng302/TestRaceTimer.java | 3 - .../java/seng302/model/mark/MarkTest.java | 5 +- .../model/stream/StreamReceiverTest.java | 106 -- .../java/seng302/server/TestConversions.java | 4 +- src/test/java/seng302/server/TestHeader.java | 7 +- src/test/java/seng302/server/TestMessage.java | 14 +- .../server/simulator/GeoUtilityTest.java | 4 +- .../map/MercatorProjectionTest.java | 6 +- .../TestImportantAnnotationState.java | 4 +- 67 files changed, 1370 insertions(+), 1602 deletions(-) delete mode 100644 src/main/java/seng302/model/stream/PacketBufferDelegate.java delete mode 100644 src/main/java/seng302/model/stream/StreamReceiver.java rename src/main/java/seng302/{model/stream/parser => utilities}/StreamParser.java (96%) rename src/main/java/seng302/{model/stream/xml/generator => utilities}/XMLGenerator.java (94%) rename src/main/java/seng302/{model/stream/xml/parser => utilities}/XMLParser.java (98%) delete mode 100644 src/main/java/seng302/visualiser/ClientSocketListener.java rename src/main/java/seng302/{model => visualiser}/map/Boundary.java (84%) rename src/main/java/seng302/{model => visualiser}/map/CanvasMap.java (96%) rename src/main/java/seng302/{model => visualiser}/map/MercatorProjection.java (96%) rename src/main/java/seng302/{model => visualiser}/map/TestMapController.java (95%) delete mode 100644 src/test/java/seng302/model/stream/StreamReceiverTest.java rename src/test/java/seng302/{model => visualiser}/map/MercatorProjectionTest.java (95%) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 7eabf6cf..1b0a855c 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -17,7 +17,9 @@ public class App extends Application { Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml")); primaryStage.setTitle("RaceVision"); - primaryStage.setScene(new Scene(root, 1530, 960)); + Scene scene = new Scene(root, 1530, 960); + scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); + primaryStage.setScene(scene); // primaryStage.setMaxWidth(1530); // primaryStage.setMaxHeight(960); primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png"))); @@ -27,11 +29,11 @@ public class App extends Application { primaryStage.setOnCloseRequest(e -> { // ClientPacketParser.appClose(); StreamReceiver.noMoreBytes(); - ClientPacketParser.appClose(); +// ClientPacketParser.appClose(); System.exit(0); }); - ClientState.primaryStage = primaryStage; +// ClientState.primaryStage = primaryStage; } public static void main(String[] args) { diff --git a/src/main/java/seng302/client/ClientPacketParser.java b/src/main/java/seng302/client/ClientPacketParser.java index bf58c4a1..49811f44 100644 --- a/src/main/java/seng302/client/ClientPacketParser.java +++ b/src/main/java/seng302/client/ClientPacketParser.java @@ -1,638 +1,631 @@ -package seng302.client; - - -import java.io.IOException; -import java.io.StringReader; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Date; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.PriorityBlockingQueue; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import seng302.models.Yacht; -import seng302.models.mark.Mark; -import seng302.models.stream.XMLParser; -import seng302.models.stream.packets.BoatPositionPacket; -import seng302.models.stream.packets.StreamPacket; - -/** - * The purpose of this class is to take in the stream of divided packets so they can be read - * and parsed in by turning the byte arrays into useful data. There are two public static hashmaps - * that are threadsafe so the visualiser can always access the latest speed and position available - * Created by kre39 on 23/04/17. - */ -public class ClientPacketParser { - - public static ConcurrentHashMap> markLocations = new ConcurrentHashMap<>(); - public static ConcurrentHashMap> boatLocations = new ConcurrentHashMap<>(); - private static boolean newRaceXmlReceived = false; - private static boolean raceStarted = false; - private static XMLParser xmlObject = new XMLParser(); - private static boolean raceFinished = false; - private static boolean streamStatus = false; - private static long timeSinceStart = -1; - private static Map boats = new ConcurrentHashMap<>(); - private static Map boatsPos = new ConcurrentSkipListMap<>(); - private static double windDirection = 0; - private static Double windSpeed = 0d; - private static Long currentTimeLong; - private static String currentTimeString; - private static boolean appRunning; - private static Map clientStateBoats = new ConcurrentHashMap<>(); - - //CONVERSION CONSTANTS - public static final Double MS_TO_KNOTS = 1.94384; - - /** - * Used to initialise the thread name and stream parser object so a thread can be executed - */ - 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 - * - * @param packet the packet to be looked at and processed - */ - public static void parsePacket(StreamPacket packet) { - try { - switch (packet.getType()) { - case HEARTBEAT: - extractHeartBeat(packet); - break; - case RACE_STATUS: - extractRaceStatus(packet); - break; - case DISPLAY_TEXT_MESSAGE: - extractDisplayMessage(packet); - break; - case XML_MESSAGE: - extractXmlMessage(packet); - break; - case RACE_START_STATUS: - extractRaceStartStatus(packet); - break; - case YACHT_EVENT_CODE: - extractYachtEventCode(packet); - break; - case YACHT_ACTION_CODE: - extractYachtActionCode(packet); - break; - case CHATTER_TEXT: - extractChatterText(packet); - break; - case BOAT_LOCATION: - extractBoatLocation(packet); - break; - case MARK_ROUNDING: - extractMarkRounding(packet); - break; - case COURSE_WIND: - extractCourseWind(packet); - break; - case AVG_WIND: - extractAvgWind(packet); - break; - } - } catch (NullPointerException e) { - System.out.println("Error parsing packet"); - } - } - - /** - * Extracts the seq num used in the heartbeat packet - * - * @param packet Packet parsed in to use the payload - */ - private static void extractHeartBeat(StreamPacket packet) { - long heartbeat = bytesToLong(packet.getPayload()); - } - - private static String getTimeZoneString() { - - Integer offset = xmlObject.getRegattaXML().getUtcOffset(); - StringBuilder utcOffset = new StringBuilder(); - utcOffset.append("GMT"); - if (offset > 0) { - utcOffset.append("+"); - utcOffset.append(offset); - } else if (offset < 0) { - utcOffset.append("-"); - utcOffset.append(offset); - } - return utcOffset.toString(); - - } - - /** - * Extracts the useful race status data from race status type packets. This method will also - * print to the console the current state of the race (if it has started/finished or is about to - * start), along side this it'll also display the amount of time since the race has started or - * time till it starts - * - * @param packet Packet parsed in to use the payload - */ - private static void extractRaceStatus(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); - int raceStatus = payload[11]; - long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); - long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); - long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); - - currentTimeLong = currentTime; - DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); - if (xmlObject.getRegattaXML() != null) { - format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString())); - currentTimeString = format.format((new Date(currentTime)).getTime()); - } - long timeTillStart = - ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000; - - if (timeTillStart > 0) { - timeSinceStart = timeTillStart; - } else { - if (raceStatus == 4 || raceStatus == 8) { - raceFinished = true; - raceStarted = false; - ClientState.setRaceStarted(false); - } else if (!raceStarted) { - raceStarted = true; - ClientState.setRaceStarted(true); - raceFinished = false; - } - timeSinceStart = timeTillStart; - } - - double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc... - windDirection = windDir / windDirFactor; - windSpeed = rawWindSpeed / 1000 * MS_TO_KNOTS; - - int noBoats = payload[22]; - int raceType = payload[23]; - for (int i = 0; i < noBoats; i++) { - long boatStatusSourceID = bytesToLong( - Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); - int boatStatus = (int) payload[28 + (i * 20)]; - int boatLegNumber = (int) payload[29 + (i * 20)]; - int boatPenaltyAwarded = (int) payload[30 + (i * 20)]; - int boatPenaltyServed = (int) payload[31 + (i * 20)]; - long estTimeAtNextMark = bytesToLong( - Arrays.copyOfRange(payload, 32 + (i * 20), 38 + (i * 20))); - long estTimeAtFinish = bytesToLong( - Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20))); - - Yacht boat = boats.get((int) boatStatusSourceID); - boat.setBoatStatus((boatStatus)); - setBoatLegPosition(boat, boatLegNumber); - boat.setPenaltiesAwarded(boatPenaltyAwarded); - boat.setPenaltiesServed(boatPenaltyServed); - boat.setEstimateTimeAtNextMark(estTimeAtNextMark); - boat.setEstimateTimeAtFinish(estTimeAtFinish); - - // 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); - clientBoat.setPenaltiesServed(boatPenaltyServed); - clientBoat.setEstimateTimeAtNextMark(estTimeAtNextMark); - clientBoat.setEstimateTimeAtFinish(estTimeAtFinish); - } - - // 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); - } - } - - private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){ - Integer placing = 1; - - 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("-"); - updatingBoat.setLegNumber(leg); - } - } - - /** - * Used to extract the messages passed through with the display message packet - * - * @param packet Packet parsed in to use the payload - */ - private static void extractDisplayMessage(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - int numOfLines = payload[3]; - int totalLen = 0; - for (int i = 0; i < numOfLines; i++) { - int lineNum = payload[4 + totalLen]; - int textLength = payload[5 + totalLen]; - byte[] messageTextBytes = Arrays - .copyOfRange(payload, 6 + totalLen, 6 + textLength + totalLen); - String messageText = new String(messageTextBytes); - totalLen += 2 + textLength; - } - } - - /** - * Used to read in the xml data. Will call the specific methods to create the course and boats - * - * @param packet Packet parsed in to use the payload - */ - private static void extractXmlMessage(StreamPacket packet) { - xmlObject = new XMLParser(); - byte[] payload = packet.getPayload(); - int messageType = payload[9]; - long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); - String xmlMessage = new String( - (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); - - //Create XML document Object - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = null; - Document doc = null; - try { - db = dbf.newDocumentBuilder(); - doc = db.parse(new InputSource(new StringReader(xmlMessage))); - } catch (ParserConfigurationException | IOException | SAXException e) { - System.out.println("[ClientPacketParser] ParserConfigurationException | IOException | SAXException"); - } - - 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.setBoatsUpdated(true); - } - if (messageType == 6) { //6 is race info xml - newRaceXmlReceived = true; - } - } - - /** - * Extracts the race start status from the packet, currently is unused within the app but - * is here for potential future use - * - * @param packet Packet parsed in to use the payload - */ - private static void extractRaceStartStatus(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long raceStartTime = bytesToLong(Arrays.copyOfRange(payload, 9, 15)); - long raceId = bytesToLong(Arrays.copyOfRange(payload, 15, 19)); - int notificationType = payload[19]; - } - - /** - * When a yacht event occurs this will parse the byte array to retrieve the necessary info, - * currently unused - * - * @param packet Packet parsed in to use the payload - */ - private static void extractYachtEventCode(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); - long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21)); - int eventId = payload[21]; - } - - /** - * When a yacht action occurs this will parse the parse the byte array to retrieve the necessary - * info, currently unused - * - * @param packet Packet parsed in to use the payload - */ - private static void extractYachtActionCode(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); - long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); - int eventId = payload[17]; - } - - /** - * Strips the message from the chatter text type packets, currently the message is unused - * - * @param packet Packet parsed in to use the payload - */ - private static void extractChatterText(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - int messageType = payload[1]; - int length = payload[2]; - String message = new String(Arrays.copyOfRange(payload, 3, 3 + length)); - System.out.println(message); - } - - /** - * Used to breakdown the boatlocation packets so the boat coordinates, id and groundspeed are - * all used All the other extra data is still being read and translated however is unused. - * - * @param packet Packet parsed in to use the payload - */ - private static void extractBoatLocation(StreamPacket packet) { - byte[] payload = packet.getPayload(); - - int deviceType = (int) payload[15]; - long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long seq = bytesToLong(Arrays.copyOfRange(payload, 11, 15)); - long boatId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); - long rawLat = bytesToLong(Arrays.copyOfRange(payload, 16, 20)); - long rawLon = bytesToLong(Arrays.copyOfRange(payload, 20, 24)); - //Converts the double to a usable lat/lon - double lat = ((180d * (double) rawLat) / Math.pow(2, 31)); - double lon = ((180d * (double) rawLon) / Math.pow(2, 31)); -// System.out.println("[CLIENT] Lat: " + lat + " Lon: " + lon); - long heading = bytesToLong(Arrays.copyOfRange(payload, 28, 30)); - double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0; - //type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat - if (deviceType == 1){ - Yacht boat = boats.get((int) boatId); - boat.setVelocity(groundSpeed); - BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); - - //add a new priority que to the boatLocations HashMap - if (!boatLocations.containsKey(boatId)) { - boatLocations.put(boatId, - new PriorityBlockingQueue<>(256, new Comparator() { - @Override - public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { - return (int) (p1.getTimeValid() - p2.getTimeValid()); - } - })); - } - boatLocations.get(boatId).put(boatPacket); - } else if (deviceType == 3) { - BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, - heading, groundSpeed); - - //add a new priority que to the boatLocations HashMap - if (!markLocations.containsKey(boatId)) { - markLocations.put(boatId, - new PriorityBlockingQueue<>(256, new Comparator() { - @Override - public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { - return (int) (p1.getTimeValid() - p2.getTimeValid()); - } - })); - } - markLocations.get(boatId).put(markPacket); - } - } - - /** - * This packet type is received when a mark or gate is rounded by a boat - * - * @param packet The packet containing the payload - */ - private static void extractMarkRounding(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); - long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); - int boatStatus = payload[17]; - int roundingSide = payload[18]; - int markType = payload[19]; - int markId = payload[20]; - - // assign mark rounding time to boat - boats.get((int)subjectId).setMarkRoundingTime(timeStamp); - - for (Mark mark : xmlObject.getRaceXML().getAllCompoundMarks()) { - if (mark.getCompoundMarkID() == markId) { - boats.get((int)subjectId).setLastMarkRounded(mark); - } - } - } - - /** - * This packet type contains periodic data on the state of the wind - * - * @param packet The packet containing the payload - */ - private static void extractCourseWind(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - int selectedWindId = payload[1]; - int loopCount = payload[2]; - ArrayList windInfo = new ArrayList<>(); - for (int i = 0; i < loopCount; i++) { - String wind = "WindId: " + payload[3 + (20 * i)]; - wind += - "\nTime: " + bytesToLong(Arrays.copyOfRange(payload, 4 + (20 * i), 10 + (20 * i))); - wind += "\nRaceId: " + bytesToLong( - Arrays.copyOfRange(payload, 10 + (20 * i), 14 + (20 * i))); - wind += "\nWindDirection: " + bytesToLong( - Arrays.copyOfRange(payload, 14 + (20 * i), 16 + (20 * i))); - wind += "\nWindSpeed: " + bytesToLong( - Arrays.copyOfRange(payload, 16 + (20 * i), 18 + (20 * i))); - wind += "\nBestUpWindAngle: " + bytesToLong( - Arrays.copyOfRange(payload, 18 + (20 * i), 20 + (20 * i))); - wind += "\nBestDownWindAngle: " + bytesToLong( - Arrays.copyOfRange(payload, 20 + (20 * i), 22 + (20 * i))); - wind += "\nFlags: " + String - .format("%8s", Integer.toBinaryString(payload[22 + (20 * i)] & 0xFF)) - .replace(' ', '0'); - windInfo.add(wind); - } - } - - /** - * This packet conatins the average wind to ground speed - * - * @param packet The packet containing the paylaod - */ - private static void extractAvgWind(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); - long rawPeriod = bytesToLong(Arrays.copyOfRange(payload, 7, 9)); - long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload, 9, 11)); - long period2 = bytesToLong(Arrays.copyOfRange(payload, 11, 13)); - long speed2 = bytesToLong(Arrays.copyOfRange(payload, 13, 15)); - long period3 = bytesToLong(Arrays.copyOfRange(payload, 15, 17)); - long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19)); - long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21)); - long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23)); - } - - /** - * takes an array of up to 7 bytes and returns a positive - * long constructed from the input bytes - * - * @return a positive long if there is less than 7 bytes -1 otherwise - */ - private static long bytesToLong(byte[] bytes) { - long partialLong = 0; - int index = 0; - for (byte b : bytes) { - if (index > 6) { - return -1; - } - partialLong = partialLong | (b & 0xFFL) << (index * 8); - index++; - } - return partialLong; - } - - /** - * returns false if race not started, true otherwise - * - * @return race started status - */ - public static boolean isRaceStarted() { - return raceStarted; - } - - /** - * returns false if stream not connected, true otherwise - * - * @return stream started status - */ - public static boolean isStreamStatus() { - return streamStatus; - } - - /** - * returns race timer - * - * @return race timer in long - */ - public static long getTimeSinceStart() { - return timeSinceStart; - } - - /** - * return false if race not finished, true otherwise - * - * @return race finished status - */ - public static boolean isRaceFinished() { - return raceFinished; - } - - /** - * return a map of boats with sourceID and the boat - * - * @return map of boats - */ - public static Map getBoats() { - return boats; - } - - - /** - * returns the latest updated object from xml parser - * - * @return the latest xml object - */ - public static XMLParser getXmlObject() { - return xmlObject; - } - - /** - * returns the wind direction in degrees - * - * @return a double wind direction value - */ - public static double getWindDirection() { - return windDirection; - } - - - /** - * Returns the wind speed in knots - * @return A double indicating the wind speed in knots - */ - public static Double getWindSpeed() { - return windSpeed; - } - - /** - * returns stream time in formatted string format - * - * @return String of stream time - */ - public static String getCurrentTimeString() { - return currentTimeString; - } - - /** - * used in boat position since tree map can sort position efficiently. - * - * @return a map of time to finish and boat. - */ - public static Map getBoatsPos() { - - return boatsPos; - } - - /** - * returns current time in stream in long - * - * @return a long value of current time - */ - public static Long getCurrentTimeLong() { - return currentTimeLong; - } - - public static void appClose() { - appRunning = false; - } - - /** - * Used to check if a new un-processed xml has been found, if so will return true before - * toggling off so that the next check will return false. - * - * @return the status of if new xml has been received - */ - public static boolean isNewRaceXmlReceived() { - if (newRaceXmlReceived) { - newRaceXmlReceived = false; - return true; - } else { - return false; - } - } -} - +//package seng302.client; +// +// +//import java.io.IOException; +//import java.io.StringReader; +//import java.text.DateFormat; +//import java.text.SimpleDateFormat; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.Date; +//import java.util.TimeZone; +//import java.util.concurrent.ConcurrentHashMap; +//import java.util.concurrent.ConcurrentSkipListMap; +//import java.util.concurrent.PriorityBlockingQueue; +//import javax.xml.parsers.DocumentBuilder; +//import javax.xml.parsers.DocumentBuilderFactory; +//import javax.xml.parsers.ParserConfigurationException; +//import org.w3c.dom.Document; +//import org.xml.sax.InputSource; +//import org.xml.sax.SAXException; +// +///** +// * The purpose of this class is to take in the stream of divided packets so they can be read +// * and parsed in by turning the byte arrays into useful data. There are two public static hashmaps +// * that are threadsafe so the visualiser can always access the latest speed and position available +// * Created by kre39 on 23/04/17. +// */ +//public class ClientPacketParser { +// +// public static ConcurrentHashMap> markLocations = new ConcurrentHashMap<>(); +// public static ConcurrentHashMap> boatLocations = new ConcurrentHashMap<>(); +// private static boolean newRaceXmlReceived = false; +// private static boolean raceStarted = false; +// private static XMLParser xmlObject = new XMLParser(); +// private static boolean raceFinished = false; +// private static boolean streamStatus = false; +// private static long timeSinceStart = -1; +// private static Map boats = new ConcurrentHashMap<>(); +// private static Map boatsPos = new ConcurrentSkipListMap<>(); +// private static double windDirection = 0; +// private static Double windSpeed = 0d; +// private static Long currentTimeLong; +// private static String currentTimeString; +// private static boolean appRunning; +// private static Map clientStateBoats = new ConcurrentHashMap<>(); +// +// //CONVERSION CONSTANTS +// public static final Double MS_TO_KNOTS = 1.94384; +// +// /** +// * Used to initialise the thread name and stream parser object so a thread can be executed +// */ +// 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 +// * +// * @param packet the packet to be looked at and processed +// */ +// public static void parsePacket(StreamPacket packet) { +// try { +// switch (packet.getType()) { +// case HEARTBEAT: +// extractHeartBeat(packet); +// break; +// case RACE_STATUS: +// extractRaceStatus(packet); +// break; +// case DISPLAY_TEXT_MESSAGE: +// extractDisplayMessage(packet); +// break; +// case XML_MESSAGE: +// extractXmlMessage(packet); +// break; +// case RACE_START_STATUS: +// extractRaceStartStatus(packet); +// break; +// case YACHT_EVENT_CODE: +// extractYachtEventCode(packet); +// break; +// case YACHT_ACTION_CODE: +// extractYachtActionCode(packet); +// break; +// case CHATTER_TEXT: +// extractChatterText(packet); +// break; +// case BOAT_LOCATION: +// extractBoatLocation(packet); +// break; +// case MARK_ROUNDING: +// extractMarkRounding(packet); +// break; +// case COURSE_WIND: +// extractCourseWind(packet); +// break; +// case AVG_WIND: +// extractAvgWind(packet); +// break; +// } +// } catch (NullPointerException e) { +// System.out.println("Error parsing packet"); +// } +// } +// +// /** +// * Extracts the seq num used in the heartbeat packet +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractHeartBeat(StreamPacket packet) { +// long heartbeat = bytesToLong(packet.getPayload()); +// } +// +// private static String getTimeZoneString() { +// +// Integer offset = xmlObject.getRegattaXML().getUtcOffset(); +// StringBuilder utcOffset = new StringBuilder(); +// utcOffset.append("GMT"); +// if (offset > 0) { +// utcOffset.append("+"); +// utcOffset.append(offset); +// } else if (offset < 0) { +// utcOffset.append("-"); +// utcOffset.append(offset); +// } +// return utcOffset.toString(); +// +// } +// +// /** +// * Extracts the useful race status data from race status type packets. This method will also +// * print to the console the current state of the race (if it has started/finished or is about to +// * start), along side this it'll also display the amount of time since the race has started or +// * time till it starts +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractRaceStatus(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); +// int raceStatus = payload[11]; +// long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); +// long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); +// long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); +// +// currentTimeLong = currentTime; +// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); +// if (xmlObject.getRegattaXML() != null) { +// format.setTimeZone(TimeZone.getTimeZone(getTimeZoneString())); +// currentTimeString = format.format((new Date(currentTime)).getTime()); +// } +// long timeTillStart = +// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000; +// +// if (timeTillStart > 0) { +// timeSinceStart = timeTillStart; +// } else { +// if (raceStatus == 4 || raceStatus == 8) { +// raceFinished = true; +// raceStarted = false; +// ClientState.setRaceStarted(false); +// } else if (!raceStarted) { +// raceStarted = true; +// ClientState.setRaceStarted(true); +// raceFinished = false; +// } +// timeSinceStart = timeTillStart; +// } +// +// double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc... +// windDirection = windDir / windDirFactor; +// windSpeed = rawWindSpeed / 1000 * MS_TO_KNOTS; +// +// int noBoats = payload[22]; +// int raceType = payload[23]; +// for (int i = 0; i < noBoats; i++) { +// long boatStatusSourceID = bytesToLong( +// Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); +// int boatStatus = (int) payload[28 + (i * 20)]; +// int boatLegNumber = (int) payload[29 + (i * 20)]; +// int boatPenaltyAwarded = (int) payload[30 + (i * 20)]; +// int boatPenaltyServed = (int) payload[31 + (i * 20)]; +// long estTimeAtNextMark = bytesToLong( +// Arrays.copyOfRange(payload, 32 + (i * 20), 38 + (i * 20))); +// long estTimeAtFinish = bytesToLong( +// Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20))); +// +// Yacht boat = boats.get((int) boatStatusSourceID); +// boat.setBoatStatus((boatStatus)); +// setBoatLegPosition(boat, boatLegNumber); +// boat.setPenaltiesAwarded(boatPenaltyAwarded); +// boat.setPenaltiesServed(boatPenaltyServed); +// boat.setEstimateTimeAtNextMark(estTimeAtNextMark); +// boat.setEstimateTimeAtFinish(estTimeAtFinish); +// +// // 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); +// clientBoat.setPenaltiesServed(boatPenaltyServed); +// clientBoat.setEstimateTimeAtNextMark(estTimeAtNextMark); +// clientBoat.setEstimateTimeAtFinish(estTimeAtFinish); +// } +// +// // 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); +// } +// } +// +// private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){ +// Integer placing = 1; +// +// 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("-"); +// updatingBoat.setLegNumber(leg); +// } +// } +// +// /** +// * Used to extract the messages passed through with the display message packet +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractDisplayMessage(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// int numOfLines = payload[3]; +// int totalLen = 0; +// for (int i = 0; i < numOfLines; i++) { +// int lineNum = payload[4 + totalLen]; +// int textLength = payload[5 + totalLen]; +// byte[] messageTextBytes = Arrays +// .copyOfRange(payload, 6 + totalLen, 6 + textLength + totalLen); +// String messageText = new String(messageTextBytes); +// totalLen += 2 + textLength; +// } +// } +// +// /** +// * Used to read in the xml data. Will call the specific methods to create the course and boats +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractXmlMessage(StreamPacket packet) { +// xmlObject = new XMLParser(); +// byte[] payload = packet.getPayload(); +// int messageType = payload[9]; +// long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); +// String xmlMessage = new String( +// (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); +// +// //Create XML document Object +// DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); +// DocumentBuilder db = null; +// Document doc = null; +// try { +// db = dbf.newDocumentBuilder(); +// doc = db.parse(new InputSource(new StringReader(xmlMessage))); +// } catch (ParserConfigurationException | IOException | SAXException e) { +// System.out.println("[ClientPacketParser] ParserConfigurationException | IOException | SAXException"); +// } +// +// 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.setBoatsUpdated(true); +// } +// if (messageType == 6) { //6 is race info xml +// newRaceXmlReceived = true; +// } +// } +// +// /** +// * Extracts the race start status from the packet, currently is unused within the app but +// * is here for potential future use +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractRaceStartStatus(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long raceStartTime = bytesToLong(Arrays.copyOfRange(payload, 9, 15)); +// long raceId = bytesToLong(Arrays.copyOfRange(payload, 15, 19)); +// int notificationType = payload[19]; +// } +// +// /** +// * When a yacht event occurs this will parse the byte array to retrieve the necessary info, +// * currently unused +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractYachtEventCode(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); +// long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); +// long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21)); +// int eventId = payload[21]; +// } +// +// /** +// * When a yacht action occurs this will parse the parse the byte array to retrieve the necessary +// * info, currently unused +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractYachtActionCode(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); +// long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); +// int eventId = payload[17]; +// } +// +// /** +// * Strips the message from the chatter text type packets, currently the message is unused +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractChatterText(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// int messageType = payload[1]; +// int length = payload[2]; +// String message = new String(Arrays.copyOfRange(payload, 3, 3 + length)); +// System.out.println(message); +// } +// +// /** +// * Used to breakdown the boatlocation packets so the boat coordinates, id and groundspeed are +// * all used All the other extra data is still being read and translated however is unused. +// * +// * @param packet Packet parsed in to use the payload +// */ +// private static void extractBoatLocation(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// +// int deviceType = (int) payload[15]; +// long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long seq = bytesToLong(Arrays.copyOfRange(payload, 11, 15)); +// long boatId = bytesToLong(Arrays.copyOfRange(payload, 7, 11)); +// long rawLat = bytesToLong(Arrays.copyOfRange(payload, 16, 20)); +// long rawLon = bytesToLong(Arrays.copyOfRange(payload, 20, 24)); +// //Converts the double to a usable lat/lon +// double lat = ((180d * (double) rawLat) / Math.pow(2, 31)); +// double lon = ((180d * (double) rawLon) / Math.pow(2, 31)); +//// System.out.println("[CLIENT] Lat: " + lat + " Lon: " + lon); +// long heading = bytesToLong(Arrays.copyOfRange(payload, 28, 30)); +// double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0; +// //type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat +// if (deviceType == 1){ +// Yacht boat = boats.get((int) boatId); +// boat.setVelocity(groundSpeed); +// BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); +// +// //add a new priority que to the boatLocations HashMap +// if (!boatLocations.containsKey(boatId)) { +// boatLocations.put(boatId, +// new PriorityBlockingQueue<>(256, new Comparator() { +// @Override +// public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { +// return (int) (p1.getTimeValid() - p2.getTimeValid()); +// } +// })); +// } +// boatLocations.get(boatId).put(boatPacket); +// } else if (deviceType == 3) { +// BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, +// heading, groundSpeed); +// +// //add a new priority que to the boatLocations HashMap +// if (!markLocations.containsKey(boatId)) { +// markLocations.put(boatId, +// new PriorityBlockingQueue<>(256, new Comparator() { +// @Override +// public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { +// return (int) (p1.getTimeValid() - p2.getTimeValid()); +// } +// })); +// } +// markLocations.get(boatId).put(markPacket); +// } +// } +// +// /** +// * This packet type is received when a mark or gate is rounded by a boat +// * +// * @param packet The packet containing the payload +// */ +// private static void extractMarkRounding(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13)); +// long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17)); +// int boatStatus = payload[17]; +// int roundingSide = payload[18]; +// int markType = payload[19]; +// int markId = payload[20]; +// +// // assign mark rounding time to boat +// boats.get((int)subjectId).setMarkRoundingTime(timeStamp); +// +// for (Mark mark : xmlObject.getRaceXML().getAllCompoundMarks()) { +// if (mark.getCompoundMarkID() == markId) { +// boats.get((int)subjectId).setLastMarkRounded(mark); +// } +// } +// } +// +// /** +// * This packet type contains periodic data on the state of the wind +// * +// * @param packet The packet containing the payload +// */ +// private static void extractCourseWind(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// int selectedWindId = payload[1]; +// int loopCount = payload[2]; +// ArrayList windInfo = new ArrayList<>(); +// for (int i = 0; i < loopCount; i++) { +// String wind = "WindId: " + payload[3 + (20 * i)]; +// wind += +// "\nTime: " + bytesToLong(Arrays.copyOfRange(payload, 4 + (20 * i), 10 + (20 * i))); +// wind += "\nRaceId: " + bytesToLong( +// Arrays.copyOfRange(payload, 10 + (20 * i), 14 + (20 * i))); +// wind += "\nWindDirection: " + bytesToLong( +// Arrays.copyOfRange(payload, 14 + (20 * i), 16 + (20 * i))); +// wind += "\nWindSpeed: " + bytesToLong( +// Arrays.copyOfRange(payload, 16 + (20 * i), 18 + (20 * i))); +// wind += "\nBestUpWindAngle: " + bytesToLong( +// Arrays.copyOfRange(payload, 18 + (20 * i), 20 + (20 * i))); +// wind += "\nBestDownWindAngle: " + bytesToLong( +// Arrays.copyOfRange(payload, 20 + (20 * i), 22 + (20 * i))); +// wind += "\nFlags: " + String +// .format("%8s", Integer.toBinaryString(payload[22 + (20 * i)] & 0xFF)) +// .replace(' ', '0'); +// windInfo.add(wind); +// } +// } +// +// /** +// * This packet conatins the average wind to ground speed +// * +// * @param packet The packet containing the paylaod +// */ +// private static void extractAvgWind(StreamPacket packet) { +// byte[] payload = packet.getPayload(); +// int messageVersionNo = payload[0]; +// long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7)); +// long rawPeriod = bytesToLong(Arrays.copyOfRange(payload, 7, 9)); +// long rawSamplePeriod = bytesToLong(Arrays.copyOfRange(payload, 9, 11)); +// long period2 = bytesToLong(Arrays.copyOfRange(payload, 11, 13)); +// long speed2 = bytesToLong(Arrays.copyOfRange(payload, 13, 15)); +// long period3 = bytesToLong(Arrays.copyOfRange(payload, 15, 17)); +// long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19)); +// long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21)); +// long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23)); +// } +// +// /** +// * takes an array of up to 7 bytes and returns a positive +// * long constructed from the input bytes +// * +// * @return a positive long if there is less than 7 bytes -1 otherwise +// */ +// private static long bytesToLong(byte[] bytes) { +// long partialLong = 0; +// int index = 0; +// for (byte b : bytes) { +// if (index > 6) { +// return -1; +// } +// partialLong = partialLong | (b & 0xFFL) << (index * 8); +// index++; +// } +// return partialLong; +// } +// +// /** +// * returns false if race not started, true otherwise +// * +// * @return race started status +// */ +// public static boolean isRaceStarted() { +// return raceStarted; +// } +// +// /** +// * returns false if stream not connected, true otherwise +// * +// * @return stream started status +// */ +// public static boolean isStreamStatus() { +// return streamStatus; +// } +// +// /** +// * returns race timer +// * +// * @return race timer in long +// */ +// public static long getTimeSinceStart() { +// return timeSinceStart; +// } +// +// /** +// * return false if race not finished, true otherwise +// * +// * @return race finished status +// */ +// public static boolean isRaceFinished() { +// return raceFinished; +// } +// +// /** +// * return a map of boats with sourceID and the boat +// * +// * @return map of boats +// */ +// public static Map getBoats() { +// return boats; +// } +// +// +// /** +// * returns the latest updated object from xml parser +// * +// * @return the latest xml object +// */ +// public static XMLParser getXmlObject() { +// return xmlObject; +// } +// +// /** +// * returns the wind direction in degrees +// * +// * @return a double wind direction value +// */ +// public static double getWindDirection() { +// return windDirection; +// } +// +// +// /** +// * Returns the wind speed in knots +// * @return A double indicating the wind speed in knots +// */ +// public static Double getWindSpeed() { +// return windSpeed; +// } +// +// /** +// * returns stream time in formatted string format +// * +// * @return String of stream time +// */ +// public static String getCurrentTimeString() { +// return currentTimeString; +// } +// +// /** +// * used in boat position since tree map can sort position efficiently. +// * +// * @return a map of time to finish and boat. +// */ +// public static Map getBoatsPos() { +// +// return boatsPos; +// } +// +// /** +// * returns current time in stream in long +// * +// * @return a long value of current time +// */ +// public static Long getCurrentTimeLong() { +// return currentTimeLong; +// } +// +// public static void appClose() { +// appRunning = false; +// } +// +// /** +// * Used to check if a new un-processed xml has been found, if so will return true before +// * toggling off so that the next check will return false. +// * +// * @return the status of if new xml has been received +// */ +// public static boolean isNewRaceXmlReceived() { +// if (newRaceXmlReceived) { +// newRaceXmlReceived = false; +// return true; +// } else { +// return false; +// } +// } +//} +// diff --git a/src/main/java/seng302/client/ClientState.java b/src/main/java/seng302/client/ClientState.java index 1c7e7a0b..9d549526 100644 --- a/src/main/java/seng302/client/ClientState.java +++ b/src/main/java/seng302/client/ClientState.java @@ -1,77 +1,77 @@ -package seng302.client; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import seng302.model.Yacht; -import javafx.stage.Stage; -import seng302.models.Yacht; - -/** - * Used by the client to store static variables to be used in game. - */ -public class ClientState { - -// private static String hostIp = ""; -// private static Boolean isHost = false; -// private static Boolean raceStarted = false; -// private static Boolean connectedToHost = false; -// private static Map boats = new ConcurrentHashMap<>(); -// private static Boolean dirtyState = true; -// private static String clientSourceId = ""; +//package seng302.client; // -// public static String getHostIp() { -// return hostIp; -// } +//import java.util.Map; +//import java.util.concurrent.ConcurrentHashMap; +//import seng302.model.Yacht; +//import javafx.stage.Stage; +//import seng302.models.Yacht; // -// public static void setHostIp(String hostIp) { -// ClientState.hostIp = hostIp; -// } +///** +// * Used by the client to store static variables to be used in game. +// */ +//public class ClientState { // -// 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; -// } -// -// public static Map getBoats() { -// return boats; -// } -// -// public static Boolean isDirtyState() { -// return dirtyState; -// } -// -// public static void setDirtyState(Boolean dirtyState) { -// ClientState.dirtyState = dirtyState; -// } -// -// public static String getClientSourceId() { -// return clientSourceId; -// } -// -// public static void setClientSourceId(String clientSourceId) { -// ClientState.clientSourceId = clientSourceId; -// } -// -// public static void setBoats(Map boats) { -// ClientState.boats = boats; -// } -} +//// private static String hostIp = ""; +//// private static Boolean isHost = false; +//// private static Boolean raceStarted = false; +//// private static Boolean connectedToHost = false; +//// private static Map boats = new ConcurrentHashMap<>(); +//// private static Boolean dirtyState = true; +//// private static String clientSourceId = ""; +//// +//// 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; +//// } +//// +//// public static Map getBoats() { +//// return boats; +//// } +//// +//// public static Boolean isDirtyState() { +//// return dirtyState; +//// } +//// +//// public static void setDirtyState(Boolean dirtyState) { +//// ClientState.dirtyState = dirtyState; +//// } +//// +//// public static String getClientSourceId() { +//// return clientSourceId; +//// } +//// +//// public static void setClientSourceId(String clientSourceId) { +//// ClientState.clientSourceId = clientSourceId; +//// } +//// +//// public static void setBoats(Map boats) { +//// ClientState.boats = boats; +//// } +//} diff --git a/src/main/java/seng302/controllers/LobbyController.java b/src/main/java/seng302/controllers/LobbyController.java index b9d407fe..59fcc3db 100644 --- a/src/main/java/seng302/controllers/LobbyController.java +++ b/src/main/java/seng302/controllers/LobbyController.java @@ -1,235 +1,235 @@ -package seng302.controllers; - -import java.io.IOException; -import java.net.URL; -import java.util.*; - -import javafx.application.Platform; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Pane; -import javafx.scene.text.Text; -import seng302.client.ClientState; -import seng302.client.ClientStateQueryingRunnable; -import seng302.gameServer.GameStages; -import seng302.gameServer.GameState; -import seng302.gameServer.MainServerThread; - -/** - * A class describing the actions of the lobby screen - * Created by wmu16 on 10/07/17. - */ -public class LobbyController implements Initializable, Observer{ - @FXML - private GridPane lobbyScreen; - @FXML - private Text lobbyIpText; - @FXML - private Button readyButton; - @FXML - private ListView firstListView; - @FXML - private ListView secondListView; - @FXML - private ListView thirdListView; - @FXML - private ListView fourthListView; - @FXML - private ListView fifthListView; - @FXML - private ListView sixthListView; - @FXML - private ListView seventhListView; - @FXML - private ListView eighthListView; - @FXML - private ImageView firstImageView; - @FXML - private ImageView secondImageView; - @FXML - private ImageView thirdImageView; - @FXML - private ImageView fourthImageView; - @FXML - private ImageView fifthImageView; - @FXML - private ImageView sixthImageView; - @FXML - private ImageView seventhImageView; - @FXML - private ImageView eighthImageView; - - private static List> competitors = new ArrayList<>(); - private static ObservableList firstCompetitor = FXCollections.observableArrayList(); - private static ObservableList secondCompetitor = FXCollections.observableArrayList(); - private static ObservableList thirdCompetitor = FXCollections.observableArrayList(); - private static ObservableList fourthCompetitor = FXCollections.observableArrayList(); - private static ObservableList fifthCompetitor = FXCollections.observableArrayList(); - private static ObservableList sixthCompetitor = FXCollections.observableArrayList(); - private static ObservableList seventhCompetitor = FXCollections.observableArrayList(); - private static ObservableList eighthCompetitor = FXCollections.observableArrayList(); - private ClientStateQueryingRunnable clientStateQueryingRunnable; - private static List imageViews; - private static List listViews; - - private int MAX_NUM_PLAYERS = 8; - - private Boolean switchedPane = false; - private MainServerThread mainServerThread; - private Controller controller; - - private void setContentPane(String jfxUrl) { - try { - AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent(); - contentPane.getChildren().removeAll(); - contentPane.getChildren().clear(); - contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); - contentPane.getChildren() - .addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); - } catch (javafx.fxml.LoadException e) { - System.out.println("[Controller] FXML load exception"); - } catch (IOException e) { - System.out.println("[Controller] IO exception"); - } catch (NullPointerException e) { -// System.out.println("[Controller] Null Pointer Exception"); - } - } - - @Override - public void initialize(URL location, ResourceBundle resources) { - if (ClientState.isHost()) { - lobbyIpText.setText("Lobby Host IP: " + ClientState.getHostIp()); - readyButton.setDisable(false); - } - else { - lobbyIpText.setText("Connected to IP: " + ClientState.getHostIp()); - readyButton.setDisable(true); - } - - // put all javafx objects in lists, so we can iterate though conveniently - imageViews = new ArrayList<>(); - Collections.addAll(imageViews, firstImageView, secondImageView, thirdImageView, fourthImageView, - fifthImageView, sixthImageView, seventhImageView, eighthImageView); - listViews = new ArrayList<>(); - Collections.addAll(listViews, firstListView, secondListView, thirdListView, fourthListView, fifthListView, - sixthListView, seventhListView, eighthListView); - competitors = new ArrayList<>(); - Collections.addAll(competitors, firstCompetitor, secondCompetitor, thirdCompetitor, - fourthCompetitor, fifthCompetitor, sixthCompetitor, seventhCompetitor, eighthCompetitor); - - initialiseListView(); - initialiseImageView(); // parrot gif init - - // 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(); - } - - /** - * Observers "ClientStateQueryingRunnable". - * When the clients state has been marked to "race start", the querying thread - * will notify this lobby to change the view - * @param o - * @param arg - */ - @Override - public void update(Observable o, Object arg) { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (arg.equals("game started") && !switchedPane) { - switchToRaceView(); - } - if (arg.equals(("update players"))) { - initialiseListView(); - } - } - }); - } - - /** - * Reset all ListViews and ImageViews according to the current competitors - */ - private void initialiseListView() { - listViews.forEach(listView -> listView.getItems().clear()); - imageViews.forEach(gif -> gif.setVisible(false)); - competitors.forEach(ol -> ol.removeAll()); - - List ids = new ArrayList<>(ClientState.getBoats().keySet()); - for (int i = 0; i < ids.size(); i++) { - competitors.get(i).add(ClientState.getBoats().get(ids.get(i)).getBoatName()); - listViews.get(i).setItems(competitors.get(i)); - imageViews.get(i).setVisible(true); - } - } - - /** - * Loads preset images into imageViews - */ - private void initialiseImageView() { - for (int i = 0; i < MAX_NUM_PLAYERS; i++) { - imageViews.get(i).setImage(new Image(getClass().getResourceAsStream("/pics/sail.png"))); - } -// Image image1 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// firstImageView.setImage(image1); -// Image image2 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// secondImageView.setImage(image2); -// Image image3 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// thirdImageView.setImage(image3); -// Image image4 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// fourthImageView.setImage(image4); -// Image image5 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// fifthImageView.setImage(image5); -// Image image6 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// sixthImageView.setImage(image6); -// Image image7 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// seventhImageView.setImage(image7); -// Image image8 = new Image(getClass().getResourceAsStream("/pics/sail.png")); -// eighthImageView.setImage(image8); - } - - @FXML - public void leaveLobbyButtonPressed() { - if (ClientState.isHost()) { - GameState.setCurrentStage(GameStages.CANCELLED); - mainServerThread.terminate(); - } - ClientState.setConnectedToHost(false); - controller.setUpStartScreen(); - } - - @FXML - public void readyButtonPressed() { - GameState.setCurrentStage(GameStages.RACING); - mainServerThread.startGame(); - } - - - private void switchToRaceView() { - if (!switchedPane) { - switchedPane = true; - setContentPane("/views/RaceView.fxml"); - } - } - - public void setMainServerThread(MainServerThread mainServerThread) { - this.mainServerThread = mainServerThread; - } - - public void setController(Controller controller) { - this.controller = controller; - } -} +//package seng302.controllers; +// +//import java.io.IOException; +//import java.net.URL; +//import java.util.*; +// +//import javafx.application.Platform; +//import javafx.collections.FXCollections; +//import javafx.collections.ObservableList; +//import javafx.fxml.FXML; +//import javafx.fxml.FXMLLoader; +//import javafx.fxml.Initializable; +//import javafx.scene.control.Button; +//import javafx.scene.control.ListView; +//import javafx.scene.image.Image; +//import javafx.scene.image.ImageView; +//import javafx.scene.layout.AnchorPane; +//import javafx.scene.layout.GridPane; +//import javafx.scene.layout.Pane; +//import javafx.scene.text.Text; +//import seng302.client.ClientState; +//import seng302.client.ClientStateQueryingRunnable; +//import seng302.gameServer.GameStages; +//import seng302.gameServer.GameState; +//import seng302.gameServer.MainServerThread; +// +///** +// * A class describing the actions of the lobby screen +// * Created by wmu16 on 10/07/17. +// */ +//public class LobbyController implements Initializable, Observer{ +// @FXML +// private GridPane lobbyScreen; +// @FXML +// private Text lobbyIpText; +// @FXML +// private Button readyButton; +// @FXML +// private ListView firstListView; +// @FXML +// private ListView secondListView; +// @FXML +// private ListView thirdListView; +// @FXML +// private ListView fourthListView; +// @FXML +// private ListView fifthListView; +// @FXML +// private ListView sixthListView; +// @FXML +// private ListView seventhListView; +// @FXML +// private ListView eighthListView; +// @FXML +// private ImageView firstImageView; +// @FXML +// private ImageView secondImageView; +// @FXML +// private ImageView thirdImageView; +// @FXML +// private ImageView fourthImageView; +// @FXML +// private ImageView fifthImageView; +// @FXML +// private ImageView sixthImageView; +// @FXML +// private ImageView seventhImageView; +// @FXML +// private ImageView eighthImageView; +// +// private static List> competitors = new ArrayList<>(); +// private static ObservableList firstCompetitor = FXCollections.observableArrayList(); +// private static ObservableList secondCompetitor = FXCollections.observableArrayList(); +// private static ObservableList thirdCompetitor = FXCollections.observableArrayList(); +// private static ObservableList fourthCompetitor = FXCollections.observableArrayList(); +// private static ObservableList fifthCompetitor = FXCollections.observableArrayList(); +// private static ObservableList sixthCompetitor = FXCollections.observableArrayList(); +// private static ObservableList seventhCompetitor = FXCollections.observableArrayList(); +// private static ObservableList eighthCompetitor = FXCollections.observableArrayList(); +// private ClientStateQueryingRunnable clientStateQueryingRunnable; +// private static List imageViews; +// private static List listViews; +// +// private int MAX_NUM_PLAYERS = 8; +// +// private Boolean switchedPane = false; +// private MainServerThread mainServerThread; +// private Controller controller; +// +// private void setContentPane(String jfxUrl) { +// try { +// AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent(); +// contentPane.getChildren().removeAll(); +// contentPane.getChildren().clear(); +// contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); +// contentPane.getChildren() +// .addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); +// } catch (javafx.fxml.LoadException e) { +// System.out.println("[Controller] FXML load exception"); +// } catch (IOException e) { +// System.out.println("[Controller] IO exception"); +// } catch (NullPointerException e) { +//// System.out.println("[Controller] Null Pointer Exception"); +// } +// } +// +// @Override +// public void initialize(URL location, ResourceBundle resources) { +// if (ClientState.isHost()) { +// lobbyIpText.setText("Lobby Host IP: " + ClientState.getHostIp()); +// readyButton.setDisable(false); +// } +// else { +// lobbyIpText.setText("Connected to IP: " + ClientState.getHostIp()); +// readyButton.setDisable(true); +// } +// +// // put all javafx objects in lists, so we can iterate though conveniently +// imageViews = new ArrayList<>(); +// Collections.addAll(imageViews, firstImageView, secondImageView, thirdImageView, fourthImageView, +// fifthImageView, sixthImageView, seventhImageView, eighthImageView); +// listViews = new ArrayList<>(); +// Collections.addAll(listViews, firstListView, secondListView, thirdListView, fourthListView, fifthListView, +// sixthListView, seventhListView, eighthListView); +// competitors = new ArrayList<>(); +// Collections.addAll(competitors, firstCompetitor, secondCompetitor, thirdCompetitor, +// fourthCompetitor, fifthCompetitor, sixthCompetitor, seventhCompetitor, eighthCompetitor); +// +// initialiseListView(); +// initialiseImageView(); // parrot gif init +// +// // 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(); +// } +// +// /** +// * Observers "ClientStateQueryingRunnable". +// * When the clients state has been marked to "race start", the querying thread +// * will notify this lobby to change the view +// * @param o +// * @param arg +// */ +// @Override +// public void update(Observable o, Object arg) { +// Platform.runLater(new Runnable() { +// @Override +// public void run() { +// if (arg.equals("game started") && !switchedPane) { +// switchToRaceView(); +// } +// if (arg.equals(("update players"))) { +// initialiseListView(); +// } +// } +// }); +// } +// +// /** +// * Reset all ListViews and ImageViews according to the current competitors +// */ +// private void initialiseListView() { +// listViews.forEach(listView -> listView.getItems().clear()); +// imageViews.forEach(gif -> gif.setVisible(false)); +// competitors.forEach(ol -> ol.removeAll()); +// +// List ids = new ArrayList<>(ClientState.getBoats().keySet()); +// for (int i = 0; i < ids.size(); i++) { +// competitors.get(i).add(ClientState.getBoats().get(ids.get(i)).getBoatName()); +// listViews.get(i).setItems(competitors.get(i)); +// imageViews.get(i).setVisible(true); +// } +// } +// +// /** +// * Loads preset images into imageViews +// */ +// private void initialiseImageView() { +// for (int i = 0; i < MAX_NUM_PLAYERS; i++) { +// imageViews.get(i).setImage(new Image(getClass().getResourceAsStream("/pics/sail.png"))); +// } +//// Image image1 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// firstImageView.setImage(image1); +//// Image image2 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// secondImageView.setImage(image2); +//// Image image3 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// thirdImageView.setImage(image3); +//// Image image4 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// fourthImageView.setImage(image4); +//// Image image5 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// fifthImageView.setImage(image5); +//// Image image6 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// sixthImageView.setImage(image6); +//// Image image7 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// seventhImageView.setImage(image7); +//// Image image8 = new Image(getClass().getResourceAsStream("/pics/sail.png")); +//// eighthImageView.setImage(image8); +// } +// +// @FXML +// public void leaveLobbyButtonPressed() { +// if (ClientState.isHost()) { +// GameState.setCurrentStage(GameStages.CANCELLED); +// mainServerThread.terminate(); +// } +// ClientState.setConnectedToHost(false); +// controller.setUpStartScreen(); +// } +// +// @FXML +// public void readyButtonPressed() { +// GameState.setCurrentStage(GameStages.RACING); +// mainServerThread.startGame(); +// } +// +// +// private void switchToRaceView() { +// if (!switchedPane) { +// switchedPane = true; +// setContentPane("/views/RaceView.fxml"); +// } +// } +// +// public void setMainServerThread(MainServerThread mainServerThread) { +// this.mainServerThread = mainServerThread; +// } +// +// public void setController(Controller controller) { +// this.controller = controller; +// } +//} diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index f4fc81c6..07ceed2d 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,12 +1,13 @@ package seng302.gameServer; -import java.util.*; - +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import seng302.model.Player; import seng302.model.Yacht; -import seng302.model.stream.packets.StreamPacket; import seng302.server.messages.BoatActionType; /** @@ -26,6 +27,7 @@ public class GameState implements Runnable { private static Map yachts; private static Boolean isRaceStarted; private static GameStages currentStage; + private static long startTime; // TODO: 26/07/17 cir27 - Super hackish fix until something more permanent can be made. private static ObservableList observablePlayers = FXCollections.observableArrayList(); @@ -170,7 +172,6 @@ public class GameState implements Runnable { } } - /** * Generates a new ID based off the size of current players + 1 * @return a playerID to be allocated to a new connetion diff --git a/src/main/java/seng302/gameServer/HeartbeatThread.java b/src/main/java/seng302/gameServer/HeartbeatThread.java index 415d1e57..0c03e672 100644 --- a/src/main/java/seng302/gameServer/HeartbeatThread.java +++ b/src/main/java/seng302/gameServer/HeartbeatThread.java @@ -1,12 +1,13 @@ package seng302.gameServer; +import java.io.IOException; +import java.util.Stack; +import java.util.Timer; +import java.util.TimerTask; import seng302.model.Player; import seng302.server.messages.Heartbeat; import seng302.server.messages.Message; -import java.io.IOException; -import java.util.*; - /** * Send Heartbeat messages to connected player at a specified interval * Will call .clientDisconnected on the delegate when a heartbeat message diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 67c3bd13..6e827d95 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -1,20 +1,13 @@ 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.time.LocalDateTime; import java.util.ArrayList; +import java.util.Observable; import java.util.Timer; import java.util.TimerTask; -import java.util.concurrent.PriorityBlockingQueue; -import java.util.logging.Logger; +import seng302.model.Player; /** * A class describing the overall server, which creates and collects server threads for each client diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 14f82819..7a5d31d7 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -3,7 +3,6 @@ package seng302.gameServer; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -15,7 +14,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Observable; import java.util.Observer; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.zip.CRC32; @@ -26,13 +24,12 @@ import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Regatta; -import seng302.model.stream.xml.generator.XMLGenerator; +import seng302.utilities.XMLGenerator; import seng302.server.messages.BoatActionType; import seng302.server.messages.BoatLocationMessage; import seng302.server.messages.BoatStatus; import seng302.server.messages.BoatSubMessage; import seng302.server.messages.Message; - import seng302.server.messages.RaceStatus; import seng302.server.messages.RaceStatusMessage; import seng302.server.messages.RaceType; @@ -270,6 +267,7 @@ public class ServerToClientThread implements Runnable, Observer { currentByte = is.read(); crcBuffer.write(currentByte); } catch (IOException e) { + e.printStackTrace(); serverLog("Socket read failed", 1); } if (currentByte == -1) { diff --git a/src/main/java/seng302/model/Corner.java b/src/main/java/seng302/model/Corner.java index 8f2f147b..77d5eed4 100644 --- a/src/main/java/seng302/model/Corner.java +++ b/src/main/java/seng302/model/Corner.java @@ -1,7 +1,5 @@ package seng302.model; -import org.w3c.dom.Node; - /** * Stores the data for the cornering of a mark. */ diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index 6d15c386..23873787 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -1,22 +1,19 @@ package seng302.model; +import static seng302.utilities.GeoUtility.getGeoCoordinate; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongWrapper; -import javafx.scene.control.ListView; import javafx.scene.paint.Color; -import seng302.model.mark.Mark; -import static seng302.utilities.GeoUtility.getGeoCoordinate; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import javafx.scene.paint.Color; -import seng302.client.ClientPacketParser; -import seng302.controllers.RaceViewController; import seng302.gameServer.GameState; +import seng302.model.mark.Mark; import seng302.utilities.GeoPoint; /** @@ -32,6 +29,11 @@ public class Yacht { void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity); } + @FunctionalInterface + public interface YachtPositionListener { + void notifyPosition(int position); + } + //BOTH AFAIK private String boatType; private Integer sourceId; @@ -137,7 +139,7 @@ public class Yacht { Double windSpeedKnots = GameState.getWindSpeedKnots(); Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading); Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle); - Double maxBoatSpeed = boatSpeedInKnots / ClientPacketParser.MS_TO_KNOTS * 1000; + Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000; if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) { if (velocity < maxBoatSpeed) { @@ -159,30 +161,22 @@ public class Yacht { velocity = 0d; } } - if (sailIn) { - Double secondsElapsed = timeInterval / 1000000.0; - Double windSpeedKnots = GameState.getWindSpeedKnots(); - Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading); - Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle); - velocity = boatSpeedInKnots / 1.943844492 * 1000; // TODO: 26/07/17 cir27 - Remove magic number - Double metersCovered = velocity * secondsElapsed; - location = getGeoCoordinate(location, heading, metersCovered); - } else { - velocity = 0d; } - } - - } - +// if (sailIn) { +// Double secondsElapsed = timeInterval / 1000000.0; +// Double windSpeedKnots = GameState.getWindSpeedKnots(); +// Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading); +// Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle); +// velocity = boatSpeedInKnots / 1.943844492 * 1000; // TODO: 26/07/17 cir27 - Remove magic number +// Double metersCovered = velocity * secondsElapsed; +// location = getGeoCoordinate(location, heading, metersCovered); +// } else { +// velocity = 0d; +// } Double metersCovered = velocity * secondsElapsed; location = getGeoCoordinate(location, heading, metersCovered); } - - public Double getHeading() { - return heading; - } - public void adjustHeading(Double amount) { Double newVal = heading + amount; lastHeading = heading; @@ -501,4 +495,8 @@ public class Yacht { public void addLocationListener (YachtLocationListener listener) { locationListeners.add(listener); } + + public void addPositionListener (YachtPositionListener listener) { + + } } diff --git a/src/main/java/seng302/model/stream/PacketBufferDelegate.java b/src/main/java/seng302/model/stream/PacketBufferDelegate.java deleted file mode 100644 index 87c16d64..00000000 --- a/src/main/java/seng302/model/stream/PacketBufferDelegate.java +++ /dev/null @@ -1,7 +0,0 @@ -package seng302.model.stream; - -import seng302.model.stream.packets.StreamPacket; - -public interface PacketBufferDelegate { - boolean addToBuffer(StreamPacket streamPacket); -} diff --git a/src/main/java/seng302/model/stream/StreamReceiver.java b/src/main/java/seng302/model/stream/StreamReceiver.java deleted file mode 100644 index c0b84f4f..00000000 --- a/src/main/java/seng302/model/stream/StreamReceiver.java +++ /dev/null @@ -1,130 +0,0 @@ -package seng302.model.stream; - -import seng302.model.stream.packets.StreamPacket; - -import java.io.*; -import java.net.Socket; -import java.util.Comparator; -import java.util.concurrent.PriorityBlockingQueue; - - -public class StreamReceiver extends Thread { - private InputStream inputStream; - private OutputStream outputStream; - private Socket host; - private ByteArrayOutputStream crcBuffer; - private Thread t; - private String threadName; - public static PriorityBlockingQueue packetBuffer; - private static boolean moreBytes; - - public StreamReceiver(String hostAddress, int hostPort, String threadName) { - this.threadName = threadName; - this.setDaemon(true); - try { - host = new Socket(hostAddress, hostPort); - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - } - } - - public void run(){ - PriorityBlockingQueue pq = new PriorityBlockingQueue<>(256, new Comparator() { - @Override - public int compare(StreamPacket s1, StreamPacket s2) { - return (int) (s1.getTimeStamp() - s2.getTimeStamp()); - } - }); - packetBuffer = pq; - connect(); - } - - public void start () { - if (t == null) { - t = new Thread (this, threadName); - t.start (); - } - } - - - public StreamReceiver(Socket host, PriorityBlockingQueue packetBuffer){ - this.host=host; - this.packetBuffer = packetBuffer; - } - - - public void connect(){ - -// int sync1; -// int sync2; -// moreBytes = true; -// while(moreBytes) { -// try { -// crcBuffer = new ByteArrayOutputStream(); -// sync1 = readByte(); -// sync2 = readByte(); -// //checking if it is the start of the packet -// if(sync1 == 0x47 && sync2 == 0x83) { -// int type = readByte(); -// //No. of milliseconds since Jan 1st 1970 -// long timeStamp = bytesToLong(getBytes(6)); -// skipBytes(4); -// long payloadLength = bytesToLong(getBytes(2)); -// byte[] payload = getBytes((int) payloadLength); -// Checksum checksum = new CRC32(); -// checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size()); -// long computedCrc = checksum.getValue(); -// long packetCrc = bytesToLong(getBytes(4)); -// if (computedCrc == packetCrc) { -// packetBuffer.add(new StreamPacket(type, payloadLength, timeStamp, payload)); -// } else { -// System.err.println("Packet has been dropped"); -// } -// } -// } catch (Exception e) { -// moreBytes = false; -// } -// } - } - - private int readByte() throws Exception { - int currentByte = -1; - try { - currentByte = inputStream.read(); - crcBuffer.write(currentByte); - } catch (IOException e) { - e.printStackTrace(); - } - if (currentByte == -1){ - throw new Exception(); - } - return currentByte; - } - - private byte[] getBytes(int n) throws Exception{ - byte[] bytes = new byte[n]; - 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++){ - readByte(); - } - } - - public static void main(String[] args) { - - StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941,"TestThread1"); - //StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, "TestThread2"); - sr.start(); - - } - - public static void noMoreBytes(){ - moreBytes = false; - } -} diff --git a/src/main/java/seng302/model/stream/parser/MarkRoundingData.java b/src/main/java/seng302/model/stream/parser/MarkRoundingData.java index b784478c..70971317 100644 --- a/src/main/java/seng302/model/stream/parser/MarkRoundingData.java +++ b/src/main/java/seng302/model/stream/parser/MarkRoundingData.java @@ -11,7 +11,7 @@ public class MarkRoundingData { private int roundingSide; private long timeStamp; - MarkRoundingData(int boatId, int markId, int roundingSide, long timeStamp) { + public MarkRoundingData(int boatId, int markId, int roundingSide, long timeStamp) { this.boatId = boatId; this.markId = markId; this.roundingSide = roundingSide; diff --git a/src/main/java/seng302/model/stream/parser/PositionUpdateData.java b/src/main/java/seng302/model/stream/parser/PositionUpdateData.java index ec312a11..6f1af7c0 100644 --- a/src/main/java/seng302/model/stream/parser/PositionUpdateData.java +++ b/src/main/java/seng302/model/stream/parser/PositionUpdateData.java @@ -14,7 +14,7 @@ public class PositionUpdateData { private double heading; private double groundSpeed; - PositionUpdateData(int deviceId, DeviceType type, double lat, double lon, + public PositionUpdateData(int deviceId, DeviceType type, double lat, double lon, double heading, double groundSpeed) { this.deviceId = deviceId; this.type = type; diff --git a/src/main/java/seng302/model/stream/parser/RaceStartData.java b/src/main/java/seng302/model/stream/parser/RaceStartData.java index e3720c4b..0bd4d926 100644 --- a/src/main/java/seng302/model/stream/parser/RaceStartData.java +++ b/src/main/java/seng302/model/stream/parser/RaceStartData.java @@ -10,7 +10,7 @@ public class RaceStartData { private int notificationType; private long timeStamp; - RaceStartData (long raceId, long raceStartTime, int notificationType, long timeStamp) { + public RaceStartData (long raceId, long raceStartTime, int notificationType, long timeStamp) { this.raceId = raceId; this.raceStartTime = raceStartTime; this.notificationType = notificationType; diff --git a/src/main/java/seng302/model/stream/parser/RaceStatusData.java b/src/main/java/seng302/model/stream/parser/RaceStatusData.java index 7ad88a83..ba836442 100644 --- a/src/main/java/seng302/model/stream/parser/RaceStatusData.java +++ b/src/main/java/seng302/model/stream/parser/RaceStatusData.java @@ -19,7 +19,7 @@ public class RaceStatusData { private long expectedStartTime; private List boatData = new ArrayList<>(); - RaceStatusData( + public RaceStatusData( long windDir, long rawWindSpeed, int raceStatus, long currentTime, long expectedStartTime) { windDirection = windDir / WIND_DIR_FACTOR; @@ -29,8 +29,8 @@ public class RaceStatusData { this.expectedStartTime = expectedStartTime; } - void addBoatData (long boatID, long estTimeToNextMark, long estTimeToFinish, int leg) { - boatData.add(new long[] {boatID, estTimeToNextMark, estTimeToFinish, leg}); + public void addBoatData (long boatID, long estTimeToNextMark, long estTimeToFinish, int leg, int boatStatus) { + boatData.add(new long[] {boatID, estTimeToNextMark, estTimeToFinish, leg, boatStatus}); } public double getWindDirection() { diff --git a/src/main/java/seng302/model/stream/xml/parser/RaceXMLData.java b/src/main/java/seng302/model/stream/xml/parser/RaceXMLData.java index 3ccdcd55..02ba0686 100644 --- a/src/main/java/seng302/model/stream/xml/parser/RaceXMLData.java +++ b/src/main/java/seng302/model/stream/xml/parser/RaceXMLData.java @@ -18,7 +18,7 @@ public class RaceXMLData { private List courseLimit; private Map individualMarks; - RaceXMLData(List participants, List compoundMarks, List markSequence, + public RaceXMLData(List participants, List compoundMarks, List markSequence, List courseLimit) { this.participants = participants; this.markSequence = markSequence; diff --git a/src/main/java/seng302/model/stream/xml/parser/RegattaXMLData.java b/src/main/java/seng302/model/stream/xml/parser/RegattaXMLData.java index 9421f1b8..a4dc783d 100644 --- a/src/main/java/seng302/model/stream/xml/parser/RegattaXMLData.java +++ b/src/main/java/seng302/model/stream/xml/parser/RegattaXMLData.java @@ -12,7 +12,7 @@ public class RegattaXMLData { private Double centralLng; private Integer utcOffset; - RegattaXMLData (Integer regattaID, String regattaName, String courseName, + public RegattaXMLData (Integer regattaID, String regattaName, String courseName, Double centralLat, Double centralLng, Integer utcOffset) { this.regattaID = regattaID; this.regattaName = regattaName; diff --git a/src/main/java/seng302/server/messages/BoatActionMessage.java b/src/main/java/seng302/server/messages/BoatActionMessage.java index cf4ea918..398c175c 100644 --- a/src/main/java/seng302/server/messages/BoatActionMessage.java +++ b/src/main/java/seng302/server/messages/BoatActionMessage.java @@ -1,9 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; - /** * Created by kre39 on 12/07/17. */ diff --git a/src/main/java/seng302/server/messages/BoatLocationMessage.java b/src/main/java/seng302/server/messages/BoatLocationMessage.java index ec0a4c0e..caba5571 100644 --- a/src/main/java/seng302/server/messages/BoatLocationMessage.java +++ b/src/main/java/seng302/server/messages/BoatLocationMessage.java @@ -1,8 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; - public class BoatLocationMessage extends Message { private final int MESSAGE_SIZE = 56; diff --git a/src/main/java/seng302/server/messages/Header.java b/src/main/java/seng302/server/messages/Header.java index 2b520611..8d0601b4 100644 --- a/src/main/java/seng302/server/messages/Header.java +++ b/src/main/java/seng302/server/messages/Header.java @@ -1,9 +1,6 @@ package seng302.server.messages; -import java.math.BigInteger; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Collections; public class Header { // From API spec diff --git a/src/main/java/seng302/server/messages/Heartbeat.java b/src/main/java/seng302/server/messages/Heartbeat.java index c86baac3..7cc3f97d 100644 --- a/src/main/java/seng302/server/messages/Heartbeat.java +++ b/src/main/java/seng302/server/messages/Heartbeat.java @@ -1,8 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; - public class Heartbeat extends Message { private final int MESSAGE_SIZE = 4; diff --git a/src/main/java/seng302/server/messages/MarkRoundingMessage.java b/src/main/java/seng302/server/messages/MarkRoundingMessage.java index 5a085255..32b15d20 100644 --- a/src/main/java/seng302/server/messages/MarkRoundingMessage.java +++ b/src/main/java/seng302/server/messages/MarkRoundingMessage.java @@ -1,8 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; - public class MarkRoundingMessage extends Message{ private final long MESSAGE_VERSION_NUMBER = 1; private final int MESSAGE_SIZE = 21; diff --git a/src/main/java/seng302/server/messages/Message.java b/src/main/java/seng302/server/messages/Message.java index 398628ab..10afb8e5 100644 --- a/src/main/java/seng302/server/messages/Message.java +++ b/src/main/java/seng302/server/messages/Message.java @@ -1,7 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; diff --git a/src/main/java/seng302/server/messages/RaceStartStatusMessage.java b/src/main/java/seng302/server/messages/RaceStartStatusMessage.java index 24158d62..693cdfda 100644 --- a/src/main/java/seng302/server/messages/RaceStartStatusMessage.java +++ b/src/main/java/seng302/server/messages/RaceStartStatusMessage.java @@ -1,8 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; - public class RaceStartStatusMessage extends Message { private final int MESSAGE_SIZE = 20; diff --git a/src/main/java/seng302/server/messages/RaceStatusMessage.java b/src/main/java/seng302/server/messages/RaceStatusMessage.java index 0310216e..709b3ab5 100644 --- a/src/main/java/seng302/server/messages/RaceStatusMessage.java +++ b/src/main/java/seng302/server/messages/RaceStatusMessage.java @@ -1,7 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; import java.util.List; import java.util.zip.CRC32; diff --git a/src/main/java/seng302/server/messages/XMLMessage.java b/src/main/java/seng302/server/messages/XMLMessage.java index 57d10a00..365cada6 100644 --- a/src/main/java/seng302/server/messages/XMLMessage.java +++ b/src/main/java/seng302/server/messages/XMLMessage.java @@ -1,8 +1,5 @@ package seng302.server.messages; -import java.io.IOException; -import java.io.OutputStream; - public class XMLMessage extends Message{ private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE; private final int MESSAGE_VERSION = 1; //Always set to 1 diff --git a/src/main/java/seng302/server/simulator/Simulator.java b/src/main/java/seng302/server/simulator/Simulator.java index 363977c9..e0da9cf3 100644 --- a/src/main/java/seng302/server/simulator/Simulator.java +++ b/src/main/java/seng302/server/simulator/Simulator.java @@ -1,15 +1,14 @@ package seng302.server.simulator; +import java.util.List; +import java.util.Observable; +import java.util.concurrent.ThreadLocalRandom; import seng302.server.simulator.mark.Corner; import seng302.server.simulator.mark.Mark; import seng302.server.simulator.parsers.RaceParser; import seng302.utilities.GeoPoint; import seng302.utilities.GeoUtility; -import java.util.List; -import java.util.Observable; -import java.util.concurrent.ThreadLocalRandom; - public class Simulator extends Observable implements Runnable { private List course; diff --git a/src/main/java/seng302/server/simulator/parsers/BoatsParser.java b/src/main/java/seng302/server/simulator/parsers/BoatsParser.java index 5d552a00..81550ca9 100644 --- a/src/main/java/seng302/server/simulator/parsers/BoatsParser.java +++ b/src/main/java/seng302/server/simulator/parsers/BoatsParser.java @@ -1,7 +1,6 @@ package seng302.server.simulator.parsers; import org.w3c.dom.Document; -import org.w3c.dom.NodeList; /** diff --git a/src/main/java/seng302/server/simulator/parsers/CourseParser.java b/src/main/java/seng302/server/simulator/parsers/CourseParser.java index f7be46cd..40108983 100644 --- a/src/main/java/seng302/server/simulator/parsers/CourseParser.java +++ b/src/main/java/seng302/server/simulator/parsers/CourseParser.java @@ -1,5 +1,9 @@ package seng302.server.simulator.parsers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -9,11 +13,6 @@ import seng302.server.simulator.mark.Corner; import seng302.server.simulator.mark.Mark; import seng302.server.simulator.mark.RoundingType; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Parses the race xml file to get course details * Created by Haoming Yin (hyi25) on 16/3/2017 diff --git a/src/main/java/seng302/server/simulator/parsers/FileParser.java b/src/main/java/seng302/server/simulator/parsers/FileParser.java index d724e0bc..01e8d024 100644 --- a/src/main/java/seng302/server/simulator/parsers/FileParser.java +++ b/src/main/java/seng302/server/simulator/parsers/FileParser.java @@ -1,12 +1,11 @@ package seng302.server.simulator.parsers; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import java.io.InputStream; import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; /** * Created by Haoming Yin (hyi25) on 16/3/2017 diff --git a/src/main/java/seng302/server/simulator/parsers/RaceParser.java b/src/main/java/seng302/server/simulator/parsers/RaceParser.java index 14bf7bb8..e3fb7674 100644 --- a/src/main/java/seng302/server/simulator/parsers/RaceParser.java +++ b/src/main/java/seng302/server/simulator/parsers/RaceParser.java @@ -1,5 +1,7 @@ package seng302.server.simulator.parsers; +import java.util.ArrayList; +import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -7,9 +9,6 @@ import org.w3c.dom.NodeList; import seng302.server.simulator.Boat; import seng302.server.simulator.mark.Corner; -import java.util.ArrayList; -import java.util.List; - /** * Parses the race xml file to get course details * Created by Haoming Yin (hyi25) on 16/3/2017 diff --git a/src/main/java/seng302/model/stream/parser/StreamParser.java b/src/main/java/seng302/utilities/StreamParser.java similarity index 96% rename from src/main/java/seng302/model/stream/parser/StreamParser.java rename to src/main/java/seng302/utilities/StreamParser.java index bee184ed..e0619108 100644 --- a/src/main/java/seng302/model/stream/parser/StreamParser.java +++ b/src/main/java/seng302/utilities/StreamParser.java @@ -1,6 +1,5 @@ -package seng302.model.stream.parser; +package seng302.utilities; -import seng302.model.stream.parser.PositionUpdateData.DeviceType; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; @@ -14,6 +13,11 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.StreamPacket; +import seng302.model.stream.parser.MarkRoundingData; +import seng302.model.stream.parser.PositionUpdateData; +import seng302.model.stream.parser.PositionUpdateData.DeviceType; +import seng302.model.stream.parser.RaceStartData; +import seng302.model.stream.parser.RaceStatusData; /** * StreamParser is a utilities class for taking byte data, formatted according to the AC35 @@ -87,22 +91,24 @@ public class StreamParser { // int noBoats = payload[22]; int raceType = payload[23]; + long boatID, estTimeAtNextMark, estTimeAtFinish; + int leg, boatStatus; for (int i = 0; i < noBoats; i++) { - long boatID = bytesToLong( + boatID = bytesToLong( Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); -// boat.setBoatStatus((int) payload[28 + (i * 20)]); + boatStatus = (int) payload[28 + (i * 20)]; // setBoatLegPosition(boat, (int) payload[29 + (i * 20)]); // boat.setPenaltiesAwarded((int) payload[30 + (i * 20)]); // boat.setPenaltiesServed((int) payload[31 + (i * 20)]); - Long estTimeAtNextMark = bytesToLong( + estTimeAtNextMark = bytesToLong( Arrays.copyOfRange(payload, 32 + (i * 20), 38 + (i * 20))); // boat.setEstimateTimeTillNextMark(estTimeAtNextMark); - Long estTimeAtFinish = bytesToLong( + estTimeAtFinish = bytesToLong( Arrays.copyOfRange(payload, 38 + (i * 20), 44 + (i * 20))); - int leg = (int) payload[29 + (i * 20)]; + leg = (int) payload[29 + (i * 20)]; // boat.setEstimateTimeAtFinish(estTimeAtFinish); - data.addBoatData(boatID, estTimeAtNextMark, estTimeAtFinish, leg); + data.addBoatData(boatID, estTimeAtNextMark, estTimeAtFinish, leg, boatStatus); } return data; } diff --git a/src/main/java/seng302/model/stream/xml/generator/XMLGenerator.java b/src/main/java/seng302/utilities/XMLGenerator.java similarity index 94% rename from src/main/java/seng302/model/stream/xml/generator/XMLGenerator.java rename to src/main/java/seng302/utilities/XMLGenerator.java index 4d2c9ab5..43154767 100644 --- a/src/main/java/seng302/model/stream/xml/generator/XMLGenerator.java +++ b/src/main/java/seng302/utilities/XMLGenerator.java @@ -1,12 +1,16 @@ -package seng302.model.stream.xml.generator; +package seng302.utilities; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import seng302.model.stream.xml.generator.Race; +import seng302.model.stream.xml.generator.Regatta; import seng302.server.messages.XMLMessageSubType; -import java.io.*; - /** * An XML generator to generate the Race, Boat, and Regatta XML dynamically */ diff --git a/src/main/java/seng302/model/stream/xml/parser/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java similarity index 98% rename from src/main/java/seng302/model/stream/xml/parser/XMLParser.java rename to src/main/java/seng302/utilities/XMLParser.java index f150d950..38f6bb0d 100644 --- a/src/main/java/seng302/model/stream/xml/parser/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -1,4 +1,5 @@ -package seng302.model.stream.xml.parser; +package seng302.utilities; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -7,13 +8,15 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import seng302.model.Yacht; import seng302.model.Corner; import seng302.model.Limit; +import seng302.model.Yacht; import seng302.model.mark.GateMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkType; import seng302.model.mark.SingleMark; +import seng302.model.stream.xml.parser.RaceXMLData; +import seng302.model.stream.xml.parser.RegattaXMLData; /** * Utilities for parsing XML documents diff --git a/src/main/java/seng302/visualiser/ClientSocketListener.java b/src/main/java/seng302/visualiser/ClientSocketListener.java deleted file mode 100644 index 552268f1..00000000 --- a/src/main/java/seng302/visualiser/ClientSocketListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package seng302.visualiser; - -import seng302.model.stream.packets.StreamPacket; - -/** - * Functional interface for receiving packets from client socket. - */ -@FunctionalInterface -public interface ClientSocketListener { - void newPacket(StreamPacket packet); -} diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index 0ce0246d..19f03251 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -5,14 +5,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; -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.model.stream.packets.StreamPacket; import seng302.server.messages.BoatActionMessage; import seng302.server.messages.Message; @@ -22,6 +24,21 @@ import seng302.server.messages.Message; * its own thread. */ public class ClientToServerThread implements Runnable { + + /** + * Functional interface for receiving packets from client socket. + */ + @FunctionalInterface + public interface ClientSocketListener { + void newPacket(); + } + + private class ByteReadException extends Exception { + private ByteReadException(String message) { + super(message); + } + } + private static final int LOG_LEVEL = 1; private Queue streamPackets = new ConcurrentLinkedQueue<>(); @@ -34,8 +51,9 @@ public class ClientToServerThread implements Runnable { private int clientId; - private Boolean updateClient = true; +// private Boolean updateClient = true; private ByteArrayOutputStream crcBuffer; + private boolean socketOpen = true; /** * Constructor for ClientToServerThread which takes in ipAddress and portNumber and attempts to @@ -53,7 +71,6 @@ public class ClientToServerThread implements Runnable { socket = new Socket(ipAddress, portNumber); is = socket.getInputStream(); os = socket.getOutputStream(); - Integer allocatedID = threeWayHandshake(); if (allocatedID != null) { clientId = allocatedID; @@ -90,8 +107,19 @@ public class ClientToServerThread implements Runnable { int sync1; int sync2; // TODO: 14/07/17 wmu16 - Work out how to fix this while loop - while(true) { /**REMOVED SOMETHING HERE ClientState.isConnectedToHost() */ + while(socketOpen) { /**REMOVED SOMETHING HERE ClientState.isConnectedToHost() */ + System.out.println("socket.isConnected() = " + socket.isConnected()); 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(); @@ -109,29 +137,33 @@ public class ClientToServerThread implements Runnable { long packetCrc = Message.bytesToLong(getBytes(4)); if (computedCrc == packetCrc) { // streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload)); - for (ClientSocketListener csl : listeners) - csl.newPacket(new StreamPacket(type, payloadLength, timeStamp, payload)); +// for (ClientSocketListener csl : listeners) +// csl.newPacket(new StreamPacket(type, payloadLength, timeStamp, payload)); + if (streamPackets.size() > 0) { + streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload)); + } else { + streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload)); + for (ClientSocketListener csl : listeners) + csl.newPacket(); + } } else { clientLog("Packet has been dropped", 1); } } - } catch (Exception e) { + } catch (ByteReadException e) { 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); + Platform.runLater(() -> { + Alert alert = new Alert(AlertType.ERROR); + alert.setHeaderText("Host has disconnected"); + alert.setContentText("Cannot find Server"); + alert.showAndWait(); + }); + clientLog(e.getMessage(), 1); return; } } -// closeSocket(); -// clientLog("Disconnected from server", 0); + closeSocket(); + clientLog("Closed connection to Server", 0); } @@ -147,7 +179,6 @@ public class ClientToServerThread implements Runnable { ourSourceID = is.read(); } catch (IOException e) { clientLog("Three way handshake failed", 1); - } if (ourSourceID != null) { try { @@ -174,7 +205,7 @@ public class ClientToServerThread implements Runnable { } - public void closeSocket() { + private void closeSocket() { try { socket.close(); } catch (IOException e) { @@ -182,6 +213,14 @@ public class ClientToServerThread implements Runnable { } } + public void setSocketToClose () { + socketOpen = false; + } + + public Queue getPacketQueue () { + return streamPackets; + } + public void addStreamObserver (ClientSocketListener streamListener) { listeners.add(streamListener); } @@ -190,7 +229,7 @@ public class ClientToServerThread implements Runnable { listeners.remove(streamListener); } - private int readByte() throws Exception { + private int readByte() throws ByteReadException { int currentByte = -1; try { currentByte = is.read(); @@ -199,12 +238,12 @@ public class ClientToServerThread implements Runnable { clientLog("Read byte failed", 1); } if (currentByte == -1) { - throw new Exception(); + throw new ByteReadException("InputStream reach end of stream"); } return currentByte; } - private byte[] getBytes(int n) throws Exception { + private byte[] getBytes(int n) throws ByteReadException { byte[] bytes = new byte[n]; for (int i = 0; i < n; i++) { bytes[i] = (byte) readByte(); @@ -212,7 +251,7 @@ public class ClientToServerThread implements Runnable { return bytes; } - private void skipBytes(long n) throws Exception { + private void skipBytes(long n) throws ByteReadException { for (int i = 0; i < n; i++) { readByte(); } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index e7295082..df509d02 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -3,29 +3,28 @@ package seng302.visualiser; import java.io.IOException; import java.time.ZoneId; import java.time.ZoneOffset; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.TimeZone; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.layout.Pane; import seng302.gameServer.GameState; import seng302.gameServer.MainServerThread; -import seng302.model.Yacht; import seng302.model.RaceState; +import seng302.model.Yacht; import seng302.model.mark.Mark; -import seng302.model.stream.parser.PositionUpdateData.DeviceType; -import seng302.model.stream.parser.MarkRoundingData; -import seng302.model.stream.parser.RaceStatusData; -import seng302.model.stream.xml.parser.RaceXMLData; -import seng302.model.stream.parser.StreamParser; -import seng302.model.stream.xml.parser.RegattaXMLData; -import seng302.model.stream.xml.parser.XMLParser; -import seng302.model.stream.parser.PositionUpdateData; import seng302.model.stream.packets.StreamPacket; -import seng302.visualiser.ClientToServerThread; +import seng302.model.stream.parser.MarkRoundingData; +import seng302.model.stream.parser.PositionUpdateData; +import seng302.model.stream.parser.PositionUpdateData.DeviceType; +import seng302.model.stream.parser.RaceStatusData; +import seng302.utilities.StreamParser; +import seng302.model.stream.xml.parser.RaceXMLData; +import seng302.model.stream.xml.parser.RegattaXMLData; +import seng302.utilities.XMLParser; import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController.CloseStatus; import seng302.visualiser.controllers.RaceViewController; @@ -61,9 +60,10 @@ public class GameClient { } LobbyController lobbyController = loadLobby("/views/LobbyView.fxml"); lobbyController.setPlayerListSource(lobbyList); + lobbyController.disableReadyButton(); lobbyController.setTitle("Connected to host - IP : " + ipAddress + " Port : " + portNumber); lobbyController.addCloseListener((exitCause) -> this.loadStartScreen()); - socketThread.addStreamObserver(this::parsePacket); + socketThread.addStreamObserver(this::parsePackets); } public void runAsHost (String ipAddress, Integer portNumber) { @@ -74,13 +74,13 @@ public class GameClient { ioe.printStackTrace(); System.out.println("Unable to make local connection to host..."); } - LobbyController lobbyController = loadLobby("/views/HostLobbyView.fxml"); + socketThread.addStreamObserver(this::parsePackets); + LobbyController lobbyController = loadLobby("/views/LobbyView.fxml"); lobbyController.setPlayerListSource(GameState.getObservablePlayers()); lobbyController.setTitle("Hosting Lobby - IP : " + ipAddress + " Port : " + portNumber); lobbyController.addCloseListener(exitCause -> { if (exitCause == CloseStatus.READY) { server.startGame(); - socketThread.addStreamObserver(this::parsePacket); } else if (exitCause == CloseStatus.LEAVE) { loadStartScreen(); } @@ -88,11 +88,11 @@ public class GameClient { } private void loadStartScreen () { - socketThread.closeSocket(); + socketThread.setSocketToClose(); socketThread = null; if (server != null) { // TODO: 26/07/17 cir27 - handle disconnecting - server.shutDown(); +// server.shutDown(); server = null; } FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/StartScreenView.fxml")); @@ -125,68 +125,78 @@ public class GameClient { // if (courseData.getParticipants().contains(id)) // racingBoats.put(id, boat); // }); - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/RaceView.fxml")); - raceView = fxmlLoader.getController(); + FXMLLoader fxmlLoader = new FXMLLoader(RaceViewController.class.getResource("/views/RaceView.fxml")); +// raceView = fxmlLoader.getController(); try { - holderPane.getChildren().add(fxmlLoader.load()); + Node node = fxmlLoader.load(); + Platform.runLater(() -> { + holderPane.getChildren().clear(); + holderPane.getChildren().add(node); + }); } catch (IOException e) { e.printStackTrace(); } + raceView = fxmlLoader.getController(); raceView.loadRace(allBoatsMap, courseData, raceState); } - private void parsePacket(StreamPacket packet) { - switch (packet.getType()) { - case RACE_STATUS: - processRaceStatusUpdate(StreamParser.extractRaceStatus(packet)); - break; + private void parsePackets() { + while (socketThread.getPacketQueue().peek() != null) { + StreamPacket packet = socketThread.getPacketQueue().poll(); + switch (packet.getType()) { + case RACE_STATUS: + processRaceStatusUpdate(StreamParser.extractRaceStatus(packet)); + startRaceIfAllDataReceived(); + break; - case REGATTA_XML: - System.out.println("REGATTA XML"); - regattaData = XMLParser.parseRegatta( - StreamParser.extractXmlMessage(packet) - ); - raceState.setTimeZone( - TimeZone.getTimeZone( - ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset())) - ) - ); - startRaceIfAllDataReceived(); - break; + case REGATTA_XML: + System.out.println("REGATTA XML"); + regattaData = XMLParser.parseRegatta( + StreamParser.extractXmlMessage(packet) + ); + raceState.setTimeZone( + TimeZone.getTimeZone( + ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset())) + ) + ); +// startRaceIfAllDataReceived(); + break; - case RACE_XML: - System.out.println("RACE XML"); - courseData = XMLParser.parseRace( - StreamParser.extractXmlMessage(packet) - ); - if (raceView != null) { - raceView.updateRaceData(courseData); - } - startRaceIfAllDataReceived(); - break; + case RACE_XML: + System.out.println("RACE XML"); + courseData = XMLParser.parseRace( + StreamParser.extractXmlMessage(packet) + ); + if (raceView != null) { + raceView.updateRaceData(courseData); + } +// startRaceIfAllDataReceived(); + break; - case BOAT_XML: - System.out.println("BOAT XML"); - allBoatsMap = XMLParser.parseBoats( - StreamParser.extractXmlMessage(packet) - ); - lobbyList.clear(); - allBoatsMap.forEach((id, boat) -> lobbyList.add(id.toString() + boat.getBoatName())); - allBoatsMap.forEach((i, b) -> System.out.println(b.getBoatName())); - startRaceIfAllDataReceived(); - break; + case BOAT_XML: + System.out.println("BOAT XML"); + allBoatsMap = XMLParser.parseBoats( + StreamParser.extractXmlMessage(packet) + ); + lobbyList.clear(); + allBoatsMap + .forEach((id, boat) -> lobbyList.add(id.toString() + boat.getBoatName())); + allBoatsMap.forEach((i, b) -> System.out.println(b.getBoatName())); +// startRaceIfAllDataReceived(); + break; - case RACE_START_STATUS: - raceState.updateState(StreamParser.extractRaceStartStatus(packet)); - break; + case RACE_START_STATUS: + raceState.updateState(StreamParser.extractRaceStartStatus(packet)); + break; - case BOAT_LOCATION: - updatePosition(StreamParser.extractBoatLocation(packet)); - break; + case BOAT_LOCATION: + updatePosition(StreamParser.extractBoatLocation(packet)); + break; - case MARK_ROUNDING: - updateMarkRounding(StreamParser.extractMarkRounding(packet)); - break; + case MARK_ROUNDING: + updateMarkRounding(StreamParser.extractMarkRounding(packet)); + break; + } } } @@ -243,6 +253,7 @@ public class GameClient { yacht.setEstimateTimeAtFinish(boatData[2]); int legNumber = (int) boatData[3]; yacht.setLegNumber(legNumber); + yacht.setBoatStatus((int) boatData[4]); if (legNumber != yacht.getLegNumber()) { int placing = 1; for (Yacht otherYacht : allBoatsMap.values()) { @@ -257,7 +268,7 @@ public class GameClient { } private void close () { - socketThread.closeSocket(); + socketThread.setSocketToClose(); } // /** Handle the key-pressed event from the text field. */ diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java index 67c77b94..1cc617dd 100644 --- a/src/main/java/seng302/visualiser/GameView.java +++ b/src/main/java/seng302/visualiser/GameView.java @@ -22,20 +22,18 @@ import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; -import seng302.model.Limit; -import seng302.visualiser.fxObjects.AnnotationBox; -import seng302.visualiser.fxObjects.BoatObject; -import seng302.visualiser.fxObjects.MarkObject; import seng302.model.Colors; +import seng302.model.Limit; import seng302.model.Yacht; -import seng302.model.map.Boundary; -import seng302.model.map.CanvasMap; import seng302.model.mark.GateMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkType; import seng302.model.mark.SingleMark; import seng302.utilities.GeoPoint; import seng302.utilities.GeoUtility; +import seng302.visualiser.fxObjects.AnnotationBox; +import seng302.visualiser.fxObjects.BoatObject; +import seng302.visualiser.fxObjects.MarkObject; /** * Created by cir27 on 20/07/17. @@ -45,11 +43,11 @@ public class GameView extends Pane { private ObservableList gameObjects; private ImageView mapImage; - private final int BUFFER_SIZE = 50; - private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias. - private final int PANEL_HEIGHT = 960; - private final int CANVAS_WIDTH = 1100; - private final int CANVAS_HEIGHT = 920; + private double bufferSize = 50; + private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias. + private double panelHeight = 960; + private double canvasWidth = 1100; + private double canvasHeight = 920; private boolean horizontalInversion = false; private double distanceScaleFactor; @@ -63,13 +61,14 @@ public class GameView extends Pane { private double metersPerPixelX; private double metersPerPixelY; - private Map markObjects = new HashMap<>(); private Map boatObjects = new HashMap<>(); private List annotations = new ArrayList<>(); private Text fpsDisplay = new Text(); - - private Polygon raceBorder = new Polygon(); + /* Note that if either of these is null then values for it have not been added and the other + should be used as the limits of the map. */ + private Polygon raceBorder; + private Map markObjects = new HashMap<>(); //FRAME RATE private Double frameRate = 60.0; @@ -205,9 +204,13 @@ public class GameView extends Pane { * in a compound mark etc.. */ public void updateBorder(List border) { - raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1)); - raceBorder.setStrokeWidth(3); - raceBorder.setFill(new Color(0,0,0,0)); + if (raceBorder == null) { + raceBorder = new Polygon(); + raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1)); + raceBorder.setStrokeWidth(3); + raceBorder.setFill(new Color(0,0,0,0)); + findCanvasScaling(); + } List boundaryPoints = new ArrayList<>(); for (Limit limit : border) { Point2D location = findScaledXY(limit.getLat(), limit.getLng()); @@ -393,24 +396,24 @@ public class GameView extends Pane { if (scaleDirection == ScaleDirection.HORIZONTAL) { referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint)); - referencePointX = BUFFER_SIZE + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint); + referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint); referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, maxLatPoint)); - referencePointY = canvasHeight - (BUFFER_SIZE + BUFFER_SIZE); + referencePointY = canvasHeight - (bufferSize + bufferSize); referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint); referencePointY = referencePointY / 2; - referencePointY += BUFFER_SIZE; + referencePointY += bufferSize; referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * Mark.calculateDistance(referencePoint, maxLatPoint); } else { - referencePointY = canvasHeight - BUFFER_SIZE; + referencePointY = canvasHeight - bufferSize; referenceAngle = Math.abs(Mark.calculateHeadingRad(referencePoint, minLonPoint)); - referencePointX = BUFFER_SIZE; + referencePointX = bufferSize; referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint); - referencePointX += ((canvasWidth - (BUFFER_SIZE + BUFFER_SIZE)) - (minLonToMaxLon * distanceScaleFactor)) / 2; + referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2; } if(horizontalInversion) { - referencePointX = canvasWidth - BUFFER_SIZE - (referencePointX - BUFFER_SIZE); + referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize); } } @@ -434,10 +437,10 @@ public class GameView extends Pane { double horiDistance = Math.cos(horiAngle) * Mark.calculateDistance(minLonPoint, maxLonPoint); - double vertScale = (canvasHeight - (BUFFER_SIZE + BUFFER_SIZE)) / vertDistance; + double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance; - if ((horiDistance * vertScale) > (canvasWidth - (BUFFER_SIZE + BUFFER_SIZE))) { - distanceScaleFactor = (canvasWidth - (BUFFER_SIZE + BUFFER_SIZE)) / horiDistance; + if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) { + distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance; scaleDirection = ScaleDirection.HORIZONTAL; } else { distanceScaleFactor = vertScale; @@ -479,7 +482,7 @@ public class GameView extends Pane { yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); } if(horizontalInversion) { - xAxisLocation = canvasWidth - BUFFER_SIZE - (xAxisLocation - BUFFER_SIZE); + xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize); } return new Point2D(xAxisLocation, yAxisLocation); } diff --git a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java index 0cdc9305..db2a5d17 100644 --- a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java +++ b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java @@ -18,7 +18,6 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import seng302.model.Yacht; -import seng302.model.stream.parser.StreamParser; public class FinishScreenViewController implements Initializable { diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index 5cbd407c..8e855cac 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -2,8 +2,9 @@ package seng302.visualiser.controllers; import java.io.IOException; import java.net.URL; -import java.util.*; - +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -11,7 +12,6 @@ import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.ListView; -import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; @@ -36,9 +36,6 @@ public class LobbyController implements Initializable { void notify(CloseStatus exitCause); } - @FXML - private ListView competitorsListView; - @FXML private GridPane lobbyScreen; @FXML @@ -259,10 +256,13 @@ public class LobbyController implements Initializable { @FXML public void leaveLobbyButtonPressed() { // TODO: 10/07/17 wmu16 - Finish function! - setContentPane("/views/StartScreenView.fxml"); +// setContentPane("/views/StartScreenView.fxml"); GameState.setCurrentStage(GameStages.CANCELLED); // TODO: 20/07/17 wmu16 - Implement some way of terminating the game // ClientState.setConnectedToHost(false); + for (LobbyCloseListener readyListener : lobbyListeners) + readyListener.notify(CloseStatus.LEAVE); + } @FXML @@ -309,11 +309,15 @@ public class LobbyController implements Initializable { } public void setPlayerListSource (ObservableList players) { - if (competitorsListView != null) - competitorsListView.setItems(players); - if (firstListView != null) { +// if (competitorsListView != null) +// competitorsListView.setItems(players); +// if (firstListView != null) { firstListView.setItems(players); firstImageView.setVisible(false); - } +// } + } + + public void disableReadyButton () { + readyButton.setDisable(true); } } diff --git a/src/main/java/seng302/visualiser/controllers/RaceViewController.java b/src/main/java/seng302/visualiser/controllers/RaceViewController.java index 0208fbd6..0b71d8d6 100644 --- a/src/main/java/seng302/visualiser/controllers/RaceViewController.java +++ b/src/main/java/seng302/visualiser/controllers/RaceViewController.java @@ -1,5 +1,11 @@ package seng302.visualiser.controllers; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import javafx.animation.KeyFrame; import javafx.animation.Timeline; @@ -9,7 +15,6 @@ import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.geometry.Point2D; import javafx.scene.Scene; - import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; @@ -30,7 +35,9 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; import javafx.util.StringConverter; -import seng302.model.Corner; +import seng302.model.RaceState; +import seng302.model.Yacht; +import seng302.model.mark.Mark; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.visualiser.GameView; import seng302.visualiser.controllers.annotations.Annotation; @@ -38,11 +45,6 @@ import seng302.visualiser.controllers.annotations.ImportantAnnotationController; import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate; import seng302.visualiser.controllers.annotations.ImportantAnnotationsState; import seng302.visualiser.fxObjects.BoatObject; -import seng302.model.*; -import seng302.model.mark.Mark; - -import java.io.IOException; -import java.util.*; /** * Controller class that manages the display of a race @@ -92,6 +94,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel raceSparkLine.getYAxis().setAutoRanging(false); sparklineYAxis.setTickMarkVisible(false); + positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); + selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); } @@ -189,11 +193,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } } }); - + annotationSlider.setValue(2); annotationSlider.valueProperty().addListener((obs, oldVal, newVal) -> setAnnotations((int) annotationSlider.getValue()) ); - annotationSlider.setValue(2); } @@ -368,14 +371,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel */ private void updateOrder() { positionVbox.getChildren().clear(); - positionVbox.getChildren().removeAll(); - positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); +// positionVbox.getChildren().removeAll(); +// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); // list of racing yacht id List sorted = new ArrayList<>(participants.values()); sorted.sort(Comparator.comparingInt(Yacht::getPositionInteger)); for (Yacht yacht : sorted) { +// System.out.println("yacht == null " + String.valueOf(yacht == null)); if (yacht.getBoatStatus() == 3) { // 3 is finish status Text textToAdd = new Text(yacht.getPositionInteger() + ". " + yacht.getShortName() + " (Finished)"); @@ -389,6 +393,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel textToAdd.setStyle(""); positionVbox.getChildren().add(textToAdd); } +// System.out.println("finished a loop :))))))))))))"); } // participants.forEach((id, yacht) ->{ // Text textToAdd = new Text(yacht.getPosition() + ". " + diff --git a/src/main/java/seng302/visualiser/controllers/StartScreenController.java b/src/main/java/seng302/visualiser/controllers/StartScreenController.java index c4d14bd6..87199442 100644 --- a/src/main/java/seng302/visualiser/controllers/StartScreenController.java +++ b/src/main/java/seng302/visualiser/controllers/StartScreenController.java @@ -1,25 +1,17 @@ package seng302.visualiser.controllers; import java.net.Inet4Address; +import java.net.InetAddress; import java.net.NetworkInterface; import java.net.URL; import java.util.Enumeration; import java.util.ResourceBundle; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; -import javafx.scene.layout.Pane; -import seng302.client.ClientState; -import seng302.visualiser.ClientToServerThread; import seng302.gameServer.GameState; -import seng302.gameServer.MainServerThread; -import java.io.IOException; -import java.net.InetAddress; import seng302.visualiser.GameClient; /** diff --git a/src/main/java/seng302/visualiser/controllers/annotations/ImportantAnnotationController.java b/src/main/java/seng302/visualiser/controllers/annotations/ImportantAnnotationController.java index 7094bb9f..0c39f226 100644 --- a/src/main/java/seng302/visualiser/controllers/annotations/ImportantAnnotationController.java +++ b/src/main/java/seng302/visualiser/controllers/annotations/ImportantAnnotationController.java @@ -1,5 +1,7 @@ package seng302.visualiser.controllers.annotations; +import java.net.URL; +import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; @@ -7,8 +9,7 @@ import javafx.scene.control.CheckBox; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import java.net.URL;; -import java.util.ResourceBundle; +; public class ImportantAnnotationController implements Initializable { diff --git a/src/main/java/seng302/visualiser/fxObjects/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/BoatObject.java index 1d31e657..6a7bdb7a 100644 --- a/src/main/java/seng302/visualiser/fxObjects/BoatObject.java +++ b/src/main/java/seng302/visualiser/fxObjects/BoatObject.java @@ -1,16 +1,14 @@ package seng302.visualiser.fxObjects; import java.util.ArrayList; - import javafx.geometry.Point2D; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.paint.Color; -import javafx.scene.shape.Circle; +import javafx.scene.paint.Paint; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.transform.Rotate; -import seng302.model.Yacht; /** * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 @@ -64,52 +62,49 @@ public class BoatObject extends Group { * polygon. */ public BoatObject(double... points) { - public BoatGroup(Yacht boat, Color color, double... points) { + this.colour = colour; destinationSet = false; - this.boat = boat; - initChildren(color, points); + initChildren(points); } /** * Creates the javafx objects that will be the in the group by default. * - * @param color The colour of the boat polygon and the trailing line. * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat * polygon. */ - private void initChildren(Color color, double... points) { - this.color = color; + private void initChildren(double... points) { +// this.colour = color; boatPoly = new Polygon(points); boatPoly.setFill(colour); - boatPoly.setFill(this.color); + boatPoly.setFill(this.colour); boatPoly.setOnMouseEntered(event -> { boatPoly.setFill(Color.FLORALWHITE); boatPoly.setStroke(Color.RED); }); boatPoly.setOnMouseExited(event -> { boatPoly.setFill(colour); - boatPoly.setFill(this.color); + boatPoly.setFill(this.colour); boatPoly.setStroke(Color.BLACK); }); boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected)); boatPoly.setCache(true); boatPoly.setCacheHint(CacheHint.SPEED); - annotationBox = new AnnotationBox(); - annotationBox.setFill(colour); - boatAnnotations = new BoatAnnotations(boat, this.color); +// annotationBox = new AnnotationBox(); +// annotationBox.setFill(colour); leftLayLine = new Line(); rightLayline = new Line(); wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren().addAll(boatPoly, annotationBox); + super.getChildren().addAll(boatPoly);//, annotationBox); } public void setFill (Paint value) { this.colour = value; boatPoly.setFill(colour); - annotationBox.setFill(colour); +// annotationBox.setFill(colour); } /** @@ -207,14 +202,14 @@ public class BoatObject extends Group { wake.setRotation(rotation, groundSpeed); // yacht.setVelocity(groundSpeed); lastTimeValid = timeValid; - boat.setVelocity(groundSpeed); +// boat.setVelocity(groundSpeed); isStopped = false; lastRotation = rotation; - boatAnnotations.update(); +// boatAnnotations.update(); distanceTravelled += Math.sqrt((dx * dx) + (dy * dy)); - if (distanceTravelled > 10 && isPlayer) { + if (distanceTravelled > 10){// && isPlayer) { distanceTravelled = 0d; if (lastPoint != null) { @@ -225,7 +220,7 @@ public class BoatObject extends Group { boatPoly.getLayoutY() ); l.getStrokeDashArray().setAll(3d, 7d); - l.setStroke(boat.getColour()); + l.setStroke(this.colour); l.setCache(true); l.setCacheHint(CacheHint.SPEED); lineGroup.getChildren().add(l); @@ -280,8 +275,7 @@ public class BoatObject extends Group { public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime, boolean trail, boolean wake) { - public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime, boolean trail, boolean wake) { - boatAnnotations.setVisible(teamName, velocity, estTime, legTime); +// boatAnnotations.setVisible(teamName, velocity, estTime, legTime); this.wake.setVisible(wake); this.lineGroup.setVisible(trail); } @@ -336,23 +330,18 @@ public class BoatObject extends Group { return isStopped; } - @Override - public String toString() { - return boat.toString(); - } - /** * Sets this boat to appear highlighted */ public void setAsPlayer() { - boatPoly.getPoints().setAll( - -BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75, - 0.0, -BOAT_HEIGHT / 1.75, - BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75 - ); - boatPoly.setStroke(Color.BLACK); - boatPoly.setStrokeWidth(3); - boatAnnotations.setAsPlayer(); - isPlayer = true; +// boatPoly.getPoints().setAll( +// -BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75, +// 0.0, -BOAT_HEIGHT / 1.75, +// BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75 +// ); +// boatPoly.setStroke(Color.BLACK); +// boatPoly.setStrokeWidth(3); +// boatAnnotations.setAsPlayer(); +// isPlayer = true; } } \ No newline at end of file diff --git a/src/main/java/seng302/model/map/Boundary.java b/src/main/java/seng302/visualiser/map/Boundary.java similarity index 84% rename from src/main/java/seng302/model/map/Boundary.java rename to src/main/java/seng302/visualiser/map/Boundary.java index ab2f1f41..53fb8d06 100644 --- a/src/main/java/seng302/model/map/Boundary.java +++ b/src/main/java/seng302/visualiser/map/Boundary.java @@ -1,4 +1,4 @@ -package seng302.model.map; +package seng302.visualiser.map; /** * The Boundary class represents a rectangle territorial boundary on a map. It @@ -7,11 +7,11 @@ package seng302.model.map; * * Created by Haoming on 10/5/17 */ -public class Boundary { +class Boundary { private double northLat, eastLng, southLat, westLng; - public Boundary(double northLat, double eastLng, double southLat, double westLng) { + Boundary(double northLat, double eastLng, double southLat, double westLng) { this.northLat = northLat; this.eastLng = eastLng; this.southLat = southLat; diff --git a/src/main/java/seng302/model/map/CanvasMap.java b/src/main/java/seng302/visualiser/map/CanvasMap.java similarity index 96% rename from src/main/java/seng302/model/map/CanvasMap.java rename to src/main/java/seng302/visualiser/map/CanvasMap.java index a24e35c6..76b28544 100644 --- a/src/main/java/seng302/model/map/CanvasMap.java +++ b/src/main/java/seng302/visualiser/map/CanvasMap.java @@ -1,13 +1,10 @@ -package seng302.model.map; +package seng302.visualiser.map; +import java.net.URL; import javafx.geometry.Point2D; import javafx.scene.image.Image; -import seng302.utilities.GeoPoint; - import javax.net.ssl.HttpsURLConnection; -import java.net.URL; - -import java.lang.Math; +import seng302.utilities.GeoPoint; /** * CanvasMap retrieves a map image with given geo boundary from Google Map server. @@ -25,12 +22,12 @@ public class CanvasMap { private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE"; - public CanvasMap(Boundary boundary) { + CanvasMap(Boundary boundary) { this.boundary = boundary; calculateOptimalMapSize(); } - public Image getMapImage() { + Image getMapImage() { try { URL url = new URL(getRequest()); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); diff --git a/src/main/java/seng302/model/map/MercatorProjection.java b/src/main/java/seng302/visualiser/map/MercatorProjection.java similarity index 96% rename from src/main/java/seng302/model/map/MercatorProjection.java rename to src/main/java/seng302/visualiser/map/MercatorProjection.java index 031a5949..864c4c06 100644 --- a/src/main/java/seng302/model/map/MercatorProjection.java +++ b/src/main/java/seng302/visualiser/map/MercatorProjection.java @@ -1,4 +1,4 @@ -package seng302.model.map; +package seng302.visualiser.map; import javafx.geometry.Point2D; import seng302.utilities.GeoPoint; @@ -28,7 +28,7 @@ public class MercatorProjection { * @param geo GeoPoint (lat, lng) location to be projected * @return the projection Point2D (x, y) on planar */ - public static Point2D toMapPoint(GeoPoint geo) { + static Point2D toMapPoint(GeoPoint geo) { double x, y; Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0); x = (origin.getX() + geo.getLng() * pixelsPerLngDegree); diff --git a/src/main/java/seng302/model/map/TestMapController.java b/src/main/java/seng302/visualiser/map/TestMapController.java similarity index 95% rename from src/main/java/seng302/model/map/TestMapController.java rename to src/main/java/seng302/visualiser/map/TestMapController.java index 18609275..cd0b4c60 100644 --- a/src/main/java/seng302/model/map/TestMapController.java +++ b/src/main/java/seng302/visualiser/map/TestMapController.java @@ -1,13 +1,12 @@ -package seng302.model.map; +package seng302.visualiser.map; +import java.net.URL; +import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; -import java.net.URL; -import java.util.ResourceBundle; - public class TestMapController implements Initializable{ @FXML diff --git a/src/main/resources/views/FinishScreenView.fxml b/src/main/resources/views/FinishScreenView.fxml index a5ef1fa1..ab1e5835 100644 --- a/src/main/resources/views/FinishScreenView.fxml +++ b/src/main/resources/views/FinishScreenView.fxml @@ -1,11 +1,15 @@ - - - - - - + + + + + + + + + + diff --git a/src/main/resources/views/HostLobbyView.fxml b/src/main/resources/views/HostLobbyView.fxml index 136f6248..0c186619 100644 --- a/src/main/resources/views/HostLobbyView.fxml +++ b/src/main/resources/views/HostLobbyView.fxml @@ -1,10 +1,14 @@ - - - - + + + + + + + + diff --git a/src/main/resources/views/LobbyView.fxml b/src/main/resources/views/LobbyView.fxml index 556e9342..96a71574 100644 --- a/src/main/resources/views/LobbyView.fxml +++ b/src/main/resources/views/LobbyView.fxml @@ -1,12 +1,16 @@ - - - - - - + + + + + + + + + + diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index 14f1754f..e13853d1 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -1,12 +1,22 @@ - - - - - - - + + + + + + + + + + + + + + + + + @@ -55,7 +65,7 @@