diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 17da9945..c945e03b 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -9,8 +9,8 @@ import seng302.models.parsers.StreamParser; import seng302.models.parsers.StreamReceiver; import seng302.server.ServerThread; -public class App extends Application -{ +public class App extends Application { + @Override public void start(Stage primaryStage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml")); @@ -39,15 +39,15 @@ public class App extends Application e.printStackTrace(); } - if (args.length == 1 && args[0].equals("-standalone")){ + if (args.length == 1 && args[0].equals("-standalone")) { return; } - if (args.length == 3 && args[0].equals("-server")){ + if (args.length == 3 && args[0].equals("-server")) { sr = new StreamReceiver(args[1], Integer.valueOf(args[2]), "RaceStream"); - } else if(args.length == 2 && args[0].equals("-server")){ + } else if (args.length == 2 && args[0].equals("-server")) { switch (args[1]) { case "internal": sr = new StreamReceiver("localhost", 4949, "RaceStream"); @@ -73,8 +73,6 @@ public class App extends Application launch(args); - - } } diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 4d57559b..9a2a9797 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -240,6 +240,17 @@ public class CanvasController { } } } + checkForCourseChanges(); + } + + private void checkForCourseChanges() { + if (StreamParser.isNewRaceXmlReceived()){ + gc.setFill(Color.SKYBLUE); + gc.fillRect(0,0, CANVAS_WIDTH, CANVAS_HEIGHT); + gc.restore(); + addRaceBorder(); + canvas.toBack(); + } } private void move(long id, RaceObject raceObject){ @@ -345,6 +356,8 @@ public class CanvasController { * Calculates x and y location for every marker that fits it to the canvas the race will be drawn on. */ private void fitMarksToCanvas() { + //Check is called once to avoid unnecessarily change the course limits once the race is running + StreamParser.isNewRaceXmlReceived(); findMinMaxPoint(); double minLonToMaxLon = scaleRaceExtremities(); calculateReferencePointLocation(minLonToMaxLon); diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 27edd1f2..22c96f13 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -58,7 +58,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private ArrayList startingBoats = new ArrayList<>(); private boolean displayFps; private Timeline timerTimeline; - private Map timelineInfos = new HashMap<>(); private Race race; private Stage stage; @@ -91,7 +90,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** * The important annotations have been changed, update this view - * * @param importantAnnotationsState The current state of the selected annotations */ public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) { @@ -344,7 +342,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** * Display the important annotations for a specific BoatGroup - * * @param bg The boat group to set the annotations for */ private void setBoatGroupImportantAnnotations(BoatGroup bg) { @@ -371,6 +368,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } else { bg.setWakeVisible(false); } + + if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { + bg.setEstTimeToNextMarkObjectVisible(true); + } else { + bg.setEstTimeToNextMarkObjectVisible(false); + } + + if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) { + bg.setLegTimeObjectVisible(true); + } else { + bg.setLegTimeObjectVisible(false); + } } private void setAnnotations(Integer annotationLevel) { @@ -382,6 +391,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(false); bg.setVelocityObjectVisible(false); + bg.setEstTimeToNextMarkObjectVisible(false); + bg.setLegTimeObjectVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); } @@ -403,6 +414,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel BoatGroup bg = (BoatGroup) ro; bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(true); + bg.setEstTimeToNextMarkObjectVisible(true); + bg.setLegTimeObjectVisible(true); bg.setLineGroupVisible(true); bg.setWakeVisible(true); } diff --git a/src/main/java/seng302/controllers/annotations/Annotation.java b/src/main/java/seng302/controllers/annotations/Annotation.java index eed70162..20a2c265 100644 --- a/src/main/java/seng302/controllers/annotations/Annotation.java +++ b/src/main/java/seng302/controllers/annotations/Annotation.java @@ -7,5 +7,7 @@ public enum Annotation { SPEED, WAKE, TRACK, - NAME + NAME, + ESTTIMETONEXTMARK, + LEGTIME } diff --git a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java index 0d1585af..8dfa8df7 100644 --- a/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java +++ b/src/main/java/seng302/controllers/annotations/ImportantAnnotationController.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.ResourceBundle; public class ImportantAnnotationController implements Initializable { + /* * JavaFX Outlets */ @@ -30,6 +31,12 @@ public class ImportantAnnotationController implements Initializable { @FXML private CheckBox boatNameSelect; + @FXML + private CheckBox boatEstTimeToNextMarkSelect; + + @FXML + private CheckBox boatElapsedTimeSelect; + @FXML private AnchorPane annotationSelectWindow; @@ -40,7 +47,7 @@ public class ImportantAnnotationController implements Initializable { private ImportantAnnotationsState importantAnnotationsState; private Stage stage; - public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage){ + public ImportantAnnotationController(ImportantAnnotationDelegate delegate, Stage stage) { this.delegate = delegate; importantAnnotationsState = new ImportantAnnotationsState(); this.stage = stage; @@ -49,10 +56,11 @@ public class ImportantAnnotationController implements Initializable { /** * Sets whether or not an annotation is considered important, then * sends an update to the delegate + * * @param annotation The annotation * @param isSet True if annotation is important */ - private void setAnnotation(Annotation annotation, Boolean isSet){ + private void setAnnotation(Annotation annotation, Boolean isSet) { importantAnnotationsState.setAnnotationState(annotation, isSet); sendUpdate(); } @@ -61,36 +69,50 @@ public class ImportantAnnotationController implements Initializable { * Sends an update to the delegate when the important * annotations have changed */ - private void sendUpdate(){ + private void sendUpdate() { this.delegate.importantAnnotationsChanged(importantAnnotationsState); } /** * Load the current state of the 'important annotations' + * * @param currentState hashmap containing the states of each annotation */ - public void loadState(ImportantAnnotationsState currentState){ + public void loadState(ImportantAnnotationsState currentState) { this.importantAnnotationsState = currentState; // Initialise checkboxes - for (Annotation annotation : importantAnnotationsState.getAnnotations()){ - switch (annotation){ + for (Annotation annotation : importantAnnotationsState.getAnnotations()) { + switch (annotation) { case WAKE: - boatWakeSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatWakeSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case SPEED: - boatSpeedSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatSpeedSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case TRACK: - boatTrackSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatTrackSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; case NAME: - boatNameSelect.setSelected(importantAnnotationsState.getAnnotationState(annotation)); + boatNameSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); break; + case ESTTIMETONEXTMARK: + boatEstTimeToNextMarkSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); + break; + + case LEGTIME: + boatElapsedTimeSelect + .setSelected(importantAnnotationsState.getAnnotationState(annotation)); + default: break; } @@ -99,15 +121,24 @@ public class ImportantAnnotationController implements Initializable { /** * View did load + * * @param location . * @param resources . */ @Override public void initialize(URL location, ResourceBundle resources) { - boatWakeSelect.setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected())); - boatSpeedSelect.setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected())); - boatTrackSelect.setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected())); - boatNameSelect.setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected())); + boatWakeSelect + .setOnAction(event -> setAnnotation(Annotation.WAKE, boatWakeSelect.isSelected())); + boatSpeedSelect + .setOnAction(event -> setAnnotation(Annotation.SPEED, boatSpeedSelect.isSelected())); + boatTrackSelect + .setOnAction(event -> setAnnotation(Annotation.TRACK, boatTrackSelect.isSelected())); + boatNameSelect + .setOnAction(event -> setAnnotation(Annotation.NAME, boatNameSelect.isSelected())); + boatEstTimeToNextMarkSelect.setOnAction(event -> setAnnotation(Annotation.ESTTIMETONEXTMARK, + boatEstTimeToNextMarkSelect.isSelected())); + boatElapsedTimeSelect.setOnAction( + event -> setAnnotation(Annotation.LEGTIME, boatElapsedTimeSelect.isSelected())); closeButton.setOnAction(event -> stage.close()); } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index ea30bc47..e07c57ee 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -1,17 +1,17 @@ package seng302.models; -import javafx.event.EventHandler; import javafx.geometry.Point2D; import javafx.scene.Group; -import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; import javafx.stage.Stage; -import seng302.controllers.RaceViewController; +import seng302.models.parsers.StreamParser; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; @@ -27,9 +27,13 @@ public class BoatGroup extends RaceObject { //Constants for drawing private static final double TEAMNAME_X_OFFSET = 10d; - private static final double TEAMNAME_Y_OFFSET = -15d; + private static final double TEAMNAME_Y_OFFSET = -29d; private static final double VELOCITY_X_OFFSET = 10d; - private static final double VELOCITY_Y_OFFSET = -5d; + private static final double VELOCITY_Y_OFFSET = -17d; + private static final double ESTTIMETONEXTMARK_X_OFFSET = 10d; + private static final double ESTTIMETONEXTMARK_Y_OFFSET = -5d; + private static final double LEGTIME_X_OFFSET = 10d; + private static final double LEGTIME_Y_OFFSET = 7d; private static final double BOAT_HEIGHT = 15d; private static final double BOAT_WIDTH = 10d; //Variables for boat logic. @@ -42,8 +46,9 @@ public class BoatGroup extends RaceObject { private Polygon boatPoly; private Text teamNameObject; private Text velocityObject; + private Text estTimeToNextMarkObject; + private Text legTimeObject; private Wake wake; - private boolean isSelected = true; //Boats annotations are visible by default at the start //Handles boat moving when connecting to a stream private boolean setToInitialLocation = false; private boolean destinationSet; @@ -90,12 +95,20 @@ public class BoatGroup extends RaceObject { private void initChildren(Color color, double... points) { boatPoly = new Polygon(points); boatPoly.setFill(color); - boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE)); - boatPoly.setOnMouseExited(event -> boatPoly.setFill(color)); - boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected)); teamNameObject = new Text(boat.getShortName()); velocityObject = new Text(String.valueOf(boat.getVelocity())); + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format + .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark); + if (boat.getMarkRoundingTime() != null) { + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); + legTimeObject = new Text("Last mark: " + elapsedTime); + } else { + legTimeObject = new Text("Last mark: -"); + } teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET); @@ -106,8 +119,19 @@ public class BoatGroup extends RaceObject { velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); destinationSet = false; + estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET); + estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET); + estTimeToNextMarkObject + .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); + + legTimeObject.setX(LEGTIME_X_OFFSET); + legTimeObject.setY(LEGTIME_Y_OFFSET); + legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY()); + wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); + super.getChildren() + .addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject, + legTimeObject); } /** @@ -136,6 +160,10 @@ public class BoatGroup extends RaceObject { teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); + estTimeToNextMarkObject.setLayoutX(estTimeToNextMarkObject.getLayoutX() + dx); + estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy); + legTimeObject.setLayoutX(legTimeObject.getLayoutX() + dx); + legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy); wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); rotateTo(rotation + currentRotation); @@ -166,6 +194,10 @@ public class BoatGroup extends RaceObject { teamNameObject.setLayoutY(y); velocityObject.setLayoutX(x); velocityObject.setLayoutY(y); + estTimeToNextMarkObject.setLayoutX(x); + estTimeToNextMarkObject.setLayoutY(y); + legTimeObject.setLayoutX(x); + legTimeObject.setLayoutY(y); wake.setLayoutX(x); wake.setLayoutY(y); wake.rotate(currentRotation); @@ -196,7 +228,7 @@ public class BoatGroup extends RaceObject { boatPoly.getLayoutY() ); l.getStrokeDashArray().setAll(3d, 7d); - l.setStroke(boat.getColour()); + l.setStroke(boatPoly.getFill()); lineGroup.getChildren().add(l); } if (destinationSet) { //Only begin drawing after the first destination is set @@ -248,6 +280,19 @@ public class BoatGroup extends RaceObject { boat.getVelocity()); } velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); + DateFormat format = new SimpleDateFormat("mm:ss"); + // estimate time to next mark + String timeToNextMark = format + .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + // elapsed time + if (boat.getMarkRoundingTime() != null) { + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); + legTimeObject.setText("Last mark: " + elapsedTime); + } else { + legTimeObject.setText("Last mark: -"); + } } else { setToInitialLocation = true; rotationalGoal = rotation; @@ -304,10 +349,6 @@ public class BoatGroup extends RaceObject { wake.rotate(rotationalGoal); } - public void paintBoat(Color color) { - boatPoly.setFill(color); - } - public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } @@ -316,6 +357,14 @@ public class BoatGroup extends RaceObject { velocityObject.setVisible(visible); } + public void setEstTimeToNextMarkObjectVisible(Boolean visible) { + estTimeToNextMarkObject.setVisible(visible); + } + + public void setLegTimeObjectVisible(Boolean visible) { + legTimeObject.setVisible(visible); + } + public void setLineGroupVisible(Boolean visible) { lineGroup.setVisible(visible); } @@ -328,21 +377,6 @@ public class BoatGroup extends RaceObject { return boat; } - /** - * This function sets the boats isSelected property AS WELL as actually acting upon the value of - * that selection. (Painting or not painting annotations) - * - * @param isSelected A Boolean indicating whether or not the boat is selected - */ - public void setIsSelected(Boolean isSelected) { - this.isSelected = isSelected; - setTeamNameObjectVisible(isSelected); - setVelocityObjectVisible(isSelected); - setLineGroupVisible(isSelected); - setWakeVisible(isSelected); - paintBoat((isSelected) ? Color.WHITE : boat.getColour()); - } - /** * Returns true if this BoatGroup contains at least one of the given IDs. * @@ -376,7 +410,7 @@ public class BoatGroup extends RaceObject { */ public Group getLowPriorityAnnotations() { Group group = new Group(); - group.getChildren().addAll(wake, lineGroup, teamNameObject, velocityObject); + group.getChildren().addAll(wake, lineGroup); return group; } @@ -401,9 +435,4 @@ public class BoatGroup extends RaceObject { } }); } - - @Override - public String toString() { - return boat.toString(); - } } diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 64509882..23ba616a 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -12,9 +12,9 @@ import java.text.SimpleDateFormat; * also done outside Boat class because some old variables are not used anymore. */ public class Yacht { + // Used in boat group private Color colour; private double velocity; - private Integer markLastPast; private String boatType; private Integer sourceID; @@ -30,6 +30,8 @@ public class Yacht { private Long estimateTimeAtNextMark; private Long estimateTimeAtFinish; private String position; + // Mark rounding + private Long markRoundingTime; /** * Used in EventTest and RaceTest. @@ -157,12 +159,12 @@ public class Yacht { this.velocity = velocity; } - public Integer getMarkLastPast() { - return markLastPast; + public Long getMarkRoundingTime() { + return markRoundingTime; } - public void setMarkLastPast(Integer markLastPast) { - this.markLastPast = markLastPast; + public void setMarkRoundingTime(Long markRoundingTime) { + this.markRoundingTime = markRoundingTime; } @Override diff --git a/src/main/java/seng302/models/parsers/PacketType.java b/src/main/java/seng302/models/parsers/PacketType.java deleted file mode 100644 index 66b86207..00000000 --- a/src/main/java/seng302/models/parsers/PacketType.java +++ /dev/null @@ -1,53 +0,0 @@ -package seng302.models.parsers; - -/** - * Created by Kusal on 4/24/2017. - */ -public enum PacketType { - HEARTBEAT, - RACE_STATUS, - DISPLAY_TEXT_MESSAGE, - XML_MESSAGE, - RACE_START_STATUS, - YACHT_EVENT_CODE, - YACHT_ACTION_CODE, - CHATTER_TEXT, - BOAT_LOCATION, - MARK_ROUNDING, - COURSE_WIND, - AVG_WIND, - OTHER; - - static PacketType assignPacketType(int packetType){ - switch(packetType){ - case 1: - return HEARTBEAT; - case 12: - return RACE_STATUS; - case 20: - return DISPLAY_TEXT_MESSAGE; - case 26: - return XML_MESSAGE; - case 27: - return RACE_START_STATUS; - case 29: - return YACHT_EVENT_CODE; - case 31: - return YACHT_ACTION_CODE; - case 36: - return CHATTER_TEXT; - case 37: - return BOAT_LOCATION; - case 38: - return MARK_ROUNDING; - case 44: - return COURSE_WIND; - case 47: - return AVG_WIND; - default: - } - return OTHER; - } - - -} diff --git a/src/main/java/seng302/models/parsers/StreamPacket.java b/src/main/java/seng302/models/parsers/StreamPacket.java deleted file mode 100644 index 5c2c0706..00000000 --- a/src/main/java/seng302/models/parsers/StreamPacket.java +++ /dev/null @@ -1,44 +0,0 @@ -package seng302.models.parsers; - -/** - * Created by kre39 on 23/04/17. - */ -public class StreamPacket { - - //Change int to an ENUM for the type - private PacketType type; - - private long messageLength; - private long timeStamp; - private byte[] payload; - - StreamPacket(int type, long messageLength, long timeStamp, byte[] payload) { - this.type = PacketType.assignPacketType(type); - this.messageLength = messageLength; - this.timeStamp = timeStamp; - this.payload = payload; -// System.out.println("type = " + this.type.toString()); - //switch the packet type to deal with what ever specific packet you want to deal with -// if (this.type == PacketType.XML_MESSAGE){ -// //System.out.println("--------"); -// System.out.println(new String(payload)); -// //StreamParser.parsePacket(this); -// } - } - - PacketType getType() { - return type; - } - - public long getMessageLength() { - return messageLength; - } - - byte[] getPayload() { - return payload; - } - - long getTimeStamp() { - return timeStamp; - } -} diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index 32d0b850..ef35a7ff 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -30,6 +30,7 @@ public class StreamParser extends Thread{ public static ConcurrentHashMap> boatPositions = new ConcurrentHashMap<>(); private String threadName; private Thread t; + private static boolean newRaceXmlReceived = false; private static boolean raceStarted = false; private static XMLParser xmlObject; private static boolean raceFinished = false; @@ -38,6 +39,7 @@ public class StreamParser extends Thread{ private static Map boats = new HashMap<>(); private static Map boatsPos = new TreeMap<>(); private static double windDirection = 0; + private static Long currentTimeLong; private static String currentTimeString; private static boolean appRunning; @@ -121,6 +123,7 @@ public class StreamParser extends Thread{ extractDisplayMessage(packet); break; case XML_MESSAGE: + newRaceXmlReceived = true; extractXmlMessage(packet); break; case RACE_START_STATUS: @@ -195,9 +198,11 @@ public class StreamParser extends Thread{ long currentTime = bytesToLong(Arrays.copyOfRange(payload,1,7)); long raceId = bytesToLong(Arrays.copyOfRange(payload,7,11)); int raceStatus = payload[11]; -// System.out.println("raceStatus = " + raceStatus); long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18)); + long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); + long windSpeed = 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())); @@ -205,7 +210,6 @@ public class StreamParser extends Thread{ } long timeTillStart = ((new Date (expectedStartTime)).getTime() - (new Date (currentTime)).getTime())/1000; - if (timeTillStart > 0) { timeSinceStart = timeTillStart; //System.out.println("Time till start: " + timeTillStart + " Seconds"); @@ -222,10 +226,10 @@ public class StreamParser extends Thread{ //System.out.println("Time since start: " + -1 * timeTillStart + " Seconds"); timeSinceStart = timeTillStart; } - long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); + double windDirFactor = 0x4000 / 90; //0x4000 is 90 degrees, 0x8000 is 180 degrees, etc... windDirection = windDir / windDirFactor; - long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); + int noBoats = payload[22]; int raceType = payload[23]; // ArrayList boatStatuses = new ArrayList<>(); @@ -235,11 +239,11 @@ public class StreamParser extends Thread{ Yacht boat = boats.get((int)(long) boatStatusSourceID); boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]); - boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); - boat.setPenaltiesServed((int)payload[30 + (i * 20)]); - Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,31 + (i * 20),37+ (i * 20))); + boat.setPenaltiesAwarded((int)payload[30 + (i * 20)]); + boat.setPenaltiesServed((int)payload[31 + (i * 20)]); + Long estTimeAtNextMark = bytesToLong(Arrays.copyOfRange(payload,32 + (i * 20),38+ (i * 20))); boat.setEstimateTimeAtNextMark(estTimeAtNextMark); - Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,37 + (i * 20),43+ (i * 20))); + Long estTimeAtFinish = bytesToLong(Arrays.copyOfRange(payload,38 + (i * 20),44+ (i * 20))); boat.setEstimateTimeAtFinish(estTimeAtFinish); boatsPos.put(estTimeAtFinish, boat); // String boatStatus = "SourceID: " + boatStatusSourceID; @@ -293,9 +297,8 @@ public class StreamParser extends Thread{ 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(); - //System.out.println("xmlMessage2 = " + xmlMessage); + 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(); @@ -312,6 +315,9 @@ public class StreamParser extends Thread{ if (messageType == 7) { //7 is the boat XML boats = xmlObject.getBoatXML().getCompetingBoats(); } + if (messageType == 6) { //6 is race info xml + newRaceXmlReceived = true; + } } /** @@ -428,6 +434,9 @@ public class StreamParser extends Thread{ int roundingSide = payload[18]; int markType = payload[19]; int markId = payload[20]; + + // assign mark rounding time to boat + boats.get((int)subjectId).setMarkRoundingTime(timeStamp); } /** @@ -574,9 +583,33 @@ public class StreamParser extends Thread{ 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; System.out.println("[CLIENT] Shutting down stream parser"); } + + /** + * 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/server/ServerThread.java b/src/main/java/seng302/server/ServerThread.java index c09eb8dc..094845ab 100644 --- a/src/main/java/seng302/server/ServerThread.java +++ b/src/main/java/seng302/server/ServerThread.java @@ -235,6 +235,28 @@ public class ServerThread implements Runnable, Observer { } } + /** + * Send the post-start race course information + */ + private void sendPostStartCourseXml(){ + Timer t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + try { + Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE); + if (raceData != null) { + server.send(raceData); + serverLog("Sending race data", 0); + } + }catch (IOException e) { + serverLog("Couldn't send an XML Message: " + e.getMessage(), 0); + } + } + },25000); + //Delays the new course xml data for 25 seconds so the boats are able to pass the starting line + } + public void run() { try{ server = new StreamingServerSocket(PORT_NUMBER); @@ -252,12 +274,13 @@ public class ServerThread implements Runnable, Observer { sendXml(); startSendingRaceStartStatusMessages(); startSendingRaceStatusMessages(); + sendPostStartCourseXml(); } /** * Start sending static boat position updates when race has finished */ - private void startSendingRaceFinishedBoatPostions(){ + private void startSendingRaceFinishedBoatPositions(){ Timer t = new Timer(); t.schedule(new TimerTask() { @Override @@ -316,7 +339,7 @@ public class ServerThread implements Runnable, Observer { } if (numOfBoatsFinished == ((List) arg).size()) { - startSendingRaceFinishedBoatPostions(); + startSendingRaceFinishedBoatPositions(); } } diff --git a/src/main/resources/server_config/courseLimits.xml b/src/main/resources/server_config/courseLimits.xml new file mode 100644 index 00000000..646f6ade --- /dev/null +++ b/src/main/resources/server_config/courseLimits.xml @@ -0,0 +1,105 @@ + + +2015-08-29T13:12:40+02:00 + +15082901 +Fleet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/server_config/race.xml b/src/main/resources/server_config/race.xml index 845f2044..06f4f626 100644 --- a/src/main/resources/server_config/race.xml +++ b/src/main/resources/server_config/race.xml @@ -1,6 +1,6 @@ - 2015-08-29T13:12:40+02:00 + 2015-08-29T11:27:15+02:00 15082901 Fleet @@ -80,6 +80,8 @@ - + + + \ No newline at end of file diff --git a/src/main/resources/views/importantAnnotationSelectView.fxml b/src/main/resources/views/importantAnnotationSelectView.fxml index fb88442d..8b21c2d9 100644 --- a/src/main/resources/views/importantAnnotationSelectView.fxml +++ b/src/main/resources/views/importantAnnotationSelectView.fxml @@ -5,7 +5,7 @@ - + @@ -15,7 +15,8 @@ - + + + diff --git a/src/test/java/seng302/models/parsers/StreamReceiverTest.java b/src/test/java/seng302/models/parsers/StreamReceiverTest.java index c7951e3b..698ee3c0 100644 --- a/src/test/java/seng302/models/parsers/StreamReceiverTest.java +++ b/src/test/java/seng302/models/parsers/StreamReceiverTest.java @@ -8,6 +8,7 @@ import java.lang.reflect.Method; import java.net.Socket; import java.util.Comparator; import java.util.concurrent.PriorityBlockingQueue; +import seng302.models.parsers.packets.StreamPacket; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when;