mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge branch 'Story62_Reading_Keystrokes' into 'develop'
Story62 reading keystrokes Big merge See merge request !44
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
engines:
|
||||||
|
pmd:
|
||||||
|
enabled: true
|
||||||
|
channel: "beta"
|
||||||
|
|
||||||
|
fixme:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
strings:
|
||||||
|
- FIXME
|
||||||
|
- TODO
|
||||||
|
- BUG
|
||||||
|
- FIX
|
||||||
|
|
||||||
|
ratings:
|
||||||
|
paths:
|
||||||
|
- "**.java"
|
||||||
@@ -4,76 +4,37 @@ import javafx.application.Application;
|
|||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
import seng302.models.PolarTable;
|
import seng302.models.PolarTable;
|
||||||
import seng302.models.stream.StreamParser;
|
|
||||||
import seng302.models.stream.StreamReceiver;
|
import seng302.models.stream.StreamReceiver;
|
||||||
import seng302.server.ServerThread;
|
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
PolarTable.parsePolarFile(getClass().getResource("/config/acc_polars.csv").getFile());
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
||||||
|
|
||||||
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
|
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
|
||||||
primaryStage.setTitle("RaceVision");
|
primaryStage.setTitle("RaceVision");
|
||||||
primaryStage.setScene(new Scene(root, 1530, 960));
|
primaryStage.setScene(new Scene(root, 1530, 960));
|
||||||
primaryStage.setMaxWidth(1530);
|
primaryStage.setMaxWidth(1530);
|
||||||
primaryStage.setMaxHeight(960);
|
primaryStage.setMaxHeight(960);
|
||||||
|
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
|
||||||
// primaryStage.setMaximized(true);
|
// primaryStage.setMaximized(true);
|
||||||
|
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
primaryStage.setOnCloseRequest(e -> {
|
primaryStage.setOnCloseRequest(e -> {
|
||||||
StreamParser.appClose();
|
ClientPacketParser.appClose();
|
||||||
StreamReceiver.noMoreBytes();
|
StreamReceiver.noMoreBytes();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
StreamReceiver sr = null;
|
|
||||||
|
|
||||||
new ServerThread("Racevision Test Server");
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length == 1 && args[0].equals("-standalone")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length == 3 && args[0].equals("-server")) {
|
|
||||||
|
|
||||||
sr = new StreamReceiver(args[1], Integer.valueOf(args[2]), "RaceStream");
|
|
||||||
|
|
||||||
} else if (args.length == 2 && args[0].equals("-server")) {
|
|
||||||
switch (args[1]) {
|
|
||||||
case "internal":
|
|
||||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
|
||||||
break;
|
|
||||||
case "staffserver":
|
|
||||||
sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream");
|
|
||||||
break;
|
|
||||||
case "official":
|
|
||||||
sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Change the StreamReceiver in this else block to change the default data source.
|
|
||||||
else{
|
|
||||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
|
||||||
}
|
|
||||||
|
|
||||||
sr.start();
|
|
||||||
StreamParser streamParser = new StreamParser("StreamParser");
|
|
||||||
streamParser.start();
|
|
||||||
|
|
||||||
launch(args);
|
launch(args);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-45
@@ -1,4 +1,4 @@
|
|||||||
package seng302.models.stream;
|
package seng302.client;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -11,7 +11,6 @@ import java.util.Comparator;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
@@ -23,6 +22,7 @@ import org.xml.sax.InputSource;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.mark.Mark;
|
import seng302.models.mark.Mark;
|
||||||
|
import seng302.models.stream.XMLParser;
|
||||||
import seng302.models.stream.packets.BoatPositionPacket;
|
import seng302.models.stream.packets.BoatPositionPacket;
|
||||||
import seng302.models.stream.packets.StreamPacket;
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ import seng302.models.stream.packets.StreamPacket;
|
|||||||
* that are threadsafe so the visualiser can always access the latest speed and position available
|
* that are threadsafe so the visualiser can always access the latest speed and position available
|
||||||
* Created by kre39 on 23/04/17.
|
* Created by kre39 on 23/04/17.
|
||||||
*/
|
*/
|
||||||
public class StreamParser extends Thread {
|
public class ClientPacketParser {
|
||||||
|
|
||||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markLocations = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> markLocations = new ConcurrentHashMap<>();
|
||||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatLocations = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatLocations = new ConcurrentHashMap<>();
|
||||||
@@ -58,54 +58,16 @@ public class StreamParser extends Thread {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to initialise the thread name and stream parser object so a thread can be executed
|
* Used to initialise the thread name and stream parser object so a thread can be executed
|
||||||
*
|
|
||||||
* @param threadName name of the thread
|
|
||||||
*/
|
*/
|
||||||
public StreamParser(String threadName) {
|
public ClientPacketParser() {
|
||||||
this.threadName = threadName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to within threading so when the stream parser thread runs, it will keep looking for a
|
|
||||||
* packet to process until it is unable to find anymore packets
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
appRunning = true;
|
|
||||||
try {
|
|
||||||
streamStatus = true;
|
|
||||||
xmlObject = new XMLParser();
|
|
||||||
while (StreamReceiver.packetBuffer == null || StreamReceiver.packetBuffer.size() < 1) {
|
|
||||||
Thread.sleep(1);
|
|
||||||
}
|
|
||||||
while (appRunning) {
|
|
||||||
StreamPacket packet = StreamReceiver.packetBuffer.take();
|
|
||||||
parsePacket(packet);
|
|
||||||
Thread.sleep(1);
|
|
||||||
while (StreamReceiver.packetBuffer.peek() == null) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to start the stream parser thread when multithreading
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
if (t == null) {
|
|
||||||
t = new Thread(this, threadName);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks at the type of the packet then sends it to the appropriate parser to extract the
|
* Looks at the type of the packet then sends it to the appropriate parser to extract the
|
||||||
* specific data associated with that packet type
|
* specific data associated with that packet type
|
||||||
*
|
*
|
||||||
* @param packet the packet to be looked at and processed
|
* @param packet the packet to be looked at and processed
|
||||||
*/
|
*/
|
||||||
private static void parsePacket(StreamPacket packet) {
|
public static void parsePacket(StreamPacket packet) {
|
||||||
try {
|
try {
|
||||||
switch (packet.getType()) {
|
switch (packet.getType()) {
|
||||||
case HEARTBEAT:
|
case HEARTBEAT:
|
||||||
@@ -145,8 +107,6 @@ public class StreamParser extends Thread {
|
|||||||
case AVG_WIND:
|
case AVG_WIND:
|
||||||
extractAvgWind(packet);
|
extractAvgWind(packet);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
System.out.println("Error parsing packet");
|
System.out.println("Error parsing packet");
|
||||||
@@ -161,6 +121,7 @@ public class StreamParser extends Thread {
|
|||||||
*/
|
*/
|
||||||
private static void extractHeartBeat(StreamPacket packet) {
|
private static void extractHeartBeat(StreamPacket packet) {
|
||||||
long heartbeat = bytesToLong(packet.getPayload());
|
long heartbeat = bytesToLong(packet.getPayload());
|
||||||
|
System.out.println("heartbeat = " + heartbeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getTimeZoneString() {
|
private static String getTimeZoneString() {
|
||||||
@@ -392,6 +353,7 @@ public class StreamParser extends Thread {
|
|||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
int length = payload[2];
|
int length = payload[2];
|
||||||
String message = new String(Arrays.copyOfRange(payload, 3, 3 + length));
|
String message = new String(Arrays.copyOfRange(payload, 3, 3 + length));
|
||||||
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package seng302.client;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.Checksum;
|
||||||
|
|
||||||
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
import seng302.server.messages.BoatActionMessage;
|
||||||
|
import seng302.server.messages.Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kre39 on 13/07/17.
|
||||||
|
*/
|
||||||
|
public class ClientToServerThread extends Thread {
|
||||||
|
private Socket socket;
|
||||||
|
private InputStream is;
|
||||||
|
private OutputStream os;
|
||||||
|
private final int PORT_NUMBER = 0;
|
||||||
|
private static final int LOG_LEVEL = 1;
|
||||||
|
|
||||||
|
private Boolean updateClient = true;
|
||||||
|
private ByteArrayOutputStream crcBuffer;
|
||||||
|
|
||||||
|
public ClientToServerThread(String ipAddress, Integer portNumber){
|
||||||
|
try {
|
||||||
|
socket = new Socket(ipAddress, portNumber);
|
||||||
|
is = socket.getInputStream();
|
||||||
|
os = socket.getOutputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serverLog(String message, int logLevel){
|
||||||
|
if(logLevel <= LOG_LEVEL){
|
||||||
|
System.out.println("[SERVER] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
int sync1;
|
||||||
|
int sync2;
|
||||||
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
//Perform a write if it is time to as delegated by the MainServerThread
|
||||||
|
if (updateClient) {
|
||||||
|
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
|
||||||
|
// try {
|
||||||
|
// GameState.outputState(os);
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// System.out.println("IO error in server thread upon writing to output stream");
|
||||||
|
// }
|
||||||
|
updateClient = false;
|
||||||
|
}
|
||||||
|
crcBuffer = new ByteArrayOutputStream();
|
||||||
|
sync1 = readByte();
|
||||||
|
sync2 = readByte();
|
||||||
|
//checking if it is the start of the packet
|
||||||
|
if(sync1 == 0x47 && sync2 == 0x83) {
|
||||||
|
int type = readByte();
|
||||||
|
//No. of milliseconds since Jan 1st 1970
|
||||||
|
long timeStamp = Message.bytesToLong(getBytes(6));
|
||||||
|
skipBytes(4);
|
||||||
|
long payloadLength = Message.bytesToLong(getBytes(2));
|
||||||
|
byte[] payload = getBytes((int) payloadLength);
|
||||||
|
Checksum checksum = new CRC32();
|
||||||
|
checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size());
|
||||||
|
long computedCrc = checksum.getValue();
|
||||||
|
long packetCrc = Message.bytesToLong(getBytes(4));
|
||||||
|
if (computedCrc == packetCrc) {
|
||||||
|
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 {
|
||||||
|
System.err.println("Packet has been dropped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
closeSocket();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the post-start race course information
|
||||||
|
*/
|
||||||
|
public void sendBoatActionMessage(BoatActionMessage boatActionMessage) {
|
||||||
|
try {
|
||||||
|
os.write(boatActionMessage.getBuffer());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void closeSocket() {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IO error in server thread upon trying to close socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int readByte() throws Exception {
|
||||||
|
int currentByte = -1;
|
||||||
|
try {
|
||||||
|
currentByte = is.read();
|
||||||
|
crcBuffer.write(currentByte);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (currentByte == -1){
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
return currentByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getBytes(int n) throws Exception{
|
||||||
|
byte[] bytes = new byte[n];
|
||||||
|
for (int i = 0; i < n; i++){
|
||||||
|
bytes[i] = (byte) readByte();
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipBytes(long n) throws Exception{
|
||||||
|
for (int i=0; i < n; i++){
|
||||||
|
readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import javafx.scene.layout.Pane;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
import seng302.fxObjects.BoatGroup;
|
import seng302.fxObjects.BoatGroup;
|
||||||
import seng302.models.Colors;
|
import seng302.models.Colors;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
@@ -31,7 +32,6 @@ import seng302.models.mark.MarkType;
|
|||||||
import seng302.models.mark.SingleMark;
|
import seng302.models.mark.SingleMark;
|
||||||
import seng302.models.map.Boundary;
|
import seng302.models.map.Boundary;
|
||||||
import seng302.models.map.CanvasMap;
|
import seng302.models.map.CanvasMap;
|
||||||
import seng302.models.stream.StreamParser;
|
|
||||||
import seng302.models.stream.XMLParser;
|
import seng302.models.stream.XMLParser;
|
||||||
import seng302.models.stream.XMLParser.RaceXMLObject.Limit;
|
import seng302.models.stream.XMLParser.RaceXMLObject.Limit;
|
||||||
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
||||||
@@ -110,6 +110,7 @@ public class CanvasController {
|
|||||||
// Bind canvas size to stack pane size.
|
// Bind canvas size to stack pane size.
|
||||||
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
|
canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH));
|
||||||
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
|
canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeCanvas() {
|
public void initializeCanvas() {
|
||||||
@@ -154,13 +155,13 @@ public class CanvasController {
|
|||||||
raceViewController.updateSparkLine();
|
raceViewController.updateSparkLine();
|
||||||
}
|
}
|
||||||
updateGroups();
|
updateGroups();
|
||||||
if (StreamParser.isRaceFinished()) {
|
if (ClientPacketParser.isRaceFinished()) {
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
lastTime = now;
|
lastTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StreamParser.isRaceFinished()) {
|
if (ClientPacketParser.isRaceFinished()) {
|
||||||
this.stop();
|
this.stop();
|
||||||
switchToFinishScreen();
|
switchToFinishScreen();
|
||||||
}
|
}
|
||||||
@@ -229,7 +230,7 @@ public class CanvasController {
|
|||||||
* in a compound mark etc..
|
* in a compound mark etc..
|
||||||
*/
|
*/
|
||||||
private void addRaceBorder() {
|
private void addRaceBorder() {
|
||||||
XMLParser.RaceXMLObject raceXMLObject = StreamParser.getXmlObject().getRaceXML();
|
XMLParser.RaceXMLObject raceXMLObject = ClientPacketParser.getXmlObject().getRaceXML();
|
||||||
ArrayList<Limit> courseLimits = raceXMLObject.getCourseLimit();
|
ArrayList<Limit> courseLimits = raceXMLObject.getCourseLimit();
|
||||||
raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1));
|
raceBorder.setStroke(new Color(0.0f, 0.0f, 0.74509807f, 1));
|
||||||
raceBorder.setStrokeWidth(3);
|
raceBorder.setStrokeWidth(3);
|
||||||
@@ -247,7 +248,7 @@ public class CanvasController {
|
|||||||
for (BoatGroup boatGroup : boatGroups) {
|
for (BoatGroup boatGroup : boatGroups) {
|
||||||
// some raceObjects will have multiple ID's (for instance gate marks)
|
// some raceObjects will have multiple ID's (for instance gate marks)
|
||||||
//checking if the current "ID" has any updates associated with it
|
//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()) {
|
if (boatGroup.isStopped()) {
|
||||||
updateBoatGroup(boatGroup);
|
updateBoatGroup(boatGroup);
|
||||||
}
|
}
|
||||||
@@ -256,7 +257,7 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
for (MarkGroup markGroup : markGroups) {
|
for (MarkGroup markGroup : markGroups) {
|
||||||
for (Long id : markGroup.getRaceIds()) {
|
for (Long id : markGroup.getRaceIds()) {
|
||||||
if (StreamParser.markLocations.containsKey(id)) {
|
if (ClientPacketParser.markLocations.containsKey(id)) {
|
||||||
updateMarkGroup(id, markGroup);
|
updateMarkGroup(id, markGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,13 +266,14 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkForCourseChanges() {
|
private void checkForCourseChanges() {
|
||||||
if (StreamParser.isNewRaceXmlReceived()){
|
if (ClientPacketParser.isNewRaceXmlReceived()) {
|
||||||
addRaceBorder();
|
addRaceBorder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBoatGroup(BoatGroup boatGroup) {
|
private void updateBoatGroup(BoatGroup boatGroup) {
|
||||||
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.boatLocations.get(boatGroup.getRaceId());
|
PriorityBlockingQueue<BoatPositionPacket> movementQueue = ClientPacketParser.boatLocations
|
||||||
|
.get(boatGroup.getRaceId());
|
||||||
// giving the movementQueue a 5 packet buffer to account for slightly out of order packets
|
// giving the movementQueue a 5 packet buffer to account for slightly out of order packets
|
||||||
if (movementQueue.size() > 0) {
|
if (movementQueue.size() > 0) {
|
||||||
try {
|
try {
|
||||||
@@ -289,7 +291,8 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateMarkGroup (long raceId, MarkGroup markGroup) {
|
void updateMarkGroup (long raceId, MarkGroup markGroup) {
|
||||||
PriorityBlockingQueue<BoatPositionPacket> movementQueue = StreamParser.markLocations.get(raceId);
|
PriorityBlockingQueue<BoatPositionPacket> movementQueue = ClientPacketParser.markLocations
|
||||||
|
.get(raceId);
|
||||||
if (movementQueue.size() > 0){
|
if (movementQueue.size() > 0){
|
||||||
try {
|
try {
|
||||||
BoatPositionPacket positionPacket = movementQueue.take();
|
BoatPositionPacket positionPacket = movementQueue.take();
|
||||||
@@ -305,12 +308,12 @@ public class CanvasController {
|
|||||||
* Draws all the boats.
|
* Draws all the boats.
|
||||||
*/
|
*/
|
||||||
private void initializeBoats() {
|
private void initializeBoats() {
|
||||||
Map<Integer, Yacht> boats = StreamParser.getBoats();
|
Map<Integer, Yacht> boats = ClientPacketParser.getBoats();
|
||||||
Group wakes = new Group();
|
Group wakes = new Group();
|
||||||
Group trails = new Group();
|
Group trails = new Group();
|
||||||
Group annotations = new Group();
|
Group annotations = new Group();
|
||||||
|
|
||||||
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
ArrayList<Participant> participants = ClientPacketParser.getXmlObject().getRaceXML()
|
||||||
.getParticipants();
|
.getParticipants();
|
||||||
ArrayList<Integer> participantIDs = new ArrayList<>();
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
for (Participant p : participants) {
|
for (Participant p : participants) {
|
||||||
@@ -334,7 +337,8 @@ public class CanvasController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeMarks() {
|
private void initializeMarks() {
|
||||||
List<Mark> allMarks = StreamParser.getXmlObject().getRaceXML().getNonDupCompoundMarks();
|
List<Mark> allMarks = ClientPacketParser.getXmlObject().getRaceXML()
|
||||||
|
.getNonDupCompoundMarks();
|
||||||
for (Mark mark : allMarks) {
|
for (Mark mark : allMarks) {
|
||||||
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
if (mark.getMarkType() == MarkType.SINGLE_MARK) {
|
||||||
SingleMark sMark = (SingleMark) mark;
|
SingleMark sMark = (SingleMark) mark;
|
||||||
@@ -400,7 +404,7 @@ public class CanvasController {
|
|||||||
*/
|
*/
|
||||||
private void fitMarksToCanvas() {
|
private void fitMarksToCanvas() {
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||||
StreamParser.isNewRaceXmlReceived();
|
ClientPacketParser.isNewRaceXmlReceived();
|
||||||
findMinMaxPoint();
|
findMinMaxPoint();
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
double minLonToMaxLon = scaleRaceExtremities();
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
calculateReferencePointLocation(minLonToMaxLon);
|
||||||
@@ -416,7 +420,7 @@ public class CanvasController {
|
|||||||
*/
|
*/
|
||||||
private void findMinMaxPoint() {
|
private void findMinMaxPoint() {
|
||||||
List<Limit> sortedPoints = new ArrayList<>();
|
List<Limit> sortedPoints = new ArrayList<>();
|
||||||
for (Limit limit : StreamParser.getXmlObject().getRaceXML().getCourseLimit()) {
|
for (Limit limit : ClientPacketParser.getXmlObject().getRaceXML().getCourseLimit()) {
|
||||||
sortedPoints.add(limit);
|
sortedPoints.add(limit);
|
||||||
}
|
}
|
||||||
sortedPoints.sort(Comparator.comparingDouble(Limit::getLat));
|
sortedPoints.sort(Comparator.comparingDouble(Limit::getLat));
|
||||||
@@ -576,4 +580,5 @@ public class CanvasController {
|
|||||||
List<MarkGroup> getMarkGroups() {
|
List<MarkGroup> getMarkGroups() {
|
||||||
return markGroups;
|
return markGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,39 +1,91 @@
|
|||||||
package seng302.controllers;
|
package seng302.controllers;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import seng302.models.stream.StreamParser;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
|
import seng302.client.ClientToServerThread;
|
||||||
|
import seng302.server.messages.BoatActionMessage;
|
||||||
|
import seng302.server.messages.BoatActionType;
|
||||||
|
|
||||||
public class Controller implements Initializable {
|
public class Controller implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane contentPane;
|
private AnchorPane contentPane;
|
||||||
|
private ClientToServerThread clientToServerThread;
|
||||||
|
|
||||||
private void setContentPane(String jfxUrl) {
|
private Object setContentPane(String jfxUrl) {
|
||||||
try {
|
try {
|
||||||
contentPane.getChildren().removeAll();
|
contentPane.getChildren().removeAll();
|
||||||
contentPane.getChildren().clear();
|
contentPane.getChildren().clear();
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
contentPane.getChildren()
|
FXMLLoader fxmlLoader = new FXMLLoader((getClass().getResource(jfxUrl)));
|
||||||
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
Parent view = fxmlLoader.load();
|
||||||
|
contentPane.getChildren().addAll(view);
|
||||||
|
return fxmlLoader.getController();
|
||||||
} catch (javafx.fxml.LoadException e) {
|
} catch (javafx.fxml.LoadException e) {
|
||||||
System.err.println(e.getCause());
|
System.err.println(e.getCause());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println(e);
|
System.err.println(e);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
StartScreenController startScreenController = (StartScreenController) setContentPane("/views/StartScreenView.fxml");
|
||||||
StreamParser.boatLocations.clear();
|
startScreenController.setController(this);
|
||||||
|
ClientPacketParser.boatLocations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handle the key-pressed event from the text field. */
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
BoatActionMessage boatActionMessage;
|
||||||
|
switch (e.getCode()){
|
||||||
|
case SPACE: // align with vmg
|
||||||
|
boatActionMessage = new BoatActionMessage(BoatActionType.VMG);
|
||||||
|
clientToServerThread.sendBoatActionMessage(boatActionMessage);
|
||||||
|
break;
|
||||||
|
case PAGE_UP: // upwind
|
||||||
|
boatActionMessage = new BoatActionMessage(BoatActionType.UPWIND);
|
||||||
|
clientToServerThread.sendBoatActionMessage(boatActionMessage);
|
||||||
|
break;
|
||||||
|
case PAGE_DOWN: // downwind
|
||||||
|
boatActionMessage = new BoatActionMessage(BoatActionType.DOWNWIND);
|
||||||
|
clientToServerThread.sendBoatActionMessage(boatActionMessage);
|
||||||
|
break;
|
||||||
|
case ENTER: // tack/gybe
|
||||||
|
boatActionMessage = new BoatActionMessage(BoatActionType.TACK_GYBE);
|
||||||
|
clientToServerThread.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) {
|
||||||
|
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);
|
||||||
|
clientToServerThread.sendBoatActionMessage(boatActionMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientToServerThread(ClientToServerThread ctt) {
|
||||||
|
clientToServerThread = ctt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
|||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.stream.StreamParser;
|
|
||||||
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
||||||
|
|
||||||
public class FinishScreenViewController implements Initializable {
|
public class FinishScreenViewController implements Initializable {
|
||||||
@@ -59,7 +59,7 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// check if the boat is racing
|
// check if the boat is racing
|
||||||
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
ArrayList<Participant> participants = ClientPacketParser.getXmlObject().getRaceXML()
|
||||||
.getParticipants();
|
.getParticipants();
|
||||||
ArrayList<Integer> participantIDs = new ArrayList<>();
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
for (Participant p : participants) {
|
for (Participant p : participants) {
|
||||||
@@ -67,7 +67,7 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add data to table
|
// add data to table
|
||||||
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
for (Yacht boat : ClientPacketParser.getBoatsPos().values()) {
|
||||||
if (participantIDs.contains(boat.getSourceID())) {
|
if (participantIDs.contains(boat.getSourceID())) {
|
||||||
data.add(boat);
|
data.add(boat);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package seng302.controllers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import seng302.gameServer.GameStages;
|
||||||
|
import seng302.gameServer.GameState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class describing the actions of the lobby screen
|
||||||
|
* Created by wmu16 on 10/07/17.
|
||||||
|
*/
|
||||||
|
public class LobbyController implements Initializable{
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ListView competitorsListView;
|
||||||
|
@FXML
|
||||||
|
private GridPane lobbyScreen;
|
||||||
|
@FXML
|
||||||
|
private Text lobbyIpText;
|
||||||
|
|
||||||
|
private static ObservableList competitors;
|
||||||
|
|
||||||
|
private void setContentPane(String jfxUrl) {
|
||||||
|
try {
|
||||||
|
AnchorPane contentPane = (AnchorPane) lobbyScreen.getParent();
|
||||||
|
contentPane.getChildren().removeAll();
|
||||||
|
contentPane.getChildren().clear();
|
||||||
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
contentPane.getChildren()
|
||||||
|
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
||||||
|
} catch (javafx.fxml.LoadException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
lobbyIpText.setText("Lobby Host IP: " + getLocalHostIp());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize() {
|
||||||
|
competitors = FXCollections.observableArrayList();
|
||||||
|
competitorsListView.setItems(competitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLocalHostIp() {
|
||||||
|
String ipAddress = null;
|
||||||
|
try {
|
||||||
|
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
NetworkInterface ni = e.nextElement();
|
||||||
|
if (ni.isLoopback())
|
||||||
|
continue;
|
||||||
|
if(ni.isPointToPoint())
|
||||||
|
continue;
|
||||||
|
if(ni.isVirtual())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Enumeration<InetAddress> addresses = ni.getInetAddresses();
|
||||||
|
while(addresses.hasMoreElements()) {
|
||||||
|
InetAddress address = addresses.nextElement();
|
||||||
|
if(address instanceof Inet4Address) { // skip all ipv6
|
||||||
|
ipAddress = address.getHostAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (ipAddress == null) {
|
||||||
|
System.out.println("[HOST] Cannot obtain local host ip address.");
|
||||||
|
}
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void leaveLobbyButtonPressed() {
|
||||||
|
// TODO: 10/07/17 wmu16 - Finish function!
|
||||||
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
|
System.out.println("Leaving lobby!");
|
||||||
|
GameState.setCurrentStage(GameStages.CANCELLED);
|
||||||
|
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void readyButtonPressed() {
|
||||||
|
GameState.setCurrentStage(GameStages.RACING);
|
||||||
|
setContentPane("/views/RaceView.fxml");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,8 @@ import javafx.stage.Stage;
|
|||||||
import javafx.stage.StageStyle;
|
import javafx.stage.StageStyle;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import seng302.utilities.GeometryUtils;
|
import seng302.client.ClientPacketParser;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.controllers.annotations.Annotation;
|
import seng302.controllers.annotations.Annotation;
|
||||||
import seng302.controllers.annotations.ImportantAnnotationController;
|
import seng302.controllers.annotations.ImportantAnnotationController;
|
||||||
import seng302.controllers.annotations.ImportantAnnotationDelegate;
|
import seng302.controllers.annotations.ImportantAnnotationDelegate;
|
||||||
@@ -38,7 +39,6 @@ import seng302.models.*;
|
|||||||
import seng302.models.mark.GateMark;
|
import seng302.models.mark.GateMark;
|
||||||
import seng302.models.mark.Mark;
|
import seng302.models.mark.Mark;
|
||||||
import seng302.models.mark.SingleMark;
|
import seng302.models.mark.SingleMark;
|
||||||
import seng302.models.stream.StreamParser;
|
|
||||||
import seng302.models.stream.XMLParser;
|
import seng302.models.stream.XMLParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -93,7 +93,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
raceSparkLine.getYAxis().setTranslateX(-5);
|
raceSparkLine.getYAxis().setTranslateX(-5);
|
||||||
raceSparkLine.getYAxis().setAutoRanging(false);
|
raceSparkLine.getYAxis().setAutoRanging(false);
|
||||||
sparklineYAxis.setTickMarkVisible(false);
|
sparklineYAxis.setTickMarkVisible(false);
|
||||||
startingBoats = new ArrayList<>(StreamParser.getBoats().values());
|
startingBoats = new ArrayList<>(ClientPacketParser.getBoats().values());
|
||||||
|
|
||||||
includedCanvasController.setup(this);
|
includedCanvasController.setup(this);
|
||||||
includedCanvasController.initializeCanvas();
|
includedCanvasController.initializeCanvas();
|
||||||
@@ -103,6 +103,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
initialiseBoatSelectionComboBox();
|
initialiseBoatSelectionComboBox();
|
||||||
includedCanvasController.timer.start();
|
includedCanvasController.timer.start();
|
||||||
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,7 +137,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
||||||
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
stage.initStyle(StageStyle.UNDECORATED);
|
stage.initStyle(StageStyle.UNDECORATED);
|
||||||
|
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|
||||||
@@ -303,7 +303,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private Mark getNextMark(BoatGroup bg) {
|
private Mark getNextMark(BoatGroup bg) {
|
||||||
Integer legNumber = bg.getBoat().getLegNumber();
|
Integer legNumber = bg.getBoat().getLegNumber();
|
||||||
|
|
||||||
List<XMLParser.RaceXMLObject.Corner> markSequence = StreamParser.getXmlObject().getRaceXML().getCompoundMarkSequence();
|
List<XMLParser.RaceXMLObject.Corner> markSequence = ClientPacketParser.getXmlObject()
|
||||||
|
.getRaceXML().getCompoundMarkSequence();
|
||||||
|
|
||||||
if (legNumber == 0) {
|
if (legNumber == 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -315,7 +316,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
if (legNumber + 2 == corner.getSeqID()) {
|
if (legNumber + 2 == corner.getSeqID()) {
|
||||||
Integer thisCompoundMarkID = corner.getCompoundMarkID();
|
Integer thisCompoundMarkID = corner.getCompoundMarkID();
|
||||||
|
|
||||||
for (Mark mark : StreamParser.getXmlObject().getRaceXML().getAllCompoundMarks()) {
|
for (Mark mark : ClientPacketParser.getXmlObject().getRaceXML()
|
||||||
|
.getAllCompoundMarks()) {
|
||||||
if (mark.getCompoundMarkID() == thisCompoundMarkID) {
|
if (mark.getCompoundMarkID() == thisCompoundMarkID) {
|
||||||
return mark;
|
return mark;
|
||||||
}
|
}
|
||||||
@@ -328,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() {
|
private void updateWindDirection() {
|
||||||
windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection()));
|
windDirectionText.setText(String.format("%.1f°", ClientPacketParser.getWindDirection()));
|
||||||
windArrowText.setRotate(StreamParser.getWindDirection());
|
windArrowText.setRotate(ClientPacketParser.getWindDirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -340,7 +342,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
* Updates the clock for the race
|
* Updates the clock for the race
|
||||||
*/
|
*/
|
||||||
private void updateRaceTime() {
|
private void updateRaceTime() {
|
||||||
if (StreamParser.isRaceFinished()) {
|
if (ClientPacketParser.isRaceFinished()) {
|
||||||
timerLabel.setFill(Color.RED);
|
timerLabel.setFill(Color.RED);
|
||||||
timerLabel.setText("Race Finished!");
|
timerLabel.setText("Race Finished!");
|
||||||
} else {
|
} else {
|
||||||
@@ -350,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
|
* in the boat selection combo box
|
||||||
*/
|
*/
|
||||||
private void updateBoatSelectionComboBox() {
|
private void updateBoatSelectionComboBox() {
|
||||||
ObservableList<Yacht> observableBoats = FXCollections
|
ObservableList<Yacht> observableBoats = FXCollections
|
||||||
.observableArrayList(StreamParser.getBoatsPos().values());
|
.observableArrayList(ClientPacketParser.getBoatsPos().values());
|
||||||
boatSelectionComboBox.setItems(observableBoats);
|
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
|
* section
|
||||||
*/
|
*/
|
||||||
private void updateOrder() {
|
private void updateOrder() {
|
||||||
@@ -370,15 +372,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
|
||||||
// list of racing boat id
|
// list of racing boat id
|
||||||
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
ArrayList<Participant> participants = ClientPacketParser.getXmlObject().getRaceXML()
|
||||||
.getParticipants();
|
.getParticipants();
|
||||||
ArrayList<Integer> participantIDs = new ArrayList<>();
|
ArrayList<Integer> participantIDs = new ArrayList<>();
|
||||||
for (Participant p : participants) {
|
for (Participant p : participants) {
|
||||||
participantIDs.add(p.getsourceID());
|
participantIDs.add(p.getsourceID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StreamParser.isRaceStarted()) {
|
if (ClientPacketParser.isRaceStarted()) {
|
||||||
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
for (Yacht boat : ClientPacketParser.getBoatsPos().values()) {
|
||||||
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
||||||
if (boat.getBoatStatus() == 3) { // 3 is finish status
|
if (boat.getBoatStatus() == 3) { // 3 is finish status
|
||||||
Text textToAdd = new Text(boat.getPosition() + ". " +
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
||||||
@@ -396,7 +398,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Yacht boat : StreamParser.getBoats().values()) {
|
for (Yacht boat : ClientPacketParser.getBoats().values()) {
|
||||||
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
if (participantIDs.contains(boat.getSourceID())) { // check if the boat is racing
|
||||||
Text textToAdd = new Text(boat.getPosition() + ". " +
|
Text textToAdd = new Text(boat.getPosition() + ". " +
|
||||||
boat.getShortName() + " ");
|
boat.getShortName() + " ");
|
||||||
@@ -434,9 +436,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Point2D markPoint2 = includedCanvasController.findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
|
Point2D markPoint2 = includedCanvasController.findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
|
||||||
HashMap<Double, Double> angleAndSpeed;
|
HashMap<Double, Double> angleAndSpeed;
|
||||||
if (isUpwind) {
|
if (isUpwind) {
|
||||||
angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
|
angleAndSpeed = PolarTable
|
||||||
|
.getOptimalUpwindVMG(ClientPacketParser.getWindSpeed());
|
||||||
} else {
|
} else {
|
||||||
angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
|
angleAndSpeed = PolarTable
|
||||||
|
.getOptimalDownwindVMG(ClientPacketParser.getWindSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
Double resultingAngle = angleAndSpeed.keySet().iterator().next();
|
Double resultingAngle = angleAndSpeed.keySet().iterator().next();
|
||||||
@@ -444,15 +448,23 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
Point2D boatCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
|
Point2D boatCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
|
||||||
Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
|
Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
|
||||||
Integer lineFuncResult = GeometryUtils.lineFunction(boatCurrentPos, gateMidPoint, markPoint2);
|
Integer lineFuncResult = GeoUtility.lineFunction(boatCurrentPos, gateMidPoint, markPoint2);
|
||||||
Line rightLayline = new Line();
|
Line rightLayline = new Line();
|
||||||
Line leftLayline = new Line();
|
Line leftLayline = new Line();
|
||||||
if (lineFuncResult == 1) {
|
if (lineFuncResult == 1) {
|
||||||
rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle,
|
||||||
leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
ClientPacketParser
|
||||||
|
.getWindDirection());
|
||||||
|
leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle,
|
||||||
|
ClientPacketParser
|
||||||
|
.getWindDirection());
|
||||||
} else if (lineFuncResult == -1) {
|
} else if (lineFuncResult == -1) {
|
||||||
rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle,
|
||||||
leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
ClientPacketParser
|
||||||
|
.getWindDirection());
|
||||||
|
leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle,
|
||||||
|
ClientPacketParser
|
||||||
|
.getWindDirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
leftLayline.setStrokeWidth(0.5);
|
leftLayline.setStrokeWidth(0.5);
|
||||||
@@ -548,16 +560,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
private String getTimeSinceStartOfRace() {
|
private String getTimeSinceStartOfRace() {
|
||||||
String timerString = "0:00";
|
String timerString = "0:00";
|
||||||
if (StreamParser.getTimeSinceStart() > 0) {
|
if (ClientPacketParser.getTimeSinceStart() > 0) {
|
||||||
String timerMinute = Long.toString(StreamParser.getTimeSinceStart() / 60);
|
String timerMinute = Long.toString(ClientPacketParser.getTimeSinceStart() / 60);
|
||||||
String timerSecond = Long.toString(StreamParser.getTimeSinceStart() % 60);
|
String timerSecond = Long.toString(ClientPacketParser.getTimeSinceStart() % 60);
|
||||||
if (timerSecond.length() == 1) {
|
if (timerSecond.length() == 1) {
|
||||||
timerSecond = "0" + timerSecond;
|
timerSecond = "0" + timerSecond;
|
||||||
}
|
}
|
||||||
timerString = "-" + timerMinute + ":" + timerSecond;
|
timerString = "-" + timerMinute + ":" + timerSecond;
|
||||||
} else {
|
} else {
|
||||||
String timerMinute = Long.toString(-1 * StreamParser.getTimeSinceStart() / 60);
|
String timerMinute = Long.toString(-1 * ClientPacketParser.getTimeSinceStart() / 60);
|
||||||
String timerSecond = Long.toString(-1 * StreamParser.getTimeSinceStart() % 60);
|
String timerSecond = Long.toString(-1 * ClientPacketParser.getTimeSinceStart() % 60);
|
||||||
if (timerSecond.length() == 1) {
|
if (timerSecond.length() == 1) {
|
||||||
timerSecond = "0" + timerSecond;
|
timerSecond = "0" + timerSecond;
|
||||||
}
|
}
|
||||||
@@ -637,4 +649,5 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
public static boolean sparkLineStatus(Integer yachtId) {
|
public static boolean sparkLineStatus(Integer yachtId) {
|
||||||
return sparkLineData.containsKey(yachtId);
|
return sparkLineData.containsKey(yachtId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,191 +1,97 @@
|
|||||||
package seng302.controllers;
|
package seng302.controllers;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.TableColumn;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import seng302.client.ClientToServerThread;
|
||||||
import seng302.models.Yacht;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.models.stream.StreamParser;
|
import seng302.gameServer.MainServerThread;
|
||||||
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
|
|
||||||
|
|
||||||
public class StartScreenController implements Initializable {
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Class describing the actions of the start screen controller
|
||||||
|
* Created by wmu16 on 10/07/17.
|
||||||
|
*/
|
||||||
|
public class StartScreenController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private GridPane gridPane;
|
private TextField ipTextField;
|
||||||
@FXML
|
@FXML
|
||||||
private Label timeTillLive;
|
private GridPane startScreen2;
|
||||||
@FXML
|
|
||||||
private Button streamButton;
|
|
||||||
@FXML
|
|
||||||
private Button switchToRaceViewButton;
|
|
||||||
@FXML
|
|
||||||
private TableView<Yacht> teamList;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<Yacht, String> boatNameCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<Yacht, String> shortNameCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<Yacht, String> countryCol;
|
|
||||||
@FXML
|
|
||||||
private TableColumn<Yacht, String> posCol;
|
|
||||||
@FXML
|
|
||||||
private Label realTime;
|
|
||||||
|
|
||||||
private boolean switchedToRaceView = false;
|
private Controller controller;
|
||||||
|
|
||||||
private void setContentPane(String jfxUrl) {
|
/**
|
||||||
|
* Loads the fxml content into the parent pane
|
||||||
|
* @param jfxUrl
|
||||||
|
* @return the controller of the fxml
|
||||||
|
*/
|
||||||
|
private Object setContentPane(String jfxUrl) {
|
||||||
try {
|
try {
|
||||||
// get the main controller anchor pane (MainView.fxml)
|
AnchorPane contentPane = (AnchorPane) startScreen2.getParent();
|
||||||
AnchorPane contentPane = (AnchorPane) gridPane.getParent();
|
|
||||||
contentPane.getChildren().removeAll();
|
contentPane.getChildren().removeAll();
|
||||||
contentPane.getChildren().clear();
|
contentPane.getChildren().clear();
|
||||||
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
contentPane.getChildren()
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(jfxUrl));
|
||||||
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
|
contentPane.getChildren().addAll((Pane) fxmlLoader.load());
|
||||||
|
return fxmlLoader.getController();
|
||||||
} catch (javafx.fxml.LoadException e) {
|
} catch (javafx.fxml.LoadException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
gridPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
teamList.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Running a timer to update the livestream status on welcome screen. Update interval is 1
|
* ATTEMPTS TO:
|
||||||
* second.
|
* Sets up a new game state with your IP address as designated as the host.
|
||||||
|
* Starts a thread to listen for incoming connections
|
||||||
|
* Switches to the lobby screen
|
||||||
*/
|
*/
|
||||||
public void startStream() {
|
@FXML
|
||||||
// reset boolean for switch to race view
|
public void hostButtonPressed() {
|
||||||
switchedToRaceView = false;
|
try {
|
||||||
|
String ipAddress = InetAddress.getLocalHost().getHostAddress();
|
||||||
|
new GameState(ipAddress);
|
||||||
|
new MainServerThread().start();
|
||||||
|
ClientToServerThread clientToServerThread = new ClientToServerThread("localhost", 4950);
|
||||||
|
controller.setClientToServerThread(clientToServerThread);
|
||||||
|
clientToServerThread.start();
|
||||||
|
// new GameServerThread("Fuck you");
|
||||||
|
// get the lobby controller so that we can pass the game server thread to it
|
||||||
|
setContentPane("/views/LobbyView.fxml");
|
||||||
|
|
||||||
if (StreamParser.isStreamStatus()) {
|
} catch (UnknownHostException e) {
|
||||||
streamButton.setVisible(false);
|
System.err.println("COULD NOT FIND YOUR IP ADDRESS!");
|
||||||
realTime.setVisible(true);
|
e.printStackTrace();
|
||||||
timeTillLive.setVisible(true);
|
|
||||||
timeTillLive.setTextFill(Color.GREEN);
|
|
||||||
timeTillLive.setText("Connecting...");
|
|
||||||
Timer timer = new Timer();
|
|
||||||
timer.scheduleAtFixedRate(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
if (StreamParser.isRaceStarted()) {
|
|
||||||
if (!switchedToRaceView) {
|
|
||||||
switchToRaceView();
|
|
||||||
}
|
}
|
||||||
timer.cancel();
|
|
||||||
}
|
}
|
||||||
if (StreamParser.isRaceFinished()) {
|
|
||||||
realTime.setText(StreamParser.getCurrentTimeString());
|
|
||||||
timeTillLive.setTextFill(Color.RED);
|
@FXML
|
||||||
timeTillLive.setText("Race finished! Waiting for new race...");
|
public void connectButtonPressed() {
|
||||||
switchToRaceViewButton.setDisable(true);
|
// TODO: 10/07/17 wmu16 - Finish function
|
||||||
} else if (StreamParser.getTimeSinceStart() > 0) {
|
String ipAddress = ipTextField.getText().trim().toLowerCase();
|
||||||
realTime.setText(StreamParser.getCurrentTimeString());
|
try {
|
||||||
updateTeamList();
|
ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, 4950);
|
||||||
timeTillLive.setTextFill(Color.RED);
|
controller.setClientToServerThread(clientToServerThread);
|
||||||
switchToRaceViewButton.setDisable(false);
|
clientToServerThread.start();
|
||||||
String timerMinute = Long
|
setContentPane("/views/LobbyView.fxml");
|
||||||
.toString(StreamParser.getTimeSinceStart() / 60);
|
} catch (Exception e){
|
||||||
String timerSecond = Long
|
e.printStackTrace();
|
||||||
.toString(StreamParser.getTimeSinceStart() % 60);
|
|
||||||
if (timerSecond.length() == 1) {
|
|
||||||
timerSecond = "0" + timerSecond;
|
|
||||||
}
|
|
||||||
String timerString = "-" + timerMinute + ":" + timerSecond;
|
|
||||||
timeTillLive.setText(timerString);
|
|
||||||
} else {
|
|
||||||
realTime.setText(StreamParser.getCurrentTimeString());
|
|
||||||
updateTeamList();
|
|
||||||
timeTillLive.setTextFill(Color.BLACK);
|
|
||||||
switchToRaceViewButton.setDisable(false);
|
|
||||||
String timerMinute = Long
|
|
||||||
.toString(-1 * StreamParser.getTimeSinceStart() / 60);
|
|
||||||
String timerSecond = Long
|
|
||||||
.toString(-1 * StreamParser.getTimeSinceStart() % 60);
|
|
||||||
if (timerSecond.length() == 1) {
|
|
||||||
timerSecond = "0" + timerSecond;
|
|
||||||
}
|
|
||||||
String timerString = timerMinute + ":" + timerSecond;
|
|
||||||
timeTillLive.setText(timerString);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 0, 1000);
|
|
||||||
} else {
|
|
||||||
timeTillLive.setText("Stream not available.");
|
|
||||||
timeTillLive.setTextFill(Color.RED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchToRaceView() {
|
public void setController(Controller controller) {
|
||||||
StreamParser.boatLocations.clear();
|
this.controller = controller;
|
||||||
switchedToRaceView = true;
|
|
||||||
setContentPane("/views/RaceView.fxml");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTeamList() {
|
|
||||||
ObservableList<Yacht> data = FXCollections.observableArrayList();
|
|
||||||
|
|
||||||
teamList.setItems(data);
|
|
||||||
|
|
||||||
boatNameCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("boatName")
|
|
||||||
);
|
|
||||||
shortNameCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("shortName")
|
|
||||||
);
|
|
||||||
countryCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("country")
|
|
||||||
);
|
|
||||||
posCol.setCellValueFactory(
|
|
||||||
new PropertyValueFactory<>("position")
|
|
||||||
);
|
|
||||||
|
|
||||||
// check if the boat is racing
|
|
||||||
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
|
|
||||||
.getParticipants();
|
|
||||||
ArrayList<Integer> participantIDs = new ArrayList<>();
|
|
||||||
for (Participant p : participants) {
|
|
||||||
participantIDs.add(p.getsourceID());
|
|
||||||
}
|
|
||||||
|
|
||||||
// add boats to the start screen list
|
|
||||||
if (StreamParser.isRaceStarted()) { // if race is started, use StreamParser.getBoatsPos()
|
|
||||||
for (Yacht boat : StreamParser.getBoatsPos().values()) {
|
|
||||||
if (participantIDs.contains(boat.getSourceID())) {
|
|
||||||
data.add(boat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // else use StreamParser.getBoats()
|
|
||||||
for (Yacht boat : StreamParser.getBoats().values()) {
|
|
||||||
if (participantIDs.contains(boat.getSourceID())) {
|
|
||||||
data.add(boat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
teamList.refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import javafx.scene.Group;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.models.stream.StreamParser;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -88,7 +88,7 @@ public class BoatAnnotations extends Group{
|
|||||||
if (boat.getTimeTillNext() != null) {
|
if (boat.getTimeTillNext() != null) {
|
||||||
DateFormat format = new SimpleDateFormat("mm:ss");
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
String timeToNextMark = format
|
String timeToNextMark = format
|
||||||
.format(boat.getTimeTillNext() - StreamParser.getCurrentTimeLong());
|
.format(boat.getTimeTillNext() - ClientPacketParser.getCurrentTimeLong());
|
||||||
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark);
|
||||||
} else {
|
} else {
|
||||||
estTimeToNextMarkObject.setText("Next mark: -");
|
estTimeToNextMarkObject.setText("Next mark: -");
|
||||||
@@ -97,7 +97,7 @@ public class BoatAnnotations extends Group{
|
|||||||
if (boat.getMarkRoundTime() != null) {
|
if (boat.getMarkRoundTime() != null) {
|
||||||
DateFormat format = new SimpleDateFormat("mm:ss");
|
DateFormat format = new SimpleDateFormat("mm:ss");
|
||||||
String elapsedTime = format
|
String elapsedTime = format
|
||||||
.format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundTime());
|
.format(ClientPacketParser.getCurrentTimeLong() - boat.getMarkRoundTime());
|
||||||
legTimeObject.setText("Last mark: " + elapsedTime);
|
legTimeObject.setText("Last mark: " + elapsedTime);
|
||||||
}else {
|
}else {
|
||||||
legTimeObject.setText("Last mark: - ");
|
legTimeObject.setText("Last mark: - ");
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import javafx.scene.paint.Color;
|
|||||||
import javafx.scene.shape.Line;
|
import javafx.scene.shape.Line;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.transform.Rotate;
|
import javafx.scene.transform.Rotate;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
import seng302.models.Yacht;
|
import seng302.models.Yacht;
|
||||||
import seng302.utilities.GeometryUtils;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.controllers.CanvasController;
|
import seng302.controllers.CanvasController;
|
||||||
import seng302.models.mark.GateMark;
|
import seng302.models.mark.GateMark;
|
||||||
import seng302.models.mark.Mark;
|
import seng302.models.mark.Mark;
|
||||||
import seng302.models.mark.SingleMark;
|
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
|
* 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) {
|
public Boolean isUpwindLeg(CanvasController canvasController, Mark nextMark) {
|
||||||
|
|
||||||
Double windAngle = StreamParser.getWindDirection();
|
Double windAngle = ClientPacketParser.getWindDirection();
|
||||||
GateMark thisGateMark = (GateMark) nextMark;
|
GateMark thisGateMark = (GateMark) nextMark;
|
||||||
SingleMark nextMark1 = thisGateMark.getSingleMark1();
|
SingleMark nextMark1 = thisGateMark.getSingleMark1();
|
||||||
SingleMark nextMark2 = thisGateMark.getSingleMark2();
|
SingleMark nextMark2 = thisGateMark.getSingleMark2();
|
||||||
@@ -246,11 +246,11 @@ public class BoatGroup extends Group {
|
|||||||
Point2D nextMarkPoint2 = canvasController.findScaledXY(nextMark2.getLatitude(), nextMark2.getLongitude());
|
Point2D nextMarkPoint2 = canvasController.findScaledXY(nextMark2.getLatitude(), nextMark2.getLongitude());
|
||||||
|
|
||||||
Point2D boatCurrentPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
Point2D boatCurrentPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
||||||
Point2D windTestPoint = GeometryUtils.makeArbitraryVectorPoint(nextMarkPoint1, windAngle, 10d);
|
Point2D windTestPoint = GeoUtility.makeArbitraryVectorPoint(nextMarkPoint1, windAngle, 10d);
|
||||||
|
|
||||||
|
|
||||||
Integer boatLineFuncResult = GeometryUtils.lineFunction(nextMarkPoint1, nextMarkPoint2, boatCurrentPoint);
|
Integer boatLineFuncResult = GeoUtility.lineFunction(nextMarkPoint1, nextMarkPoint2, boatCurrentPoint);
|
||||||
Integer windLineFuncResult = GeometryUtils.lineFunction(nextMarkPoint1, nextMarkPoint2, windTestPoint);
|
Integer windLineFuncResult = GeoUtility.lineFunction(nextMarkPoint1, nextMarkPoint2, windTestPoint);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import seng302.models.Player;
|
||||||
|
|
||||||
|
public interface ClientConnectionDelegate {
|
||||||
|
/**
|
||||||
|
* A player has connected to the server
|
||||||
|
* @param serverToClientThread The player that has connected
|
||||||
|
*/
|
||||||
|
void clientConnected(ServerToClientThread serverToClientThread);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player has disconnected from the server
|
||||||
|
* @param player The player that has disconnected
|
||||||
|
*/
|
||||||
|
void clientDisconnected(Player player);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum describing the states of the game
|
||||||
|
* Created by wmu16 on 11/07/17.
|
||||||
|
*/
|
||||||
|
public enum GameStages {
|
||||||
|
|
||||||
|
LOBBYING(0),
|
||||||
|
PRE_RACE(1),
|
||||||
|
RACING(2),
|
||||||
|
FINISHED(3),
|
||||||
|
CANCELLED(4);
|
||||||
|
|
||||||
|
private long code;
|
||||||
|
|
||||||
|
GameStages(long code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCode(){
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
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)
|
||||||
|
* Created by wmu16 on 10/07/17.
|
||||||
|
*/
|
||||||
|
public class GameState {
|
||||||
|
|
||||||
|
private static Long previousUpdateTime;
|
||||||
|
private static Double windDirection = 0d;
|
||||||
|
private static Double windSpeed = 0d;
|
||||||
|
|
||||||
|
private static String hostIpAddress;
|
||||||
|
private static List<Player> players;
|
||||||
|
private static Map<Integer, Yacht> yachts;
|
||||||
|
private static Boolean isRaceStarted;
|
||||||
|
private static GameStages currentStage;
|
||||||
|
|
||||||
|
public GameState(String hostIpAddress) {
|
||||||
|
GameState.hostIpAddress = hostIpAddress;
|
||||||
|
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 List<Player> getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addPlayer(Player player) {
|
||||||
|
players.add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removePlayer(Player player) {
|
||||||
|
players.remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addYacht(Integer sourceId, Yacht yatch) {
|
||||||
|
yachts.put(sourceId, yatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean getIsRaceStarted() {
|
||||||
|
return isRaceStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameStages getCurrentStage() {
|
||||||
|
return currentStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCurrentStage(GameStages currentStage) {
|
||||||
|
GameState.currentStage = currentStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import seng302.models.Player;
|
||||||
|
import seng302.server.messages.Heartbeat;
|
||||||
|
import seng302.server.messages.Message;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Heartbeat messages to connected player at a specified interval
|
||||||
|
* Will call .clientDisconnected on the delegate when a heartbeat message
|
||||||
|
* cannot be sent to a player
|
||||||
|
*/
|
||||||
|
public class HeartbeatThread extends Thread{
|
||||||
|
private final int HEARTBEAT_PERIOD = 5000;
|
||||||
|
private ClientConnectionDelegate delegate;
|
||||||
|
private Integer seqNum;
|
||||||
|
private Stack<Player> disconnectedPlayers;
|
||||||
|
|
||||||
|
public HeartbeatThread(ClientConnectionDelegate delegate){
|
||||||
|
this.delegate = delegate;
|
||||||
|
seqNum = 0;
|
||||||
|
disconnectedPlayers = new Stack<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player has lost connection to the server
|
||||||
|
* The player is added to a stack so that the delegate
|
||||||
|
* can be notified
|
||||||
|
*
|
||||||
|
* @param player The player that has disconnected
|
||||||
|
*/
|
||||||
|
private void playerLostConnection(Player player){
|
||||||
|
disconnectedPlayers.push(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a heartbeat message to each connected player
|
||||||
|
* The delegate is notified if a player has disconnected
|
||||||
|
*/
|
||||||
|
private void sendHeartbeatToAllPlayers(){
|
||||||
|
Message heartbeat = new Heartbeat(seqNum);
|
||||||
|
|
||||||
|
for (Player player : GameState.getPlayers()){
|
||||||
|
if (!player.getSocket().isConnected()){
|
||||||
|
playerLostConnection(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
|
||||||
|
} catch (IOException e) {
|
||||||
|
playerLostConnection(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDelegate();
|
||||||
|
seqNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the delegate about
|
||||||
|
* each disconnected player
|
||||||
|
*/
|
||||||
|
private void updateDelegate() {
|
||||||
|
while (!disconnectedPlayers.empty()){
|
||||||
|
delegate.clientDisconnected(disconnectedPlayers.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
Timer t = new Timer();
|
||||||
|
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sendHeartbeatToAllPlayers();
|
||||||
|
}
|
||||||
|
}, 0, HEARTBEAT_PERIOD);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
|
import seng302.models.Player;
|
||||||
|
import seng302.models.stream.PacketBufferDelegate;
|
||||||
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class describing the overall server, which creates and collects server threads for each client
|
||||||
|
* Created by wmu16 on 13/07/17.
|
||||||
|
*/
|
||||||
|
public class MainServerThread extends Thread implements PacketBufferDelegate, ClientConnectionDelegate{
|
||||||
|
|
||||||
|
private static final int PORT = 4950;
|
||||||
|
private static final Integer MAX_NUM_PLAYERS = 3;
|
||||||
|
private static final int LOG_LEVEL = 1;
|
||||||
|
|
||||||
|
private ServerSocket serverSocket = null;
|
||||||
|
private Socket socket;
|
||||||
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
|
|
||||||
|
private PriorityBlockingQueue<StreamPacket> packetBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
public MainServerThread() {
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(PORT);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IO error in server thread handler upon trying to make new server socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
packetBuffer = new PriorityBlockingQueue<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
ServerListenThread serverListenThread;
|
||||||
|
HeartbeatThread heartbeatThread;
|
||||||
|
|
||||||
|
serverListenThread = new ServerListenThread(serverSocket, this);
|
||||||
|
heartbeatThread = new HeartbeatThread(this);
|
||||||
|
|
||||||
|
heartbeatThread.start();
|
||||||
|
serverListenThread.start();
|
||||||
|
|
||||||
|
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000 / 60); //60 times per second we should calculate the game state
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
||||||
|
GameState.update();
|
||||||
|
}
|
||||||
|
//RACING
|
||||||
|
if (GameState.getCurrentStage() == GameStages.RACING) {
|
||||||
|
GameState.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//FINISHED
|
||||||
|
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||||
|
|
||||||
|
}
|
||||||
|
updateClients();
|
||||||
|
|
||||||
|
while (!packetBuffer.isEmpty()){
|
||||||
|
System.out.println("WHATUPPP");
|
||||||
|
try {
|
||||||
|
StreamPacket packet = packetBuffer.take();
|
||||||
|
ClientPacketParser.parsePacket(packet);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("WHOOPSIES");
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
|
||||||
|
try {
|
||||||
|
serverSocket.close();
|
||||||
|
return;
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IO error in server thread handler upon closing socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateClients() {
|
||||||
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
|
serverToClientThread.updateClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void serverLog(String message, int logLevel){
|
||||||
|
if(logLevel <= LOG_LEVEL){
|
||||||
|
System.out.println("[SERVER] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addToBuffer(StreamPacket streamPacket) {
|
||||||
|
System.out.println("HEY HI");
|
||||||
|
return packetBuffer.add(streamPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeRace(){
|
||||||
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
|
serverToClientThread.updateClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client has tried to connect to the server
|
||||||
|
* @param serverToClientThread The player that connected
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clientConnected(ServerToClientThread serverToClientThread) {
|
||||||
|
serverLog("Player Connected From " + serverToClientThread.getName(), 0);
|
||||||
|
serverToClientThreads.add(serverToClientThread);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player has left the game, remove the player from the GameState
|
||||||
|
* @param player The player that left
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clientDisconnected(Player player) {
|
||||||
|
serverLog("Player disconnected", 0);
|
||||||
|
GameState.removePlayer(player);
|
||||||
|
// sendXml();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import seng302.models.Player;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for a thread to listen to connections
|
||||||
|
* Created by wmu16 on 11/07/17.
|
||||||
|
*/
|
||||||
|
public class ServerListenThread extends Thread{
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
private ClientConnectionDelegate delegate;
|
||||||
|
|
||||||
|
public ServerListenThread(ServerSocket serverSocket, ClientConnectionDelegate delegate){
|
||||||
|
this.serverSocket = serverSocket;
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for a connection and upon finding one, creates a Player object and adds it to the universal GameState
|
||||||
|
*/
|
||||||
|
private void acceptConnection() {
|
||||||
|
try {
|
||||||
|
Socket thisClient = serverSocket.accept();
|
||||||
|
if (thisClient != null){
|
||||||
|
ServerToClientThread thisConnection = new ServerToClientThread(thisClient);
|
||||||
|
thisConnection.start();
|
||||||
|
delegate.clientConnected(thisConnection);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
while (true){
|
||||||
|
acceptConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import seng302.client.ClientPacketParser;
|
||||||
|
import seng302.models.Player;
|
||||||
|
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.
|
||||||
|
* All server threads created and owned by the server thread handler which can trigger client updates on its threads
|
||||||
|
* Created by wmu16 on 13/07/17.
|
||||||
|
*/
|
||||||
|
public class ServerToClientThread extends Thread {
|
||||||
|
private static final Integer MAX_ID_ATTEMPTS = 10;
|
||||||
|
|
||||||
|
private InputStream is;
|
||||||
|
private OutputStream os;
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
private ByteArrayOutputStream crcBuffer;
|
||||||
|
|
||||||
|
private Boolean userIdentified = false;
|
||||||
|
private Boolean connected = true;
|
||||||
|
private Boolean updateClient = true;
|
||||||
|
|
||||||
|
private Integer sourceId;
|
||||||
|
|
||||||
|
public ServerToClientThread(Socket socket) {
|
||||||
|
this.socket = socket;
|
||||||
|
try {
|
||||||
|
is = socket.getInputStream();
|
||||||
|
os = socket.getOutputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IO error in server thread upon grabbing streams");
|
||||||
|
}
|
||||||
|
// 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() {
|
||||||
|
int sync1;
|
||||||
|
int sync2;
|
||||||
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
|
while(true) {
|
||||||
|
//System.out.print(".");
|
||||||
|
|
||||||
|
try {
|
||||||
|
//Perform a write if it is time to as delegated by the MainServerThread
|
||||||
|
if (updateClient) {
|
||||||
|
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
|
||||||
|
ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Hello, it's me");
|
||||||
|
sendMessage(chatterMessage);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// GameState.outputState(os);
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// System.out.println("IO error in server thread upon writing to output stream");
|
||||||
|
// }
|
||||||
|
updateClient = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
crcBuffer = new ByteArrayOutputStream();
|
||||||
|
sync1 = readByte();
|
||||||
|
sync2 = readByte();
|
||||||
|
|
||||||
|
//checking if it is the start of the packet
|
||||||
|
if(sync1 == 0x47 && sync2 == 0x83) {
|
||||||
|
int type = readByte();
|
||||||
|
//No. of milliseconds since Jan 1st 1970
|
||||||
|
long timeStamp = Message.bytesToLong(getBytes(6));
|
||||||
|
skipBytes(4);
|
||||||
|
long payloadLength = Message.bytesToLong(getBytes(2));
|
||||||
|
byte[] payload = getBytes((int) payloadLength);
|
||||||
|
Checksum checksum = new CRC32();
|
||||||
|
checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size());
|
||||||
|
long computedCrc = checksum.getValue();
|
||||||
|
long packetCrc = Message.bytesToLong(getBytes(4));
|
||||||
|
if (computedCrc == packetCrc) {
|
||||||
|
//System.out.println("RECEIVED A PACKET");
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
closeSocket();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateClient() {
|
||||||
|
updateClient = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to confirm the connection just accepted.
|
||||||
|
* Sends ID, expects that ID echoed for confirmation,
|
||||||
|
* if so, sends a confirmation packet back to that connection
|
||||||
|
* Creates a player instance with that ID and this thread and adds it to the GameState
|
||||||
|
* If not, close the socket and end the threads execution
|
||||||
|
*/
|
||||||
|
private void threeWayHandshake() {
|
||||||
|
// // TODO: 13/07/17 Finish using AC35
|
||||||
|
// Integer playerID = GameState.getUniquePlayerID();
|
||||||
|
// Integer confirmationID = null;
|
||||||
|
// Integer identificationAttempt = 0
|
||||||
|
// while (!userIdentified) {
|
||||||
|
// os.write(playerID); //Send out new ID looking for echo
|
||||||
|
// confirmationID = is.read();
|
||||||
|
// if (playerID == idConfirmation) { //ID is echoed back. Connection is a client
|
||||||
|
// os.write( some determined confirmation message ); //Confirm to client
|
||||||
|
// GameState.addPlayer(new Player(playerID, this)); //Create a player in game state for client
|
||||||
|
// userIdentified = true;
|
||||||
|
// } else if (identificationAttempt > MAX_ID_ATTEMPTS) { //No response. not a client. tidy up and go home.
|
||||||
|
// closeSocket();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// identificationAttempt++;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeSocket() {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IO error in server thread upon trying to close socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int readByte() throws Exception {
|
||||||
|
int currentByte = -1;
|
||||||
|
try {
|
||||||
|
// @TODO @FIX ConnectionReset Exception when a client disconnects before it is garbage collected
|
||||||
|
currentByte = is.read();
|
||||||
|
crcBuffer.write(currentByte);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (currentByte == -1){
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
return currentByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getBytes(int n) throws Exception{
|
||||||
|
byte[] bytes = new byte[n];
|
||||||
|
for (int i = 0; i < n; i++){
|
||||||
|
bytes[i] = (byte) readByte();
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipBytes(long n) throws Exception{
|
||||||
|
for (int i=0; i < n; i++){
|
||||||
|
readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(Message message){
|
||||||
|
try {
|
||||||
|
os.write(message.getBuffer());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package seng302.models;
|
||||||
|
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Class defining a player and their respective details in the game as held by the model
|
||||||
|
* Created by wmu16 on 10/07/17.
|
||||||
|
*/
|
||||||
|
public class Player {
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
private Yacht yacht;
|
||||||
|
private Integer lastMarkPassed;
|
||||||
|
|
||||||
|
|
||||||
|
public Player(Socket socket) {
|
||||||
|
this.socket = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket getSocket() {
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLastMarkPassed() {
|
||||||
|
return lastMarkPassed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastMarkPassed(Integer lastMarkPassed) {
|
||||||
|
this.lastMarkPassed = lastMarkPassed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Yacht getYacht() {
|
||||||
|
return yacht;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String playerAddress = null;
|
||||||
|
|
||||||
|
if (socket == null){
|
||||||
|
return "Disconnected Player";
|
||||||
|
}
|
||||||
|
|
||||||
|
playerAddress = socket.getRemoteSocketAddress().toString();
|
||||||
|
|
||||||
|
|
||||||
|
return playerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof Player)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Player) obj).socket.equals(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(){
|
||||||
|
return socket.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package seng302.models;
|
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.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@@ -24,9 +27,8 @@ public final class PolarTable {
|
|||||||
* Iterates through each row of the polar table, in pairs, to extract the row into a hashmap of angle to boat speed.
|
* Iterates through each row of the polar table, in pairs, to extract the row into a hashmap of angle to boat speed.
|
||||||
* These angle boatspeed hashmaps are then added to an outer hashmap at the end of wind speed key to each row hashmap
|
* These angle boatspeed hashmaps are then added to an outer hashmap at the end of wind speed key to each row hashmap
|
||||||
* as a value
|
* as a value
|
||||||
* @param file containing the polar csv information
|
|
||||||
*/
|
*/
|
||||||
public static void parsePolarFile(String file) {
|
public static void parsePolarFile(InputStream polarFile) {
|
||||||
polarTable = new HashMap<>();
|
polarTable = new HashMap<>();
|
||||||
upwindOptimal = new HashMap<>();
|
upwindOptimal = new HashMap<>();
|
||||||
downwindOptimal = new HashMap<>();
|
downwindOptimal = new HashMap<>();
|
||||||
@@ -34,7 +36,7 @@ public final class PolarTable {
|
|||||||
String line;
|
String line;
|
||||||
Boolean isHeaderLine = true;
|
Boolean isHeaderLine = true;
|
||||||
|
|
||||||
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) {
|
||||||
while ((line = br.readLine()) != null) {
|
while ((line = br.readLine()) != null) {
|
||||||
String[] thisLine = line.split(",");
|
String[] thisLine = line.split(",");
|
||||||
|
|
||||||
@@ -69,6 +71,8 @@ public final class PolarTable {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +143,7 @@ public final class PolarTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Double getClosestMatch(Double thisWindSpeed) {
|
public static Double getClosestMatch(Double thisWindSpeed) {
|
||||||
|
|
||||||
ArrayList<Double> windValues = new ArrayList<>(polarTable.keySet());
|
ArrayList<Double> windValues = new ArrayList<>(polarTable.keySet());
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
import static seng302.utilities.GeoUtility.getGeoCoordinate;
|
||||||
import seng302.models.mark.Mark;
|
|
||||||
import seng302.controllers.RaceViewController;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
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.
|
* Yacht class for the racing boat.
|
||||||
@@ -24,6 +27,10 @@ public class Yacht {
|
|||||||
private String shortName;
|
private String shortName;
|
||||||
private String boatName;
|
private String boatName;
|
||||||
private String country;
|
private String country;
|
||||||
|
|
||||||
|
// Situational data
|
||||||
|
|
||||||
|
|
||||||
// Boat status
|
// Boat status
|
||||||
private Integer boatStatus;
|
private Integer boatStatus;
|
||||||
private Integer legNumber;
|
private Integer legNumber;
|
||||||
@@ -31,7 +38,9 @@ public class Yacht {
|
|||||||
private Integer penaltiesServed;
|
private Integer penaltiesServed;
|
||||||
private Long estimateTimeAtFinish;
|
private Long estimateTimeAtFinish;
|
||||||
private String position;
|
private String position;
|
||||||
private double velocity;
|
private GeoPoint location;
|
||||||
|
private Double heading;
|
||||||
|
private Double velocity;
|
||||||
private Long timeTillNext;
|
private Long timeTillNext;
|
||||||
private Long markRoundTime;
|
private Long markRoundTime;
|
||||||
|
|
||||||
@@ -45,8 +54,12 @@ public class Yacht {
|
|||||||
*
|
*
|
||||||
* @param boatName Create a yacht object with name.
|
* @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.boatName = boatName;
|
||||||
|
this.shortName = shortName;
|
||||||
|
this.location = location;
|
||||||
|
this.heading = heading;
|
||||||
|
this.velocity = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +87,41 @@ public class Yacht {
|
|||||||
this.position = "-";
|
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<Double, Double> 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() {
|
public String getBoatType() {
|
||||||
return boatType;
|
return boatType;
|
||||||
}
|
}
|
||||||
@@ -191,11 +239,6 @@ public class Yacht {
|
|||||||
this.lastMarkRounded = lastMarkRounded;
|
this.lastMarkRounded = lastMarkRounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return boatName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNextMark(Mark nextMark) {
|
public void setNextMark(Mark nextMark) {
|
||||||
this.nextMark = nextMark;
|
this.nextMark = nextMark;
|
||||||
}
|
}
|
||||||
@@ -204,4 +247,9 @@ public class Yacht {
|
|||||||
return nextMark;
|
return nextMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return boatName;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package seng302.models.stream;
|
||||||
|
|
||||||
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
|
||||||
|
public interface PacketBufferDelegate {
|
||||||
|
boolean addToBuffer(StreamPacket streamPacket);
|
||||||
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
package seng302.models.stream;
|
package seng302.models.stream;
|
||||||
|
|
||||||
import seng302.models.stream.packets.StreamPacket;
|
import seng302.models.stream.packets.StreamPacket;
|
||||||
|
import seng302.server.messages.BoatActionMessage;
|
||||||
|
import seng302.server.messages.BoatActionType;
|
||||||
|
import seng302.server.messages.Heartbeat;
|
||||||
|
import seng302.server.messages.Message;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
@@ -13,7 +17,8 @@ import java.util.zip.Checksum;
|
|||||||
|
|
||||||
|
|
||||||
public class StreamReceiver extends Thread {
|
public class StreamReceiver extends Thread {
|
||||||
private InputStream stream;
|
private InputStream inputStream;
|
||||||
|
private OutputStream outputStream;
|
||||||
private Socket host;
|
private Socket host;
|
||||||
private ByteArrayOutputStream crcBuffer;
|
private ByteArrayOutputStream crcBuffer;
|
||||||
private Thread t;
|
private Thread t;
|
||||||
@@ -58,49 +63,43 @@ public class StreamReceiver extends Thread {
|
|||||||
|
|
||||||
|
|
||||||
public void connect(){
|
public void connect(){
|
||||||
try {
|
|
||||||
stream = host.getInputStream();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sync1;
|
// int sync1;
|
||||||
int sync2;
|
// int sync2;
|
||||||
moreBytes = true;
|
// moreBytes = true;
|
||||||
while(moreBytes) {
|
// while(moreBytes) {
|
||||||
try {
|
// try {
|
||||||
crcBuffer = new ByteArrayOutputStream();
|
// crcBuffer = new ByteArrayOutputStream();
|
||||||
sync1 = readByte();
|
// sync1 = readByte();
|
||||||
sync2 = readByte();
|
// sync2 = readByte();
|
||||||
//checking if it is the start of the packet
|
// //checking if it is the start of the packet
|
||||||
if(sync1 == 0x47 && sync2 == 0x83) {
|
// if(sync1 == 0x47 && sync2 == 0x83) {
|
||||||
int type = readByte();
|
// int type = readByte();
|
||||||
//No. of milliseconds since Jan 1st 1970
|
// //No. of milliseconds since Jan 1st 1970
|
||||||
long timeStamp = bytesToLong(getBytes(6));
|
// long timeStamp = bytesToLong(getBytes(6));
|
||||||
skipBytes(4);
|
// skipBytes(4);
|
||||||
long payloadLength = bytesToLong(getBytes(2));
|
// long payloadLength = bytesToLong(getBytes(2));
|
||||||
byte[] payload = getBytes((int) payloadLength);
|
// byte[] payload = getBytes((int) payloadLength);
|
||||||
Checksum checksum = new CRC32();
|
// Checksum checksum = new CRC32();
|
||||||
checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size());
|
// checksum.update(crcBuffer.toByteArray(), 0, crcBuffer.size());
|
||||||
long computedCrc = checksum.getValue();
|
// long computedCrc = checksum.getValue();
|
||||||
long packetCrc = bytesToLong(getBytes(4));
|
// long packetCrc = bytesToLong(getBytes(4));
|
||||||
if (computedCrc == packetCrc) {
|
// if (computedCrc == packetCrc) {
|
||||||
packetBuffer.add(new StreamPacket(type, payloadLength, timeStamp, payload));
|
// packetBuffer.add(new StreamPacket(type, payloadLength, timeStamp, payload));
|
||||||
} else {
|
// } else {
|
||||||
System.err.println("Packet has been dropped");
|
// System.err.println("Packet has been dropped");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
moreBytes = false;
|
// moreBytes = false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readByte() throws Exception {
|
private int readByte() throws Exception {
|
||||||
int currentByte = -1;
|
int currentByte = -1;
|
||||||
try {
|
try {
|
||||||
currentByte = stream.read();
|
currentByte = inputStream.read();
|
||||||
crcBuffer.write(currentByte);
|
crcBuffer.write(currentByte);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public enum PacketType {
|
|||||||
MARK_ROUNDING,
|
MARK_ROUNDING,
|
||||||
COURSE_WIND,
|
COURSE_WIND,
|
||||||
AVG_WIND,
|
AVG_WIND,
|
||||||
|
BOAT_ACTION,
|
||||||
OTHER;
|
OTHER;
|
||||||
|
|
||||||
public static PacketType assignPacketType(int packetType){
|
public static PacketType assignPacketType(int packetType){
|
||||||
@@ -44,6 +45,8 @@ public enum PacketType {
|
|||||||
return COURSE_WIND;
|
return COURSE_WIND;
|
||||||
case 47:
|
case 47:
|
||||||
return AVG_WIND;
|
return AVG_WIND;
|
||||||
|
case 100:
|
||||||
|
return BOAT_ACTION;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return OTHER;
|
return OTHER;
|
||||||
|
|||||||
@@ -1,332 +0,0 @@
|
|||||||
package seng302.server;
|
|
||||||
|
|
||||||
import seng302.server.messages.*;
|
|
||||||
import seng302.server.simulator.Boat;
|
|
||||||
import seng302.server.simulator.Simulator;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class ServerThread implements Runnable, Observer {
|
|
||||||
private StreamingServerSocket server;
|
|
||||||
private long startTime;
|
|
||||||
private boolean raceStarted = false;
|
|
||||||
private Map<Integer,Boolean> boatsFinished = new HashMap<>();
|
|
||||||
private List<Boat> boats;
|
|
||||||
private Simulator raceSimulator;
|
|
||||||
private boolean sendingRaceFinishedLocationMessages = true;
|
|
||||||
|
|
||||||
private final int HEARTBEAT_PERIOD = 5000;
|
|
||||||
private final int RACE_STATUS_PERIOD = 1000/2;
|
|
||||||
private final int RACE_START_STATUS_PERIOD = 1000;
|
|
||||||
private final int BOAT_LOCATION_PERIOD = 1000/5;
|
|
||||||
private final int PORT_NUMBER = 4949;
|
|
||||||
private final int TIME_TILL_RACE_START = 20*1000;
|
|
||||||
private static final int LOG_LEVEL = 1;
|
|
||||||
|
|
||||||
public ServerThread(String threadName){
|
|
||||||
Thread runner = new Thread(this, threadName);
|
|
||||||
runner.setDaemon(true);
|
|
||||||
|
|
||||||
raceSimulator = new Simulator(BOAT_LOCATION_PERIOD);
|
|
||||||
raceSimulator.addObserver(this);
|
|
||||||
// run race simulator, so it can send boats' static location.
|
|
||||||
Thread raceSimulatorThread = new Thread(raceSimulator, "Race Simulator");
|
|
||||||
|
|
||||||
boats = raceSimulator.getBoats();
|
|
||||||
|
|
||||||
for (Boat b : boats){
|
|
||||||
boatsFinished.put(b.getSourceID(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
runner.start();
|
|
||||||
raceSimulatorThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void serverLog(String message, int logLevel){
|
|
||||||
if(logLevel <= LOG_LEVEL){
|
|
||||||
System.out.println("[SERVER] " + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and returns an XML Message from the file specified
|
|
||||||
* @param fileName The source XML file
|
|
||||||
* @param type The XML Message type
|
|
||||||
* @return The XML Message
|
|
||||||
*/
|
|
||||||
private Message getXmlMessage(String fileName, XMLMessageSubType type){
|
|
||||||
String fileContents = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream thisStream = this.getClass().getResourceAsStream(fileName);
|
|
||||||
fileContents = new String(org.apache.commons.io.IOUtils.toByteArray(thisStream));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NullPointerException e){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileContents != null){
|
|
||||||
return new XMLMessage(fileContents, type, server.getSequenceNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Get a race status message for the current race
|
|
||||||
*/
|
|
||||||
private Message getRaceStatusMessage(){
|
|
||||||
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
|
|
||||||
BoatStatus boatStatus;
|
|
||||||
RaceStatus raceStatus;
|
|
||||||
boolean thereAreBoatsNotFinished = false;
|
|
||||||
|
|
||||||
for (Boat b : boats){
|
|
||||||
if (!raceStarted){
|
|
||||||
boatStatus = BoatStatus.PRESTART;
|
|
||||||
thereAreBoatsNotFinished = true;
|
|
||||||
}
|
|
||||||
else if(boatsFinished.get(b.getSourceID())){
|
|
||||||
boatStatus = BoatStatus.FINISHED;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
boatStatus = BoatStatus.PRESTART;
|
|
||||||
thereAreBoatsNotFinished = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BoatSubMessage m = new BoatSubMessage(b.getSourceID(), boatStatus, b.getLastPassedCorner().getSeqID(), 0, 0, b.getEstimatedTimeTillFinish(), b.getEstimatedTimeTillFinish());
|
|
||||||
boatSubMessages.add(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thereAreBoatsNotFinished){
|
|
||||||
if (raceStarted){
|
|
||||||
raceStatus = RaceStatus.STARTED;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
long timeDifference = startTime - currentTime;
|
|
||||||
|
|
||||||
if (timeDifference > 60*3){
|
|
||||||
raceStatus = RaceStatus.PRESTART;
|
|
||||||
}
|
|
||||||
else if (timeDifference > 60){
|
|
||||||
raceStatus = RaceStatus.WARNING;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
raceStatus = RaceStatus.PREPARATORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
raceStatus = RaceStatus.TERMINATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RaceStatusMessage(1, raceStatus, startTime, WindDirection.SOUTH,
|
|
||||||
100, boats.size(), RaceType.MATCH_RACE, 1, boatSubMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts an instance of the race simulator
|
|
||||||
*/
|
|
||||||
private void startRaceSim(){
|
|
||||||
// set race started to true, so the simulator will start moving boats
|
|
||||||
raceSimulator.setRaceStarted(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts sending heartbeat messages to the client
|
|
||||||
*/
|
|
||||||
private void startSendingHeartbeats() {
|
|
||||||
Timer t = new Timer();
|
|
||||||
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Message heartbeat = new Heartbeat(server.getSequenceNumber());
|
|
||||||
|
|
||||||
try {
|
|
||||||
server.send(heartbeat);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0, HEARTBEAT_PERIOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start sending race start status messages until race starts
|
|
||||||
*/
|
|
||||||
private void startSendingRaceStartStatusMessages(){
|
|
||||||
Timer t = new Timer();
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Message raceStartStatusMessage = new RaceStartStatusMessage(server.getSequenceNumber(), startTime , 1,
|
|
||||||
RaceStartNotificationType.SET_RACE_START_TIME);
|
|
||||||
try {
|
|
||||||
if (startTime < System.currentTimeMillis() && !raceStarted){
|
|
||||||
startRaceSim();
|
|
||||||
raceStarted = true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
server.send(raceStartStatusMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0, RACE_START_STATUS_PERIOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start sending race start status messages until race starts
|
|
||||||
*/
|
|
||||||
private void startSendingRaceStatusMessages(){
|
|
||||||
Timer t = new Timer();
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Message raceStatusMessage = getRaceStatusMessage();
|
|
||||||
try {
|
|
||||||
server.send(raceStatusMessage);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0, RACE_STATUS_PERIOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the race, boat, and regatta XML files to the client
|
|
||||||
*/
|
|
||||||
private void sendXml(){
|
|
||||||
try{
|
|
||||||
Message raceData = getXmlMessage("/server_config/race.xml", XMLMessageSubType.RACE);
|
|
||||||
Message boatData = getXmlMessage("/server_config/boats.xml", XMLMessageSubType.BOAT);
|
|
||||||
Message regatta = getXmlMessage("/server_config/regatta.xml", XMLMessageSubType.REGATTA);
|
|
||||||
|
|
||||||
if (raceData != null){
|
|
||||||
server.send(raceData);
|
|
||||||
}
|
|
||||||
if (boatData != null){
|
|
||||||
server.send(boatData);
|
|
||||||
}
|
|
||||||
if (regatta != null){
|
|
||||||
server.send(regatta);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the post-start race course information
|
|
||||||
*/
|
|
||||||
private void sendPostStartCourseXml(){
|
|
||||||
Timer t = new Timer();
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Message raceData = getXmlMessage("/server_config/courseLimits.xml", XMLMessageSubType.RACE);
|
|
||||||
if (raceData != null) {
|
|
||||||
server.send(raceData);
|
|
||||||
}
|
|
||||||
}catch (IOException e) {
|
|
||||||
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},25000);
|
|
||||||
//Delays the new course xml data for 25 seconds so the boats are able to pass the starting line
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try{
|
|
||||||
server = new StreamingServerSocket(PORT_NUMBER);
|
|
||||||
}
|
|
||||||
catch (IOException e){
|
|
||||||
serverLog("Failed to bind socket: " + e.getMessage(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for client to connect
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
startTime = System.currentTimeMillis() + TIME_TILL_RACE_START;
|
|
||||||
|
|
||||||
startSendingHeartbeats();
|
|
||||||
sendXml();
|
|
||||||
startSendingRaceStartStatusMessages();
|
|
||||||
startSendingRaceStatusMessages();
|
|
||||||
sendPostStartCourseXml();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start sending static boat position updates when race has finished
|
|
||||||
*/
|
|
||||||
private void startSendingRaceFinishedBoatPositions(){
|
|
||||||
Timer t = new Timer();
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
for (Boat b : raceSimulator.getBoats()){
|
|
||||||
Message m = new BoatLocationMessage(b.getSourceID(), server.getSequenceNumber(), b.getLat(),
|
|
||||||
b.getLng(), b.getLastPassedCorner().getBearingToNextCorner(),
|
|
||||||
((long) 0));
|
|
||||||
|
|
||||||
server.send(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0, BOAT_LOCATION_PERIOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a boat location message when they are updated by the simulator
|
|
||||||
* @param o .
|
|
||||||
* @param arg .
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void update(Observable o, Object arg) {
|
|
||||||
// Only send if server started
|
|
||||||
// TODO: I don't understand why i need to check server is null or not ... confused - haoming 2/5/17
|
|
||||||
if(server == null || !server.isStarted()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numOfBoatsFinished = 0;
|
|
||||||
for (Boat boat : (List<Boat>) arg){
|
|
||||||
try {
|
|
||||||
if (boat.isFinished()) {
|
|
||||||
numOfBoatsFinished ++;
|
|
||||||
if (!boatsFinished.get(boat.getSourceID())) {
|
|
||||||
boatsFinished.put(boat.getSourceID(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message m = new BoatLocationMessage(boat.getSourceID(), 1, boat.getLat(),
|
|
||||||
boat.getLng(), boat.getLastPassedCorner().getBearingToNextCorner(),
|
|
||||||
((long) boat.getSpeed()));
|
|
||||||
server.send(m);
|
|
||||||
} catch (IOException e) {
|
|
||||||
serverLog("Couldn't send a boat status message", 3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (NullPointerException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numOfBoatsFinished == ((List<Boat>) arg).size()) {
|
|
||||||
startSendingRaceFinishedBoatPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package seng302.server;
|
|
||||||
|
|
||||||
import seng302.server.messages.Message;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.channels.ServerSocketChannel;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
class StreamingServerSocket {
|
|
||||||
private ServerSocketChannel socket;
|
|
||||||
private SocketChannel client;
|
|
||||||
private short seqNum;
|
|
||||||
private boolean isServerStarted;
|
|
||||||
|
|
||||||
StreamingServerSocket(int port) throws IOException{
|
|
||||||
socket = ServerSocketChannel.open();
|
|
||||||
socket.socket().bind(new InetSocketAddress("localhost", port));
|
|
||||||
//socket.setSoTimeout(10000);
|
|
||||||
seqNum = 0;
|
|
||||||
isServerStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start(){
|
|
||||||
try {
|
|
||||||
client = socket.accept();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.getMessage();
|
|
||||||
}
|
|
||||||
if (client.socket() == null){
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
isServerStarted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(Message message) throws IOException{
|
|
||||||
if (client == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.send(client);
|
|
||||||
|
|
||||||
seqNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSequenceNumber(){
|
|
||||||
return seqNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStarted(){
|
|
||||||
return isServerStarted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kre39 on 12/07/17.
|
||||||
|
*/
|
||||||
|
public class BoatActionMessage extends Message{
|
||||||
|
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
|
||||||
|
private final int MESSAGE_SIZE = 1;
|
||||||
|
private BoatActionType actionType;
|
||||||
|
|
||||||
|
public BoatActionMessage(BoatActionType actionType) {
|
||||||
|
this.actionType = actionType;
|
||||||
|
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
|
||||||
|
allocateBuffer();
|
||||||
|
writeHeaderToBuffer();
|
||||||
|
// Write message fields
|
||||||
|
putInt(actionType.getValue(), 1);
|
||||||
|
writeCRC();
|
||||||
|
rewind();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kre39 on 12/07/17.
|
||||||
|
*/
|
||||||
|
public enum BoatActionType {
|
||||||
|
|
||||||
|
VMG(1),
|
||||||
|
SAILS_IN(2),
|
||||||
|
SAILS_OUT(3),
|
||||||
|
TACK_GYBE(4),
|
||||||
|
UPWIND(5),
|
||||||
|
DOWNWIND(6);
|
||||||
|
|
||||||
|
private final int type;
|
||||||
|
private static final Map<Integer, BoatActionType> intToTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (BoatActionType type : BoatActionType.values()) {
|
||||||
|
intToTypeMap.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoatActionType(int type){
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoatActionType getType(int value) {
|
||||||
|
return intToTypeMap.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class BoatLocationMessage extends Message {
|
public class BoatLocationMessage extends Message {
|
||||||
private final int MESSAGE_SIZE = 56;
|
private final int MESSAGE_SIZE = 56;
|
||||||
@@ -64,6 +64,36 @@ public class BoatLocationMessage extends Message {
|
|||||||
this.rudderAngle = 0;
|
this.rudderAngle = 0;
|
||||||
|
|
||||||
setHeader(new Header(MessageType.BOAT_LOCATION, 1, (short) getSize()));
|
setHeader(new Header(MessageType.BOAT_LOCATION, 1, (short) getSize()));
|
||||||
|
allocateBuffer();
|
||||||
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
|
long headingToSend = (long)((heading/360.0) * 65535.0);
|
||||||
|
|
||||||
|
putByte((byte) messageVersionNumber);
|
||||||
|
putInt(time, 6);
|
||||||
|
putInt((int) sourceId, 4);
|
||||||
|
putUnsignedInt((int) sequenceNum, 4);
|
||||||
|
putByte((byte) deviceType.getCode());
|
||||||
|
putInt((int) latLonToBinaryPackedLong(latitude), 4);
|
||||||
|
putInt((int) latLonToBinaryPackedLong(longitude), 4);
|
||||||
|
putInt((int) altitude, 4);
|
||||||
|
putInt(headingToSend, 2);
|
||||||
|
putInt((int) pitch, 2);
|
||||||
|
putInt((int) roll, 2);
|
||||||
|
putInt((int) boatSpeed, 2);
|
||||||
|
putUnsignedInt((int) COG, 2);
|
||||||
|
putUnsignedInt((int) SOG, 2);
|
||||||
|
putUnsignedInt((int) apparentWindSpeed, 2);
|
||||||
|
putInt((int) apparentWindAngle, 2);
|
||||||
|
putUnsignedInt((int) trueWindSpeed, 2);
|
||||||
|
putUnsignedInt((int) trueWindDirection, 2);
|
||||||
|
putInt((int) trueWindAngle, 2);
|
||||||
|
putUnsignedInt((int) currentDrift, 2);
|
||||||
|
putUnsignedInt((int) currentSet, 2);
|
||||||
|
putInt((int) rudderAngle, 2);
|
||||||
|
|
||||||
|
writeCRC();
|
||||||
|
rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,41 +154,4 @@ public class BoatLocationMessage extends Message {
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
return MESSAGE_SIZE;
|
return MESSAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(SocketChannel outputStream) throws IOException{
|
|
||||||
allocateBuffer();
|
|
||||||
writeHeaderToBuffer();
|
|
||||||
|
|
||||||
long headingToSend = (long)((heading/360.0) * 65535.0);
|
|
||||||
|
|
||||||
putByte((byte) messageVersionNumber);
|
|
||||||
putInt(time, 6);
|
|
||||||
putInt((int) sourceId, 4);
|
|
||||||
putUnsignedInt((int) sequenceNum, 4);
|
|
||||||
putByte((byte) deviceType.getCode());
|
|
||||||
putInt((int) latLonToBinaryPackedLong(latitude), 4);
|
|
||||||
putInt((int) latLonToBinaryPackedLong(longitude), 4);
|
|
||||||
putInt((int) altitude, 4);
|
|
||||||
putInt(headingToSend, 2);
|
|
||||||
putInt((int) pitch, 2);
|
|
||||||
putInt((int) roll, 2);
|
|
||||||
putInt((int) boatSpeed, 2);
|
|
||||||
putUnsignedInt((int) COG, 2);
|
|
||||||
putUnsignedInt((int) SOG, 2);
|
|
||||||
putUnsignedInt((int) apparentWindSpeed, 2);
|
|
||||||
putInt((int) apparentWindAngle, 2);
|
|
||||||
putUnsignedInt((int) trueWindSpeed, 2);
|
|
||||||
putUnsignedInt((int) trueWindDirection, 2);
|
|
||||||
putInt((int) trueWindAngle, 2);
|
|
||||||
putUnsignedInt((int) currentDrift, 2);
|
|
||||||
putUnsignedInt((int) currentSet, 2);
|
|
||||||
putInt((int) rudderAngle, 2);
|
|
||||||
|
|
||||||
writeCRC();
|
|
||||||
rewind();
|
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kre39 on 20/07/17.
|
||||||
|
*/
|
||||||
|
public class ChatterMessage extends Message {
|
||||||
|
|
||||||
|
private final long MESSAGE_VERSION_NUMBER = 1;
|
||||||
|
private final int MESSAGE_SIZE = 3;
|
||||||
|
private int message_type;
|
||||||
|
private int message_size = 21;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ChatterMessage(int message_type, int message_size, String message) {
|
||||||
|
this.message_type = message_type;
|
||||||
|
this.message_size = message_size;
|
||||||
|
this.message = message;
|
||||||
|
|
||||||
|
setHeader(new Header(MessageType.CHATTER_TEXT, 1, (short) getSize()));
|
||||||
|
allocateBuffer();
|
||||||
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
|
putByte((byte) MESSAGE_VERSION_NUMBER);
|
||||||
|
putInt(message_type, 1);
|
||||||
|
putInt(message_size, 1);
|
||||||
|
putBytes(message.getBytes());
|
||||||
|
|
||||||
|
writeCRC();
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE + message_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -43,10 +43,21 @@ public class Header {
|
|||||||
buff.position(buffPos);
|
buff.position(buffPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the buffer
|
||||||
|
*/
|
||||||
|
public void reset(){
|
||||||
|
buffPos = 0;
|
||||||
|
buff.clear();
|
||||||
|
buff.position(buffPos);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a ByteBuffer containing the message header
|
* @return a ByteBuffer containing the message header
|
||||||
*/
|
*/
|
||||||
public ByteBuffer getByteBuffer(){
|
public ByteBuffer getByteBuffer(){
|
||||||
|
reset();
|
||||||
|
|
||||||
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte1).array(), syncByte1);
|
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte1).array(), syncByte1);
|
||||||
|
|
||||||
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte2).array(), syncByte2);
|
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte2).array(), syncByte2);
|
||||||
|
|||||||
@@ -1,32 +1,16 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.io.OutputStream;
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
|
|
||||||
public class Heartbeat extends Message {
|
public class Heartbeat extends Message {
|
||||||
private final int MESSAGE_SIZE = 4;
|
private final int MESSAGE_SIZE = 4;
|
||||||
private int seqNo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Heartbeat from the AC35 Streaming data spec
|
* Heartbeat from the AC35 Streaming data spec
|
||||||
* @param seqNo Increment every time a message is sent
|
* @param seqNo Increment every time a message is sent
|
||||||
*/
|
*/
|
||||||
public Heartbeat(int seqNo){
|
public Heartbeat(int seqNo){
|
||||||
this.seqNo = seqNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return MESSAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(SocketChannel outputStream) throws IOException {
|
|
||||||
setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize()));
|
setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize()));
|
||||||
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
@@ -36,7 +20,11 @@ public class Heartbeat extends Message {
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.Channels;
|
import java.io.OutputStream;
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
|
|
||||||
public class MarkRoundingMessage extends Message{
|
public class MarkRoundingMessage extends Message{
|
||||||
private final long MESSAGE_VERSION_NUMBER = 1;
|
private final long MESSAGE_VERSION_NUMBER = 1;
|
||||||
@@ -33,15 +30,6 @@ public class MarkRoundingMessage extends Message{
|
|||||||
this.markId = markId;
|
this.markId = markId;
|
||||||
|
|
||||||
setHeader(new Header(MessageType.MARK_ROUNDING, 1, (short) getSize()));
|
setHeader(new Header(MessageType.MARK_ROUNDING, 1, (short) getSize()));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return MESSAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(SocketChannel outputStream) throws IOException {
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -56,7 +44,10 @@ public class MarkRoundingMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
@@ -33,11 +33,6 @@ public abstract class Message {
|
|||||||
*/
|
*/
|
||||||
public abstract int getSize();
|
public abstract int getSize();
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the message as through the outputStream
|
|
||||||
*/
|
|
||||||
public abstract void send(SocketChannel outputStream) throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate byte buffer to correct size
|
* Allocate byte buffer to correct size
|
||||||
*/
|
*/
|
||||||
@@ -45,6 +40,7 @@ public abstract class Message {
|
|||||||
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
|
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
bufferPosition = 0;
|
bufferPosition = 0;
|
||||||
|
buffer.position(bufferPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,10 +157,10 @@ public abstract class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The current buffer
|
* @return The current buffer as a byte array
|
||||||
*/
|
*/
|
||||||
public ByteBuffer getBuffer(){
|
public byte[] getBuffer(){
|
||||||
return buffer;
|
return buffer.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,6 +189,25 @@ public abstract class Message {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* takes an array of up to 7 bytes in little endian format and
|
||||||
|
* returns a positive long constructed from the input bytes
|
||||||
|
*
|
||||||
|
* @return a positive long if there is less than 8 bytes -1 otherwise
|
||||||
|
*/
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverse an array of bytes
|
* Reverse an array of bytes
|
||||||
* @param data The byte[] to reverse
|
* @param data The byte[] to reverse
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public enum MessageType {
|
|||||||
BOAT_LOCATION(37),
|
BOAT_LOCATION(37),
|
||||||
MARK_ROUNDING(38),
|
MARK_ROUNDING(38),
|
||||||
COURSE_WIND(44),
|
COURSE_WIND(44),
|
||||||
AVERAGE_WIND(47);
|
AVERAGE_WIND(47),
|
||||||
|
BOAT_ACTION(100);
|
||||||
|
|
||||||
private int code;
|
private int code;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.Channels;
|
import java.io.OutputStream;
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
|
|
||||||
public class RaceStartStatusMessage extends Message {
|
public class RaceStartStatusMessage extends Message {
|
||||||
private final int MESSAGE_SIZE = 20;
|
private final int MESSAGE_SIZE = 20;
|
||||||
@@ -32,15 +29,6 @@ public class RaceStartStatusMessage extends Message {
|
|||||||
this.raceId = raceId;
|
this.raceId = raceId;
|
||||||
|
|
||||||
setHeader(new Header(MessageType.RACE_START_STATUS, 1, (short) getSize()));
|
setHeader(new Header(MessageType.RACE_START_STATUS, 1, (short) getSize()));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return MESSAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(SocketChannel outputStream) throws IOException {
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -53,7 +41,11 @@ public class RaceStartStatusMessage extends Message {
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
@@ -47,22 +47,6 @@ public class RaceStatusMessage extends Message{
|
|||||||
crc = new CRC32();
|
crc = new CRC32();
|
||||||
|
|
||||||
setHeader(new Header(MESSAGE_TYPE, (int) sourceId, (short) getSize()));
|
setHeader(new Header(MESSAGE_TYPE, (int) sourceId, (short) getSize()));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the size of this message in bytes
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
return MESSAGE_BASE_SIZE + (20 * ((int) numBoatsInRace));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send this message as a stream of bytes
|
|
||||||
* @param outputStream The output stream to send the message
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void send(SocketChannel outputStream) throws IOException {
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -82,7 +66,14 @@ public class RaceStatusMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size of this message in bytes
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_BASE_SIZE + (20 * ((int) numBoatsInRace));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.io.OutputStream;
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.channels.WritableByteChannel;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
|
|
||||||
public class XMLMessage extends Message{
|
public class XMLMessage extends Message{
|
||||||
private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE;
|
private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE;
|
||||||
@@ -35,20 +30,6 @@ public class XMLMessage extends Message{
|
|||||||
sequence = sequenceNum;
|
sequence = sequenceNum;
|
||||||
|
|
||||||
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The length of this message
|
|
||||||
*/
|
|
||||||
public int getSize(){
|
|
||||||
return MESSAGE_SIZE + content.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send this message as a stream of bytes
|
|
||||||
* @param outputStream The output stream to send the message
|
|
||||||
*/
|
|
||||||
public void send(SocketChannel outputStream) throws IOException {
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -63,7 +44,12 @@ public class XMLMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
outputStream.write(getBuffer());
|
/**
|
||||||
|
* @return The length of this message
|
||||||
|
*/
|
||||||
|
public int getSize(){
|
||||||
|
return MESSAGE_SIZE + content.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
|
||||||
public class GeoUtility {
|
public class GeoUtility {
|
||||||
|
|
||||||
private static double EARTH_RADIUS = 6378.137;
|
private static double EARTH_RADIUS = 6378.137;
|
||||||
@@ -77,4 +79,55 @@ public class GeoUtility {
|
|||||||
|
|
||||||
return new GeoPoint(Math.toDegrees(endLat), Math.toDegrees(endLng));
|
return new GeoPoint(Math.toDegrees(endLat), Math.toDegrees(endLng));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the line function on two points of a line and a test point to test which side of the line that point is
|
||||||
|
* on. If the return value is
|
||||||
|
* return 1, then the point is on one side of the line,
|
||||||
|
* return -1 then the point is on the other side of the line
|
||||||
|
* return 0 then the point is exactly on the line.
|
||||||
|
* @param linePoint1 One point of the line
|
||||||
|
* @param linePoint2 Second point of the line
|
||||||
|
* @param testPoint The point to test with this line
|
||||||
|
* @return A return value indicating which side of the line the point is on
|
||||||
|
*/
|
||||||
|
public static Integer lineFunction(Point2D linePoint1, Point2D linePoint2, Point2D testPoint) {
|
||||||
|
|
||||||
|
Double x = testPoint.getX();
|
||||||
|
Double y = testPoint.getY();
|
||||||
|
Double x1 = linePoint1.getX();
|
||||||
|
Double y1 = linePoint1.getY();
|
||||||
|
Double x2 = linePoint2.getX();
|
||||||
|
Double y2 = linePoint2.getY();
|
||||||
|
|
||||||
|
Double result = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1); //Line function
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (result < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a point and a vector (angle and vector length) Will create a new point, that vector away from the origin
|
||||||
|
* point
|
||||||
|
* @param originPoint The point with which to use as the base for our vector addition
|
||||||
|
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
|
||||||
|
* @param vectorLength The length out on this angle from the origin point to create the new point
|
||||||
|
* @return a Point2D
|
||||||
|
*/
|
||||||
|
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg, Double vectorLength) {
|
||||||
|
|
||||||
|
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
|
||||||
|
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
|
||||||
|
|
||||||
|
return new Point2D(endPointX, endPointY);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
package seng302.utilities;
|
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Class for performing geometric calculations on the canvas
|
|
||||||
* Created by wmu16 on 24/05/17.
|
|
||||||
*/
|
|
||||||
public final class GeometryUtils {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the line function on two points of a line and a test point to test which side of the line that point is
|
|
||||||
* on. If the return value is
|
|
||||||
* return 1, then the point is on one side of the line,
|
|
||||||
* return -1 then the point is on the other side of the line
|
|
||||||
* return 0 then the point is exactly on the line.
|
|
||||||
* @param linePoint1 One point of the line
|
|
||||||
* @param linePoint2 Second point of the line
|
|
||||||
* @param testPoint The point to test with this line
|
|
||||||
* @return A return value indicating which side of the line the point is on
|
|
||||||
*/
|
|
||||||
public static Integer lineFunction(Point2D linePoint1, Point2D linePoint2, Point2D testPoint) {
|
|
||||||
|
|
||||||
Double x = testPoint.getX();
|
|
||||||
Double y = testPoint.getY();
|
|
||||||
Double x1 = linePoint1.getX();
|
|
||||||
Double y1 = linePoint1.getY();
|
|
||||||
Double x2 = linePoint2.getX();
|
|
||||||
Double y2 = linePoint2.getY();
|
|
||||||
|
|
||||||
Double result = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1); //Line function
|
|
||||||
|
|
||||||
if (result > 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (result < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a point and a vector (angle and vector length) Will create a new point, that vector away from the origin
|
|
||||||
* point
|
|
||||||
* @param originPoint The point with which to use as the base for our vector addition
|
|
||||||
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
|
|
||||||
* @param vectorLength The length out on this angle from the origin point to create the new point
|
|
||||||
* @return a Point2D
|
|
||||||
*/
|
|
||||||
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg, Double vectorLength) {
|
|
||||||
|
|
||||||
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
|
|
||||||
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
|
|
||||||
|
|
||||||
return new Point2D(endPointX, endPointY);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -168,7 +168,7 @@ Remove scroll bars
|
|||||||
|
|
||||||
.ui-table *.scroll-bar:vertical *.increment-arrow,
|
.ui-table *.scroll-bar:vertical *.increment-arrow,
|
||||||
.ui-table *.scroll-bar:vertical *.decrement-arrow {
|
.ui-table *.scroll-bar:vertical *.decrement-arrow {
|
||||||
-fx-background-color: null;
|
-fx-background-color: #0e6d6c;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
@@ -177,7 +177,7 @@ Remove scroll bars
|
|||||||
|
|
||||||
.ui-table *.scroll-bar:vertical *.increment-button,
|
.ui-table *.scroll-bar:vertical *.increment-button,
|
||||||
.ui-table *.scroll-bar:vertical *.decrement-button {
|
.ui-table *.scroll-bar:vertical *.decrement-button {
|
||||||
-fx-background-color: null;
|
-fx-background-color: #0e6d6c;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
|
<GridPane fx:id="lobbyScreen" nodeOrientation="LEFT_TO_RIGHT" prefHeight="533.0" prefWidth="802.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.LobbyController">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="171.0" minHeight="0.0" prefHeight="31.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="399.0" minHeight="10.0" prefHeight="394.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="63.0" minHeight="10.0" prefHeight="26.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Text fx:id="lobbyIpText" fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="Lobby: IP" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="29.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
<GridPane GridPane.rowIndex="2">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Button focusTraversable="false" mnemonicParsing="false" onAction="#readyButtonPressed" prefWidth="101.0" text="Ready" GridPane.halignment="CENTER" />
|
||||||
|
<Button focusTraversable="false" mnemonicParsing="false" onAction="#leaveLobbyButtonPressed" text="Leave Lobby" GridPane.columnIndex="1" GridPane.halignment="CENTER" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
<AnchorPane focusTraversable="true" prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<GridPane layoutX="335.0" layoutY="146.0" prefHeight="399.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="261.0" minWidth="0.0" prefWidth="2.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="261.0" minWidth="0.0" prefWidth="2.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="125.0" minHeight="0.0" prefHeight="0.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="266.0" minHeight="10.0" prefHeight="266.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<ListView fx:id="competitorsListView" layoutX="154.0" layoutY="59.0" prefHeight="266.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children></AnchorPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
@@ -7,4 +7,5 @@
|
|||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
<AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller" />
|
|
||||||
|
<AnchorPane fx:id="contentPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onKeyPressed="#keyPressed" onKeyReleased="#keyReleased" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.Controller" />
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<Font name="System Bold" size="13.0" />
|
<Font name="System Bold" size="13.0" />
|
||||||
</font>
|
</font>
|
||||||
</Text>
|
</Text>
|
||||||
<CheckBox fx:id="toggleFps" graphicTextGap="0.0" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" styleClass="ui-checkbox" text="Show FPS" textFill="WHITE" />
|
<CheckBox fx:id="toggleFps" focusTraversable="false" graphicTextGap="0.0" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" styleClass="ui-checkbox" text="Show FPS" textFill="WHITE" />
|
||||||
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" styleClass="text-white" />
|
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" styleClass="text-white" />
|
||||||
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
|
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
|
||||||
<children>
|
<children>
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
</Pane>
|
</Pane>
|
||||||
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="2.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" styleClass="ui-slider" />
|
<Slider fx:id="annotationSlider" blockIncrement="1.0" layoutX="38.0" layoutY="527.0" majorTickUnit="1.0" max="2.0" minorTickCount="0" prefHeight="51.0" prefWidth="170.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" styleClass="ui-slider" />
|
||||||
<Label layoutX="10.0" layoutY="499.0" text="Annotations" textFill="WHITE" />
|
<Label layoutX="10.0" layoutY="499.0" text="Annotations" textFill="WHITE" />
|
||||||
<Button fx:id="selectAnnotationBtn" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
<Button fx:id="selectAnnotationBtn" focusTraversable="false" layoutX="35.0" layoutY="578.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="170.0" styleClass="blue-ui-btn" text="Select Annotations" textFill="WHITE" />
|
||||||
<Text fill="WHITE" layoutX="11.0" layoutY="649.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Boat Selection" />
|
<Text fill="WHITE" layoutX="11.0" layoutY="649.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Boat Selection" />
|
||||||
<ComboBox fx:id="boatSelectionComboBox" layoutX="37.0" layoutY="664.0" prefHeight="25.0" prefWidth="170.0" promptText="Select Boat" styleClass="combo-box-base" />
|
<ComboBox fx:id="boatSelectionComboBox" focusTraversable="false" layoutX="37.0" layoutY="664.0" prefHeight="25.0" prefWidth="170.0" promptText="Select Boat" styleClass="combo-box-base" />
|
||||||
<LineChart fx:id="raceSparkLine" layoutX="-1.0" layoutY="719.0" legendVisible="false" prefHeight="277.0" prefWidth="246.0" title="Boat Positions">
|
<LineChart fx:id="raceSparkLine" layoutX="-1.0" layoutY="719.0" legendVisible="false" prefHeight="277.0" prefWidth="246.0" title="Boat Positions">
|
||||||
<xAxis>
|
<xAxis>
|
||||||
<CategoryAxis label="Leg Number" side="BOTTOM" styleClass="spark-line-xaxis" />
|
<CategoryAxis label="Leg Number" side="BOTTOM" styleClass="spark-line-xaxis" />
|
||||||
|
|||||||
@@ -1,60 +1,48 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import javafx.geometry.*?>
|
<?import javafx.geometry.*?>
|
||||||
<?import javafx.scene.control.*?>
|
|
||||||
<?import javafx.scene.text.*?>
|
|
||||||
<?import javafx.scene.canvas.*?>
|
|
||||||
<?import java.lang.*?>
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<GridPane fx:id="gridPane" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.StartScreenController">
|
<GridPane fx:id="startScreen2" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.controllers.StartScreenController">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints percentHeight="10.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="52.0" minHeight="52.0" prefHeight="52.0" vgrow="SOMETIMES" />
|
<RowConstraints vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="0.0" percentHeight="8.0" prefHeight="0.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="72.0" prefHeight="72.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="28.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="65.0" minHeight="36.0" prefHeight="46.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="55.0" minHeight="55.0" percentHeight="9.0" prefHeight="55.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="108.0" minHeight="72.0" prefHeight="98.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="0.0" minHeight="0.0" percentHeight="29.0" prefHeight="0.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="72.0" prefHeight="72.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="93.0" minHeight="72.0" prefHeight="72.0" vgrow="SOMETIMES" />
|
|
||||||
<RowConstraints maxHeight="283.0" minHeight="262.0" prefHeight="283.0" vgrow="SOMETIMES" />
|
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Label alignment="CENTER" text="Welcome to Race Vision" textFill="WHITE" GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
|
<Label alignment="CENTER" text="Welcome to Race Vision" textFill="WHITE" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
|
||||||
<font>
|
<font>
|
||||||
<Font size="40.0" />
|
<Font size="40.0" />
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</Label>
|
||||||
<Label text="Your live AC35 livestream" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1">
|
<Button mnemonicParsing="false" onAction="#hostButtonPressed" prefHeight="25.0" prefWidth="175.0" text="Host" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
|
||||||
<font>
|
<Button mnemonicParsing="false" onAction="#connectButtonPressed" prefHeight="25.0" prefWidth="147.0" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||||
<Font size="20.0" />
|
<TextField fx:id="ipTextField" maxWidth="-Infinity" prefHeight="25.0" prefWidth="200.0" text="localhost" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
|
||||||
</font>
|
|
||||||
</Label>
|
|
||||||
<Label text="Livestream Status:" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
|
|
||||||
<font>
|
|
||||||
<Font size="28.0" />
|
|
||||||
</font>
|
|
||||||
</Label>
|
|
||||||
<Label fx:id="timeTillLive" text="0:00 minutes" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="4">
|
|
||||||
<font>
|
|
||||||
<Font size="27.0" />
|
|
||||||
</font>
|
|
||||||
</Label>
|
|
||||||
<Button fx:id="streamButton" mnemonicParsing="false" onAction="#startStream" styleClass="blue-ui-btn" text="Click to stream" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
|
|
||||||
<Button fx:id="switchToRaceViewButton" disable="true" mnemonicParsing="false" onAction="#switchToRaceView" styleClass="blue-ui-btn" text="Watch Race" GridPane.halignment="CENTER" GridPane.rowIndex="7" GridPane.valignment="TOP" />
|
|
||||||
<TableView fx:id="teamList" maxWidth="661.0" prefHeight="324.0" prefWidth="629.0" styleClass="ui-table" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="5" GridPane.vgrow="NEVER">
|
|
||||||
<columns>
|
|
||||||
<TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" />
|
|
||||||
<TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" />
|
|
||||||
<TableColumn fx:id="shortNameCol" editable="false" maxWidth="155.18472290039062" minWidth="107.0" prefWidth="155.18472290039062" resizable="false" sortable="false" text="Short Name" />
|
|
||||||
<TableColumn fx:id="countryCol" editable="false" maxWidth="258.9999694824219" minWidth="147.0" prefWidth="258.9999694824219" resizable="false" sortable="false" text="Country" />
|
|
||||||
</columns>
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets top="10.0" />
|
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</TableView>
|
</TextField>
|
||||||
<Label fx:id="realTime" text="Local time" textFill="WHITE" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="BOTTOM" />
|
<Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="OR" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="3">
|
||||||
|
<font>
|
||||||
|
<Font size="21.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package seng302;
|
|||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.utilities.GeometryUtils;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@@ -35,9 +35,9 @@ public class TestGeoUtils {
|
|||||||
@Test
|
@Test
|
||||||
public void testLineFunction() {
|
public void testLineFunction() {
|
||||||
|
|
||||||
Integer lineFunctionResult1 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint1);
|
Integer lineFunctionResult1 = GeoUtility.lineFunction(linePoint1, linePoint2, arbitraryPoint1);
|
||||||
Integer lineFunctionResult2 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint2);
|
Integer lineFunctionResult2 = GeoUtility.lineFunction(linePoint1, linePoint2, arbitraryPoint2);
|
||||||
Integer lineFunctionResult3 = GeometryUtils.lineFunction(linePoint1, linePoint2, arbitraryPoint3);
|
Integer lineFunctionResult3 = GeoUtility.lineFunction(linePoint1, linePoint2, arbitraryPoint3);
|
||||||
|
|
||||||
//Point1 and Point2 are on opposite sides
|
//Point1 and Point2 are on opposite sides
|
||||||
assertEquals(Math.abs(lineFunctionResult1), Math.abs(lineFunctionResult2));
|
assertEquals(Math.abs(lineFunctionResult1), Math.abs(lineFunctionResult2));
|
||||||
@@ -51,13 +51,13 @@ public class TestGeoUtils {
|
|||||||
public void testMakeArbitraryVectorPoint() {
|
public void testMakeArbitraryVectorPoint() {
|
||||||
|
|
||||||
//Make a point (1,0) from point (0,0)
|
//Make a point (1,0) from point (0,0)
|
||||||
Point2D newPoint = GeometryUtils.makeArbitraryVectorPoint(linePoint1, 0d, 1d);
|
Point2D newPoint = GeoUtility.makeArbitraryVectorPoint(linePoint1, 0d, 1d);
|
||||||
Point2D expected = new Point2D(1,0);
|
Point2D expected = new Point2D(1,0);
|
||||||
|
|
||||||
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
|
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
|
||||||
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
|
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
|
||||||
|
|
||||||
newPoint = GeometryUtils.makeArbitraryVectorPoint(linePoint1, 90d, 1d);
|
newPoint = GeoUtility.makeArbitraryVectorPoint(linePoint1, 90d, 1d);
|
||||||
expected = new Point2D(0, 1);
|
expected = new Point2D(0, 1);
|
||||||
|
|
||||||
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
|
assertEquals(expected.getX(), newPoint.getX(), 1E-6);
|
||||||
|
|||||||
@@ -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<Yacht> yachts = new ArrayList<Yacht>();
|
||||||
|
|
||||||
|
@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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -61,16 +61,16 @@ public class StreamReceiverTest {
|
|||||||
assert pq.size() == 0;
|
assert pq.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
public void connectReadsAPacket() throws Exception {
|
// public void connectReadsAPacket() throws Exception {
|
||||||
Socket host=mock(Socket.class);
|
// Socket host=mock(Socket.class);
|
||||||
InputStream stream = new ByteArrayInputStream(workingPacket);
|
// InputStream stream = new ByteArrayInputStream(workingPacket);
|
||||||
when(host.getInputStream()).thenReturn(stream);
|
// when(host.getInputStream()).thenReturn(stream);
|
||||||
StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
// StreamReceiver streamReceiver = new StreamReceiver(host, pq);
|
||||||
|
//
|
||||||
streamReceiver.connect();
|
// streamReceiver.connect();
|
||||||
assert pq.size() == 1;
|
// assert pq.size() == 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void connectDropsAMismatchedCrc() throws Exception {
|
public void connectDropsAMismatchedCrc() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user