From 63d24c001fc483fbefbcb311a381c96e7118eab7 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 19 Jul 2017 19:39:31 +1200 Subject: [PATCH 1/4] Added position update in yacht #story[1047] --- .../java/seng302/gameServer/GameState.java | 27 ++++++++++--------- src/main/java/seng302/models/Yacht.java | 13 +++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index d36968fc..288689ee 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,8 +1,12 @@ 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; /** * A Static class to hold information about the current state of the game (model) @@ -10,8 +14,10 @@ import java.util.ArrayList; */ public class GameState { + private static Long previousUpdateTime; 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 +26,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; } @@ -50,16 +58,11 @@ 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 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/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 7ea7e97e..cc6aa577 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -81,6 +81,19 @@ 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; + // 111111 meters is approximately 1 degree of lat/long at the equator + lat = lat + (metersCovered * Math.sin(heading * (2 * Math.PI / 360))) / 111111; + lon = lon + (metersCovered * Math.cos(heading * (2 * Math.PI / 360))) / (111111 * Math + .cos(lat * (2 * Math.PI / 360))); + // formula take from https://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters + } + public String getBoatType() { return boatType; } From e317de7562889f99b0a4663b94155a5a4fa2022a Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Thu, 20 Jul 2017 13:11:37 +1200 Subject: [PATCH 2/4] Added mock yachts to the game state for each client #story[1047] --- .../java/seng302/gameServer/GameState.java | 10 +++- .../seng302/gameServer/MainServerThread.java | 6 ++- .../gameServer/ServerToClientThread.java | 6 +++ src/main/java/seng302/models/Yacht.java | 46 +++++-------------- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 288689ee..115bf2cd 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -15,6 +15,9 @@ import seng302.models.Yacht; public class GameState { private static Long previousUpdateTime; + private static Double windDirection = 0d; + private static Double windSpeed = 0d; + private static String hostIpAddress; private static List players; private static Map yachts; @@ -46,6 +49,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; } @@ -58,7 +65,8 @@ public class GameState { GameState.currentStage = currentStage; } - public void update() { + + public static void update() { Long timeInterval = System.currentTimeMillis() - previousUpdateTime; previousUpdateTime = System.currentTimeMillis(); for (Yacht yacht : yachts.values()) { diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 8caf5e9c..5ef2faaa 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -57,10 +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) { - + GameState.update(); } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 7198875c..d094e9cf 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -1,7 +1,9 @@ package seng302.gameServer; +import java.util.Random; import seng302.gameServer.GameState; import seng302.models.Player; +import seng302.models.Yacht; import seng302.models.stream.PacketBufferDelegate; import seng302.models.stream.StreamParser; import seng302.models.stream.packets.StreamPacket; @@ -11,6 +13,7 @@ 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. @@ -31,6 +34,7 @@ public class ServerToClientThread extends Thread { private Boolean connected = true; private Boolean updateClient = true; + private Integer mockId = 100; public ServerToClientThread(Socket socket) { this.socket = socket; try { @@ -41,6 +45,8 @@ public class ServerToClientThread extends Thread { } // threeWayHandshake(); GameState.addPlayer(new Player(socket)); + GameState.addYacht(mockId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); + mockId += 1; } public void run() { diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index cc6aa577..c6c88944 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 static seng302.utilities.GeoUtility.getGeoCoordinate; + import javafx.scene.paint.Color; import seng302.models.mark.Mark; import seng302.controllers.RaceViewController; import java.text.DateFormat; import java.text.SimpleDateFormat; +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; } /** @@ -87,11 +93,7 @@ public class Yacht { public void update(Long timeInterval) { Double secondsElapsed = timeInterval / 1000000.0; Double metersCovered = velocity * secondsElapsed; - // 111111 meters is approximately 1 degree of lat/long at the equator - lat = lat + (metersCovered * Math.sin(heading * (2 * Math.PI / 360))) / 111111; - lon = lon + (metersCovered * Math.cos(heading * (2 * Math.PI / 360))) / (111111 * Math - .cos(lat * (2 * Math.PI / 360))); - // formula take from https://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters + location = getGeoCoordinate(location, heading, metersCovered); } public String getBoatType() { @@ -219,30 +221,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; From da7a34fc55c34fb37337dabadf5cc80801a27052 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Thu, 20 Jul 2017 14:30:13 +1200 Subject: [PATCH 3/4] Started adding functionality to calculate yacht velocity from the wind speed and direction using polar tables. Also began writing tests to cover this functionality, as it can't currently be tested within the game itself. #story[986] --- .../java/seng302/gameServer/GameState.java | 12 +++++-- src/main/java/seng302/models/PolarTable.java | 7 ++-- src/main/java/seng302/models/Yacht.java | 34 +++++++++++++++--- src/test/java/seng302/models/YachtTest.java | 36 +++++++++++++++++++ 4 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 src/test/java/seng302/models/YachtTest.java diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 115bf2cd..cb515f40 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,11 +1,9 @@ package seng302.gameServer; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import seng302.models.Player; - -import java.util.ArrayList; import seng302.models.Yacht; /** @@ -65,6 +63,14 @@ public class GameState { GameState.currentStage = currentStage; } + public static Double getWindDirection() { + return windDirection; + } + + public static Double getWindSpeed() { + return windSpeed; + } + public static void update() { Long timeInterval = System.currentTimeMillis() - previousUpdateTime; 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 c6c88944..7e45549d 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -2,12 +2,12 @@ package seng302.models; import static seng302.utilities.GeoUtility.getGeoCoordinate; -import javafx.scene.paint.Color; -import seng302.models.mark.Mark; -import seng302.controllers.RaceViewController; - 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; /** @@ -96,6 +96,32 @@ public class Yacht { 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; } 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. + } + } + +} From 49c0c029c38932fc94b2a623096486dfa164586f Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Thu, 20 Jul 2017 19:35:59 +1200 Subject: [PATCH 4/4] adjusted the way the server is receiving key presses to enable them be passed through to the game state #pair[ptg19, wmu16] #story[989] --- src/main/java/seng302/App.java | 4 +- .../ClientPacketParser.java} | 31 ++------- .../seng302/client/ClientToServerThread.java | 5 +- .../seng302/controllers/CanvasController.java | 32 ++++----- .../java/seng302/controllers/Controller.java | 4 +- .../FinishScreenViewController.java | 6 +- .../controllers/RaceViewController.java | 66 +++++++++++-------- .../seng302/fxObjects/BoatAnnotations.java | 6 +- .../java/seng302/fxObjects/BoatGroup.java | 4 +- .../java/seng302/gameServer/GameState.java | 17 +++++ .../seng302/gameServer/MainServerThread.java | 4 +- .../gameServer/ServerPacketParser.java | 37 +++++++++++ .../gameServer/ServerToClientThread.java | 26 +++++--- .../server/messages/BoatActionMessage.java | 2 +- .../server/messages/BoatActionType.java | 34 +++++----- 15 files changed, 162 insertions(+), 116 deletions(-) rename src/main/java/seng302/{models/stream/StreamParser.java => client/ClientPacketParser.java} (96%) create mode 100644 src/main/java/seng302/gameServer/ServerPacketParser.java 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 f1ea501a..c0467484 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"); @@ -489,27 +487,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 6a7b995d..a2f23419 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; /** @@ -77,7 +75,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 8eb336e7..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,7 +93,7 @@ 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(); @@ -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 115bf2cd..0b1debb4 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -7,6 +7,7 @@ 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) @@ -65,6 +66,22 @@ public class GameState { GameState.currentStage = currentStage; } + 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; diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 5ef2faaa..b28dce91 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; @@ -77,7 +77,7 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl 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 d094e9cf..9a7d8786 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -1,12 +1,13 @@ package seng302.gameServer; + import java.util.Random; -import seng302.gameServer.GameState; +import seng302.client.ClientPacketParser; import seng302.models.Player; import seng302.models.Yacht; -import seng302.models.stream.PacketBufferDelegate; -import seng302.models.stream.StreamParser; +import seng302.models.stream.packets.PacketType; import seng302.models.stream.packets.StreamPacket; +import seng302.server.messages.BoatActionType; import seng302.server.messages.Message; import java.io.*; @@ -21,7 +22,6 @@ import seng302.utilities.GeoPoint; * Created by wmu16 on 13/07/17. */ public class ServerToClientThread extends Thread { - private static final Integer MAX_ID_ATTEMPTS = 10; private InputStream is; @@ -34,7 +34,8 @@ public class ServerToClientThread extends Thread { private Boolean connected = true; private Boolean updateClient = true; - private Integer mockId = 100; + private Integer sourceId; + public ServerToClientThread(Socket socket) { this.socket = socket; try { @@ -45,8 +46,9 @@ public class ServerToClientThread extends Thread { } // threeWayHandshake(); GameState.addPlayer(new Player(socket)); - GameState.addYacht(mockId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); - mockId += 1; + 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() { @@ -85,8 +87,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/server/messages/BoatActionMessage.java b/src/main/java/seng302/server/messages/BoatActionMessage.java index 9dfc5769..5007f329 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; } }