From 8a40119a9857ff31d178cbc1efcc65fe63e82791 Mon Sep 17 00:00:00 2001 From: Calum Date: Sun, 6 Aug 2017 22:17:08 +1200 Subject: [PATCH] Action packets now sent at regular 20ms intervals #issue[38] #implement --- pom.xml | 15 +++ .../server/messages/BoatActionType.java | 3 +- src/main/java/seng302/model/Yacht.java | 2 +- .../{visualiser => v}/map/Boundary.java | 2 +- .../{visualiser => v}/map/CanvasMap.java | 2 +- .../map/MercatorProjection.java | 4 +- .../map/TestMapController.java | 2 +- .../visualiser/ClientToServerThread.java | 62 +++++++-- .../java/seng302/visualiser/GameClient.java | 75 ++++------- .../java/seng302/visualiser/GameView.java | 4 +- .../controllers/LobbyController.java | 125 ++++++------------ src/main/resources/views/LobbyView.fxml | 51 +++---- src/main/resources/views/TestMapView.fxml | 2 +- .../RegularPacketsTest.java | 123 +++++++++++++++++ .../TestImportantAnnotationState.java | 2 +- .../map/MercatorProjectionTest.java | 1 + 16 files changed, 286 insertions(+), 189 deletions(-) rename src/main/java/seng302/{visualiser => v}/map/Boundary.java (96%) rename src/main/java/seng302/{visualiser => v}/map/CanvasMap.java (98%) rename src/main/java/seng302/{visualiser => v}/map/MercatorProjection.java (96%) rename src/main/java/seng302/{visualiser => v}/map/TestMapController.java (95%) create mode 100644 src/test/java/seng302/visualiser/ClientToServerTests/RegularPacketsTest.java rename src/test/java/seng302/{visualizer => visualiser}/annotations/TestImportantAnnotationState.java (97%) diff --git a/pom.xml b/pom.xml index aac3b0c7..b329e067 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,21 @@ commons-cli 1.4 + + + org.testfx + testfx-core + 4.0.1-alpha + test + + + + org.testfx + testfx-junit + 4.0.6-alpha + test + + diff --git a/src/main/java/seng302/gameServer/server/messages/BoatActionType.java b/src/main/java/seng302/gameServer/server/messages/BoatActionType.java index 53fc6018..1b9fdd58 100644 --- a/src/main/java/seng302/gameServer/server/messages/BoatActionType.java +++ b/src/main/java/seng302/gameServer/server/messages/BoatActionType.java @@ -13,7 +13,8 @@ public enum BoatActionType { SAILS_OUT(3), TACK_GYBE(4), UPWIND(5), - DOWNWIND(6); + DOWNWIND(6), + MAINTAIN_HEADING(7); private final int type; private static final Map intToTypeMap = new HashMap<>(); diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index d7cd1f9e..9afe778a 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -48,7 +48,7 @@ public class Yacht { private Integer legNumber = 0; //SERVER SIDE - private final Double TURN_STEP = 5.0; + static public final Double TURN_STEP = 1.0; //This should be in some utils class somewhere 2bh. Public for tests sake. private Double lastHeading; private Boolean sailIn; private GeoPoint location; diff --git a/src/main/java/seng302/visualiser/map/Boundary.java b/src/main/java/seng302/v/map/Boundary.java similarity index 96% rename from src/main/java/seng302/visualiser/map/Boundary.java rename to src/main/java/seng302/v/map/Boundary.java index 21f2661d..68085ec7 100644 --- a/src/main/java/seng302/visualiser/map/Boundary.java +++ b/src/main/java/seng302/v/map/Boundary.java @@ -1,4 +1,4 @@ -package seng302.visualiser.map; +package seng302.v.map; /** * The Boundary class represents a rectangle territorial boundary on a map. It diff --git a/src/main/java/seng302/visualiser/map/CanvasMap.java b/src/main/java/seng302/v/map/CanvasMap.java similarity index 98% rename from src/main/java/seng302/visualiser/map/CanvasMap.java rename to src/main/java/seng302/v/map/CanvasMap.java index e79805e4..10cd60c3 100644 --- a/src/main/java/seng302/visualiser/map/CanvasMap.java +++ b/src/main/java/seng302/v/map/CanvasMap.java @@ -1,4 +1,4 @@ -package seng302.visualiser.map; +package seng302.v.map; import java.net.URL; import javafx.geometry.Point2D; diff --git a/src/main/java/seng302/visualiser/map/MercatorProjection.java b/src/main/java/seng302/v/map/MercatorProjection.java similarity index 96% rename from src/main/java/seng302/visualiser/map/MercatorProjection.java rename to src/main/java/seng302/v/map/MercatorProjection.java index 3f86e628..28bd341f 100644 --- a/src/main/java/seng302/visualiser/map/MercatorProjection.java +++ b/src/main/java/seng302/v/map/MercatorProjection.java @@ -1,4 +1,4 @@ -package seng302.visualiser.map; +package seng302.v.map; import javafx.geometry.Point2D; import seng302.model.GeoPoint; @@ -28,7 +28,7 @@ public class MercatorProjection { * @param geo GeoPoint (lat, lng) location to be projected * @return the projection Point2D (x, y) on planar */ - static Point2D toMapPoint(GeoPoint geo) { + public static Point2D toMapPoint(GeoPoint geo) { double x, y; Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0); x = (origin.getX() + geo.getLng() * pixelsPerLngDegree); diff --git a/src/main/java/seng302/visualiser/map/TestMapController.java b/src/main/java/seng302/v/map/TestMapController.java similarity index 95% rename from src/main/java/seng302/visualiser/map/TestMapController.java rename to src/main/java/seng302/v/map/TestMapController.java index cd0b4c60..520a1e3b 100644 --- a/src/main/java/seng302/visualiser/map/TestMapController.java +++ b/src/main/java/seng302/v/map/TestMapController.java @@ -1,4 +1,4 @@ -package seng302.visualiser.map; +package seng302.v.map; import java.net.URL; import java.util.ResourceBundle; diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index 414696c8..1bfaa10d 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -9,12 +9,15 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Queue; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.zip.CRC32; import java.util.zip.Checksum; import javafx.application.Platform; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; +import seng302.gameServer.server.messages.BoatActionType; import seng302.model.stream.packets.StreamPacket; import seng302.gameServer.server.messages.BoatActionMessage; import seng302.gameServer.server.messages.Message; @@ -47,11 +50,15 @@ public class ClientToServerThread implements Runnable { private Socket socket; private InputStream is; + + //Output stream private OutputStream os; + private Timer osTimer = new Timer(); + private Queue eventQueue = new ConcurrentLinkedQueue<>(); + private boolean upwindFlag = false, downwindFlag = false; + static public final int PACKET_SENDING_INTERVAL_MS = 20; private int clientId; - -// private Boolean updateClient = true; private ByteArrayOutputStream crcBuffer; private boolean socketOpen = true; @@ -83,6 +90,15 @@ public class ClientToServerThread implements Runnable { thread = new Thread(this); thread.start(); + + osTimer.scheduleAtFixedRate( + new TimerTask() { + @Override + public void run() { + processBoatActionQueue(); + } + }, 0, PACKET_SENDING_INTERVAL_MS + ); } /** @@ -181,18 +197,42 @@ public class ClientToServerThread implements Runnable { /** - * Send the post-start race course information - * @param boatActionMessage The message to send + * Processes next element in the queue of events to send. */ - public void sendBoatActionMessage(BoatActionMessage boatActionMessage) { + private void processBoatActionQueue() { + BoatActionType action = eventQueue.poll(); + if (action != null) { + switch (action) { + case MAINTAIN_HEADING: + downwindFlag = upwindFlag = false; break; + case DOWNWIND: + downwindFlag = true; break; + case UPWIND: + upwindFlag = true; break; + default: + sendBoatAction(new BoatActionMessage(action)); break; + } + } + if (downwindFlag) { + sendBoatAction(new BoatActionMessage(BoatActionType.DOWNWIND)); + } + if (upwindFlag) { + sendBoatAction(new BoatActionMessage(BoatActionType.UPWIND)); + } + } + + /** + * Sends a boat action of the given message type. + * @param message The given message type. + */ + private void sendBoatAction(BoatActionMessage message) { try { - os.write(boatActionMessage.getBuffer()); + os.write(message.getBuffer()); } catch (IOException e) { clientLog("Could not write to server", 1); } } - private void closeSocket() { try { socket.close(); @@ -245,11 +285,11 @@ public class ClientToServerThread implements Runnable { } } - public Thread getThread() { - return thread; - } - public int getClientId () { return clientId; } + + public void sendBoatEvent(BoatActionType actionType) { + eventQueue.add(actionType); + } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 915eef37..0b52a3a4 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -13,6 +13,7 @@ import javafx.scene.Node; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Pane; import seng302.gameServer.MainServerThread; +import seng302.gameServer.server.messages.BoatActionType; import seng302.model.RaceState; import seng302.model.Yacht; import seng302.model.stream.packets.StreamPacket; @@ -22,8 +23,6 @@ import seng302.model.stream.parser.PositionUpdateData.DeviceType; import seng302.model.stream.parser.RaceStatusData; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; -import seng302.gameServer.server.messages.BoatActionMessage; -import seng302.gameServer.server.messages.BoatActionType; import seng302.utilities.StreamParser; import seng302.utilities.XMLParser; import seng302.visualiser.controllers.LobbyController; @@ -48,9 +47,6 @@ public class GameClient { private ObservableList clientLobbyList = FXCollections.observableArrayList(); - private long lastSendingTime; - private int KEY_STROKE_SENDING_FREQUENCY = 50; - public GameClient(Pane holder) { this.holderPane = holder; } @@ -174,17 +170,13 @@ public class GameClient { break; case BOAT_XML: - System.out.println("GOT SUM BOATS YAY :)"); allBoatsMap = XMLParser.parseBoats( StreamParser.extractXmlMessage(packet) ); clientLobbyList.clear(); allBoatsMap.forEach((id, boat) -> { clientLobbyList.add(id + " " + boat.getBoatName()); -// System.out.println(id + " " + boat.getBoatName()); - }); -// startRaceIfAllDataReceived(); break; case RACE_START_STATUS: @@ -279,47 +271,34 @@ public class GameClient { * Handle the key-pressed event from the text field. * @param e The key event triggering this call */ - public void keyPressed(KeyEvent e) { - BoatActionMessage boatActionMessage; - long currentTime = System.currentTimeMillis(); - if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY) { - lastSendingTime = currentTime; - switch (e.getCode()) { - case SPACE: // align with vmg - boatActionMessage = new BoatActionMessage(BoatActionType.VMG); - socketThread.sendBoatActionMessage(boatActionMessage); - break; - case PAGE_UP: // upwind - boatActionMessage = new BoatActionMessage(BoatActionType.UPWIND); - socketThread.sendBoatActionMessage(boatActionMessage); - break; - case PAGE_DOWN: // downwind - boatActionMessage = new BoatActionMessage(BoatActionType.DOWNWIND); - socketThread.sendBoatActionMessage(boatActionMessage); - break; - case ENTER: // tack/gybe - boatActionMessage = new BoatActionMessage(BoatActionType.TACK_GYBE); - socketThread.sendBoatActionMessage(boatActionMessage); - break; - //TODO Allow a zoom in and zoom out methods - case Z: // zoom in - System.out.println("Zoom in"); - break; - case X: // zoom out - System.out.println("Zoom out"); - break; - } - } - } - - public void keyReleased(KeyEvent e) { + private void keyPressed(KeyEvent e) { switch (e.getCode()) { - //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) - case SHIFT: // sails in/sails out - BoatActionMessage boatActionMessage = new BoatActionMessage( - BoatActionType.SAILS_IN); - socketThread.sendBoatActionMessage(boatActionMessage); + case SPACE: // align with vmg + socketThread.sendBoatEvent(BoatActionType.VMG); break; + case PAGE_UP: // upwind + socketThread.sendBoatEvent(BoatActionType.UPWIND); break; + case PAGE_DOWN: // downwind + socketThread.sendBoatEvent(BoatActionType.DOWNWIND); break; + case ENTER: // tack/gybe + socketThread.sendBoatEvent(BoatActionType.TACK_GYBE); break; + //TODO Allow a zoom in and zoom out methods + case Z: // zoom in + System.out.println("Zoom in"); + break; + case X: // zoom out + System.out.println("Zoom out"); break; } } + + private void keyReleased(KeyEvent e) { + switch (e.getCode()) { + //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) + case SHIFT: // sails in/sails out + socketThread.sendBoatEvent(BoatActionType.SAILS_IN); break; + case PAGE_UP: + case PAGE_DOWN: + socketThread.sendBoatEvent(BoatActionType.MAINTAIN_HEADING); break; + } + } } diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java index 73d49b89..180f85ca 100644 --- a/src/main/java/seng302/visualiser/GameView.java +++ b/src/main/java/seng302/visualiser/GameView.java @@ -32,8 +32,8 @@ import seng302.visualiser.fxObjects.BoatObject; import seng302.visualiser.fxObjects.CourseBoundary; import seng302.visualiser.fxObjects.Gate; import seng302.visualiser.fxObjects.Marker; -import seng302.visualiser.map.Boundary; -import seng302.visualiser.map.CanvasMap; +import seng302.v.map.Boundary; +import seng302.v.map.CanvasMap; /** * Created by cir27 on 20/07/17. diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index 1a8b13e3..809bd3b5 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -4,15 +4,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import javafx.application.Platform; -import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Button; -import javafx.scene.control.ListView; +import javafx.scene.control.TextArea; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.GridPane; import javafx.scene.text.Text; import seng302.gameServer.GameStages; import seng302.gameServer.GameState; @@ -33,28 +31,26 @@ public class LobbyController { void notify(CloseStatus exitCause); } - @FXML - private GridPane lobbyScreen; @FXML private Text lobbyIpText; @FXML private Button readyButton; @FXML - private ListView firstListView; + private TextArea playerOneTxt; @FXML - private ListView secondListView; + private TextArea playerTwoTxt; @FXML - private ListView thirdListView; + private TextArea playerThreeTxt; @FXML - private ListView fourthListView; + private TextArea playerFourTxt; @FXML - private ListView fifthListView; + private TextArea playerFiveTxt; @FXML - private ListView sixthListView; + private TextArea playerSixTxt; @FXML - private ListView seventhListView; + private TextArea playerSevenTxt; @FXML - private ListView eighthListView; + private TextArea playerEightTxt; @FXML private ImageView firstImageView; @FXML @@ -72,79 +68,67 @@ public class LobbyController { @FXML private ImageView eighthImageView; - private List> competitors = new ArrayList<>(); - private ObservableList firstCompetitor = FXCollections.observableArrayList(); - private ObservableList secondCompetitor = FXCollections.observableArrayList(); - private ObservableList thirdCompetitor = FXCollections.observableArrayList(); - private ObservableList fourthCompetitor = FXCollections.observableArrayList(); - private ObservableList fifthCompetitor = FXCollections.observableArrayList(); - private ObservableList sixthCompetitor = FXCollections.observableArrayList(); - private ObservableList seventhCompetitor = FXCollections.observableArrayList(); - private ObservableList eighthCompetitor = FXCollections.observableArrayList(); - private List imageViews = new ArrayList<>(); - private List listViews; + private List