From 8e18ad62ca4e2f04280af9f340cf193d1aeee9ff Mon Sep 17 00:00:00 2001 From: fjc40 Date: Thu, 6 Jul 2017 16:02:11 +1200 Subject: [PATCH] Added LatestMessages to network.Messages. This is an object that encapsulates the latest up to date set of race messages. Race stores a reference to it. MockRace writes to it, and eventually, VisualiserRace will read from it. Updated MockRace, MockOutput, Event to use it. Angle now implements hashCode(). --- .../src/main/java/mock/app/Event.java | 11 +- .../src/main/java/mock/app/MockOutput.java | 197 +++++++++++++----- .../src/main/java/mock/model/MockRace.java | 52 +++-- .../java/network/Messages/LatestMessages.java | 142 +++++++++++++ .../src/main/java/shared/model/Angle.java | 7 + .../main/java/shared/model/GPSCoordinate.java | 16 +- .../src/main/java/shared/model/Race.java | 18 +- .../Controllers/StartController.java | 19 +- .../java/visualiser/app/VisualiserInput.java | 8 +- 9 files changed, 361 insertions(+), 109 deletions(-) create mode 100644 racevisionGame/src/main/java/network/Messages/LatestMessages.java diff --git a/racevisionGame/src/main/java/mock/app/Event.java b/racevisionGame/src/main/java/mock/app/Event.java index 2c67de2f..1328f2a2 100644 --- a/racevisionGame/src/main/java/mock/app/Event.java +++ b/racevisionGame/src/main/java/mock/app/Event.java @@ -3,6 +3,7 @@ package mock.app; import mock.model.MockRace; import mock.model.Polars; import network.Messages.Enums.MessageType; +import network.Messages.LatestMessages; import org.xml.sax.SAXException; import shared.dataInput.*; import shared.exceptions.InvalidBoatDataException; @@ -28,6 +29,8 @@ public class Event { private String boatXML; private Polars boatPolars; private MockOutput mockOutput; + private LatestMessages latestMessages; + public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) { @@ -36,9 +39,13 @@ public class Event { this.regattaXML = regattaXML; this.boatPolars = boatPolars; + this.latestMessages = new LatestMessages(); + + try { - mockOutput = new MockOutput(); + this.mockOutput = new MockOutput(this.latestMessages); new Thread(mockOutput).start(); + } catch (IOException e) { e.printStackTrace(); } @@ -57,7 +64,7 @@ public class Event { RegattaDataSource regattaDataSource = new RegattaXMLReader(this.regattaXML); //Create and start race. - MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.mockOutput); + MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.latestMessages); new Thread(newRace).start(); diff --git a/racevisionGame/src/main/java/mock/app/MockOutput.java b/racevisionGame/src/main/java/mock/app/MockOutput.java index e0a03f80..ca584376 100644 --- a/racevisionGame/src/main/java/mock/app/MockOutput.java +++ b/racevisionGame/src/main/java/mock/app/MockOutput.java @@ -7,6 +7,7 @@ import network.MessageEncoders.RaceVisionByteEncoder; import network.MessageEncoders.XMLMessageEncoder; import network.Messages.BoatLocation; import network.Messages.Enums.MessageType; +import network.Messages.LatestMessages; import network.Messages.RaceStatus; import network.Messages.XMLMessage; @@ -37,8 +38,14 @@ public class MockOutput implements Runnable ///Output stream which wraps around mockSocket outstream. private DataOutputStream outToVisualiser; - ///A queue that contains items that are waiting to be sent. - private ArrayBlockingQueue messagesToSendQueue = new ArrayBlockingQueue<>(99999999); + + /** + * An object containing the set of latest messages to send. + * Every server frame, MockOutput reads messages from this, and send them. + */ + private LatestMessages latestMessages; + + ///Sequence numbers used in messages. private short messageNumber = 1; @@ -56,11 +63,15 @@ public class MockOutput implements Runnable /** * Ctor. + * @param latestMessages The collection of messages to send to connected clients. * @throws IOException if server socket cannot be opened. */ - public MockOutput() throws IOException { - lastHeartbeatTime = System.currentTimeMillis(); - serverSocket = new ServerSocket(serverPort); + public MockOutput(LatestMessages latestMessages) throws IOException { + + this.lastHeartbeatTime = System.currentTimeMillis(); + this.serverSocket = new ServerSocket(serverPort); + + this.latestMessages = latestMessages; } /** @@ -91,78 +102,93 @@ public class MockOutput implements Runnable * @param xmlString the xml string to send * @param messageType the kind of xml string, values given in AC35 spec (5 regatta, 6 race, 7 boat) */ - public synchronized void parseXMLString(String xmlString, int messageType){ - XMLMessageEncoder encoder = new XMLMessageEncoder(messageNumber, System.currentTimeMillis(), messageType, xmlSequenceNumber,(short) xmlString.length(), xmlString); + public synchronized byte[] parseXMLString(String xmlString, int messageType) { + + XMLMessageEncoder encoder = new XMLMessageEncoder( + messageNumber, + System.currentTimeMillis(), + messageType, + xmlSequenceNumber, + (short) xmlString.length(), + xmlString); + + //iterates the sequence numbers xmlSequenceNumber++; + byte[] encodedXML = encoder.encode(); - BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.XMLMESSAGE, System.currentTimeMillis(), messageNumber, (short)encodedXML.length, encodedXML); + BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder( + MessageType.XMLMESSAGE, + System.currentTimeMillis(), + messageNumber, + (short)encodedXML.length, + encodedXML); + + //iterates the message number messageNumber++; - addMessageToBufferToSend(binaryMessageEncoder.getFullMessage()); + return binaryMessageEncoder.getFullMessage(); + } /** - * Used to give the mocOutput information about boat location to be made into a message and sent - * @param sourceID id of the boat - * @param lat latitude of boat - * @param lon longitude of boat - * @param heading heading of boat - * @param speed speed of boat - * @param time historical time of race + * Encodes/serialises a BoatLocation message, and returns it. + * @param boatLocation The BoatLocation message to serialise. + * @return The BoatLocation message in a serialised form. */ - public synchronized void parseBoatLocation(int sourceID, double lat, double lon, double heading, double speed, long time){ + private synchronized byte[] parseBoatLocation(BoatLocation boatLocation){ - BoatLocation boatLocation = new BoatLocation(sourceID, lat, lon, boatLocationSequenceNumber, heading, speed, time); - //iterates the sequence number - boatLocationSequenceNumber++; - //encodeds the messages + //Encodes the message. byte[] encodedBoatLoc = RaceVisionByteEncoder.boatLocation(boatLocation); - //encodeds the full message with header - BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.BOATLOCATION, System.currentTimeMillis(), messageNumber, (short)encodedBoatLoc.length, - encodedBoatLoc); + //Encodes the full message with header. + BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder( + MessageType.BOATLOCATION, + System.currentTimeMillis(), + messageNumber, + (short) encodedBoatLoc.length, + encodedBoatLoc ); //iterates the message number messageNumber++; - addMessageToBufferToSend(binaryMessageEncoder.getFullMessage()); + return binaryMessageEncoder.getFullMessage(); + } /** - * Parse the race status data and add it to the buffer to be sent - * @param raceStatus race status to parses + * Encodes/serialises a RaceStatus message, and returns it. + * @param raceStatus The RaceStatus message to serialise. + * @return The RaceStatus message in a serialised form. */ - public synchronized void parseRaceStatus(RaceStatus raceStatus){ + private synchronized byte[] parseRaceStatus(RaceStatus raceStatus){ //iterates the sequence number raceStatusSequenceNumber++; - //encodeds the messages + //Encodes the messages. byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus); - //encodeds the full message with header - BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.RACESTATUS, System.currentTimeMillis(), messageNumber, (short)encodedRaceStatus.length, - encodedRaceStatus); + //Encodes the full message with header. + BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder( + MessageType.RACESTATUS, + System.currentTimeMillis(), + messageNumber, + (short) encodedRaceStatus.length, + encodedRaceStatus ); //iterates the message number messageNumber++; - addMessageToBufferToSend(binaryMessageEncoder.getFullMessage()); + return binaryMessageEncoder.getFullMessage(); - } - /** - * Add a message to the buffer to be sent - * @param messagesToSendBuffer message to add to the buffer - */ - private synchronized void addMessageToBufferToSend(byte[] messagesToSendBuffer) { - this.messagesToSendQueue.add(messagesToSendBuffer); } + /** * Sending loop of the Server */ @@ -175,7 +201,7 @@ public class MockOutput implements Runnable outToVisualiser = new DataOutputStream(mockSocket.getOutputStream()); - if (boatsXml == null || regattaXml == null || raceXml == null){ + if (boatsXml == null || regattaXml == null || raceXml == null) { try { Thread.sleep(500); } catch (InterruptedException e) { @@ -184,34 +210,91 @@ public class MockOutput implements Runnable continue; } - parseXMLString(raceXml, XMLMessage.XMLTypeRace); - parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta); - parseXMLString(boatsXml, XMLMessage.XMLTypeBoat); + //Encode xml files. We send them inside the loop, depending on the sentXMLs boolean. + byte[] raceXMLBlob = parseXMLString(raceXml, XMLMessage.XMLTypeRace); + byte[] regattaXMLBlob = parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta); + byte[] boatsXMLBlob = parseXMLString(boatsXml, XMLMessage.XMLTypeBoat); + + + long previousFrameTime = System.currentTimeMillis(); + boolean sentXMLs = false; while(true) { try { - //Sends a heartbeat every so often. - if (timeSinceHeartbeat() >= heartbeatPeriod) { - outToVisualiser.write(heartbeat()); - lastHeartbeatTime = System.currentTimeMillis(); - } - //Checks the buffer to see if there is anything to send. - while (messagesToSendQueue.size() > 0) { - //Grabs message from head of queue. - byte[] binaryMessage = messagesToSendQueue.remove(); + long currentFrameTime = System.currentTimeMillis(); + + //This is the time elapsed, in milliseconds, since the last server "frame". + long framePeriod = currentFrameTime - previousFrameTime; + + //We only attempt to send packets every X milliseconds. + long minimumFramePeriod = 16; + if (framePeriod >= minimumFramePeriod) { + + //Sends a heartbeat every so often. + if (timeSinceHeartbeat() >= heartbeatPeriod) { + outToVisualiser.write(heartbeat()); + lastHeartbeatTime = System.currentTimeMillis(); + } + + //Send XML messages. + if (!sentXMLs) { + outToVisualiser.write(raceXMLBlob); + outToVisualiser.write(regattaXMLBlob); + outToVisualiser.write(boatsXMLBlob); + sentXMLs = true; + } + + //Sens the RaceStatus message. + if (this.latestMessages.getRaceStatus() != null) { + byte[] raceStatusBlob = this.parseRaceStatus(this.latestMessages.getRaceStatus()); + + this.outToVisualiser.write(raceStatusBlob); + } - //sends the message to the visualiser - outToVisualiser.write(binaryMessage); + //Send all of the BoatLocation messages. + for (int sourceID : this.latestMessages.getBoatLocationMap().keySet()) { + + //Get the message. + BoatLocation boatLocation = this.latestMessages.getBoatLocation(sourceID); + if (boatLocation != null) { + + //Encode. + byte[] boatLocationBlob = this.parseBoatLocation(boatLocation); + + //Write it. + this.outToVisualiser.write(boatLocationBlob); + + } + } + + previousFrameTime = currentFrameTime; + + + } else { + //Wait until the frame period will be large enough. + long timeToWait = minimumFramePeriod - framePeriod; + + try { + Thread.sleep(timeToWait); + } catch (InterruptedException e) { + //If we get interrupted, exit the function. + e.printStackTrace(); + //Re-set the interrupt flag. + Thread.currentThread().interrupt(); + return; + } } - }catch(SocketException e){ + + } catch (SocketException e) { break; } } } + } catch (IOException e) { e.printStackTrace(); } @@ -247,7 +330,7 @@ public class MockOutput implements Runnable public static void main(String argv[]) throws Exception { - MockOutput client = new MockOutput(); + MockOutput client = new MockOutput(new LatestMessages()); client.run(); } diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index d5ae1b4c..9413fc62 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -2,8 +2,10 @@ package mock.model; import javafx.animation.AnimationTimer; import mock.app.MockOutput; +import network.Messages.BoatLocation; import network.Messages.BoatStatus; import network.Messages.Enums.BoatStatusEnum; +import network.Messages.LatestMessages; import network.Messages.RaceStatus; import network.Utils.AC35UnitConverter; import shared.dataInput.BoatDataSource; @@ -52,12 +54,6 @@ public class MockRace extends Race { private int dnfChance = 0; - /** - * The mockOutput to send messages to. - */ - private MockOutput mockOutput; - - /** * Used to generate random numbers when changing the wind direction. @@ -88,13 +84,12 @@ public class MockRace extends Race { * @param raceDataSource Data source for race related data (participating boats, legs, etc...). * @param regattaDataSource Data source for race related data (course name, location, timezone, etc...). * @param polars The polars table to be used for boat simulation. - * @param mockOutput The mockOutput to send events to. + * @param latestMessages The LatestMessages to send events to. */ - public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, MockOutput mockOutput) { + public MockRace(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, Polars polars, LatestMessages latestMessages) { - super(boatDataSource, raceDataSource, regattaDataSource); + super(boatDataSource, raceDataSource, regattaDataSource, latestMessages); - this.mockOutput = mockOutput; this.boats = this.generateMockBoats(boatDataSource.getBoats(), raceDataSource.getParticipants(), polars); @@ -175,14 +170,20 @@ public class MockRace extends Race { */ private void parseIndividualMark(Mark mark) { - this.mockOutput.parseBoatLocation( + //Create message. + BoatLocation boatLocation = new BoatLocation( mark.getSourceID(), mark.getPosition().getLatitude(), mark.getPosition().getLongitude(), - 0, - 0, - this.totalTimeElapsed + this.startTime - ); + boatLocationSequenceNumber, + 0, 0, + totalTimeElapsed + startTime); + + //Iterates the sequence number. + boatLocationSequenceNumber++; + + this.latestMessages.setBoatLocation(boatLocation); + } @@ -206,14 +207,19 @@ public class MockRace extends Race { */ private void parseIndividualBoatLocation(MockBoat boat) { - this.mockOutput.parseBoatLocation( + BoatLocation boatLocation = new BoatLocation( boat.getSourceID(), boat.getCurrentPosition().getLatitude(), boat.getCurrentPosition().getLongitude(), + boatLocationSequenceNumber, boat.getBearing().degrees(), boat.getCurrentSpeed(), - startTime + totalTimeElapsed - ); + startTime + totalTimeElapsed); + + //Iterates the sequence number. + boatLocationSequenceNumber++; + + this.latestMessages.setBoatLocation(boatLocation); } @@ -272,7 +278,6 @@ public class MockRace extends Race { boatStatuses.add(boatStatus); } - //TODO REFACTOR for consistency, could send parameters to mockOutput instead of the whole racestatus. This will also fix the sequence number issue. //Convert wind direction and speed to ints. //TODO this conversion should be done inside the racestatus class. int windDirectionInt = AC35UnitConverter.encodeHeading(this.windDirection.degrees()); @@ -283,12 +288,14 @@ public class MockRace extends Race { System.currentTimeMillis(), this.raceId, this.getRaceStatusEnum().getValue(), - this.startTime, windDirectionInt, + this.startTime, + windDirectionInt, windSpeedInt, this.getRaceType().getValue(), - boatStatuses ); + boatStatuses); + - mockOutput.parseRaceStatus(raceStatus); + this.latestMessages.setRaceStatus(raceStatus); } @@ -427,7 +434,6 @@ public class MockRace extends Race { parseRaceStatus(); if (iters > 500) { - mockOutput.stop(); stop(); } iters++; diff --git a/racevisionGame/src/main/java/network/Messages/LatestMessages.java b/racevisionGame/src/main/java/network/Messages/LatestMessages.java new file mode 100644 index 00000000..139543a0 --- /dev/null +++ b/racevisionGame/src/main/java/network/Messages/LatestMessages.java @@ -0,0 +1,142 @@ +package network.Messages; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class contains a set of the latest messages received (e.g., the latest RaceStatus, the latest BoatLocation for each boat, etc...). + */ +public class LatestMessages { + + /** + * The latest RaceStatus message. + */ + private RaceStatus raceStatus; + + /** + * A map of the last BoatStatus message received, for each boat. + */ + private final Map boatStatusMap = new HashMap<>(); + + /** + * A map of the last BoatLocation message received, for each boat. + */ + private final Map boatLocationMap = new HashMap<>(); + + /** + * The last AverageWind message received. + */ + private AverageWind averageWind; + + /** + * The last CourseWinds message received. + */ + private CourseWinds courseWinds; + + + + + /** + * Ctor. + */ + public LatestMessages() { + } + + + + + /** + * Gets the latest RaceStatus message received. + * @return The latest RaceStatus message received. + */ + public RaceStatus getRaceStatus() { + return raceStatus; + } + + /** + * Sets the latest RaceStatus message received. + * @param raceStatus The new RaceStatus message to store. + */ + public void setRaceStatus(RaceStatus raceStatus) { + this.raceStatus = raceStatus; + } + + + + /** + * Returns the latest BoatStatus message received for a given boat. + * @param sourceID Source ID of the boat. + * @return The latest BoatStatus message for the specified boat. + */ + public BoatStatus getBoatStatus(int sourceID) { + return boatStatusMap.get(sourceID); + } + + /** + * Inserts a BoatStatus message for a given boat. + * @param boatStatus The BoatStatus message to set. + */ + public void setBoatStatus(BoatStatus boatStatus) { + boatStatusMap.put(boatStatus.getSourceID(), boatStatus); + } + + + + /** + * Returns the latest BoatLocation message received for a given boat. + * @param sourceID Source ID of the boat. + * @return The latest BoatLocation message for the specified boat. + */ + public BoatLocation getBoatLocation(int sourceID) { + return boatLocationMap.get(sourceID); + } + + /** + * Inserts a BoatLocation message for a given boat. + * @param boatLocation The BoatLocation message to set. + */ + public void setBoatLocation(BoatLocation boatLocation) { + //TODO should compare the sequence number of the new boatLocation with the existing boatLocation for this boat (if it exists), and use the newer one. + boatLocationMap.put(boatLocation.getSourceID(), boatLocation); + } + + + + /** + * Gets the latest AverageWind message received. + * @return The latest AverageWind message received. + */ + public AverageWind getAverageWind() { + return averageWind; + } + + /** + * Sets the latest AverageWind message received. + * @param averageWind The new AverageWind message to store. + */ + public void setAverageWind(AverageWind averageWind) { + this.averageWind = averageWind; + } + + + /** + * Gets the latest CourseWinds message received. + * @return The latest CourseWinds message received. + */ + public CourseWinds getCourseWinds() { + return courseWinds; + } + + /** + * Sets the latest CourseWinds message received. + * @param courseWinds The new CourseWinds message to store. + */ + public void setCourseWinds(CourseWinds courseWinds) { + this.courseWinds = courseWinds; + } + + + public Map getBoatLocationMap() { + return boatLocationMap; + } +} diff --git a/racevisionGame/src/main/java/shared/model/Angle.java b/racevisionGame/src/main/java/shared/model/Angle.java index d96ff50e..00610b65 100644 --- a/racevisionGame/src/main/java/shared/model/Angle.java +++ b/racevisionGame/src/main/java/shared/model/Angle.java @@ -84,6 +84,13 @@ public class Angle implements Comparable { } + @Override + public int hashCode() { + return Double.hashCode(this.degrees); + } + + + /** * Returns an int describing the ordering between this angle object, and another. * @param o Other angle to compare to. diff --git a/racevisionGame/src/main/java/shared/model/GPSCoordinate.java b/racevisionGame/src/main/java/shared/model/GPSCoordinate.java index 5018e351..63302bf2 100644 --- a/racevisionGame/src/main/java/shared/model/GPSCoordinate.java +++ b/racevisionGame/src/main/java/shared/model/GPSCoordinate.java @@ -335,12 +335,12 @@ public class GPSCoordinate { //Get the bearing between two adjacent points. Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); - //Calculate angle perpendicular to bearing. - Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); + //Calculate angle perpindicular to bearing. + Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); //Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge. - GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); - GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); + GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); + GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); //Add edge to list. shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); @@ -355,12 +355,12 @@ public class GPSCoordinate { //Get the bearing between two adjacent points. Bearing bearing = GPSCoordinate.calculateBearing(firstPoint, secondPoint); - //Calculate angle perpendicular to bearing. - Bearing perpendicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); + //Calculate angle perpindicular to bearing. + Bearing perpindicularBearing = Bearing.fromDegrees(bearing.degrees() + (90d * clockwiseScaleFactor)); //Translate both first and second point by 50m, using this bearing. These form our inwards shifted edge. - GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); - GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpendicularBearing)); + GPSCoordinate firstPointTranslated = GPSCoordinate.calculateNewPosition(firstPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); + GPSCoordinate secondPointTranslated = GPSCoordinate.calculateNewPosition(secondPoint, shrinkDistance, Azimuth.fromBearing(perpindicularBearing)); //Add edge to list. shrunkEdges.add(new Pair<>(firstPointTranslated, secondPointTranslated)); diff --git a/racevisionGame/src/main/java/shared/model/Race.java b/racevisionGame/src/main/java/shared/model/Race.java index 8b170134..49b13b50 100644 --- a/racevisionGame/src/main/java/shared/model/Race.java +++ b/racevisionGame/src/main/java/shared/model/Race.java @@ -5,6 +5,7 @@ import javafx.collections.FXCollections; import mock.model.VMG; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceTypeEnum; +import network.Messages.LatestMessages; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; @@ -40,6 +41,18 @@ public abstract class Race implements Runnable { */ protected RegattaDataSource regattaDataSource; + /** + * The collection of latest race messages. + * Can be either read from or written to. + */ + protected LatestMessages latestMessages; + + /** + * The sequence number of the latest boatLocation message sent or received. + */ + protected int boatLocationSequenceNumber = 1; + + /** * A list of compound marks in the race. @@ -102,14 +115,17 @@ public abstract class Race implements Runnable { * @param boatDataSource Data source for boat related data (yachts and marker boats). * @param raceDataSource Data source for race related data (participating boats, legs, etc...). * @param regattaDataSource Data source for race related data (course name, location, timezone, etc...). + * @param latestMessages The collection of latest messages, which can be written to, or read from. */ - public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource) { + public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages) { //Keep a reference to data sources. this.raceDataSource = raceDataSource; this.boatDataSource = boatDataSource; this.regattaDataSource = regattaDataSource; + this.latestMessages = latestMessages; + this.compoundMarks = raceDataSource.getCompoundMarks(); diff --git a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java b/racevisionGame/src/main/java/visualiser/Controllers/StartController.java index 1b7078d7..7b126d2f 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/StartController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/StartController.java @@ -11,10 +11,9 @@ import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; -import seng302.Mock.StreamedCourse; -import seng302.Model.Boat; -import seng302.Model.RaceClock; -import seng302.VisualiserInput; +import visualiser.app.VisualiserInput; +import visualiser.model.RaceClock; +import visualiser.model.VisualiserBoat; import java.io.IOException; import java.net.Socket; @@ -35,18 +34,16 @@ public class StartController extends Controller implements Observer { @FXML private Label raceTitleLabel; @FXML private Label raceStartLabel; - @FXML private TableView boatNameTable; - @FXML private TableColumn boatNameColumn; - @FXML private TableColumn boatCodeColumn; + @FXML private TableView boatNameTable; + @FXML private TableColumn boatNameColumn; + @FXML private TableColumn boatCodeColumn; @FXML private Label timeZoneTime; @FXML private Label timer; @FXML private Label raceStatusLabel; - //@FXML Button fifteenMinButton; private RaceClock raceClock; - private StreamedCourse raceData; private int raceStat; private VisualiserInput visualiserInput; @@ -80,8 +77,8 @@ public class StartController extends Controller implements Observer { * Initiliases the tables that are to be shown on the pane */ private void initialiseTables() { - List boats = raceData.getBoats(); - ObservableList observableBoats = FXCollections.observableArrayList(boats); + List boats = raceData.getBoats(); + ObservableList observableBoats = FXCollections.observableArrayList(boats); boatNameTable.setItems(observableBoats); boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().getName()); diff --git a/racevisionGame/src/main/java/visualiser/app/VisualiserInput.java b/racevisionGame/src/main/java/visualiser/app/VisualiserInput.java index 39a4cc5c..0d6d97ed 100644 --- a/racevisionGame/src/main/java/visualiser/app/VisualiserInput.java +++ b/racevisionGame/src/main/java/visualiser/app/VisualiserInput.java @@ -1,8 +1,7 @@ package visualiser.app; import javafx.application.Platform; +import network.Messages.*; import org.xml.sax.SAXException; -import seng302.Networking.BinaryMessageDecoder; -import seng302.Networking.Exceptions.InvalidMessageException; import javax.xml.parsers.ParserConfigurationException; import java.io.DataInputStream; @@ -13,12 +12,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import static seng302.Networking.Utils.ByteConverter.bytesToShort; - /** * TCP client which receives packets/messages from a race data source * (e.g., mock source, official source), and exposes them to any observers. - * @see seng302.Mock.StreamedCourse */ public class VisualiserInput implements Runnable { @@ -30,8 +26,6 @@ public class VisualiserInput implements Runnable { ///The socket that we have connected to. private Socket connectionSocket; - ///Object to store parsed course data. //TODO comment? - private StreamedCourse course; ///The last RaceStatus message received. private RaceStatus raceStatus;