Merge remote-tracking branch 'remotes/origin/master' into minimap_test
This commit is contained in:
@@ -78,6 +78,18 @@
|
|||||||
<version>0.7</version>
|
<version>0.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20160810</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public class Event {
|
|||||||
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
* @throws EventConstructionException Thrown if we cannot create an Event for any reason.
|
||||||
*/
|
*/
|
||||||
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
public Event(boolean singlePlayer, int mapIndex) throws EventConstructionException {
|
||||||
|
PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
|
||||||
this.mapIndex = mapIndex;
|
this.mapIndex = mapIndex;
|
||||||
String raceXMLFile;
|
String raceXMLFile;
|
||||||
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
String boatsXMLFile = "mock/mockXML/boatTest.xml";
|
||||||
@@ -109,6 +110,7 @@ public class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double windAngle = 300;
|
double windAngle = 300;
|
||||||
|
double windSpeed = 12;
|
||||||
|
|
||||||
//Read XML files.
|
//Read XML files.
|
||||||
try {
|
try {
|
||||||
@@ -119,6 +121,7 @@ public class Event {
|
|||||||
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, -1, true);
|
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, -1, true);
|
||||||
} else {
|
} else {
|
||||||
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle, false);
|
this.raceXML = RaceXMLCreator.alterRaceToWind(this.raceXML, XMLFileType.Contents, windAngle, false);
|
||||||
|
this.raceXML = RaceXMLCreator.scaleRaceSize(raceXML, windSpeed, 15 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);
|
this.boatXML = XMLReader.readXMLFileToString(boatsXMLFile, StandardCharsets.UTF_8);
|
||||||
@@ -131,7 +134,6 @@ public class Event {
|
|||||||
this.xmlFileType = XMLFileType.Contents;
|
this.xmlFileType = XMLFileType.Contents;
|
||||||
|
|
||||||
this.boatPolars = PolarParser.parse("mock/polars/acc_polars.csv");
|
this.boatPolars = PolarParser.parse("mock/polars/acc_polars.csv");
|
||||||
PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
|
|
||||||
|
|
||||||
|
|
||||||
//Parse the XML files into data sources.
|
//Parse the XML files into data sources.
|
||||||
@@ -152,7 +154,7 @@ public class Event {
|
|||||||
|
|
||||||
WindGenerator windGenerator = new ShiftingWindGenerator(
|
WindGenerator windGenerator = new ShiftingWindGenerator(
|
||||||
Bearing.fromDegrees(windAngle),
|
Bearing.fromDegrees(windAngle),
|
||||||
12
|
windSpeed
|
||||||
);
|
);
|
||||||
|
|
||||||
MockRace mockRace = new MockRace(
|
MockRace mockRace = new MockRace(
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.util.logging.Logger;
|
|||||||
public class RaceServer {
|
public class RaceServer {
|
||||||
private MockRace race;
|
private MockRace race;
|
||||||
private LatestMessages latestMessages;
|
private LatestMessages latestMessages;
|
||||||
private static RaceServer server;
|
|
||||||
private List<YachtEvent> collisionEvents = new ArrayList<>();
|
private List<YachtEvent> collisionEvents = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
@@ -50,16 +49,10 @@ public class RaceServer {
|
|||||||
|
|
||||||
|
|
||||||
public RaceServer(MockRace race, LatestMessages latestMessages) {
|
public RaceServer(MockRace race, LatestMessages latestMessages) {
|
||||||
server = this;
|
|
||||||
this.race = race;
|
this.race = race;
|
||||||
this.latestMessages = latestMessages;
|
this.latestMessages = latestMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void staticUpdateXML() {
|
|
||||||
if (server != null) {
|
|
||||||
server.updateXMLFiles();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the race to create a snapshot, and places it in latestMessages.
|
* Parses the race to create a snapshot, and places it in latestMessages.
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package mock.xml;
|
package mock.xml;
|
||||||
|
|
||||||
|
import mock.model.NewPolars;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import shared.dataInput.RaceXMLReader;
|
import shared.dataInput.RaceXMLReader;
|
||||||
import shared.enums.XMLFileType;
|
import shared.enums.XMLFileType;
|
||||||
import shared.exceptions.InvalidRaceDataException;
|
import shared.exceptions.InvalidRaceDataException;
|
||||||
import shared.exceptions.XMLReaderException;
|
import shared.exceptions.XMLReaderException;
|
||||||
|
import shared.model.Bearing;
|
||||||
import shared.model.CompoundMark;
|
import shared.model.CompoundMark;
|
||||||
import shared.model.Constants;
|
import shared.model.Constants;
|
||||||
import shared.model.GPSCoordinate;
|
import shared.model.GPSCoordinate;
|
||||||
import shared.xml.Race.XMLCompoundMark;
|
import shared.xml.Race.*;
|
||||||
import shared.xml.Race.XMLLimit;
|
|
||||||
import shared.xml.Race.XMLMark;
|
|
||||||
import shared.xml.Race.XMLRace;
|
|
||||||
import shared.xml.XMLUtilities;
|
import shared.xml.XMLUtilities;
|
||||||
|
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
@@ -20,6 +19,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper Class for creating a Race XML
|
* Helper Class for creating a Race XML
|
||||||
@@ -125,6 +126,140 @@ public class RaceXMLCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates the race in a specified direction.
|
||||||
|
* @param s xml file name or contents.
|
||||||
|
* @param windSpeed speed that the wind is at.
|
||||||
|
* @param milliseconds time the race should take at fastest
|
||||||
|
* @return the new xml file as a string
|
||||||
|
* @throws XMLReaderException if the xml is not readable
|
||||||
|
* @throws InvalidRaceDataException if the race is invalid
|
||||||
|
*/
|
||||||
|
public static String scaleRaceSize(String s, double windSpeed, double milliseconds) throws XMLReaderException, InvalidRaceDataException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
XMLRace race = XMLUtilities.xmlToClass(
|
||||||
|
s,
|
||||||
|
RaceXMLCreator.class.getClassLoader().getResource("mock/mockXML/schema/raceSchema.xsd"),
|
||||||
|
XMLRace.class);
|
||||||
|
|
||||||
|
scaleRace(race, windSpeed, milliseconds);
|
||||||
|
|
||||||
|
return XMLUtilities.classToXML(race);
|
||||||
|
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException | JAXBException e) {
|
||||||
|
throw new InvalidRaceDataException("Could not parse or marshall race data file.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an estimate of how long a race will take using an average Speed
|
||||||
|
* @param race race to estimate
|
||||||
|
* @param averageSpeed average speed that the boats move at
|
||||||
|
* @return the estimated amount of time it will take a boat to finish the race (skewed to minimum).
|
||||||
|
*/
|
||||||
|
public static double getRaceLength(XMLRace race, double averageSpeed){
|
||||||
|
double raceRoundingTime = 5000; //5 seconds to round a mark
|
||||||
|
double totalDistance = 0; //in nautical miles
|
||||||
|
XMLMark prevMark = null;
|
||||||
|
double avgSpeed = averageSpeed / 60 / 60; //knots is /hour
|
||||||
|
for (XMLCorner corner : race.getCompoundMarkSequence().getCorner()){
|
||||||
|
int index = corner.getCompoundMarkID() - 1;
|
||||||
|
XMLCompoundMark cm = race.getCourse().getCompoundMark().get(index);
|
||||||
|
XMLMark mark = cm.getMark().get(0);
|
||||||
|
if (prevMark != null){
|
||||||
|
totalDistance += getDistance(mark, prevMark);
|
||||||
|
}
|
||||||
|
prevMark = mark;
|
||||||
|
}
|
||||||
|
//total time = total dist / average speed + race extra rounding time * number of marks
|
||||||
|
double totalTime = totalDistance / avgSpeed * 1000 +
|
||||||
|
raceRoundingTime * race.getCompoundMarkSequence().getCorner().size();
|
||||||
|
return totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the destance between two marks
|
||||||
|
* @param a mark 1
|
||||||
|
* @param b mark 2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static double getDistance(XMLMark a, XMLMark b){
|
||||||
|
GPSCoordinate coorda = new GPSCoordinate(a.getTargetLat(), a.getTargetLng());
|
||||||
|
GPSCoordinate coordb = new GPSCoordinate(b.getTargetLat(), b.getTargetLng());
|
||||||
|
return GPSCoordinate.calculateDistanceNauticalMiles(coorda, coordb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the race based on the windspeed the race is running at and the amount of time it should be completed in.
|
||||||
|
* @param race Race to scale
|
||||||
|
* @param windSpeed windspeed of the race, this is used with the polars
|
||||||
|
* @param milliseconds milliseconds the race should take.
|
||||||
|
*/
|
||||||
|
private static void scaleRace(XMLRace race, double windSpeed, double milliseconds) {
|
||||||
|
GPSCoordinate center = getCenter(race);
|
||||||
|
//sort the compound marks
|
||||||
|
Collections.sort(race.getCompoundMarkSequence().getCorner(), (c1, c2) -> {
|
||||||
|
if (c1.getSeqID() < c2.getSeqID()) return -1;
|
||||||
|
if (c1.getSeqID() > c2.getSeqID()) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
//sort compound mark id
|
||||||
|
Collections.sort(race.getCourse().getCompoundMark(), (c1, c2) -> {
|
||||||
|
if (c1.getCompoundMarkID() < c2.getCompoundMarkID()) return -1;
|
||||||
|
if (c1.getCompoundMarkID() > c2.getCompoundMarkID()) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
//get the fastest time it would take.
|
||||||
|
double bestUpWindSpeed = NewPolars.setBestVMG(Bearing.fromDegrees(0), windSpeed, Bearing.fromDegrees(45)).getSpeed();
|
||||||
|
double bestDownWindSpeed = NewPolars.setBestVMG(Bearing.fromDegrees(0), windSpeed, Bearing.fromDegrees(45)).getSpeed();
|
||||||
|
double averageSpeed = (bestDownWindSpeed + bestUpWindSpeed) / 2;
|
||||||
|
double raceApproximateTime = getRaceLength(race, averageSpeed);
|
||||||
|
double scale = milliseconds / raceApproximateTime;
|
||||||
|
for (XMLCorner cm: race.getCompoundMarkSequence().getCorner()){
|
||||||
|
int index = cm.getCompoundMarkID() - 1;
|
||||||
|
XMLCompoundMark mark = race.getCourse().getCompoundMark().get(index);
|
||||||
|
for (XMLMark m: mark.getMark()){
|
||||||
|
scalePoint(m, center, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (XMLLimit limit: race.getCourseLimit().getLimit()){
|
||||||
|
scalePoint(limit, center, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales a point from the the center(pivot)
|
||||||
|
* @param mark mark the scale
|
||||||
|
* @param center center as pivot
|
||||||
|
* @param scale scale to scale at.
|
||||||
|
*/
|
||||||
|
private static void scalePoint(XMLMark mark, GPSCoordinate center, double scale){
|
||||||
|
double latDiff = mark.getTargetLat() - center.getLatitude();
|
||||||
|
double longDiff = mark.getTargetLng() - center.getLongitude();
|
||||||
|
double latScaled = latDiff * scale + center.getLatitude();
|
||||||
|
double longScaled = longDiff * scale + center.getLongitude();
|
||||||
|
mark.setTargetLat(latScaled);
|
||||||
|
mark.setTargetLng(longScaled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales a boundary from the center(pivot)
|
||||||
|
* @param limit boundary point
|
||||||
|
* @param center pivot
|
||||||
|
* @param scale scale
|
||||||
|
*/
|
||||||
|
private static void scalePoint(XMLLimit limit, GPSCoordinate center, double scale){
|
||||||
|
double latDiff = limit.getLat() - center.getLatitude();
|
||||||
|
double longDiff = limit.getLon() - center.getLongitude();
|
||||||
|
double latScaled = latDiff * scale + center.getLatitude();
|
||||||
|
double longScaled = longDiff * scale + center.getLongitude();
|
||||||
|
limit.setLat(latScaled);
|
||||||
|
limit.setLon(longScaled);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a Race.CourseLimit.Limit to a GPS coordinate
|
* Converts a Race.CourseLimit.Limit to a GPS coordinate
|
||||||
* @param limit limit to convert
|
* @param limit limit to convert
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ public class LatestMessages extends Observable {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
RaceServer.staticUpdateXML();
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,10 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource {
|
|||||||
return sequenceNumber;
|
return sequenceNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSequenceNumber(int sequenceNumber) {
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementSequenceNumber() {
|
public void incrementSequenceNumber() {
|
||||||
sequenceNumber++;
|
sequenceNumber++;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class EmptyBoatDataSource implements BoatDataSource {
|
|||||||
private final Map<Integer, Mark> markerMap = new HashMap<>();
|
private final Map<Integer, Mark> markerMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
private int sequenceNumber = 0;
|
private int sequenceNumber = -1;
|
||||||
|
|
||||||
|
|
||||||
public EmptyBoatDataSource() {
|
public EmptyBoatDataSource() {
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public class EmptyRaceDataSource implements RaceDataSource {
|
|||||||
private RaceTypeEnum raceType = RaceTypeEnum.NOT_A_RACE_TYPE;
|
private RaceTypeEnum raceType = RaceTypeEnum.NOT_A_RACE_TYPE;
|
||||||
|
|
||||||
|
|
||||||
private int sequenceNumber = 0;
|
private int sequenceNumber = -1;
|
||||||
|
|
||||||
|
|
||||||
public EmptyRaceDataSource() {
|
public EmptyRaceDataSource() {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class EmptyRegattaDataSource implements RegattaDataSource {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private int sequenceNumber = 0;
|
private int sequenceNumber = -1;
|
||||||
|
|
||||||
|
|
||||||
public EmptyRegattaDataSource() {
|
public EmptyRegattaDataSource() {
|
||||||
|
|||||||
@@ -499,6 +499,10 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource {
|
|||||||
return sequenceNumber;
|
return sequenceNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSequenceNumber(int sequenceNumber) {
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementSequenceNumber() {
|
public void incrementSequenceNumber() {
|
||||||
sequenceNumber++;
|
sequenceNumber++;
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource {
|
|||||||
return sequenceNumber;
|
return sequenceNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSequenceNumber(int sequenceNumber) {
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementSequenceNumber() {
|
public void incrementSequenceNumber() {
|
||||||
sequenceNumber++;
|
sequenceNumber++;
|
||||||
|
|||||||
@@ -148,26 +148,32 @@ public abstract class RaceState extends Observable{
|
|||||||
* @param raceDataSource New race data source.
|
* @param raceDataSource New race data source.
|
||||||
*/
|
*/
|
||||||
public void setRaceDataSource(RaceDataSource raceDataSource) {
|
public void setRaceDataSource(RaceDataSource raceDataSource) {
|
||||||
|
if ((this.raceDataSource == null) || (raceDataSource.getSequenceNumber() > this.raceDataSource.getSequenceNumber())) {
|
||||||
this.raceDataSource = raceDataSource;
|
this.raceDataSource = raceDataSource;
|
||||||
this.getRaceClock().setStartingTime(raceDataSource.getStartDateTime());
|
this.getRaceClock().setStartingTime(raceDataSource.getStartDateTime());
|
||||||
useLegsList(raceDataSource.getLegs());
|
useLegsList(raceDataSource.getLegs());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the boat data source for the race.
|
* Sets the boat data source for the race.
|
||||||
* @param boatDataSource New boat data source.
|
* @param boatDataSource New boat data source.
|
||||||
*/
|
*/
|
||||||
public void setBoatDataSource(BoatDataSource boatDataSource) {
|
public void setBoatDataSource(BoatDataSource boatDataSource) {
|
||||||
|
if ((this.boatDataSource == null) || (boatDataSource.getSequenceNumber() > this.boatDataSource.getSequenceNumber())) {
|
||||||
this.boatDataSource = boatDataSource;
|
this.boatDataSource = boatDataSource;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the regatta data source for the race.
|
* Sets the regatta data source for the race.
|
||||||
* @param regattaDataSource New regatta data source.
|
* @param regattaDataSource New regatta data source.
|
||||||
*/
|
*/
|
||||||
public void setRegattaDataSource(RegattaDataSource regattaDataSource) {
|
public void setRegattaDataSource(RegattaDataSource regattaDataSource) {
|
||||||
|
if ((this.regattaDataSource == null) || (regattaDataSource.getSequenceNumber() > this.regattaDataSource.getSequenceNumber())) {
|
||||||
this.regattaDataSource = regattaDataSource;
|
this.regattaDataSource = regattaDataSource;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package shared.utils;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class that has functions to read information from a url to json object.
|
||||||
|
*/
|
||||||
|
public class JsonReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads all data from a Reader
|
||||||
|
* @param rd reader to read from
|
||||||
|
* @return string that the reader has currently read
|
||||||
|
* @throws IOException if the reader is invalid
|
||||||
|
*/
|
||||||
|
private static String readAll(Reader rd) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int cp;
|
||||||
|
while ((cp = rd.read()) != -1) {
|
||||||
|
sb.append((char) cp);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a Json Object from a URL
|
||||||
|
* @param url url to read from
|
||||||
|
* @return JSONObject that has been read
|
||||||
|
* @throws IOException if the reader cannot obtain information
|
||||||
|
* @throws JSONException if the read information is not json parsable.
|
||||||
|
*/
|
||||||
|
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
|
||||||
|
InputStream is = new URL(url).openStream();
|
||||||
|
try {
|
||||||
|
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||||
|
String jsonText = readAll(rd);
|
||||||
|
JSONObject json = new JSONObject(jsonText);
|
||||||
|
return json;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a Json Array from a URL
|
||||||
|
* @param url url to read from
|
||||||
|
* @return JSONArray that has been read
|
||||||
|
* @throws IOException if the reader cannot obtain information
|
||||||
|
* @throws JSONException if the read information is not json parsable.
|
||||||
|
*/
|
||||||
|
public static JSONArray readJsonFromUrlArray(String url) throws IOException, JSONException {
|
||||||
|
InputStream is = new URL(url).openStream();
|
||||||
|
try {
|
||||||
|
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||||
|
String jsonText = readAll(rd);
|
||||||
|
JSONArray json = new JSONArray(jsonText);
|
||||||
|
return json;
|
||||||
|
} finally {
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -41,8 +41,8 @@ public class BoatsXMLMessageCommand implements Command {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
if (boatDataSource.getSequenceNumber() > visualiserRace.getBoatDataSource().getSequenceNumber()) {
|
||||||
visualiserRace.setBoatDataSource(boatDataSource);
|
visualiserRace.setBoatDataSource(boatDataSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -38,7 +38,9 @@ public class RaceXMLMessageCommand implements Command {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
|
||||||
|
if (raceDataSource.getSequenceNumber() > visualiserRace.getRaceDataSource().getSequenceNumber()) {
|
||||||
visualiserRace.setRaceDataSource(raceDataSource);
|
visualiserRace.setRaceDataSource(raceDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -37,8 +37,9 @@ public class RegattaXMLMessageCommand implements Command {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
if (regattaDataSource.getSequenceNumber() > visualiserRace.getRegattaDataSource().getSequenceNumber()) {
|
||||||
visualiserRace.setRegattaDataSource(regattaDataSource);
|
visualiserRace.setRegattaDataSource(regattaDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -34,17 +34,20 @@ public class XMLMessageCommandFactory {
|
|||||||
switch (message.getXmlMsgSubType()) {
|
switch (message.getXmlMsgSubType()) {
|
||||||
|
|
||||||
case BOAT:
|
case BOAT:
|
||||||
BoatDataSource boatDataSource = new BoatXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
BoatXMLReader boatDataSource = new BoatXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
||||||
|
boatDataSource.setSequenceNumber(message.getSequenceNumber());
|
||||||
return new BoatsXMLMessageCommand(boatDataSource, visualiserRace);
|
return new BoatsXMLMessageCommand(boatDataSource, visualiserRace);
|
||||||
|
|
||||||
|
|
||||||
case RACE:
|
case RACE:
|
||||||
RaceDataSource raceDataSource = new RaceXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
RaceXMLReader raceDataSource = new RaceXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
||||||
|
raceDataSource.setSequenceNumber(message.getSequenceNumber());
|
||||||
return new RaceXMLMessageCommand(raceDataSource, visualiserRace);
|
return new RaceXMLMessageCommand(raceDataSource, visualiserRace);
|
||||||
|
|
||||||
|
|
||||||
case REGATTA:
|
case REGATTA:
|
||||||
RegattaDataSource regattaDataSource = new RegattaXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
RegattaXMLReader regattaDataSource = new RegattaXMLReader(message.getXmlMessage(), XMLFileType.Contents);
|
||||||
|
regattaDataSource.setSequenceNumber(message.getSequenceNumber());
|
||||||
return new RegattaXMLMessageCommand(regattaDataSource, visualiserRace);
|
return new RegattaXMLMessageCommand(regattaDataSource, visualiserRace);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import javafx.scene.image.Image;
|
|||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import mock.app.Event;
|
import mock.app.Event;
|
||||||
import mock.exceptions.EventConstructionException;
|
import mock.exceptions.EventConstructionException;
|
||||||
|
import network.Messages.Enums.RequestToJoinEnum;
|
||||||
import visualiser.app.App;
|
import visualiser.app.App;
|
||||||
import visualiser.app.MatchBrowserSingleton;
|
import visualiser.app.MatchBrowserSingleton;
|
||||||
|
import visualiser.network.HttpMatchBrowserHost;
|
||||||
import visualiser.network.MatchBrowserInterface;
|
import visualiser.network.MatchBrowserInterface;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -64,8 +66,11 @@ public class HostGameController extends Controller {
|
|||||||
try {
|
try {
|
||||||
App.game = new Event(false, currentMapIndex);
|
App.game = new Event(false, currentMapIndex);
|
||||||
App.gameType = currentMapIndex;
|
App.gameType = currentMapIndex;
|
||||||
|
|
||||||
|
HttpMatchBrowserHost matchBrowserHost = new HttpMatchBrowserHost();
|
||||||
|
new Thread(matchBrowserHost).start();
|
||||||
connectSocket("localhost", 4942);
|
connectSocket("localhost", 4942);
|
||||||
alertMatchBrowser();
|
//alertMatchBrowser();
|
||||||
|
|
||||||
} catch (EventConstructionException e) {
|
} catch (EventConstructionException e) {
|
||||||
Logger.getGlobal().log(Level.SEVERE, "Could not create Event.", e);
|
Logger.getGlobal().log(Level.SEVERE, "Could not create Event.", e);
|
||||||
@@ -98,7 +103,7 @@ public class HostGameController extends Controller {
|
|||||||
public void connectSocket(String address, int port) throws IOException {
|
public void connectSocket(String address, int port) throws IOException {
|
||||||
Socket socket = new Socket(address, port);
|
Socket socket = new Socket(address, port);
|
||||||
InGameLobbyController iglc = (InGameLobbyController)loadScene("gameLobby.fxml");
|
InGameLobbyController iglc = (InGameLobbyController)loadScene("gameLobby.fxml");
|
||||||
iglc.enterGameLobby(socket, true);
|
iglc.enterGameLobby(socket, true, RequestToJoinEnum.PARTICIPANT);//TODO may want to let the host spectate if they wish.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.PhongMaterial;
|
import javafx.scene.paint.PhongMaterial;
|
||||||
import javafx.scene.shape.MeshView;
|
import javafx.scene.shape.MeshView;
|
||||||
import mock.app.Event;
|
import mock.app.Event;
|
||||||
import network.Messages.Enums.RaceStatusEnum;
|
import network.Messages.Enums.RaceStatusEnum;
|
||||||
import network.Messages.Enums.RequestToJoinEnum;
|
import network.Messages.Enums.RequestToJoinEnum;
|
||||||
|
import shared.model.Boat;
|
||||||
import visualiser.app.App;
|
import visualiser.app.App;
|
||||||
import visualiser.gameController.ControllerClient;
|
import visualiser.gameController.ControllerClient;
|
||||||
import visualiser.layout.SeaSurface;
|
import visualiser.layout.SeaSurface;
|
||||||
@@ -28,6 +30,7 @@ import visualiser.layout.View3D;
|
|||||||
import visualiser.model.VisualiserBoat;
|
import visualiser.model.VisualiserBoat;
|
||||||
import visualiser.model.VisualiserRaceEvent;
|
import visualiser.model.VisualiserRaceEvent;
|
||||||
import visualiser.model.VisualiserRaceState;
|
import visualiser.model.VisualiserRaceState;
|
||||||
|
import visualiser.network.HttpMatchBrowserHost;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@@ -124,15 +127,25 @@ public class InGameLobbyController extends Controller {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(Change change) {
|
public void onChanged(Change change) {
|
||||||
Platform.runLater(
|
Platform.runLater(() -> {
|
||||||
() -> {
|
while (change.next()) {
|
||||||
while (change.next()){
|
if (change.wasAdded() || change.wasRemoved() || change.wasUpdated()) {
|
||||||
if (change.wasAdded() || change.wasRemoved() || change.wasUpdated()){
|
populateLobby();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populateLobby() {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
resetLobby();
|
resetLobby();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int row = 0;
|
int row = 0;
|
||||||
for (VisualiserBoat boat :visualiserRaceEvent.getVisualiserRaceState().getBoats()) {
|
|
||||||
|
ArrayList<VisualiserBoat> copy = new ArrayList<>(visualiserRaceEvent.getVisualiserRaceState().getBoats());
|
||||||
|
|
||||||
|
for (VisualiserBoat boat : copy) {
|
||||||
View3D playerBoatToSet = new View3D();
|
View3D playerBoatToSet = new View3D();
|
||||||
playerBoatToSet.setItems(subjects);
|
playerBoatToSet.setItems(subjects);
|
||||||
|
|
||||||
@@ -173,12 +186,10 @@ public class InGameLobbyController extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(ConcurrentModificationException e){
|
catch(ConcurrentModificationException e){
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
private void populatePlayers(ListChangeListener.Change change){
|
private void populatePlayers(ListChangeListener.Change change){
|
||||||
@@ -191,7 +202,6 @@ public class InGameLobbyController extends Controller {
|
|||||||
//Initialises the race clock.
|
//Initialises the race clock.
|
||||||
initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState());
|
initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState());
|
||||||
|
|
||||||
|
|
||||||
//Starts the race countdown timer.
|
//Starts the race countdown timer.
|
||||||
countdownTimer();
|
countdownTimer();
|
||||||
}
|
}
|
||||||
@@ -227,7 +237,6 @@ public class InGameLobbyController extends Controller {
|
|||||||
new AnimationTimer() {
|
new AnimationTimer() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(long arg0) {
|
public void handle(long arg0) {
|
||||||
|
|
||||||
//Get the current race status.
|
//Get the current race status.
|
||||||
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
|
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
|
||||||
|
|
||||||
@@ -267,10 +276,16 @@ public class InGameLobbyController extends Controller {
|
|||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enterGameLobby(Socket socket, boolean isHost){
|
/**
|
||||||
|
* Joins a game and enters the game lobby for it.
|
||||||
|
* @param socket Socket to connect to.
|
||||||
|
* @param isHost Whether this client is the host.
|
||||||
|
* @param joinType How the client wishes to join (e.g., participant).
|
||||||
|
*/
|
||||||
|
public void enterGameLobby(Socket socket, boolean isHost, RequestToJoinEnum joinType){
|
||||||
try {
|
try {
|
||||||
|
|
||||||
this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT);
|
this.visualiserRaceEvent = new VisualiserRaceEvent(socket, joinType);
|
||||||
this.isHost = isHost;
|
this.isHost = isHost;
|
||||||
this.controllerClient = visualiserRaceEvent.getControllerClient();
|
this.controllerClient = visualiserRaceEvent.getControllerClient();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package visualiser.Controllers;
|
package visualiser.Controllers;
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
@@ -8,10 +9,15 @@ import javafx.scene.control.TableColumn;
|
|||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import network.Messages.Enums.RequestToJoinEnum;
|
||||||
import javafx.scene.media.AudioClip;
|
import javafx.scene.media.AudioClip;
|
||||||
import network.Messages.HostGame;
|
import network.Messages.HostGame;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import shared.utils.JsonReader;
|
||||||
import visualiser.app.MatchBrowserSingleton;
|
import visualiser.app.MatchBrowserSingleton;
|
||||||
import visualiser.model.RaceConnection;
|
import visualiser.model.RaceConnection;
|
||||||
|
import visualiser.network.HttpMatchBrowserClient;
|
||||||
import visualiser.network.MatchBrowserLobbyInterface;
|
import visualiser.network.MatchBrowserLobbyInterface;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -30,6 +36,7 @@ public class LobbyController extends Controller {
|
|||||||
private @FXML TableColumn<RaceConnection, String> hostNameColumn;
|
private @FXML TableColumn<RaceConnection, String> hostNameColumn;
|
||||||
private @FXML TableColumn<RaceConnection, String> statusColumn;
|
private @FXML TableColumn<RaceConnection, String> statusColumn;
|
||||||
private @FXML Button joinGameBtn;
|
private @FXML Button joinGameBtn;
|
||||||
|
private @FXML Button spectateButton;
|
||||||
private @FXML TextField addressFld;
|
private @FXML TextField addressFld;
|
||||||
private @FXML TextField portFld;
|
private @FXML TextField portFld;
|
||||||
|
|
||||||
@@ -39,17 +46,17 @@ public class LobbyController extends Controller {
|
|||||||
private AudioClip sound;
|
private AudioClip sound;
|
||||||
|
|
||||||
//the socket for match browser
|
//the socket for match browser
|
||||||
private DatagramSocket udpSocket;
|
private HttpMatchBrowserClient httpMatchBrowserClient;
|
||||||
private MatchBrowserLobbyInterface matchBrowserLobbyInterface;
|
|
||||||
|
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
httpMatchBrowserClient = new HttpMatchBrowserClient();
|
||||||
|
new Thread(httpMatchBrowserClient, "Match Client").start();
|
||||||
// set up the connection table
|
// set up the connection table
|
||||||
connections = FXCollections.observableArrayList();
|
|
||||||
customConnections = FXCollections.observableArrayList();
|
customConnections = FXCollections.observableArrayList();
|
||||||
//connections.add(new RaceConnection("localhost", 4942, "Local Game"));
|
//connections.add(new RaceConnection("localhost", 4942, "Local Game"));
|
||||||
|
|
||||||
lobbyTable.setItems(connections);
|
lobbyTable.setItems(httpMatchBrowserClient.connections);
|
||||||
gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty());
|
gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty());
|
||||||
hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
|
hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
|
||||||
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
|
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
|
||||||
@@ -57,13 +64,15 @@ public class LobbyController extends Controller {
|
|||||||
lobbyTable.getSelectionModel().selectedItemProperty().addListener((obs, prev, curr) -> {
|
lobbyTable.getSelectionModel().selectedItemProperty().addListener((obs, prev, curr) -> {
|
||||||
if (curr != null && curr.statusProperty().getValue().equals("Ready")) {
|
if (curr != null && curr.statusProperty().getValue().equals("Ready")) {
|
||||||
joinGameBtn.setDisable(false);
|
joinGameBtn.setDisable(false);
|
||||||
|
spectateButton.setDisable(false);
|
||||||
} else {
|
} else {
|
||||||
joinGameBtn.setDisable(true);
|
joinGameBtn.setDisable(true);
|
||||||
|
spectateButton.setDisable(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
joinGameBtn.setDisable(true);
|
joinGameBtn.setDisable(true);
|
||||||
|
spectateButton.setDisable(true);
|
||||||
|
|
||||||
this.udpSocket = MatchBrowserSingleton.getInstance().getUdpSocket();
|
|
||||||
receiveMatchData();
|
receiveMatchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,27 +89,47 @@ public class LobbyController extends Controller {
|
|||||||
try {
|
try {
|
||||||
if (lobbyTable.getSelectionModel().getSelectedItem().statusProperty().getValue().equals("Ready")) {
|
if (lobbyTable.getSelectionModel().getSelectedItem().statusProperty().getValue().equals("Ready")) {
|
||||||
joinGameBtn.setDisable(false);
|
joinGameBtn.setDisable(false);
|
||||||
|
spectateButton.setDisable(false);
|
||||||
} else {
|
} else {
|
||||||
joinGameBtn.setDisable(true);
|
joinGameBtn.setDisable(true);
|
||||||
|
spectateButton.setDisable(true);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored){}
|
} catch (Exception ignored){}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a connection.
|
* Connect to a connection.
|
||||||
|
* @param joinType How the client wishes to join (e.g., participant).
|
||||||
* @throws IOException socket error
|
* @throws IOException socket error
|
||||||
*/
|
*/
|
||||||
public void connectSocket() throws IOException {
|
public void connectSocket(RequestToJoinEnum joinType) throws IOException {
|
||||||
|
httpMatchBrowserClient.interrupt();
|
||||||
RaceConnection connection = lobbyTable.getSelectionModel().getSelectedItem();
|
RaceConnection connection = lobbyTable.getSelectionModel().getSelectedItem();
|
||||||
Socket socket = new Socket(connection.getHostname(), connection.getPort());
|
Socket socket = new Socket(connection.getHostname(), connection.getPort());
|
||||||
InGameLobbyController iglc = (InGameLobbyController)loadScene("gameLobby.fxml");
|
InGameLobbyController iglc = (InGameLobbyController)loadScene("gameLobby.fxml");
|
||||||
iglc.enterGameLobby(socket, false);
|
iglc.enterGameLobby(socket, false, joinType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests to join the game as a participant.
|
||||||
|
* @throws IOException socket error.
|
||||||
|
*/
|
||||||
|
public void connectParticipate() throws IOException {
|
||||||
|
connectSocket(RequestToJoinEnum.PARTICIPANT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests to join the game as a spectator.
|
||||||
|
* @throws IOException socket error.
|
||||||
|
*/
|
||||||
|
public void connectSpectate() throws IOException {
|
||||||
|
connectSocket(RequestToJoinEnum.SPECTATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void menuBtnPressed() throws IOException {
|
public void menuBtnPressed() throws IOException {
|
||||||
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
|
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
|
||||||
sound.play();
|
sound.play();
|
||||||
matchBrowserLobbyInterface.closeSocket();
|
httpMatchBrowserClient.interrupt();
|
||||||
loadScene("title.fxml");
|
loadScene("title.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +153,7 @@ public class LobbyController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void receiveMatchData(){
|
public void receiveMatchData(){
|
||||||
|
/*
|
||||||
matchBrowserLobbyInterface = new MatchBrowserLobbyInterface();
|
matchBrowserLobbyInterface = new MatchBrowserLobbyInterface();
|
||||||
try {
|
try {
|
||||||
matchBrowserLobbyInterface.startReceivingHostData(new DatagramSocket(4941));
|
matchBrowserLobbyInterface.startReceivingHostData(new DatagramSocket(4941));
|
||||||
@@ -136,17 +166,24 @@ public class LobbyController extends Controller {
|
|||||||
matchBrowserLobbyInterface.addObserver(o);
|
matchBrowserLobbyInterface.addObserver(o);
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
System.err.println("Socket 4941 in use");
|
System.err.println("Socket 4941 in use");
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the games received from the server
|
* Adds the games received from the server
|
||||||
*/
|
*/
|
||||||
private void addServerGames() {
|
private void addServerGames() {
|
||||||
connections.clear();
|
httpMatchBrowserClient.connections.addAll(customConnections);
|
||||||
connections.addAll(customConnections);
|
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends RaceConnection> c) {
|
||||||
|
refreshBtnPressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
for (HostGame game : matchBrowserLobbyInterface.getGames()) {
|
for (HostGame game : matchBrowserLobbyInterface.getGames()) {
|
||||||
connections.add(new RaceConnection(game.getIp(), 4942, "Boat Game"));
|
connections.add(new RaceConnection(game.getIp(), 4942, "Boat Game"));
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,6 +433,7 @@ public class RaceViewController extends Controller {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
|
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
|
||||||
|
if (target != null) {
|
||||||
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
|
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
|
||||||
|
|
||||||
nextMarkArrow.setX(view3D.getPivot().getX());
|
nextMarkArrow.setX(view3D.getPivot().getX());
|
||||||
@@ -440,6 +441,7 @@ public class RaceViewController extends Controller {
|
|||||||
nextMarkArrow.setZ(view3D.getPivot().getZ() + 15);
|
nextMarkArrow.setZ(view3D.getPivot().getZ() + 15);
|
||||||
nextMarkArrow.setHeading(headingToMark.degrees());
|
nextMarkArrow.setHeading(headingToMark.degrees());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
arrowToNextMark.start();
|
arrowToNextMark.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,25 @@ public class ThisBoat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSailsOut(boolean sailsOut) {
|
public void setSailsOut(boolean sailsOut) {
|
||||||
|
if (this.boat != null) {
|
||||||
this.boat.setSailsOut(sailsOut);
|
this.boat.setSailsOut(sailsOut);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSailsOut() {
|
public boolean isSailsOut() {
|
||||||
|
if (this.boat != null) {
|
||||||
return this.boat.isSailsOut();
|
return this.boat.isSailsOut();
|
||||||
|
} else {
|
||||||
|
return true;//TODO junk value to allow the client to spectate.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSourceID() {
|
public int getSourceID() {
|
||||||
|
if (this.boat != null) {
|
||||||
return this.boat.getSourceID();
|
return this.boat.getSourceID();
|
||||||
|
} else {
|
||||||
|
return 0;//TODO junk value to allow the client to spectate.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBoat(VisualiserBoat boat) {
|
public void setBoat(VisualiserBoat boat) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import shared.dataInput.EmptyBoatDataSource;
|
|||||||
import shared.dataInput.EmptyRaceDataSource;
|
import shared.dataInput.EmptyRaceDataSource;
|
||||||
import shared.dataInput.EmptyRegattaDataSource;
|
import shared.dataInput.EmptyRegattaDataSource;
|
||||||
import visualiser.gameController.ControllerClient;
|
import visualiser.gameController.ControllerClient;
|
||||||
|
import visualiser.network.HttpMatchBrowserHost;
|
||||||
import visualiser.network.ServerConnection;
|
import visualiser.network.ServerConnection;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -115,5 +116,8 @@ public class VisualiserRaceEvent {
|
|||||||
this.visualiserRaceServiceThread.interrupt();
|
this.visualiserRaceServiceThread.interrupt();
|
||||||
this.serverConnectionThread.interrupt();
|
this.serverConnectionThread.interrupt();
|
||||||
serverConnection.terminate();
|
serverConnection.terminate();
|
||||||
|
if (HttpMatchBrowserHost.httpMatchBrowserHost != null) {
|
||||||
|
HttpMatchBrowserHost.httpMatchBrowserHost.interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class VisualiserRaceState extends RaceState {
|
|||||||
super.setRaceDataSource(raceDataSource);
|
super.setRaceDataSource(raceDataSource);
|
||||||
|
|
||||||
if (getBoatDataSource() != null) {
|
if (getBoatDataSource() != null) {
|
||||||
this.generateVisualiserBoats(this.boats, getBoatDataSource().getBoats(), raceDataSource.getParticipants(), unassignedColors);
|
this.generateVisualiserBoats(this.boats, getBoatDataSource().getBoats(), getRaceDataSource().getParticipants(), unassignedColors);
|
||||||
}
|
}
|
||||||
|
|
||||||
initialiseLegCompletionOrder();
|
initialiseLegCompletionOrder();
|
||||||
@@ -109,7 +109,7 @@ public class VisualiserRaceState extends RaceState {
|
|||||||
super.setBoatDataSource(boatDataSource);
|
super.setBoatDataSource(boatDataSource);
|
||||||
|
|
||||||
if (getRaceDataSource() != null) {
|
if (getRaceDataSource() != null) {
|
||||||
this.generateVisualiserBoats(this.boats, boatDataSource.getBoats(), getRaceDataSource().getParticipants(), unassignedColors);
|
this.generateVisualiserBoats(this.boats, getBoatDataSource().getBoats(), getRaceDataSource().getParticipants(), unassignedColors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package visualiser.network;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import shared.utils.JsonReader;
|
||||||
|
import visualiser.model.RaceConnection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Gondr on 19/09/2017.
|
||||||
|
*/
|
||||||
|
public class HttpMatchBrowserClient extends Thread {
|
||||||
|
public ObservableList<RaceConnection> connections = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the matches that have been running in the past 5 seconds.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while(!Thread.interrupted()) {
|
||||||
|
try {
|
||||||
|
JSONArray cons = JsonReader.readJsonFromUrlArray("http://api.umbrasheep.com/seng/get_matches/");
|
||||||
|
connections.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < cons.length(); i++) {
|
||||||
|
JSONObject con = (JSONObject) cons.get(i);
|
||||||
|
//using "ip_address" will give their public ip
|
||||||
|
connections.add(new RaceConnection((String) con.get("local_ip"), con.getInt("port"), "Boat Game"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package visualiser.network;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an Http connection that hosts a game
|
||||||
|
*/
|
||||||
|
public class HttpMatchBrowserHost extends Thread {
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private List<NameValuePair> params;
|
||||||
|
|
||||||
|
public static HttpMatchBrowserHost httpMatchBrowserHost = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, this sends out the creation message of the race.
|
||||||
|
* the thread should be run as soon as possible as the race is only valid for 5 seconds
|
||||||
|
* until it requires a heartbeat from the start function.
|
||||||
|
* @throws IOException if the hosting url is unreachable.
|
||||||
|
*/
|
||||||
|
public HttpMatchBrowserHost() throws IOException {
|
||||||
|
httpMatchBrowserHost = this;
|
||||||
|
httpClient = HttpClients.createDefault();
|
||||||
|
|
||||||
|
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
|
||||||
|
boolean matches = false;
|
||||||
|
String ip = "";
|
||||||
|
Pattern ipPattern = Pattern.compile("192.168.1.*");
|
||||||
|
while(e.hasMoreElements())
|
||||||
|
{
|
||||||
|
if (matches){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NetworkInterface n = (NetworkInterface) e.nextElement();
|
||||||
|
Enumeration<InetAddress> ee = n.getInetAddresses();
|
||||||
|
while (ee.hasMoreElements())
|
||||||
|
{
|
||||||
|
InetAddress i = ee.nextElement();
|
||||||
|
matches = ipPattern.matcher(i.getHostAddress()).matches();
|
||||||
|
if (matches){
|
||||||
|
ip = i.getHostAddress();
|
||||||
|
//System.out.println(ip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request parameters and other properties.
|
||||||
|
params = new ArrayList<>(2);
|
||||||
|
params.add(new BasicNameValuePair("ip", ip));
|
||||||
|
params.add(new BasicNameValuePair("port", "4942"));
|
||||||
|
params.add(new BasicNameValuePair("magic", "Thomas and Seng"));
|
||||||
|
|
||||||
|
sendHttp("http://api.umbrasheep.com/seng/registermatch/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a post to a server.
|
||||||
|
* @param domain url of to send to
|
||||||
|
* @throws IOException if the url is unreachable.
|
||||||
|
*/
|
||||||
|
public void sendHttp(String domain) throws IOException {
|
||||||
|
HttpPost httppost = new HttpPost(domain);
|
||||||
|
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||||
|
|
||||||
|
//Execute and get the response.
|
||||||
|
HttpResponse response = httpClient.execute(httppost);
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
InputStream instream = entity.getContent();
|
||||||
|
try {
|
||||||
|
// do something useful
|
||||||
|
} finally {
|
||||||
|
instream.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IOException("No Response from Host");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* THe host starts sending out heartbeat messages every 2 seconds.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while(!Thread.interrupted()){
|
||||||
|
try {
|
||||||
|
sendHttp("http://api.umbrasheep.com/seng/keep_match_alive/");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,8 +26,9 @@ public class MatchBrowserInterface {
|
|||||||
|
|
||||||
public MatchBrowserInterface() {
|
public MatchBrowserInterface() {
|
||||||
try {//132.181.16.13 is the ip of the CI as of 13/9/17
|
try {//132.181.16.13 is the ip of the CI as of 13/9/17
|
||||||
|
//this.IPAddress = InetAddress.getByName("132.181.16.13"); //InetAddress.getLocalHost();
|
||||||
//this.IPAddress = InetAddress.getByName("umbrasheep.com"); //InetAddress.getLocalHost();
|
//this.IPAddress = InetAddress.getByName("umbrasheep.com"); //InetAddress.getLocalHost();
|
||||||
this.IPAddress = InetAddress.getByName("132.181.16.13"); //InetAddress.getLocalHost();
|
this.IPAddress = InetAddress.getByName("191.101.233.116"); //InetAddress.getLocalHost();
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<AnchorPane fx:id="lobbyWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.LobbyController">
|
<AnchorPane fx:id="lobbyWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.LobbyController">
|
||||||
@@ -40,30 +41,6 @@
|
|||||||
<Font size="36.0" />
|
<Font size="36.0" />
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</Label>
|
||||||
<GridPane fx:id="buttonsGridPane" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
|
||||||
<columnConstraints>
|
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
|
||||||
</columnConstraints>
|
|
||||||
<rowConstraints>
|
|
||||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
|
|
||||||
</rowConstraints>
|
|
||||||
<children>
|
|
||||||
<Button fx:id="joinGameBtn" mnemonicParsing="false" onAction="#connectSocket" text="Connect to Game" GridPane.columnIndex="2">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets right="20.0" />
|
|
||||||
</GridPane.margin></Button>
|
|
||||||
<Button mnemonicParsing="false" onAction="#refreshBtnPressed" text="Refresh" GridPane.columnIndex="1">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="10.0" right="10.0" />
|
|
||||||
</GridPane.margin></Button>
|
|
||||||
<Button mnemonicParsing="false" onAction="#addConnectionPressed" text="Add">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="20.0" />
|
|
||||||
</GridPane.margin></Button>
|
|
||||||
</children>
|
|
||||||
</GridPane>
|
|
||||||
<GridPane fx:id="ipPortGridPane" GridPane.rowIndex="2">
|
<GridPane fx:id="ipPortGridPane" GridPane.rowIndex="2">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
@@ -79,16 +56,44 @@
|
|||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
<opaqueInsets>
|
<opaqueInsets>
|
||||||
<Insets />
|
<Insets />
|
||||||
</opaqueInsets></TextField>
|
</opaqueInsets>
|
||||||
|
</TextField>
|
||||||
<TextField fx:id="portFld" promptText="Port Number" GridPane.columnIndex="1">
|
<TextField fx:id="portFld" promptText="Port Number" GridPane.columnIndex="1">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets left="20.0" right="20.0" />
|
<Insets left="20.0" right="20.0" />
|
||||||
</GridPane.margin></TextField>
|
</GridPane.margin>
|
||||||
|
</TextField>
|
||||||
</children>
|
</children>
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets />
|
<Insets />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
<GridPane fx:id="buttonsGridPane" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Button mnemonicParsing="false" onAction="#refreshBtnPressed" text="Refresh" GridPane.columnIndex="1">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="10.0" right="10.0" />
|
||||||
|
</GridPane.margin></Button>
|
||||||
|
<Button mnemonicParsing="false" onAction="#addConnectionPressed" text="Add">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="20.0" />
|
||||||
|
</GridPane.margin></Button>
|
||||||
|
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="2">
|
||||||
|
<children>
|
||||||
|
<Button fx:id="joinGameBtn" mnemonicParsing="false" onAction="#connectParticipate" text="Participate!" />
|
||||||
|
<Button fx:id="spectateButton" mnemonicParsing="false" onAction="#connectSpectate" text="Spectate!" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu">
|
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets left="50.0" />
|
<Insets left="50.0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user