diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index aa0286f4..7069d719 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -6,8 +6,8 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; +import seng302.client.ClientPacketParser; import seng302.models.PolarTable; -import seng302.models.stream.StreamParser; import seng302.models.stream.StreamReceiver; public class App extends Application { @@ -26,7 +26,7 @@ public class App extends Application { primaryStage.show(); primaryStage.setOnCloseRequest(e -> { - StreamParser.appClose(); + ClientPacketParser.appClose(); StreamReceiver.noMoreBytes(); System.exit(0); }); diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/client/ClientPacketParser.java similarity index 96% rename from src/main/java/seng302/models/stream/StreamParser.java rename to src/main/java/seng302/client/ClientPacketParser.java index a1c0d985..2cae4857 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/client/ClientPacketParser.java @@ -1,4 +1,4 @@ -package seng302.models.stream; +package seng302.client; import java.io.IOException; @@ -22,6 +22,7 @@ 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; @@ -31,7 +32,7 @@ import seng302.models.stream.packets.StreamPacket; * that are threadsafe so the visualiser can always access the latest speed and position available * Created by kre39 on 23/04/17. */ -public class StreamParser{ +public class ClientPacketParser { public static ConcurrentHashMap> markLocations = new ConcurrentHashMap<>(); public static ConcurrentHashMap> boatLocations = new ConcurrentHashMap<>(); @@ -58,7 +59,7 @@ public class StreamParser{ /** * Used to initialise the thread name and stream parser object so a thread can be executed */ - public StreamParser() { + public ClientPacketParser() { } /** * Looks at the type of the packet then sends it to the appropriate parser to extract the @@ -106,9 +107,6 @@ public class StreamParser{ case AVG_WIND: extractAvgWind(packet); break; - case BOAT_ACTION: - extractBoatAction(packet); - break; } } catch (NullPointerException e) { System.out.println("Error parsing packet"); @@ -491,27 +489,6 @@ public class StreamParser{ long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23)); } - - private static void extractBoatAction(StreamPacket packet) { - byte[] payload = packet.getPayload(); - int messageVersionNo = payload[0]; - long actionType = bytesToLong(Arrays.copyOfRange(payload, 0, 1)); - if (actionType == 1) { - System.out.println("VMG"); - } else if (actionType == 2) { - System.out.println("SAILS IN"); - } else if (actionType == 3) { - System.out.println("SAILS OUT"); - } else if (actionType == 4) { - System.out.println("TACK/GYBE"); - } else if (actionType == 5) { - System.out.println("UPWIND"); - } else if (actionType == 6) { - System.out.println("DOWNWIND"); - } - - } - /** * takes an array of up to 7 bytes and returns a positive * long constructed from the input bytes diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index 216315dc..e2c1cff9 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -8,10 +8,8 @@ import java.net.Socket; import java.util.zip.CRC32; import java.util.zip.Checksum; -import seng302.models.stream.StreamParser; import seng302.models.stream.packets.StreamPacket; import seng302.server.messages.BoatActionMessage; -import seng302.server.messages.BoatActionType; import seng302.server.messages.Message; /** @@ -76,7 +74,8 @@ public class ClientToServerThread extends Thread { long computedCrc = checksum.getValue(); long packetCrc = Message.bytesToLong(getBytes(4)); if (computedCrc == packetCrc) { - StreamParser.parsePacket(new StreamPacket(type, payloadLength, timeStamp, payload)); + ClientPacketParser + .parsePacket(new StreamPacket(type, payloadLength, timeStamp, payload)); // TODO: 17/07/17 wmu16 - Fix this or maybe we dont need to go through the main server at all!?!? // packetBufferDelegate.addToBuffer(new StreamPacket(type, payloadLength, timeStamp, payload)); } else { diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 8a9f86ec..5c69f846 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -15,13 +15,13 @@ import javafx.scene.Group; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.image.ImageView; -import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; +import seng302.client.ClientPacketParser; import seng302.fxObjects.BoatGroup; import seng302.models.Colors; import seng302.models.Yacht; @@ -32,7 +32,6 @@ import seng302.models.mark.MarkType; import seng302.models.mark.SingleMark; import seng302.models.map.Boundary; import seng302.models.map.CanvasMap; -import seng302.models.stream.StreamParser; import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser.RaceXMLObject.Limit; import seng302.models.stream.XMLParser.RaceXMLObject.Participant; @@ -156,13 +155,13 @@ public class CanvasController { raceViewController.updateSparkLine(); } updateGroups(); - if (StreamParser.isRaceFinished()) { + if (ClientPacketParser.isRaceFinished()) { this.stop(); } lastTime = now; } } - if (StreamParser.isRaceFinished()) { + if (ClientPacketParser.isRaceFinished()) { this.stop(); switchToFinishScreen(); } @@ -231,7 +230,7 @@ public class CanvasController { * in a compound mark etc.. */ private void addRaceBorder() { - XMLParser.RaceXMLObject raceXMLObject = StreamParser.getXmlObject().getRaceXML(); + XMLParser.RaceXMLObject raceXMLObject = ClientPacketParser.getXmlObject().getRaceXML(); ArrayList courseLimits = raceXMLObject.getCourseLimit(); raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1)); raceBorder.setStrokeWidth(3); @@ -249,7 +248,7 @@ public class CanvasController { for (BoatGroup boatGroup : boatGroups) { // some raceObjects will have multiple ID's (for instance gate marks) //checking if the current "ID" has any updates associated with it - if (StreamParser.boatLocations.containsKey(boatGroup.getRaceId())) { + if (ClientPacketParser.boatLocations.containsKey(boatGroup.getRaceId())) { if (boatGroup.isStopped()) { updateBoatGroup(boatGroup); } @@ -258,7 +257,7 @@ public class CanvasController { } for (MarkGroup markGroup : markGroups) { for (Long id : markGroup.getRaceIds()) { - if (StreamParser.markLocations.containsKey(id)) { + if (ClientPacketParser.markLocations.containsKey(id)) { updateMarkGroup(id, markGroup); } } @@ -267,13 +266,14 @@ public class CanvasController { } private void checkForCourseChanges() { - if (StreamParser.isNewRaceXmlReceived()){ + if (ClientPacketParser.isNewRaceXmlReceived()) { addRaceBorder(); } } private void updateBoatGroup(BoatGroup boatGroup) { - PriorityBlockingQueue movementQueue = StreamParser.boatLocations.get(boatGroup.getRaceId()); + PriorityBlockingQueue movementQueue = ClientPacketParser.boatLocations + .get(boatGroup.getRaceId()); // giving the movementQueue a 5 packet buffer to account for slightly out of order packets if (movementQueue.size() > 0) { try { @@ -291,7 +291,8 @@ public class CanvasController { } void updateMarkGroup (long raceId, MarkGroup markGroup) { - PriorityBlockingQueue movementQueue = StreamParser.markLocations.get(raceId); + PriorityBlockingQueue movementQueue = ClientPacketParser.markLocations + .get(raceId); if (movementQueue.size() > 0){ try { BoatPositionPacket positionPacket = movementQueue.take(); @@ -307,12 +308,12 @@ public class CanvasController { * Draws all the boats. */ private void initializeBoats() { - Map boats = StreamParser.getBoats(); + Map boats = ClientPacketParser.getBoats(); Group wakes = new Group(); Group trails = new Group(); Group annotations = new Group(); - ArrayList participants = StreamParser.getXmlObject().getRaceXML() + ArrayList participants = ClientPacketParser.getXmlObject().getRaceXML() .getParticipants(); ArrayList participantIDs = new ArrayList<>(); for (Participant p : participants) { @@ -336,7 +337,8 @@ public class CanvasController { } private void initializeMarks() { - List allMarks = StreamParser.getXmlObject().getRaceXML().getNonDupCompoundMarks(); + List allMarks = ClientPacketParser.getXmlObject().getRaceXML() + .getNonDupCompoundMarks(); for (Mark mark : allMarks) { if (mark.getMarkType() == MarkType.SINGLE_MARK) { SingleMark sMark = (SingleMark) mark; @@ -402,7 +404,7 @@ public class CanvasController { */ private void fitMarksToCanvas() { //Check is called once to avoid unnecessarily change the course limits once the race is running - StreamParser.isNewRaceXmlReceived(); + ClientPacketParser.isNewRaceXmlReceived(); findMinMaxPoint(); double minLonToMaxLon = scaleRaceExtremities(); calculateReferencePointLocation(minLonToMaxLon); @@ -418,7 +420,7 @@ public class CanvasController { */ private void findMinMaxPoint() { List sortedPoints = new ArrayList<>(); - for (Limit limit : StreamParser.getXmlObject().getRaceXML().getCourseLimit()) { + for (Limit limit : ClientPacketParser.getXmlObject().getRaceXML().getCourseLimit()) { sortedPoints.add(limit); } sortedPoints.sort(Comparator.comparingDouble(Limit::getLat)); diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 24d433c9..5ca31ee7 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -9,7 +9,7 @@ import javafx.fxml.Initializable; import javafx.scene.Parent; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; -import seng302.models.stream.StreamParser; +import seng302.client.ClientPacketParser; import seng302.client.ClientToServerThread; import seng302.server.messages.BoatActionMessage; import seng302.server.messages.BoatActionType; @@ -42,7 +42,7 @@ public class Controller implements Initializable { contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); StartScreenController startScreenController = (StartScreenController) setContentPane("/views/StartScreenView.fxml"); startScreenController.setController(this); - StreamParser.boatLocations.clear(); + ClientPacketParser.boatLocations.clear(); } /** Handle the key-pressed event from the text field. */ diff --git a/src/main/java/seng302/controllers/FinishScreenViewController.java b/src/main/java/seng302/controllers/FinishScreenViewController.java index a2d79f36..1491c7c9 100644 --- a/src/main/java/seng302/controllers/FinishScreenViewController.java +++ b/src/main/java/seng302/controllers/FinishScreenViewController.java @@ -15,8 +15,8 @@ import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; +import seng302.client.ClientPacketParser; import seng302.models.Yacht; -import seng302.models.stream.StreamParser; import seng302.models.stream.XMLParser.RaceXMLObject.Participant; public class FinishScreenViewController implements Initializable { @@ -59,7 +59,7 @@ public class FinishScreenViewController implements Initializable { ); // check if the boat is racing - ArrayList participants = StreamParser.getXmlObject().getRaceXML() + ArrayList participants = ClientPacketParser.getXmlObject().getRaceXML() .getParticipants(); ArrayList participantIDs = new ArrayList<>(); for (Participant p : participants) { @@ -67,7 +67,7 @@ public class FinishScreenViewController implements Initializable { } // add data to table - for (Yacht boat : StreamParser.getBoatsPos().values()) { + for (Yacht boat : ClientPacketParser.getBoatsPos().values()) { if (participantIDs.contains(boat.getSourceID())) { data.add(boat); } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 397b54cb..0fa8b17c 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -4,7 +4,6 @@ import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.geometry.Point2D; @@ -17,7 +16,6 @@ import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Slider; -import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; @@ -29,6 +27,7 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; import javafx.util.StringConverter; +import seng302.client.ClientPacketParser; import seng302.utilities.GeoUtility; import seng302.controllers.annotations.Annotation; import seng302.controllers.annotations.ImportantAnnotationController; @@ -40,7 +39,6 @@ import seng302.models.*; import seng302.models.mark.GateMark; import seng302.models.mark.Mark; import seng302.models.mark.SingleMark; -import seng302.models.stream.StreamParser; import seng302.models.stream.XMLParser; import java.io.IOException; @@ -95,16 +93,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel raceSparkLine.getYAxis().setTranslateX(-5); raceSparkLine.getYAxis().setAutoRanging(false); sparklineYAxis.setTickMarkVisible(false); - //startingBoats = new ArrayList<>(StreamParser.getBoats().values()); + startingBoats = new ArrayList<>(ClientPacketParser.getBoats().values()); - //includedCanvasController.setup(this); - //includedCanvasController.initializeCanvas(); - //initializeUpdateTimer(); - //initialiseFPSCheckBox(); - //initialiseAnnotationSlider(); - //initialiseBoatSelectionComboBox(); - //includedCanvasController.timer.start(); - //selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); + includedCanvasController.setup(this); + includedCanvasController.initializeCanvas(); + initializeUpdateTimer(); + initialiseFPSCheckBox(); + initialiseAnnotationSlider(); + initialiseBoatSelectionComboBox(); + includedCanvasController.timer.start(); + selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView()); } @@ -305,7 +303,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private Mark getNextMark(BoatGroup bg) { Integer legNumber = bg.getBoat().getLegNumber(); - List markSequence = StreamParser.getXmlObject().getRaceXML().getCompoundMarkSequence(); + List markSequence = ClientPacketParser.getXmlObject() + .getRaceXML().getCompoundMarkSequence(); if (legNumber == 0) { return null; @@ -317,7 +316,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel if (legNumber + 2 == corner.getSeqID()) { Integer thisCompoundMarkID = corner.getCompoundMarkID(); - for (Mark mark : StreamParser.getXmlObject().getRaceXML().getAllCompoundMarks()) { + for (Mark mark : ClientPacketParser.getXmlObject().getRaceXML() + .getAllCompoundMarks()) { if (mark.getCompoundMarkID() == thisCompoundMarkID) { return mark; } @@ -330,11 +330,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** - * Updates the wind direction arrow and text as from info from the StreamParser + * Updates the wind direction arrow and text as from info from the ClientPacketParser */ private void updateWindDirection() { - windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection())); - windArrowText.setRotate(StreamParser.getWindDirection()); + windDirectionText.setText(String.format("%.1f°", ClientPacketParser.getWindDirection())); + windArrowText.setRotate(ClientPacketParser.getWindDirection()); } @@ -342,7 +342,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * Updates the clock for the race */ private void updateRaceTime() { - if (StreamParser.isRaceFinished()) { + if (ClientPacketParser.isRaceFinished()) { timerLabel.setFill(Color.RED); timerLabel.setText("Race Finished!"); } else { @@ -352,18 +352,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** - * Grabs the boats currently in the race as from the StreamParser and sets them to be selectable + * Grabs the boats currently in the race as from the ClientPacketParser and sets them to be selectable * in the boat selection combo box */ private void updateBoatSelectionComboBox() { ObservableList observableBoats = FXCollections - .observableArrayList(StreamParser.getBoatsPos().values()); + .observableArrayList(ClientPacketParser.getBoatsPos().values()); boatSelectionComboBox.setItems(observableBoats); } /** - * Updates the order of the boats as from the StreamParser and sets them in the boat order + * Updates the order of the boats as from the ClientPacketParser and sets them in the boat order * section */ private void updateOrder() { @@ -372,15 +372,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); // list of racing boat id - ArrayList participants = StreamParser.getXmlObject().getRaceXML() + ArrayList participants = ClientPacketParser.getXmlObject().getRaceXML() .getParticipants(); ArrayList participantIDs = new ArrayList<>(); for (Participant p : participants) { participantIDs.add(p.getsourceID()); } - if (StreamParser.isRaceStarted()) { - for (Yacht boat : StreamParser.getBoatsPos().values()) { + if (ClientPacketParser.isRaceStarted()) { + for (Yacht boat : ClientPacketParser.getBoatsPos().values()) { if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing if (boat.getBoatStatus() == 3) { // 3 is finish status Text textToAdd = new Text(boat.getPosition() + ". " + @@ -398,7 +398,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } } } else { - for (Yacht boat : StreamParser.getBoats().values()) { + for (Yacht boat : ClientPacketParser.getBoats().values()) { if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing Text textToAdd = new Text(boat.getPosition() + ". " + boat.getShortName() + " "); @@ -436,9 +436,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Point2D markPoint2 = includedCanvasController.findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude()); HashMap angleAndSpeed; if (isUpwind) { - angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed()); + angleAndSpeed = PolarTable + .getOptimalUpwindVMG(ClientPacketParser.getWindSpeed()); } else { - angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed()); + angleAndSpeed = PolarTable + .getOptimalDownwindVMG(ClientPacketParser.getWindSpeed()); } Double resultingAngle = angleAndSpeed.keySet().iterator().next(); @@ -450,11 +452,19 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Line rightLayline = new Line(); Line leftLayline = new Line(); if (lineFuncResult == 1) { - rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection()); - leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection()); + rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, + ClientPacketParser + .getWindDirection()); + leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, + ClientPacketParser + .getWindDirection()); } else if (lineFuncResult == -1) { - rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection()); - leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection()); + rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, + ClientPacketParser + .getWindDirection()); + leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, + ClientPacketParser + .getWindDirection()); } leftLayline.setStrokeWidth(0.5); @@ -550,16 +560,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private String getTimeSinceStartOfRace() { String timerString = "0:00"; - if (StreamParser.getTimeSinceStart() > 0) { - String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60); - String timerSecond = Long.toString(StreamParser.getTimeSinceStart() % 60); + if (ClientPacketParser.getTimeSinceStart() > 0) { + String timerMinute = Long.toString(ClientPacketParser.getTimeSinceStart() / 60); + String timerSecond = Long.toString(ClientPacketParser.getTimeSinceStart() % 60); if (timerSecond.length() == 1) { timerSecond = "0" + timerSecond; } timerString = "-" + timerMinute + ":" + timerSecond; } else { - String timerMinute = Long.toString(-1 * StreamParser.getTimeSinceStart() / 60); - String timerSecond = Long.toString(-1 * StreamParser.getTimeSinceStart() % 60); + String timerMinute = Long.toString(-1 * ClientPacketParser.getTimeSinceStart() / 60); + String timerSecond = Long.toString(-1 * ClientPacketParser.getTimeSinceStart() % 60); if (timerSecond.length() == 1) { timerSecond = "0" + timerSecond; } diff --git a/src/main/java/seng302/fxObjects/BoatAnnotations.java b/src/main/java/seng302/fxObjects/BoatAnnotations.java index fbba2257..c8848418 100644 --- a/src/main/java/seng302/fxObjects/BoatAnnotations.java +++ b/src/main/java/seng302/fxObjects/BoatAnnotations.java @@ -5,8 +5,8 @@ import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; +import seng302.client.ClientPacketParser; import seng302.models.Yacht; -import seng302.models.stream.StreamParser; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -88,7 +88,7 @@ public class BoatAnnotations extends Group{ if (boat.getTimeTillNext() != null) { DateFormat format = new SimpleDateFormat("mm:ss"); String timeToNextMark = format - .format(boat.getTimeTillNext() - StreamParser.getCurrentTimeLong()); + .format(boat.getTimeTillNext() - ClientPacketParser.getCurrentTimeLong()); estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); } else { estTimeToNextMarkObject.setText("Next mark: -"); @@ -97,7 +97,7 @@ public class BoatAnnotations extends Group{ if (boat.getMarkRoundTime() != null) { DateFormat format = new SimpleDateFormat("mm:ss"); String elapsedTime = format - .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundTime()); + .format(ClientPacketParser.getCurrentTimeLong() - boat.getMarkRoundTime()); legTimeObject.setText("Last mark: " + elapsedTime); }else { legTimeObject.setText("Last mark: - "); diff --git a/src/main/java/seng302/fxObjects/BoatGroup.java b/src/main/java/seng302/fxObjects/BoatGroup.java index 12d23ee8..acf0c0cb 100644 --- a/src/main/java/seng302/fxObjects/BoatGroup.java +++ b/src/main/java/seng302/fxObjects/BoatGroup.java @@ -9,13 +9,13 @@ import javafx.scene.paint.Color; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.transform.Rotate; +import seng302.client.ClientPacketParser; import seng302.models.Yacht; import seng302.utilities.GeoUtility; import seng302.controllers.CanvasController; import seng302.models.mark.GateMark; import seng302.models.mark.Mark; import seng302.models.mark.SingleMark; -import seng302.models.stream.StreamParser; /** * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 @@ -238,7 +238,7 @@ public class BoatGroup extends Group { */ public Boolean isUpwindLeg(CanvasController canvasController, Mark nextMark) { - Double windAngle = StreamParser.getWindDirection(); + Double windAngle = ClientPacketParser.getWindDirection(); GateMark thisGateMark = (GateMark) nextMark; SingleMark nextMark1 = thisGateMark.getSingleMark1(); SingleMark nextMark2 = thisGateMark.getSingleMark2(); diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index d36968fc..20aaaf4f 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,8 +1,13 @@ package seng302.gameServer; +import java.util.List; +import java.util.Map; +import java.util.Set; import seng302.models.Player; import java.util.ArrayList; +import seng302.models.Yacht; +import seng302.server.messages.BoatActionType; /** * A Static class to hold information about the current state of the game (model) @@ -10,8 +15,13 @@ import java.util.ArrayList; */ public class GameState { + private static Long previousUpdateTime; + private static Double windDirection = 0d; + private static Double windSpeed = 0d; + private static String hostIpAddress; - private static ArrayList players; + private static List players; + private static Map yachts; private static Boolean isRaceStarted; private static GameStages currentStage; @@ -20,13 +30,15 @@ public class GameState { players = new ArrayList<>(); currentStage = GameStages.LOBBYING; isRaceStarted = false; + //set this when game stage changes to prerace + previousUpdateTime = System.currentTimeMillis(); } public static String getHostIpAddress() { return hostIpAddress; } - public static ArrayList getPlayers() { + public static List getPlayers() { return players; } @@ -38,6 +50,10 @@ public class GameState { players.remove(player); } + public static void addYacht(Integer sourceId, Yacht yatch) { + yachts.put(sourceId, yatch); + } + public static Boolean getIsRaceStarted() { return isRaceStarted; } @@ -50,16 +66,36 @@ public class GameState { GameState.currentStage = currentStage; } - /** - * This iterates through all players and updates each players info to its new state based on its current data - */ - private void update(){ - for(Player player : players) { - // TODO: 10/07/17 wmu16 - Update all player info + public static Double getWindDirection() { + return windDirection; + } + + public static Double getWindSpeed() { + return windSpeed; + } + + public static void updateBoat(Integer sourceId, BoatActionType actionType) { + switch (actionType) { + case VMG: + break; + case SAILS_IN: + break; + case SAILS_OUT: + break; + case TACK_GYBE: + break; + case UPWIND: + break; + case DOWNWIND: + break; } } - - - + public static void update() { + Long timeInterval = System.currentTimeMillis() - previousUpdateTime; + previousUpdateTime = System.currentTimeMillis(); + for (Yacht yacht : yachts.values()) { + yacht.update(timeInterval); + } + } } diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index df6c1fcc..5149eee5 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -1,8 +1,8 @@ package seng302.gameServer; +import seng302.client.ClientPacketParser; import seng302.models.Player; import seng302.models.stream.PacketBufferDelegate; -import seng302.models.stream.StreamParser; import seng302.models.stream.packets.StreamPacket; import java.io.IOException; @@ -57,11 +57,12 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl e.printStackTrace(); } - - + if (GameState.getCurrentStage() == GameStages.PRE_RACE) { + GameState.update(); + } //RACING if (GameState.getCurrentStage() == GameStages.RACING) { - updateClients(); + GameState.update(); } @@ -71,12 +72,11 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl } updateClients(); - while (!packetBuffer.isEmpty()){ System.out.println("WHATUPPP"); try { StreamPacket packet = packetBuffer.take(); - StreamParser.parsePacket(packet); + ClientPacketParser.parsePacket(packet); } catch (InterruptedException e) { continue; } diff --git a/src/main/java/seng302/gameServer/ServerPacketParser.java b/src/main/java/seng302/gameServer/ServerPacketParser.java new file mode 100644 index 00000000..155ebe04 --- /dev/null +++ b/src/main/java/seng302/gameServer/ServerPacketParser.java @@ -0,0 +1,37 @@ +package seng302.gameServer; + +import java.util.Arrays; +import seng302.models.stream.packets.StreamPacket; +import seng302.server.messages.BoatActionType; + + +public class ServerPacketParser { + + + public static BoatActionType extractBoatAction(StreamPacket packet) { + byte[] payload = packet.getPayload(); + int messageVersionNo = payload[0]; + long actionTypeValue = bytesToLong(Arrays.copyOfRange(payload, 0, 1)); + return BoatActionType.getType((int) actionTypeValue); + } + + /** + * 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; + } +} + diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 6ea157bf..14b98db8 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -1,18 +1,22 @@ package seng302.gameServer; -import seng302.gameServer.GameState; + +import java.util.Random; +import seng302.client.ClientPacketParser; import seng302.models.Player; -import seng302.models.stream.PacketBufferDelegate; -import seng302.models.stream.StreamParser; +import seng302.models.Yacht; +import seng302.models.stream.packets.PacketType; import seng302.models.stream.packets.StreamPacket; import seng302.server.messages.ChatterMessage; import seng302.server.messages.Heartbeat; +import seng302.server.messages.BoatActionType; import seng302.server.messages.Message; import java.io.*; import java.net.Socket; import java.util.zip.CRC32; import java.util.zip.Checksum; +import seng302.utilities.GeoPoint; /** * A class describing a single connection to a Client for the purposes of sending and receiving on its own thread. @@ -20,7 +24,6 @@ import java.util.zip.Checksum; * Created by wmu16 on 13/07/17. */ public class ServerToClientThread extends Thread { - private static final Integer MAX_ID_ATTEMPTS = 10; private InputStream is; @@ -33,6 +36,8 @@ public class ServerToClientThread extends Thread { private Boolean connected = true; private Boolean updateClient = true; + private Integer sourceId; + public ServerToClientThread(Socket socket) { this.socket = socket; try { @@ -43,6 +48,9 @@ public class ServerToClientThread extends Thread { } // threeWayHandshake(); GameState.addPlayer(new Player(socket)); + Random rand = new Random(); + sourceId = rand.nextInt(100000); + GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); } public void run() { @@ -86,8 +94,14 @@ public class ServerToClientThread extends Thread { long packetCrc = Message.bytesToLong(getBytes(4)); if (computedCrc == packetCrc) { //System.out.println("RECEIVED A PACKET"); - StreamParser.parsePacket(new StreamPacket(type, payloadLength, timeStamp, payload)); - // TODO: 17/07/17 wmu16 - Fix this or maybe we dont need to go through the main server at all!?!? + switch (PacketType.assignPacketType(type)) { + case BOAT_ACTION: + BoatActionType actionType = ServerPacketParser + .extractBoatAction( + new StreamPacket(type, payloadLength, timeStamp, payload)); + GameState.updateBoat(sourceId, actionType); + break; + } } else { System.err.println("Packet has been dropped"); } diff --git a/src/main/java/seng302/models/PolarTable.java b/src/main/java/seng302/models/PolarTable.java index b40b54dd..83df7711 100644 --- a/src/main/java/seng302/models/PolarTable.java +++ b/src/main/java/seng302/models/PolarTable.java @@ -1,6 +1,9 @@ package seng302.models; -import java.io.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; @@ -140,7 +143,7 @@ public final class PolarTable { } - private static Double getClosestMatch(Double thisWindSpeed) { + public static Double getClosestMatch(Double thisWindSpeed) { ArrayList windValues = new ArrayList<>(polarTable.keySet()); diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 7ea7e97e..7e45549d 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -1,11 +1,14 @@ package seng302.models; -import javafx.scene.paint.Color; -import seng302.models.mark.Mark; -import seng302.controllers.RaceViewController; +import static seng302.utilities.GeoUtility.getGeoCoordinate; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Map; +import javafx.scene.paint.Color; +import seng302.controllers.RaceViewController; +import seng302.models.mark.Mark; +import seng302.utilities.GeoPoint; /** * Yacht class for the racing boat. @@ -35,10 +38,9 @@ public class Yacht { private Integer penaltiesServed; private Long estimateTimeAtFinish; private String position; - private Double lat; - private Double lon; - private Float heading; - private double velocity; + private GeoPoint location; + private Double heading; + private Double velocity; private Long timeTillNext; private Long markRoundTime; @@ -52,8 +54,12 @@ public class Yacht { * * @param boatName Create a yacht object with name. */ - public Yacht(String boatName) { + public Yacht(String boatName, String shortName, GeoPoint location, Double heading) { this.boatName = boatName; + this.shortName = shortName; + this.location = location; + this.heading = heading; + this.velocity = 0.0; } /** @@ -81,6 +87,41 @@ public class Yacht { this.position = "-"; } + /** + * @param timeInterval since last update in milliseconds + */ + public void update(Long timeInterval) { + Double secondsElapsed = timeInterval / 1000000.0; + Double metersCovered = velocity * secondsElapsed; + location = getGeoCoordinate(location, heading, metersCovered); + } + + /** + * Adjusts the yachts velocity based on the wind direction and speed from the polar table. + * + * @param windDir current wind Direction TODO: 20/07/17 ajm412: (TWA or AWA, not 100% sure?) + * @param windSpd current wind Speed + */ + public void updateYachtVelocity(Double windDir, Double windSpd) { + Double closestSpd = PolarTable.getClosestMatch(windSpd); + Map polarsFromClosestSpd = PolarTable.getPolarTable().get(closestSpd); + + Double closest = 0d; + Double closest_key = 0d; + + for (Double key : polarsFromClosestSpd.keySet()) { + Double difference = Math.abs(key - windDir); + if (difference <= closest) { + closest = difference; + closest_key = key; + } + } +// System.out.println("Closest angle " + closest_key); +// System.out.println("WindDir " + windDir); + velocity = polarsFromClosestSpd.get(closest_key); + } + + public String getBoatType() { return boatType; } @@ -206,30 +247,6 @@ public class Yacht { return nextMark; } - public Double getLat() { - return lat; - } - - public void setLat(Double lat) { - this.lat = lat; - } - - public Double getLon() { - return lon; - } - - public void setLon(Double lon) { - this.lon = lon; - } - - public Float getHeading() { - return heading; - } - - public void setHeading(Float heading) { - this.heading = heading; - } - @Override public String toString() { return boatName; diff --git a/src/main/java/seng302/server/messages/BoatActionMessage.java b/src/main/java/seng302/server/messages/BoatActionMessage.java index 4a53f40a..cf4ea918 100644 --- a/src/main/java/seng302/server/messages/BoatActionMessage.java +++ b/src/main/java/seng302/server/messages/BoatActionMessage.java @@ -18,7 +18,7 @@ public class BoatActionMessage extends Message{ allocateBuffer(); writeHeaderToBuffer(); // Write message fields - putInt((int) BoatActionType.getBoatPacketType(actionType), 1); + putInt(actionType.getValue(), 1); writeCRC(); rewind(); diff --git a/src/main/java/seng302/server/messages/BoatActionType.java b/src/main/java/seng302/server/messages/BoatActionType.java index e323b6fe..f8318af7 100644 --- a/src/main/java/seng302/server/messages/BoatActionType.java +++ b/src/main/java/seng302/server/messages/BoatActionType.java @@ -1,5 +1,8 @@ package seng302.server.messages; +import java.util.HashMap; +import java.util.Map; + /** * Created by kre39 on 12/07/17. */ @@ -12,31 +15,24 @@ public enum BoatActionType { UPWIND(5), DOWNWIND(6); - private int type; + private final int type; + private static final Map intToTypeMap = new HashMap<>(); + + static { + for (BoatActionType type : BoatActionType.values()) { + intToTypeMap.put(type.getValue(), type); + } + } BoatActionType(int type){ this.type = type; } - public int getType(){ - return this.type; + public static BoatActionType getType(int value) { + return intToTypeMap.get(value); } - public static Short getBoatPacketType(BoatActionType type){ - switch (type){ - case VMG: - return 1; - case SAILS_IN: - return 2; - case SAILS_OUT: - return 3; - case TACK_GYBE: - return 4; - case UPWIND: - return 5; - case DOWNWIND: - return 6; - } - return 0; + public int getValue() { + return this.type; } } diff --git a/src/test/java/seng302/models/YachtTest.java b/src/test/java/seng302/models/YachtTest.java new file mode 100644 index 00000000..257e5f59 --- /dev/null +++ b/src/test/java/seng302/models/YachtTest.java @@ -0,0 +1,36 @@ +package seng302.models; + + +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import seng302.utilities.GeoPoint; + +public class YachtTest { + + Double windDir; + Double windSpd; + List yachts = new ArrayList(); + + @Before + public void setUp() { + PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv")); + windDir = 90d; + windSpd = 10d; + + yachts.add(new Yacht("Yacht 1", "Y1", new GeoPoint(-30.0, 20.0), 160.0)); + yachts.add(new Yacht("Yacht 2", "Y2", new GeoPoint(-40.0, -20.0), 100.0)); + yachts.add(new Yacht("Yacht 3", "Y3", new GeoPoint(-35.0, -15.5), 20.0)); + } + + @Test + public void testVelocityUpdate() { + for (Yacht yacht : yachts) { + yacht.updateYachtVelocity(windDir, windSpd); + System.out.println(yacht.getVelocity()); + // TODO: 20/07/17 ajm412: add assertions. + } + } + +}