mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge branch 'Story47CourseLimits' into 'develop'
Story47 course limits The idea was to have the course canvas update whenever we receive a new xml packet for the race data. Specifically for a few seconds after the race where the course boundaries change, going from a boundary which contains the start line to cutting off the start line as soon as the boats start. See merge request !30
This commit is contained in:
@@ -9,8 +9,8 @@ import seng302.models.parsers.StreamParser;
|
||||
import seng302.models.parsers.StreamReceiver;
|
||||
import seng302.server.ServerThread;
|
||||
|
||||
public class App extends Application
|
||||
{
|
||||
public class App extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Parent root = FXMLLoader.load(getClass().getResource("/views/MainView.fxml"));
|
||||
@@ -39,15 +39,15 @@ public class App extends Application
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (args.length == 1 && args[0].equals("-standalone")){
|
||||
if (args.length == 1 && args[0].equals("-standalone")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length == 3 && args[0].equals("-server")){
|
||||
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")){
|
||||
} else if (args.length == 2 && args[0].equals("-server")) {
|
||||
switch (args[1]) {
|
||||
case "internal":
|
||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||
@@ -62,8 +62,6 @@ public class App extends Application
|
||||
}
|
||||
//Change the StreamReceiver in this else block to change the default data source.
|
||||
else{
|
||||
// sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream");
|
||||
|
||||
sr = new StreamReceiver("localhost", 4949, "RaceStream");
|
||||
}
|
||||
|
||||
@@ -73,8 +71,6 @@ public class App extends Application
|
||||
|
||||
launch(args);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,6 +240,17 @@ public class CanvasController {
|
||||
}
|
||||
}
|
||||
}
|
||||
checkForCourseChanges();
|
||||
}
|
||||
|
||||
private void checkForCourseChanges() {
|
||||
if (StreamParser.isNewRaceXmlReceived()){
|
||||
gc.setFill(Color.SKYBLUE);
|
||||
gc.fillRect(0,0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
gc.restore();
|
||||
addRaceBorder();
|
||||
canvas.toBack();
|
||||
}
|
||||
}
|
||||
|
||||
private void move(long id, RaceObject raceObject){
|
||||
@@ -345,6 +356,8 @@ public class CanvasController {
|
||||
* Calculates x and y location for every marker that fits it to the canvas the race will be drawn on.
|
||||
*/
|
||||
private void fitMarksToCanvas() {
|
||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||
StreamParser.isNewRaceXmlReceived();
|
||||
findMinMaxPoint();
|
||||
double minLonToMaxLon = scaleRaceExtremities();
|
||||
calculateReferencePointLocation(minLonToMaxLon);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package seng302.models.parsers;
|
||||
|
||||
/**
|
||||
* Created by Kusal on 4/24/2017.
|
||||
*/
|
||||
public enum PacketType {
|
||||
HEARTBEAT,
|
||||
RACE_STATUS,
|
||||
DISPLAY_TEXT_MESSAGE,
|
||||
XML_MESSAGE,
|
||||
RACE_START_STATUS,
|
||||
YACHT_EVENT_CODE,
|
||||
YACHT_ACTION_CODE,
|
||||
CHATTER_TEXT,
|
||||
BOAT_LOCATION,
|
||||
MARK_ROUNDING,
|
||||
COURSE_WIND,
|
||||
AVG_WIND,
|
||||
OTHER;
|
||||
|
||||
static PacketType assignPacketType(int packetType){
|
||||
switch(packetType){
|
||||
case 1:
|
||||
return HEARTBEAT;
|
||||
case 12:
|
||||
return RACE_STATUS;
|
||||
case 20:
|
||||
return DISPLAY_TEXT_MESSAGE;
|
||||
case 26:
|
||||
return XML_MESSAGE;
|
||||
case 27:
|
||||
return RACE_START_STATUS;
|
||||
case 29:
|
||||
return YACHT_EVENT_CODE;
|
||||
case 31:
|
||||
return YACHT_ACTION_CODE;
|
||||
case 36:
|
||||
return CHATTER_TEXT;
|
||||
case 37:
|
||||
return BOAT_LOCATION;
|
||||
case 38:
|
||||
return MARK_ROUNDING;
|
||||
case 44:
|
||||
return COURSE_WIND;
|
||||
case 47:
|
||||
return AVG_WIND;
|
||||
default:
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package seng302.models.parsers;
|
||||
|
||||
/**
|
||||
* Created by kre39 on 23/04/17.
|
||||
*/
|
||||
public class StreamPacket {
|
||||
|
||||
//Change int to an ENUM for the type
|
||||
private PacketType type;
|
||||
|
||||
private long messageLength;
|
||||
private long timeStamp;
|
||||
private byte[] payload;
|
||||
|
||||
StreamPacket(int type, long messageLength, long timeStamp, byte[] payload) {
|
||||
this.type = PacketType.assignPacketType(type);
|
||||
this.messageLength = messageLength;
|
||||
this.timeStamp = timeStamp;
|
||||
this.payload = payload;
|
||||
// System.out.println("type = " + this.type.toString());
|
||||
//switch the packet type to deal with what ever specific packet you want to deal with
|
||||
// if (this.type == PacketType.XML_MESSAGE){
|
||||
// //System.out.println("--------");
|
||||
// System.out.println(new String(payload));
|
||||
// //StreamParser.parsePacket(this);
|
||||
// }
|
||||
}
|
||||
|
||||
PacketType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public long getMessageLength() {
|
||||
return messageLength;
|
||||
}
|
||||
|
||||
byte[] getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
long getTimeStamp() {
|
||||
return timeStamp;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class StreamParser extends Thread{
|
||||
public static ConcurrentHashMap<Long, PriorityBlockingQueue<BoatPositionPacket>> boatPositions = new ConcurrentHashMap<>();
|
||||
private String threadName;
|
||||
private Thread t;
|
||||
private static boolean newRaceXmlReceived = false;
|
||||
private static boolean raceStarted = false;
|
||||
private static XMLParser xmlObject;
|
||||
private static boolean raceFinished = false;
|
||||
@@ -123,6 +124,7 @@ public class StreamParser extends Thread{
|
||||
extractDisplayMessage(packet);
|
||||
break;
|
||||
case XML_MESSAGE:
|
||||
newRaceXmlReceived = true;
|
||||
extractXmlMessage(packet);
|
||||
break;
|
||||
case RACE_START_STATUS:
|
||||
@@ -296,9 +298,8 @@ public class StreamParser extends Thread{
|
||||
byte[] payload = packet.getPayload();
|
||||
|
||||
int messageType = payload[9];
|
||||
long messagelength = bytesToLong(Arrays.copyOfRange(payload,12,14));
|
||||
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messagelength)))).trim();
|
||||
//System.out.println("xmlMessage2 = " + xmlMessage);
|
||||
long messageLength = bytesToLong(Arrays.copyOfRange(payload,12,14));
|
||||
String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messageLength)))).trim();
|
||||
|
||||
//Create XML document Object
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
@@ -315,6 +316,9 @@ public class StreamParser extends Thread{
|
||||
if (messageType == 7) { //7 is the boat XML
|
||||
boats = xmlObject.getBoatXML().getCompetingBoats();
|
||||
}
|
||||
if (messageType == 6) { //6 is race info xml
|
||||
newRaceXmlReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,5 +597,20 @@ public class StreamParser extends Thread{
|
||||
appRunning = false;
|
||||
System.out.println("[CLIENT] Shutting down stream parser");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if a new un-processed xml has been found, if so will return true before
|
||||
* toggling off so that the next check will return false.
|
||||
*
|
||||
* @return the status of if new xml has been received
|
||||
*/
|
||||
public static boolean isNewRaceXmlReceived(){
|
||||
if (newRaceXmlReceived){
|
||||
newRaceXmlReceived = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +235,28 @@ public class ServerThread implements Runnable, Observer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
serverLog("Sending race data", 0);
|
||||
}
|
||||
}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);
|
||||
@@ -252,12 +274,13 @@ public class ServerThread implements Runnable, Observer {
|
||||
sendXml();
|
||||
startSendingRaceStartStatusMessages();
|
||||
startSendingRaceStatusMessages();
|
||||
sendPostStartCourseXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start sending static boat position updates when race has finished
|
||||
*/
|
||||
private void startSendingRaceFinishedBoatPostions(){
|
||||
private void startSendingRaceFinishedBoatPositions(){
|
||||
Timer t = new Timer();
|
||||
t.schedule(new TimerTask() {
|
||||
@Override
|
||||
@@ -316,7 +339,7 @@ public class ServerThread implements Runnable, Observer {
|
||||
}
|
||||
|
||||
if (numOfBoatsFinished == ((List<Boat>) arg).size()) {
|
||||
startSendingRaceFinishedBoatPostions();
|
||||
startSendingRaceFinishedBoatPositions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Race>
|
||||
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
|
||||
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False"/>
|
||||
<RaceID>15082901</RaceID>
|
||||
<RaceType>Fleet</RaceType>
|
||||
<Participants>
|
||||
<Yacht SourceID="101"/>
|
||||
<Yacht SourceID="102"/>
|
||||
<Yacht SourceID="103"/>
|
||||
<Yacht SourceID="104"/>
|
||||
<Yacht SourceID="105"/>
|
||||
<Yacht SourceID="106"/>
|
||||
</Participants>
|
||||
<Course>
|
||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330"
|
||||
SourceID="122"/>
|
||||
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.6703330" TargetLng="11.8278330"
|
||||
SourceID="123"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="2" Name="Mark1">
|
||||
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="3" Name="Mark2">
|
||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="124"/>
|
||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="125"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="4" Name="Mark3">
|
||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="126"/>
|
||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="127"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="5" Name="Mark2">
|
||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="124"/>
|
||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="125"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="6" Name="Mark3">
|
||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="126"/>
|
||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="127"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="7" Name="Mark2">
|
||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="124"/>
|
||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="125"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="8" Name="Mark3">
|
||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="126"/>
|
||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="127"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="9" Name="Mark2">
|
||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="124"/>
|
||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
||||
SourceID="125"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="10" Name="Mark3">
|
||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="126"/>
|
||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
||||
SourceID="127"/>
|
||||
</CompoundMark>
|
||||
<CompoundMark CompoundMarkID="11" Name="Mark4">
|
||||
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.6715240" TargetLng="11.8444950"
|
||||
SourceID="128"/>
|
||||
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950"
|
||||
SourceID="129"/>
|
||||
</CompoundMark>
|
||||
</Course>
|
||||
<CompoundMarkSequence>
|
||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3"/>
|
||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3"/>
|
||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3"/>
|
||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3"/>
|
||||
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
|
||||
<Corner SeqID="6" CompoundMarkID="6" Rounding="PS" ZoneSize="3"/>
|
||||
<Corner SeqID="7" CompoundMarkID="7" Rounding="SP" ZoneSize="3"/>
|
||||
<Corner SeqID="8" CompoundMarkID="8" Rounding="PS" ZoneSize="3"/>
|
||||
<Corner SeqID="9" CompoundMarkID="9" Rounding="SP" ZoneSize="3"/>
|
||||
<Corner SeqID="10" CompoundMarkID="10" Rounding="PS" ZoneSize="3"/>
|
||||
<Corner SeqID="11" CompoundMarkID="11" Rounding="PS" ZoneSize="3"/>
|
||||
</CompoundMarkSequence>
|
||||
<CourseLimit>
|
||||
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100"/>
|
||||
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010"/>
|
||||
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790"/>
|
||||
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610"/>
|
||||
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910"/>
|
||||
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840"/>
|
||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030"/>
|
||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660"/>
|
||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920"/>
|
||||
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340"/>
|
||||
</CourseLimit>
|
||||
</Race>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Race>
|
||||
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
|
||||
<CreationTimeDate>2015-08-29T11:27:15+02:00</CreationTimeDate>
|
||||
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False" />
|
||||
<RaceID>15082901</RaceID>
|
||||
<RaceType>Fleet</RaceType>
|
||||
@@ -80,6 +80,8 @@
|
||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030" />
|
||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660" />
|
||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920" />
|
||||
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340" />
|
||||
<Limit SeqID="10" Lat="57.6692230" Lon="11.8231430" />
|
||||
<Limit SeqID="11" Lat="57.6725370" Lon="11.8272480" />
|
||||
<Limit SeqID="12" Lat="57.6708220" Lon="11.8321340" />
|
||||
</CourseLimit>
|
||||
</Race>
|
||||
@@ -8,6 +8,7 @@ import java.lang.reflect.Method;
|
||||
import java.net.Socket;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import seng302.models.parsers.packets.StreamPacket;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
Reference in New Issue
Block a user