mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # src/main/java/seng302/model/ClientYacht.java # src/main/java/seng302/visualiser/GameView.java # src/test/java/seng302/visualiser/map/BoatSailAnimationToggleTest.java # src/test/java/steps/ToggleSailSteps.java
This commit is contained in:
@@ -180,3 +180,7 @@ local.properties
|
|||||||
.recommenders/
|
.recommenders/
|
||||||
|
|
||||||
Makefile
|
Makefile
|
||||||
|
|
||||||
|
infer-out/
|
||||||
|
infer.txt
|
||||||
|
log.log
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.server.messages.BoatAction;
|
import seng302.gameServer.server.messages.BoatAction;
|
||||||
@@ -12,6 +14,7 @@ import seng302.gameServer.server.messages.MarkRoundingMessage;
|
|||||||
import seng302.gameServer.server.messages.MarkType;
|
import seng302.gameServer.server.messages.MarkType;
|
||||||
import seng302.gameServer.server.messages.Message;
|
import seng302.gameServer.server.messages.Message;
|
||||||
import seng302.gameServer.server.messages.RoundingBoatStatus;
|
import seng302.gameServer.server.messages.RoundingBoatStatus;
|
||||||
|
import seng302.gameServer.server.messages.YachtEventCodeMessage;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
@@ -29,8 +32,8 @@ import seng302.utilities.GeoUtility;
|
|||||||
public class GameState implements Runnable {
|
public class GameState implements Runnable {
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface MarkPassingListener {
|
interface NewMessageListener {
|
||||||
void markPassing(Message message);
|
void notify(Message message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(GameState.class);
|
private Logger logger = LoggerFactory.getLogger(GameState.class);
|
||||||
@@ -38,6 +41,11 @@ public class GameState implements Runnable {
|
|||||||
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
||||||
public static Integer MAX_PLAYERS = 8;
|
public static Integer MAX_PLAYERS = 8;
|
||||||
public static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
public static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
||||||
|
public static final Double MARK_COLLISION_DISTANCE = 15d;
|
||||||
|
public static final Double YACHT_COLLISION_DISTANCE = 25.0;
|
||||||
|
public static final Double BOUNCE_DISTANCE_MARK = 20.0;
|
||||||
|
public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
|
||||||
|
public static final Double COLLISION_VELOCITY_PENALTY = 0.3;
|
||||||
|
|
||||||
private static Long previousUpdateTime;
|
private static Long previousUpdateTime;
|
||||||
public static Double windDirection;
|
public static Double windDirection;
|
||||||
@@ -50,8 +58,9 @@ public class GameState implements Runnable {
|
|||||||
private static GameStages currentStage;
|
private static GameStages currentStage;
|
||||||
private static MarkOrder markOrder;
|
private static MarkOrder markOrder;
|
||||||
private static long startTime;
|
private static long startTime;
|
||||||
|
private static Set<Mark> marks;
|
||||||
|
|
||||||
private static List<MarkPassingListener> markListeners;
|
private static List<NewMessageListener> markListeners;
|
||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
/*
|
/*
|
||||||
@@ -81,12 +90,18 @@ public class GameState implements Runnable {
|
|||||||
markListeners = new ArrayList<>();
|
markListeners = new ArrayList<>();
|
||||||
|
|
||||||
new Thread(this).start(); //Run the auto updates on the game state
|
new Thread(this).start(); //Run the auto updates on the game state
|
||||||
|
|
||||||
|
marks = new MarkOrder().getAllMarks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getHostIpAddress() {
|
public static String getHostIpAddress() {
|
||||||
return hostIpAddress;
|
return hostIpAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Mark> getMarks(){
|
||||||
|
return Collections.unmodifiableSet(marks);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Player> getPlayers() {
|
public static List<Player> getPlayers() {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
@@ -120,7 +135,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setCurrentStage(GameStages currentStage) {
|
public static void setCurrentStage(GameStages currentStage) {
|
||||||
if (currentStage == GameStages.RACING){
|
if (currentStage == GameStages.RACING) {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,12 +236,49 @@ public class GameState implements Runnable {
|
|||||||
yacht.runAutoPilot();
|
yacht.runAutoPilot();
|
||||||
yacht.updateLocation(timeInterval);
|
yacht.updateLocation(timeInterval);
|
||||||
if (!yacht.getFinishedRace()) {
|
if (!yacht.getFinishedRace()) {
|
||||||
|
checkForCollision(yacht);
|
||||||
checkForLegProgression(yacht);
|
checkForLegProgression(yacht);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void checkForCollision(ServerYacht serverYacht) {
|
||||||
|
ServerYacht collidedYacht = checkCollision(serverYacht);
|
||||||
|
if (collidedYacht != null) {
|
||||||
|
GeoPoint originalLocation = serverYacht.getLocation();
|
||||||
|
serverYacht.setLocation(
|
||||||
|
calculateBounceBack(serverYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
||||||
|
);
|
||||||
|
serverYacht.setCurrentVelocity(
|
||||||
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
|
);
|
||||||
|
collidedYacht.setLocation(
|
||||||
|
calculateBounceBack(collidedYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
||||||
|
);
|
||||||
|
collidedYacht.setCurrentVelocity(
|
||||||
|
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
|
);
|
||||||
|
notifyMessageListeners(
|
||||||
|
new YachtEventCodeMessage(serverYacht.getSourceId())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Mark collidedMark = markCollidedWith(serverYacht);
|
||||||
|
if (collidedMark != null) {
|
||||||
|
serverYacht.setLocation(
|
||||||
|
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
|
||||||
|
);
|
||||||
|
serverYacht.setCurrentVelocity(
|
||||||
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
|
);
|
||||||
|
notifyMessageListeners(
|
||||||
|
new YachtEventCodeMessage(serverYacht.getSourceId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void updateVelocity(ServerYacht yacht) {
|
private void updateVelocity(ServerYacht yacht) {
|
||||||
Double velocity = yacht.getCurrentVelocity();
|
Double velocity = yacht.getCurrentVelocity();
|
||||||
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
||||||
@@ -235,7 +287,7 @@ public class GameState implements Runnable {
|
|||||||
// TODO: 15/08/17 remove magic numbers from these equations.
|
// TODO: 15/08/17 remove magic numbers from these equations.
|
||||||
if (yacht.getSailIn()) {
|
if (yacht.getSailIn()) {
|
||||||
if (velocity < maxBoatSpeed - 500) {
|
if (velocity < maxBoatSpeed - 500) {
|
||||||
yacht.changeVelocity(maxBoatSpeed / 150);
|
yacht.changeVelocity(maxBoatSpeed / 100);
|
||||||
} else if (velocity > maxBoatSpeed + 500) {
|
} else if (velocity > maxBoatSpeed + 500) {
|
||||||
yacht.changeVelocity(-maxBoatSpeed / 100);
|
yacht.changeVelocity(-maxBoatSpeed / 100);
|
||||||
} else {
|
} else {
|
||||||
@@ -317,6 +369,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we pass the start line gate in the correct direction, progress
|
* If we pass the start line gate in the correct direction, progress
|
||||||
*
|
*
|
||||||
@@ -449,6 +502,50 @@ public class GameState implements Runnable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Mark markCollidedWith(ServerYacht yacht) {
|
||||||
|
Set<Mark> marksInRace = GameState.getMarks();
|
||||||
|
for (Mark mark : marksInRace) {
|
||||||
|
if (GeoUtility.getDistance(yacht.getLocation(), mark)
|
||||||
|
<= MARK_COLLISION_DISTANCE) {
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the new position of the boat after it has had a collision
|
||||||
|
*
|
||||||
|
* @return The boats new position
|
||||||
|
*/
|
||||||
|
private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith, Double bounceDistance) {
|
||||||
|
Double heading = GeoUtility.getBearing(yacht.getLocation(), collidedWith);
|
||||||
|
// Invert heading
|
||||||
|
heading -= 180;
|
||||||
|
Integer newHeading = Math.floorMod(heading.intValue(), 360);
|
||||||
|
return GeoUtility.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collision detection which iterates through all the yachts and check if any yacht collided
|
||||||
|
* with this yacht. Return collided yacht or null if no collision.
|
||||||
|
*
|
||||||
|
* @return yacht to compare to all other yachts.
|
||||||
|
*/
|
||||||
|
private static ServerYacht checkCollision(ServerYacht yacht) {
|
||||||
|
|
||||||
|
for (ServerYacht otherYacht : GameState.getYachts().values()) {
|
||||||
|
if (otherYacht != yacht) {
|
||||||
|
Double distance = GeoUtility.getDistance(otherYacht.getLocation(), yacht.getLocation());
|
||||||
|
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||||
|
return otherYacht;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void sendMarkRoundingMessage(ServerYacht yacht) {
|
private void sendMarkRoundingMessage(ServerYacht yacht) {
|
||||||
Integer sourceID = yacht.getSourceId();
|
Integer sourceID = yacht.getSourceId();
|
||||||
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
|
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
|
||||||
@@ -461,11 +558,14 @@ public class GameState implements Runnable {
|
|||||||
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
|
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
|
||||||
roundingMark.getSourceID());
|
roundingMark.getSourceID());
|
||||||
|
|
||||||
for (MarkPassingListener mpl : markListeners) {
|
notifyMessageListeners(markRoundingMessage);
|
||||||
mpl.markPassing(markRoundingMessage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void notifyMessageListeners(Message message) {
|
||||||
|
for (NewMessageListener mpl : markListeners) {
|
||||||
|
mpl.notify(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void logMarkRounding(ServerYacht yacht) {
|
private void logMarkRounding(ServerYacht yacht) {
|
||||||
Mark roundingMark = yacht.getClosestCurrentMark();
|
Mark roundingMark = yacht.getClosestCurrentMark();
|
||||||
@@ -475,7 +575,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void addMarkPassListener(MarkPassingListener listener) {
|
public static void addMarkPassListener(NewMessageListener listener) {
|
||||||
markListeners.add(listener);
|
markListeners.add(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,22 @@ import java.io.IOException;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Observable;
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import seng302.gameServer.server.messages.Message;
|
import seng302.gameServer.server.messages.Message;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.visualiser.GameClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing the overall server, which creates and collects server threads for each client
|
* A class describing the overall server, which creates and collects server threads for each client
|
||||||
* Created by wmu16 on 13/07/17.
|
* Created by wmu16 on 13/07/17.
|
||||||
*/
|
*/
|
||||||
public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{
|
public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
||||||
|
|
||||||
private static final int PORT = 4942;
|
private static final int PORT = 4942;
|
||||||
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
||||||
@@ -27,6 +31,8 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
|
|
||||||
|
private GameClient gameClient;
|
||||||
|
|
||||||
public MainServerThread() {
|
public MainServerThread() {
|
||||||
new GameState("localhost");
|
new GameState("localhost");
|
||||||
try {
|
try {
|
||||||
@@ -47,7 +53,6 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
HeartbeatThread heartbeatThread;
|
HeartbeatThread heartbeatThread;
|
||||||
|
|
||||||
serverListenThread = new ServerListenThread(serverSocket, this);
|
serverListenThread = new ServerListenThread(serverSocket, this);
|
||||||
|
|
||||||
heartbeatThread = new HeartbeatThread(this);
|
heartbeatThread = new HeartbeatThread(this);
|
||||||
|
|
||||||
heartbeatThread.start();
|
heartbeatThread.start();
|
||||||
@@ -98,14 +103,16 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serverLog(String message, int logLevel){
|
static void serverLog(String message, int logLevel) {
|
||||||
if(logLevel <= LOG_LEVEL){
|
if (logLevel <= LOG_LEVEL) {
|
||||||
System.out.println("[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
System.out.println(
|
||||||
|
"[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client has tried to connect to the server
|
* A client has tried to connect to the server
|
||||||
|
*
|
||||||
* @param serverToClientThread The player that connected
|
* @param serverToClientThread The player that connected
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -121,6 +128,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A player has left the game, remove the player from the GameState
|
* A player has left the game, remove the player from the GameState
|
||||||
|
*
|
||||||
* @param player The player that left
|
* @param player The player that left
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -142,11 +150,10 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
setChanged();
|
|
||||||
notifyObservers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public void startGame() {
|
||||||
|
initialiseBoatPositions();
|
||||||
Timer t = new Timer();
|
Timer t = new Timer();
|
||||||
|
|
||||||
t.schedule(new TimerTask() {
|
t.schedule(new TimerTask() {
|
||||||
@@ -163,4 +170,56 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
|
|||||||
public void terminate() {
|
public void terminate() {
|
||||||
terminated = true;
|
terminated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass GameClient to main server thread so it can access the properties inside.
|
||||||
|
*
|
||||||
|
* @param gameClient gameClient
|
||||||
|
*/
|
||||||
|
public void setGameClient(GameClient gameClient) {
|
||||||
|
this.gameClient = gameClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise boats to specific spaced out geopoints behind starting line.
|
||||||
|
*/
|
||||||
|
private void initialiseBoatPositions() {
|
||||||
|
// Getting the start line compound marks
|
||||||
|
CompoundMark cm = gameClient.getCourseData().getCompoundMarks().get(1);
|
||||||
|
GeoPoint startMark1 = new GeoPoint(cm.getMarks().get(0).getLat(),
|
||||||
|
cm.getMarks().get(0).getLng());
|
||||||
|
GeoPoint startMark2 = new GeoPoint(cm.getMarks().get(1).getLat(),
|
||||||
|
cm.getMarks().get(1).getLng());
|
||||||
|
|
||||||
|
// Calculating midpoint
|
||||||
|
Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
|
||||||
|
Double length = GeoUtility.getDistance(startMark1, startMark2);
|
||||||
|
GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
|
||||||
|
|
||||||
|
// Setting each boats position side by side
|
||||||
|
double DISTANCE_FACTOR = 50.0; // distance apart in meters
|
||||||
|
int boatIndex = 0;
|
||||||
|
for (ServerYacht yacht : GameState.getYachts().values()) {
|
||||||
|
int distanceApart = boatIndex / 2;
|
||||||
|
|
||||||
|
if (boatIndex % 2 == 1 && boatIndex != 0) {
|
||||||
|
distanceApart++;
|
||||||
|
distanceApart *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeoPoint spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * DISTANCE_FACTOR);
|
||||||
|
|
||||||
|
if (yacht.getHeading() < perpendicularAngle) {
|
||||||
|
spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCE_FACTOR);
|
||||||
|
} else {
|
||||||
|
spawnMark = GeoUtility
|
||||||
|
.getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCE_FACTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
yacht.setLocation(spawnMark);
|
||||||
|
boatIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ import java.util.zip.CRC32;
|
|||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.server.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.stream.packets.PacketType;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.model.stream.xml.generator.Race;
|
||||||
|
import seng302.model.stream.xml.generator.Regatta;
|
||||||
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.gameServer.server.messages.BoatAction;
|
import seng302.gameServer.server.messages.BoatAction;
|
||||||
import seng302.gameServer.server.messages.BoatLocationMessage;
|
import seng302.gameServer.server.messages.BoatLocationMessage;
|
||||||
import seng302.gameServer.server.messages.BoatStatus;
|
|
||||||
import seng302.gameServer.server.messages.BoatSubMessage;
|
import seng302.gameServer.server.messages.BoatSubMessage;
|
||||||
import seng302.gameServer.server.messages.ClientType;
|
import seng302.gameServer.server.messages.ClientType;
|
||||||
import seng302.gameServer.server.messages.Message;
|
import seng302.gameServer.server.messages.Message;
|
||||||
@@ -32,13 +38,7 @@ import seng302.gameServer.server.messages.RegistrationResponseMessage;
|
|||||||
import seng302.gameServer.server.messages.RegistrationResponseStatus;
|
import seng302.gameServer.server.messages.RegistrationResponseStatus;
|
||||||
import seng302.gameServer.server.messages.XMLMessage;
|
import seng302.gameServer.server.messages.XMLMessage;
|
||||||
import seng302.gameServer.server.messages.XMLMessageSubType;
|
import seng302.gameServer.server.messages.XMLMessageSubType;
|
||||||
import seng302.model.Player;
|
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.packets.PacketType;
|
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
|
||||||
import seng302.model.stream.xml.generator.Race;
|
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
|
||||||
import seng302.utilities.XMLGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
||||||
@@ -75,6 +75,8 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
|
|
||||||
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
private ServerYacht yacht;
|
||||||
|
|
||||||
public ServerToClientThread(Socket socket) {
|
public ServerToClientThread(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
seqNo = 0;
|
seqNo = 0;
|
||||||
@@ -167,7 +169,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
int sync2;
|
int sync2;
|
||||||
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
|
|
||||||
|
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -346,6 +347,14 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServerYacht getYacht() {
|
||||||
|
return yacht;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendCollisionMessage(Integer yachtId) {
|
||||||
|
sendMessage(new YachtEventCodeMessage(yachtId));
|
||||||
|
}
|
||||||
|
|
||||||
public void addConnectionListener(ConnectionListener listener) {
|
public void addConnectionListener(ConnectionListener listener) {
|
||||||
connectionListeners.add(listener);
|
connectionListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package seng302.gameServer.server.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by zyt10 on 10/08/17.
|
||||||
|
*/
|
||||||
|
public class YachtEventCodeMessage extends Message {
|
||||||
|
|
||||||
|
private final MessageType MESSAGE_TYPE = MessageType.YACHT_EVENT_CODE;
|
||||||
|
private final int MESSAGE_VERSION = 1; //Always set to 1
|
||||||
|
private final int MESSAGE_SIZE = 22;
|
||||||
|
|
||||||
|
// Message fields
|
||||||
|
private long timeStamp;
|
||||||
|
private long ack = 0x00; //Unused
|
||||||
|
private int raceId;
|
||||||
|
private int destSourceId;
|
||||||
|
private int incidentId;
|
||||||
|
private int eventId;
|
||||||
|
|
||||||
|
|
||||||
|
public YachtEventCodeMessage(Integer subjectId) {
|
||||||
|
timeStamp = System.currentTimeMillis() / 1000L;
|
||||||
|
ack = 0;
|
||||||
|
raceId = 1;
|
||||||
|
destSourceId = subjectId; // collision boat source id
|
||||||
|
incidentId = 0;
|
||||||
|
eventId = 33;
|
||||||
|
|
||||||
|
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
||||||
|
allocateBuffer();
|
||||||
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
|
// Write message fields
|
||||||
|
putUnsignedByte((byte) MESSAGE_VERSION);
|
||||||
|
putInt((int) timeStamp, 6);
|
||||||
|
putInt((int) ack, 2);
|
||||||
|
putInt((int) raceId, 4);
|
||||||
|
putInt((int) destSourceId, 4);
|
||||||
|
putInt((int) incidentId, 4);
|
||||||
|
putInt((int) eventId, 1);
|
||||||
|
|
||||||
|
writeCRC();
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The length of this message
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
return MESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,9 @@ package seng302.model;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||||
import javafx.beans.property.ReadOnlyLongProperty;
|
import javafx.beans.property.ReadOnlyLongProperty;
|
||||||
@@ -12,31 +13,23 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.GameState;
|
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.utilities.GeoUtility;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat.
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
*
|
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
||||||
* Class created to store more variables (eg. boat statuses) compared to the XMLParser boat class,
|
* not used anymore.
|
||||||
* also done outside Boat class because some old variables are not used anymore.
|
|
||||||
*/
|
*/
|
||||||
public class ClientYacht {
|
public class ClientYacht extends Observable {
|
||||||
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface YachtLocationListener {
|
public interface YachtLocationListener {
|
||||||
|
void notifyLocation(ClientYacht clientYacht, double lat, double lon, double heading,
|
||||||
void notifyLocation(ClientYacht yacht, double lat, double lon, double heading,
|
Boolean sailsIn, double velocity);
|
||||||
double velocity, boolean sailIn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
||||||
|
|
||||||
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 3/08/17 wmu16 - Look into this value further
|
|
||||||
|
|
||||||
|
|
||||||
//BOTH AFAIK
|
//BOTH AFAIK
|
||||||
private String boatType;
|
private String boatType;
|
||||||
@@ -47,29 +40,15 @@ public class ClientYacht {
|
|||||||
private String country;
|
private String country;
|
||||||
|
|
||||||
private Long estimateTimeAtFinish;
|
private Long estimateTimeAtFinish;
|
||||||
|
private Boolean sailIn = false;
|
||||||
private Integer currentMarkSeqID = 0;
|
private Integer currentMarkSeqID = 0;
|
||||||
private Long markRoundTime;
|
private Long markRoundTime;
|
||||||
private Double distanceToCurrentMark;
|
|
||||||
private Long timeTillNext;
|
private Long timeTillNext;
|
||||||
private Double heading;
|
private Double heading;
|
||||||
private Integer legNumber = 0;
|
private Integer legNumber = 0;
|
||||||
|
|
||||||
//SERVER SIDE
|
|
||||||
public static final Double TURN_STEP = 5.0; //This should be in some utils class somewhere 2bh. Public for tests sake.
|
|
||||||
private Double lastHeading;
|
|
||||||
private Boolean sailIn = false;
|
|
||||||
private GeoPoint location;
|
private GeoPoint location;
|
||||||
private Integer boatStatus;
|
private Integer boatStatus;
|
||||||
private Double velocity;
|
private Double currentVelocity;
|
||||||
private Boolean isAuto;
|
|
||||||
private Double autoHeading;
|
|
||||||
|
|
||||||
//MARK ROUNDING INFO
|
|
||||||
private GeoPoint lastLocation; //For purposes of mark rounding calculations
|
|
||||||
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
|
|
||||||
private Boolean hasPassedLine;
|
|
||||||
private Boolean hasPassedThroughGate;
|
|
||||||
private Boolean finishedRace;
|
|
||||||
|
|
||||||
//CLIENT SIDE
|
//CLIENT SIDE
|
||||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||||
@@ -79,7 +58,6 @@ public class ClientYacht {
|
|||||||
private CompoundMark lastMarkRounded;
|
private CompoundMark lastMarkRounded;
|
||||||
private Integer positionInt = 0;
|
private Integer positionInt = 0;
|
||||||
private Color colour;
|
private Color colour;
|
||||||
private Boolean clientSailsIn = true;
|
|
||||||
|
|
||||||
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
||||||
String boatName, String country) {
|
String boatName, String country) {
|
||||||
@@ -89,389 +67,19 @@ public class ClientYacht {
|
|||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
this.boatName = boatName;
|
this.boatName = boatName;
|
||||||
this.country = country;
|
this.country = country;
|
||||||
this.sailIn = false;
|
|
||||||
this.isAuto = false;
|
|
||||||
this.location = new GeoPoint(57.670341, 11.826856);
|
this.location = new GeoPoint(57.670341, 11.826856);
|
||||||
this.lastLocation = location;
|
|
||||||
this.heading = 120.0; //In degrees
|
this.heading = 120.0; //In degrees
|
||||||
this.velocity = 0d; //in mms-1
|
this.currentVelocity = 0d;
|
||||||
|
this.boatStatus = 1;
|
||||||
this.hasEnteredRoundingZone = false;
|
|
||||||
this.hasPassedLine = false;
|
|
||||||
this.hasPassedThroughGate = false;
|
|
||||||
this.finishedRace = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param timeInterval since last update in milliseconds
|
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
||||||
|
* rounding package.
|
||||||
*/
|
*/
|
||||||
public void update(Long timeInterval) {
|
@Override
|
||||||
|
public void addObserver(Observer o) {
|
||||||
Double secondsElapsed = timeInterval / 1000000.0;
|
super.addObserver(o);
|
||||||
Double windSpeedKnots = GameState.getWindSpeedKnots();
|
|
||||||
Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading);
|
|
||||||
Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle);
|
|
||||||
Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000;
|
|
||||||
if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
|
|
||||||
|
|
||||||
if (velocity < maxBoatSpeed) {
|
|
||||||
velocity += maxBoatSpeed / 15; // Acceleration
|
|
||||||
}
|
|
||||||
if (velocity > maxBoatSpeed) {
|
|
||||||
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // Deceleration
|
|
||||||
|
|
||||||
if (velocity > 0d) {
|
|
||||||
if (maxBoatSpeed != 0d) {
|
|
||||||
velocity -= maxBoatSpeed / 600;
|
|
||||||
} else {
|
|
||||||
velocity -= velocity / 100;
|
|
||||||
}
|
|
||||||
if (velocity < 0) {
|
|
||||||
velocity = 0d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runAutoPilot();
|
|
||||||
|
|
||||||
//UPDATE BOAT LOCATION
|
|
||||||
lastLocation = location;
|
|
||||||
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
|
|
||||||
|
|
||||||
//CHECK FOR MARK ROUNDING
|
|
||||||
if (!finishedRace) {
|
|
||||||
checkForLegProgression();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 3/08/17 wmu16 - Implement line cross check here
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the distance to the next mark (closest of the two if a gate mark). For purposes
|
|
||||||
* of mark rounding
|
|
||||||
*
|
|
||||||
* @return A distance in metres. Returns -1 if there is no next mark
|
|
||||||
* @throws IndexOutOfBoundsException If the next mark is null (ie the last mark in the race)
|
|
||||||
* Check first using {@link seng302.model.mark.MarkOrder#isLastMark(Integer)}
|
|
||||||
*/
|
|
||||||
public Double calcDistanceToCurrentMark() throws IndexOutOfBoundsException {
|
|
||||||
CompoundMark nextMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
|
||||||
|
|
||||||
if (nextMark.isGate()) {
|
|
||||||
Mark sub1 = nextMark.getSubMark(1);
|
|
||||||
Mark sub2 = nextMark.getSubMark(2);
|
|
||||||
Double distance1 = GeoUtility.getDistance(location, sub1);
|
|
||||||
Double distance2 = GeoUtility.getDistance(location, sub2);
|
|
||||||
return (distance1 < distance2) ? distance1 : distance2;
|
|
||||||
} else {
|
|
||||||
return GeoUtility.getDistance(location, nextMark.getSubMark(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 4 Different cases of progression in the race
|
|
||||||
* 1 - Passing the start line
|
|
||||||
* 2 - Passing any in-race Gate
|
|
||||||
* 3 - Passing any in-race Mark
|
|
||||||
* 4 - Passing the finish line
|
|
||||||
*/
|
|
||||||
private void checkForLegProgression() {
|
|
||||||
CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
|
||||||
if (currentMarkSeqID == 0) {
|
|
||||||
checkStartLineCrossing(currentMark);
|
|
||||||
} else if (GameState.getMarkOrder().isLastMark(currentMarkSeqID)) {
|
|
||||||
checkFinishLineCrossing(currentMark);
|
|
||||||
} else if (currentMark.isGate()) {
|
|
||||||
checkGateRounding(currentMark);
|
|
||||||
} else {
|
|
||||||
checkMarkRounding(currentMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we pass the start line gate in the correct direction, progress
|
|
||||||
*
|
|
||||||
* @param currentMark The current gate
|
|
||||||
*/
|
|
||||||
private void checkStartLineCrossing(CompoundMark currentMark) {
|
|
||||||
Mark mark1 = currentMark.getSubMark(1);
|
|
||||||
Mark mark2 = currentMark.getSubMark(2);
|
|
||||||
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
|
|
||||||
|
|
||||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
|
||||||
if (crossedLine > 0) {
|
|
||||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, nextMark.getMidPoint());
|
|
||||||
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
|
|
||||||
currentMarkSeqID++;
|
|
||||||
logMarkRounding(currentMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This algorithm checks for mark rounding. And increments the currentMarSeqID number attribute
|
|
||||||
* of the yacht if so.
|
|
||||||
* A visual representation of this algorithm can be seen on the Wiki under
|
|
||||||
* 'mark passing algorithm'
|
|
||||||
*/
|
|
||||||
private void checkMarkRounding(CompoundMark currentMark) {
|
|
||||||
distanceToCurrentMark = calcDistanceToCurrentMark();
|
|
||||||
GeoPoint nextPoint = GameState.getMarkOrder().getNextMark(currentMarkSeqID).getMidPoint();
|
|
||||||
GeoPoint prevPoint = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID)
|
|
||||||
.getMidPoint();
|
|
||||||
GeoPoint midPoint = GeoUtility.getDirtyMidPoint(nextPoint, prevPoint);
|
|
||||||
|
|
||||||
//1 TEST FOR ENTERING THE ROUNDING DISTANCE
|
|
||||||
if (distanceToCurrentMark < ROUNDING_DISTANCE) {
|
|
||||||
hasEnteredRoundingZone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//In case current mark is a gate, loop through all marks just in case
|
|
||||||
for (Mark thisCurrentMark : currentMark.getMarks()) {
|
|
||||||
if (GeoUtility.isPointInTriangle(lastLocation, location, midPoint, thisCurrentMark)) {
|
|
||||||
hasPassedLine = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPassedLine && hasEnteredRoundingZone) {
|
|
||||||
currentMarkSeqID++;
|
|
||||||
hasPassedLine = false;
|
|
||||||
hasEnteredRoundingZone = false;
|
|
||||||
hasPassedThroughGate = false;
|
|
||||||
logMarkRounding(currentMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a gate line has been crossed and in the correct direction
|
|
||||||
*
|
|
||||||
* @param currentMark The current gate
|
|
||||||
*/
|
|
||||||
private void checkGateRounding(CompoundMark currentMark) {
|
|
||||||
Mark mark1 = currentMark.getSubMark(1);
|
|
||||||
Mark mark2 = currentMark.getSubMark(2);
|
|
||||||
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
|
|
||||||
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
|
|
||||||
|
|
||||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
|
||||||
|
|
||||||
//We have crossed the line
|
|
||||||
if (crossedLine > 0) {
|
|
||||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
|
||||||
|
|
||||||
//Check we cross the line in the correct direction
|
|
||||||
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
|
||||||
hasPassedThroughGate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean prevMarkSide = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
|
||||||
Boolean nextMarkSide = GeoUtility.isClockwise(mark1, mark2, nextMark.getMidPoint());
|
|
||||||
|
|
||||||
if (hasPassedThroughGate) {
|
|
||||||
//Check if we need to round this gate after passing through
|
|
||||||
if (prevMarkSide == nextMarkSide) {
|
|
||||||
checkMarkRounding(currentMark);
|
|
||||||
} else {
|
|
||||||
currentMarkSeqID++;
|
|
||||||
logMarkRounding(currentMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we pass the finish gate in the correct direction
|
|
||||||
*
|
|
||||||
* @param currentMark The current gate
|
|
||||||
*/
|
|
||||||
private void checkFinishLineCrossing(CompoundMark currentMark) {
|
|
||||||
Mark mark1 = currentMark.getSubMark(1);
|
|
||||||
Mark mark2 = currentMark.getSubMark(2);
|
|
||||||
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
|
|
||||||
|
|
||||||
Integer crossedLine = GeoUtility.checkCrossedLine(mark1, mark2, lastLocation, location);
|
|
||||||
if (crossedLine > 0) {
|
|
||||||
Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint());
|
|
||||||
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
|
|
||||||
currentMarkSeqID++;
|
|
||||||
finishedRace = true;
|
|
||||||
logMarkRounding(currentMark);
|
|
||||||
logger.debug(sourceId + " finished");
|
|
||||||
// TODO: 8/08/17 wmu16 - Do something!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts the heading of the boat by a given amount, while recording the boats
|
|
||||||
* last heading.
|
|
||||||
*
|
|
||||||
* @param amount the amount by which to adjust the boat heading.
|
|
||||||
*/
|
|
||||||
public void adjustHeading(Double amount) {
|
|
||||||
Double newVal = heading + amount;
|
|
||||||
lastHeading = heading;
|
|
||||||
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swaps the boats direction from one side of the wind to the other.
|
|
||||||
*/
|
|
||||||
public void tackGybe(Double windDirection) {
|
|
||||||
if (isAuto) {
|
|
||||||
disableAutoPilot();
|
|
||||||
} else {
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
Double newVal = (-2 * normalizedHeading) + heading;
|
|
||||||
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
|
|
||||||
setAutoPilot(newHeading);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
|
|
||||||
*
|
|
||||||
* @param thisHeading The heading to move the boat towards.
|
|
||||||
*/
|
|
||||||
private void setAutoPilot(Double thisHeading) {
|
|
||||||
isAuto = true;
|
|
||||||
autoHeading = thisHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the auto pilot function.
|
|
||||||
*/
|
|
||||||
public void disableAutoPilot() {
|
|
||||||
isAuto = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
|
|
||||||
* in the event that the boat is within the range of 1 turn step of its goal.
|
|
||||||
*/
|
|
||||||
public void runAutoPilot() {
|
|
||||||
if (isAuto) {
|
|
||||||
turnTowardsHeading(autoHeading);
|
|
||||||
if (Math.abs(heading - autoHeading)
|
|
||||||
<= TURN_STEP) { //Cancel when within 1 turn step of target.
|
|
||||||
isAuto = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleSailIn() {
|
|
||||||
sailIn = !sailIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void turnUpwind() {
|
|
||||||
disableAutoPilot();
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
if (normalizedHeading == 0) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void turnDownwind() {
|
|
||||||
disableAutoPilot();
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
if (normalizedHeading == 0) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(TURN_STEP);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
|
|
||||||
* and uses this to calculate a heading to move the yacht towards.
|
|
||||||
*/
|
|
||||||
public void turnToVMG() {
|
|
||||||
if (isAuto) {
|
|
||||||
disableAutoPilot();
|
|
||||||
} else {
|
|
||||||
Double normalizedHeading = normalizeHeading();
|
|
||||||
Double optimalHeading;
|
|
||||||
HashMap<Double, Double> optimalPolarMap;
|
|
||||||
|
|
||||||
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
|
|
||||||
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
|
|
||||||
} else {
|
|
||||||
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
|
|
||||||
}
|
|
||||||
optimalHeading = optimalPolarMap.keySet().iterator().next();
|
|
||||||
|
|
||||||
if (normalizedHeading > 180) {
|
|
||||||
optimalHeading = 360 - optimalHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take optimal heading and turn into a boat heading rather than a wind heading.
|
|
||||||
optimalHeading =
|
|
||||||
optimalHeading + GameState.getWindDirection();
|
|
||||||
|
|
||||||
setAutoPilot(optimalHeading);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a given heading and rotates the boat towards that heading.
|
|
||||||
* This does not care about being upwind or downwind, just which direction will reach a given
|
|
||||||
* heading faster.
|
|
||||||
*
|
|
||||||
* @param newHeading The heading to turn the yacht towards.
|
|
||||||
*/
|
|
||||||
private void turnTowardsHeading(Double newHeading) {
|
|
||||||
Double newVal = heading - newHeading;
|
|
||||||
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
|
|
||||||
adjustHeading(TURN_STEP / 5);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-TURN_STEP / 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a heading normalized for the wind direction. Heading direction into the wind is 0,
|
|
||||||
* directly away is 180.
|
|
||||||
*
|
|
||||||
* @return The normalized heading accounting for wind direction.
|
|
||||||
*/
|
|
||||||
private Double normalizeHeading() {
|
|
||||||
Double normalizedHeading = heading - GameState.windDirection;
|
|
||||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
|
||||||
return normalizedHeading;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBoatType() {
|
public String getBoatType() {
|
||||||
@@ -521,9 +129,6 @@ public class ClientYacht {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLegNumber(Integer legNumber) {
|
public void setLegNumber(Integer legNumber) {
|
||||||
// if (colour != null && position != "-" && legNumber != this.legNumber) {
|
|
||||||
// RaceViewController.updateYachtPositionSparkline(this, legNumber);
|
|
||||||
// }
|
|
||||||
this.legNumber = legNumber;
|
this.legNumber = legNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,18 +165,10 @@ public class ClientYacht {
|
|||||||
return velocityProperty.getReadOnlyProperty();
|
return velocityProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getVelocityMMS() {
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyLongProperty timeTillNextProperty() {
|
public ReadOnlyLongProperty timeTillNextProperty() {
|
||||||
return timeTillNextProperty.getReadOnlyProperty();
|
return timeTillNextProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getVelocityKnots() {
|
|
||||||
return velocity / 1000 * 1.943844492; // TODO: 26/07/17 cir27 - remove magic number
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getTimeTillNext() {
|
public Long getTimeTillNext() {
|
||||||
return timeTillNext;
|
return timeTillNext;
|
||||||
}
|
}
|
||||||
@@ -592,6 +189,11 @@ public class ClientYacht {
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toggleSail() {
|
||||||
|
sailIn = !sailIn;
|
||||||
|
}
|
||||||
|
//// TODO: 15/08/17 asd
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current location of the boat in lat and long whilst preserving the last location
|
* Sets the current location of the boat in lat and long whilst preserving the last location
|
||||||
*
|
*
|
||||||
@@ -599,8 +201,6 @@ public class ClientYacht {
|
|||||||
* @param lng Longitude
|
* @param lng Longitude
|
||||||
*/
|
*/
|
||||||
public void setLocation(Double lat, Double lng) {
|
public void setLocation(Double lat, Double lng) {
|
||||||
lastLocation.setLat(location.getLat());
|
|
||||||
lastLocation.setLng(location.getLng());
|
|
||||||
location.setLat(lat);
|
location.setLat(lat);
|
||||||
location.setLng(lng);
|
location.setLng(lng);
|
||||||
}
|
}
|
||||||
@@ -613,10 +213,6 @@ public class ClientYacht {
|
|||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getSailIn() {
|
|
||||||
return sailIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return boatName;
|
return boatName;
|
||||||
@@ -626,7 +222,7 @@ public class ClientYacht {
|
|||||||
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
|
this.timeSinceLastMarkProperty.set(timeSinceLastMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyLongProperty timeSinceLastMarkProperty () {
|
public ReadOnlyLongProperty timeSinceLastMarkProperty() {
|
||||||
return timeSinceLastMarkProperty.getReadOnlyProperty();
|
return timeSinceLastMarkProperty.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,51 +239,30 @@ public class ClientYacht {
|
|||||||
this.colour = colour;
|
this.colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleClientSail() {
|
// public Double getCurrentVelocity() {
|
||||||
clientSailsIn = !clientSailsIn;
|
// return currentVelocity;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// public void setCurrentVelocity(Double currentVelocity) {
|
||||||
|
// this.currentVelocity = currentVelocity;
|
||||||
|
// }
|
||||||
|
|
||||||
public Double getVelocity() {
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVelocity(Double velocity) {
|
|
||||||
this.velocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getDistanceToCurrentMark() {
|
|
||||||
return distanceToCurrentMark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getClientSailsIn() {
|
|
||||||
return clientSailsIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
public void updateLocation(double lat, double lng, double heading, double velocity) {
|
||||||
setLocation(lat, lng);
|
setLocation(lat, lng);
|
||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
this.velocity = velocity;
|
// this.currentVelocity = velocity;
|
||||||
updateVelocityProperty(velocity);
|
updateVelocityProperty(velocity);
|
||||||
for (YachtLocationListener yll : locationListeners) {
|
for (YachtLocationListener yll : locationListeners) {
|
||||||
yll.notifyLocation(this, lat, lng, heading, velocity, clientSailsIn);
|
yll.notifyLocation(this, lat, lng, heading, sailIn, velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMarkRounding(CompoundMark currentMark) {
|
|
||||||
String typeString = "mark";
|
|
||||||
if (currentMark.isGate()) {
|
|
||||||
typeString = "gate";
|
|
||||||
}
|
|
||||||
logger.debug(
|
|
||||||
String.format("BoatID %d passed %s %s with id %d. Now on leg %d",
|
|
||||||
sourceId,
|
|
||||||
typeString,
|
|
||||||
currentMark.getMarks().get(0).getName(),
|
|
||||||
currentMark.getId(),
|
|
||||||
currentMarkSeqID));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addLocationListener(YachtLocationListener listener) {
|
public void addLocationListener(YachtLocationListener listener) {
|
||||||
locationListeners.add(listener);
|
locationListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getSailIn () {
|
||||||
|
return sailIn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import javafx.scene.paint.Color;
|
|||||||
* Enum for generating colours.
|
* Enum for generating colours.
|
||||||
*/
|
*/
|
||||||
public enum Colors {
|
public enum Colors {
|
||||||
RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE;
|
RED, PERU, GOLD, GREEN, BLUE, PURPLE, DEEPPINK, GRAY;
|
||||||
|
|
||||||
static Integer index = 0;
|
static Integer index = 0;
|
||||||
|
|
||||||
public static Color getColor() {
|
public static Color getColor() {
|
||||||
if (index == 6) {
|
if (index == 8) {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
return Color.valueOf(values()[index++].toString());
|
return Color.valueOf(values()[index++].toString());
|
||||||
|
|||||||
@@ -28,4 +28,9 @@ public class GeoPoint {
|
|||||||
public void setLng(double lng) {
|
public void setLng(double lng) {
|
||||||
this.lng = lng;
|
this.lng = lng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "lat: " + lat + " lng: " + lng;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ public class ServerYacht extends Observable {
|
|||||||
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
|
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLocation(GeoPoint geoPoint) {
|
||||||
|
location = geoPoint;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
||||||
* rounding package.
|
* rounding package.
|
||||||
@@ -386,4 +390,6 @@ public class ServerYacht extends Observable {
|
|||||||
public Boolean hasPassedLine() {
|
public Boolean hasPassedLine() {
|
||||||
return hasPassedLine;
|
return hasPassedLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ package seng302.model.mark;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@@ -19,14 +15,15 @@ import seng302.model.stream.xml.generator.Race;
|
|||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to hold the order of the marks in the race.
|
* Class to hold the order of the marks in the race.
|
||||||
*/
|
*/
|
||||||
public class MarkOrder {
|
public class MarkOrder {
|
||||||
|
|
||||||
private List<CompoundMark> raceMarkOrder;
|
private List<CompoundMark> raceMarkOrder;
|
||||||
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
||||||
|
private Set<Mark> allMarks;
|
||||||
|
|
||||||
public MarkOrder(){
|
public MarkOrder(){
|
||||||
loadRaceProperties();
|
loadRaceProperties();
|
||||||
@@ -76,6 +73,10 @@ public class MarkOrder {
|
|||||||
return raceMarkOrder.get(currentSeqID + 1);
|
return raceMarkOrder.get(currentSeqID + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Mark> getAllMarks(){
|
||||||
|
return Collections.unmodifiableSet(allMarks);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the race order from an XML string
|
* Loads the race order from an XML string
|
||||||
* @param xml An AC35 RaceXML
|
* @param xml An AC35 RaceXML
|
||||||
@@ -86,6 +87,7 @@ public class MarkOrder {
|
|||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
Document doc;
|
Document doc;
|
||||||
|
allMarks = new HashSet<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db = dbf.newDocumentBuilder();
|
db = dbf.newDocumentBuilder();
|
||||||
@@ -107,6 +109,7 @@ public class MarkOrder {
|
|||||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
||||||
compoundMark.setRoundingSide(RoundingSide.getRoundingSide(corner.getRounding()));
|
compoundMark.setRoundingSide(RoundingSide.getRoundingSide(corner.getRounding()));
|
||||||
course.add(compoundMark);
|
course.add(compoundMark);
|
||||||
|
allMarks.addAll(compoundMark.getMarks());
|
||||||
}
|
}
|
||||||
|
|
||||||
return course;
|
return course;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package seng302.model.stream.parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores parsed data from yacht event code packet
|
||||||
|
*/
|
||||||
|
public class YachtEventData {
|
||||||
|
private Long subjectId;
|
||||||
|
private Long incidentId;
|
||||||
|
private Integer eventId;
|
||||||
|
private Long timeStamp;
|
||||||
|
|
||||||
|
public YachtEventData(Long subjectId, Long incidentId, Integer eventId, Long timeStamp) {
|
||||||
|
this.subjectId = subjectId;
|
||||||
|
this.incidentId = incidentId;
|
||||||
|
this.eventId = eventId;
|
||||||
|
this.timeStamp = timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSubjectId() {
|
||||||
|
return subjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getIncidentId() {
|
||||||
|
return incidentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getEventId() {
|
||||||
|
return eventId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTimeStamp() {
|
||||||
|
return timeStamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,15 +13,12 @@ import org.xml.sax.InputSource;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import seng302.model.stream.packets.PacketType;
|
import seng302.model.stream.packets.PacketType;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.parser.MarkRoundingData;
|
import seng302.model.stream.parser.*;
|
||||||
import seng302.model.stream.parser.PositionUpdateData;
|
|
||||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
||||||
import seng302.model.stream.parser.RaceStartData;
|
|
||||||
import seng302.model.stream.parser.RaceStatusData;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StreamParser is a utilities class for taking byte data, formatted according to the AC35
|
* StreamParser is a utilities class for taking byte data, formatted according to the AC35 streaming
|
||||||
* streaming protocol, and parsing it into basic data types or collections.
|
* protocol, and parsing it into basic data types or collections.
|
||||||
*
|
*
|
||||||
* Created by kre39 on 23/04/17.
|
* Created by kre39 on 23/04/17.
|
||||||
*/
|
*/
|
||||||
@@ -34,8 +31,9 @@ public class StreamParser {
|
|||||||
* @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise.
|
* @return the packet sequence number if the packet is of type HEARTBEAT, null otherwise.
|
||||||
*/
|
*/
|
||||||
public static Long extractHeartBeat(StreamPacket packet) {
|
public static Long extractHeartBeat(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.HEARTBEAT)
|
if (packet.getType() != PacketType.HEARTBEAT) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
long heartbeat = bytesToLong(packet.getPayload());
|
long heartbeat = bytesToLong(packet.getPayload());
|
||||||
System.out.println("heartbeat = " + heartbeat);
|
System.out.println("heartbeat = " + heartbeat);
|
||||||
return heartbeat;
|
return heartbeat;
|
||||||
@@ -52,16 +50,17 @@ public class StreamParser {
|
|||||||
* containing the parsed packet data.
|
* containing the parsed packet data.
|
||||||
*/
|
*/
|
||||||
public static RaceStatusData extractRaceStatus(StreamPacket packet) {
|
public static RaceStatusData extractRaceStatus(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.RACE_STATUS)
|
if (packet.getType() != PacketType.RACE_STATUS) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long currentTime = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 7, 11));
|
||||||
int raceStatus = payload[11];
|
int raceStatus = payload[11];
|
||||||
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload,12,18));
|
long expectedStartTime = bytesToLong(Arrays.copyOfRange(payload, 12, 18));
|
||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
||||||
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22));
|
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
||||||
|
|
||||||
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
||||||
// currentTime = format.format((new Date(currentTime)))
|
// currentTime = format.format((new Date(currentTime)))
|
||||||
@@ -70,7 +69,6 @@ public class StreamParser {
|
|||||||
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// long timeTillStart =
|
// long timeTillStart =
|
||||||
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
||||||
//
|
//
|
||||||
@@ -139,8 +137,9 @@ public class StreamParser {
|
|||||||
* DISPLAY_TEXT_MESSAGE.
|
* DISPLAY_TEXT_MESSAGE.
|
||||||
*/
|
*/
|
||||||
public static List<String> extractDisplayMessage(StreamPacket packet) {
|
public static List<String> extractDisplayMessage(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE)
|
if (packet.getType() != PacketType.DISPLAY_TEXT_MESSAGE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
List<String> message = new ArrayList<>();
|
List<String> message = new ArrayList<>();
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
@@ -166,10 +165,11 @@ public class StreamParser {
|
|||||||
* XML_MESSAGE.
|
* XML_MESSAGE.
|
||||||
*/
|
*/
|
||||||
public static Document extractXmlMessage(StreamPacket packet) {
|
public static Document extractXmlMessage(StreamPacket packet) {
|
||||||
if ( packet.getType() != PacketType.RACE_XML &&
|
if (packet.getType() != PacketType.RACE_XML &&
|
||||||
packet.getType() != PacketType.REGATTA_XML &&
|
packet.getType() != PacketType.REGATTA_XML &&
|
||||||
packet.getType() != PacketType.BOAT_XML )
|
packet.getType() != PacketType.BOAT_XML) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageType = payload[9];
|
int messageType = payload[9];
|
||||||
@@ -194,8 +194,8 @@ public class StreamParser {
|
|||||||
* Extracts the race start status from the packet and returns it as a long array.
|
* Extracts the race start status from the packet and returns it as a long array.
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if
|
* @return An array of form [raceID, raceStartTime, notificationType, timeStamp] or null if the
|
||||||
* the packet type is not of RACE_START_STATUS.
|
* packet type is not of RACE_START_STATUS.
|
||||||
*/
|
*/
|
||||||
public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
|
public static RaceStartData extractRaceStartStatus(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.RACE_START_STATUS) {
|
if (packet.getType() != PacketType.RACE_START_STATUS) {
|
||||||
@@ -212,23 +212,25 @@ public class StreamParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the the byte array in a StreamPacket for yacht events to retrieve the necessary info
|
* Parses the the byte array in a StreamPacket for yacht events to retrieve the necessary info
|
||||||
* and returns it a an array of longs.
|
* and returns it as YachtEventData.
|
||||||
*
|
*
|
||||||
* @param packet Packet parsed in to use the payload
|
* @param packet Packet parsed in to use the payload
|
||||||
* @return the event data in the form [boatID, incidentID, eventID, timeStamp]. Returns null if
|
* @return the event data in the form of YachtEventData. Returns null if the packet is not of
|
||||||
* the packet is not of type YACHT_EVENT_CODE.
|
* type YACHT_EVENT_CODE.
|
||||||
*/
|
*/
|
||||||
public static long[] extractYachtEventCode(StreamPacket packet) {
|
public static YachtEventData extractYachtEventCode(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.YACHT_EVENT_CODE)
|
if (packet.getType() != PacketType.YACHT_EVENT_CODE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
|
long ackNumber = bytesToLong(Arrays.copyOfRange(payload, 7, 9));
|
||||||
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
long raceId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 17, 21));
|
||||||
int eventId = payload[21];
|
int eventId = payload[21];
|
||||||
return new long[] {subjectId, incidentId, eventId, timeStamp};
|
return new YachtEventData(subjectId, incidentId, eventId, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,15 +241,16 @@ public class StreamParser {
|
|||||||
* Returns null if the packet is not of type YACHT_ACTION_CODE.
|
* Returns null if the packet is not of type YACHT_ACTION_CODE.
|
||||||
*/
|
*/
|
||||||
public static long[] extractYachtActionCode(StreamPacket packet) {
|
public static long[] extractYachtActionCode(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.YACHT_ACTION_CODE)
|
if (packet.getType() != PacketType.YACHT_ACTION_CODE) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
long subjectId = bytesToLong(Arrays.copyOfRange(payload, 9, 13));
|
||||||
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
long incidentId = bytesToLong(Arrays.copyOfRange(payload, 13, 17));
|
||||||
int eventId = payload[17];
|
int eventId = payload[17];
|
||||||
return new long[] {subjectId, incidentId, eventId, timeStamp};
|
return new long[]{subjectId, incidentId, eventId, timeStamp};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,8 +261,9 @@ public class StreamParser {
|
|||||||
* CHATTER_TEXT.
|
* CHATTER_TEXT.
|
||||||
*/
|
*/
|
||||||
public static String extractChatterText(StreamPacket packet) {
|
public static String extractChatterText(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.CHATTER_TEXT)
|
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
@@ -276,8 +280,9 @@ public class StreamParser {
|
|||||||
* is not of type BOAT_LOCATION.
|
* is not of type BOAT_LOCATION.
|
||||||
*/
|
*/
|
||||||
public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
|
public static PositionUpdateData extractBoatLocation(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.BOAT_LOCATION)
|
if (packet.getType() != PacketType.BOAT_LOCATION) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int deviceType = (int) payload[15];
|
int deviceType = (int) payload[15];
|
||||||
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeValid = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -293,10 +298,11 @@ public class StreamParser {
|
|||||||
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
|
double groundSpeed = bytesToLong(Arrays.copyOfRange(payload, 38, 40)) / 1000.0;
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
if (deviceType == 1)
|
if (deviceType == 1) {
|
||||||
type = DeviceType.YACHT_TYPE;
|
type = DeviceType.YACHT_TYPE;
|
||||||
else
|
} else {
|
||||||
type = DeviceType.MARK_TYPE;
|
type = DeviceType.MARK_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed);
|
return new PositionUpdateData((int) boatId, type, lat, lon, heading, groundSpeed);
|
||||||
}
|
}
|
||||||
@@ -309,8 +315,9 @@ public class StreamParser {
|
|||||||
* if packet is not of type MARK_ROUNDING.
|
* if packet is not of type MARK_ROUNDING.
|
||||||
*/
|
*/
|
||||||
public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
|
public static MarkRoundingData extractMarkRounding(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.MARK_ROUNDING)
|
if (packet.getType() != PacketType.MARK_ROUNDING) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -325,16 +332,17 @@ public class StreamParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list containing the string value of data within the given stream packet for
|
* Returns a list containing the string value of data within the given stream packet for course
|
||||||
* course wind.
|
* wind.
|
||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
* @return the string values of the wind packet. Returns null if the packet is not of type
|
* @return the string values of the wind packet. Returns null if the packet is not of type
|
||||||
* COURSE_WIND.
|
* COURSE_WIND.
|
||||||
*/
|
*/
|
||||||
public static List<String> extractCourseWind(StreamPacket packet) {
|
public static List<String> extractCourseWind(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.COURSE_WIND)
|
if (packet.getType() != PacketType.COURSE_WIND) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int selectedWindId = payload[1];
|
int selectedWindId = payload[1];
|
||||||
@@ -366,13 +374,13 @@ public class StreamParser {
|
|||||||
* Returns the parsed data from a StreamPacket for average wind data.
|
* Returns the parsed data from a StreamPacket for average wind data.
|
||||||
*
|
*
|
||||||
* @param packet The packet containing the payload
|
* @param packet The packet containing the payload
|
||||||
* @return The wind data in the form
|
* @return The wind data in the form [rawPeriod, rawSamplePeriod, period2, speed2, period3,
|
||||||
* [rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timestamp]
|
* speed3, period4, speed4, timestamp] or null if the packet is not of type AVG_WIND.
|
||||||
* or null if the packet is not of type AVG_WIND.
|
|
||||||
*/
|
*/
|
||||||
public static long[] extractAvgWind(StreamPacket packet) {
|
public static long[] extractAvgWind(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.AVG_WIND)
|
if (packet.getType() != PacketType.AVG_WIND) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
long timeStamp = bytesToLong(Arrays.copyOfRange(payload, 1, 7));
|
||||||
@@ -384,7 +392,7 @@ public class StreamParser {
|
|||||||
long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19));
|
long speed3 = bytesToLong(Arrays.copyOfRange(payload, 17, 19));
|
||||||
long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21));
|
long period4 = bytesToLong(Arrays.copyOfRange(payload, 19, 21));
|
||||||
long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23));
|
long speed4 = bytesToLong(Arrays.copyOfRange(payload, 21, 23));
|
||||||
return new long[] {
|
return new long[]{
|
||||||
rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timeStamp
|
rawPeriod, rawSamplePeriod, period2, speed2, period3, speed3, period4, speed4, timeStamp
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -410,8 +418,7 @@ public class StreamParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* takes an array of up to 7 bytes and returns a positive
|
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
||||||
* long constructed from the input bytes
|
|
||||||
*
|
*
|
||||||
* @param bytes the byte array to conver to Long
|
* @param bytes the byte array to conver to Long
|
||||||
* @return a positive long if there is less than 7 bytes -1 otherwise
|
* @return a positive long if there is less than 7 bytes -1 otherwise
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import seng302.model.stream.parser.MarkRoundingData;
|
|||||||
import seng302.model.stream.parser.PositionUpdateData;
|
import seng302.model.stream.parser.PositionUpdateData;
|
||||||
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
|
||||||
import seng302.model.stream.parser.RaceStatusData;
|
import seng302.model.stream.parser.RaceStatusData;
|
||||||
|
import seng302.model.stream.parser.YachtEventData;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.StreamParser;
|
import seng302.utilities.StreamParser;
|
||||||
@@ -102,6 +103,8 @@ public class GameClient {
|
|||||||
loadStartScreen();
|
loadStartScreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.setGameClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStartScreen() {
|
private void loadStartScreen() {
|
||||||
@@ -126,7 +129,8 @@ public class GameClient {
|
|||||||
* @return the lobby controller.
|
* @return the lobby controller.
|
||||||
*/
|
*/
|
||||||
private LobbyController loadLobby() {
|
private LobbyController loadLobby() {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource("/views/LobbyView.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
|
GameClient.class.getResource("/views/LobbyView.fxml"));
|
||||||
try {
|
try {
|
||||||
holderPane.getChildren().clear();
|
holderPane.getChildren().clear();
|
||||||
holderPane.getChildren().add(fxmlLoader.load());
|
holderPane.getChildren().add(fxmlLoader.load());
|
||||||
@@ -155,6 +159,20 @@ public class GameClient {
|
|||||||
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadFinishScreenView() {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
|
getClass().getResource("/views/FinishScreenView.fxml"));
|
||||||
|
try {
|
||||||
|
final Node finishScreenFX = fxmlLoader.load();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
holderPane.getChildren().clear();
|
||||||
|
holderPane.getChildren().add(finishScreenFX);
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void parsePackets() {
|
private void parsePackets() {
|
||||||
while (socketThread.getPacketQueue().peek() != null) {
|
while (socketThread.getPacketQueue().peek() != null) {
|
||||||
StreamPacket packet = socketThread.getPacketQueue().poll();
|
StreamPacket packet = socketThread.getPacketQueue().poll();
|
||||||
@@ -205,14 +223,19 @@ public class GameClient {
|
|||||||
case MARK_ROUNDING:
|
case MARK_ROUNDING:
|
||||||
updateMarkRounding(StreamParser.extractMarkRounding(packet));
|
updateMarkRounding(StreamParser.extractMarkRounding(packet));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case YACHT_EVENT_CODE:
|
||||||
|
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startRaceIfAllDataReceived() {
|
private void startRaceIfAllDataReceived() {
|
||||||
if (allXMLReceived() && raceView == null)
|
if (allXMLReceived() && raceView == null) {
|
||||||
loadRaceView();
|
loadRaceView();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean allXMLReceived() {
|
private boolean allXMLReceived() {
|
||||||
return courseData != null && allBoatsMap != null && regattaData != null;
|
return courseData != null && allBoatsMap != null && regattaData != null;
|
||||||
@@ -257,8 +280,19 @@ public class GameClient {
|
|||||||
private void processRaceStatusUpdate(RaceStatusData data) {
|
private void processRaceStatusUpdate(RaceStatusData data) {
|
||||||
if (allXMLReceived()) {
|
if (allXMLReceived()) {
|
||||||
raceState.updateState(data);
|
raceState.updateState(data);
|
||||||
if (raceView != null)
|
if (raceView != null) {
|
||||||
raceView.getGameView().setWindDir(raceState.getWindDirection());
|
raceView.getGameView().setWindDir(raceState.getWindDirection());
|
||||||
|
}
|
||||||
|
boolean raceFinished = true;
|
||||||
|
for (ClientYacht yacht : allBoatsMap.values()) {
|
||||||
|
if (yacht.getBoatStatus() != 3) {
|
||||||
|
raceFinished = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (raceFinished == true) {
|
||||||
|
loadFinishScreenView();
|
||||||
|
}
|
||||||
|
|
||||||
for (long[] boatData : data.getBoatData()) {
|
for (long[] boatData : data.getBoatData()) {
|
||||||
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
|
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
|
||||||
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
|
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
|
||||||
@@ -313,11 +347,25 @@ public class GameClient {
|
|||||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
//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
|
case SHIFT: // sails in/sails out
|
||||||
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
raceView.getGameView().getPlayerYacht().toggleClientSail();
|
raceView.getGameView().getPlayerYacht().toggleSail();
|
||||||
break;
|
break;
|
||||||
case PAGE_UP:
|
case PAGE_UP:
|
||||||
case PAGE_DOWN:
|
case PAGE_DOWN:
|
||||||
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RaceXMLData getCourseData() {
|
||||||
|
return courseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells race view to show a collision animation.
|
||||||
|
*/
|
||||||
|
private void showCollisionAlert(YachtEventData yachtEventData) {
|
||||||
|
// 33 is the agreed code to show collision
|
||||||
|
if (yachtEventData.getEventId() == 33) {
|
||||||
|
raceView.showCollision(yachtEventData.getSubjectId());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,23 +7,24 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
|
import javafx.animation.KeyFrame;
|
||||||
|
import javafx.animation.KeyValue;
|
||||||
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.Group;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.KeyCode;
|
|
||||||
import javafx.scene.input.KeyEvent;
|
|
||||||
import javafx.scene.input.ScrollEvent;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import javafx.util.Duration;
|
||||||
import seng302.model.Colors;
|
import seng302.model.Colors;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
@@ -112,7 +113,7 @@ public class GameView extends Pane {
|
|||||||
VERTICAL
|
VERTICAL
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameView () {
|
public GameView() {
|
||||||
gameObjects = this.getChildren();
|
gameObjects = this.getChildren();
|
||||||
// create image view for map, bind panel size to image
|
// create image view for map, bind panel size to image
|
||||||
gameObjects.add(mapImage);
|
gameObjects.add(mapImage);
|
||||||
@@ -122,49 +123,10 @@ public class GameView extends Pane {
|
|||||||
gameObjects.add(fpsDisplay);
|
gameObjects.add(fpsDisplay);
|
||||||
gameObjects.add(raceBorder);
|
gameObjects.add(raceBorder);
|
||||||
gameObjects.add(markers);
|
gameObjects.add(markers);
|
||||||
//
|
|
||||||
// this.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
|
||||||
// @Override public void handle(KeyEvent event) {
|
|
||||||
// event.consume();
|
|
||||||
// switch (event.getCode()) {
|
|
||||||
// case Z:
|
|
||||||
// scaleFactor = scaleFactor * 1.2;
|
|
||||||
// break;
|
|
||||||
// case X:
|
|
||||||
// scaleFactor = scaleFactor * 0.8;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// if (event.getCode() == KeyCode.Z || event.getCode() == KeyCode.X) {
|
|
||||||
// for (Node child : getChildren()) {
|
|
||||||
// child.setScaleX(child.getScaleX() * scaleFactor);
|
|
||||||
// child.setScaleY(child.getScaleY() * scaleFactor);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// this.setOnScroll(new EventHandler<ScrollEvent>() {
|
|
||||||
// @Override public void handle(ScrollEvent event) {
|
|
||||||
// event.consume();
|
|
||||||
// if (event.getDeltaY() == 0) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// double scaleFactor =
|
|
||||||
// (event.getDeltaY() > 0)
|
|
||||||
// ? SCALE_DELTA
|
|
||||||
// : 1/SCALE_DELTA;
|
|
||||||
// for (Node child : getChildren()) {
|
|
||||||
// child.setScaleX(child.getScaleX() * scaleFactor);
|
|
||||||
// child.setScaleY(child.getScaleY() * scaleFactor);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
initializeTimer();
|
initializeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer () {
|
private void initializeTimer() {
|
||||||
Arrays.fill(frameTimes, 1_000_000_000 / 60);
|
Arrays.fill(frameTimes, 1_000_000_000 / 60);
|
||||||
timer = new AnimationTimer() {
|
timer = new AnimationTimer() {
|
||||||
private long lastTime = 0;
|
private long lastTime = 0;
|
||||||
@@ -207,8 +169,8 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First find the top right and bottom left points' geo locations, then retrieve
|
* First find the top right and bottom left points' geo locations, then retrieve map from google
|
||||||
* map from google to display on image view. - Haoming 22/5/2017
|
* to display on image view. - Haoming 22/5/2017
|
||||||
*/
|
*/
|
||||||
private void drawGoogleMap() {
|
private void drawGoogleMap() {
|
||||||
findMetersPerPixel();
|
findMetersPerPixel();
|
||||||
@@ -266,13 +228,23 @@ public class GameView extends Pane {
|
|||||||
for (Mark mark : cMark.getMarks()) {
|
for (Mark mark : cMark.getMarks()) {
|
||||||
makeAndBindMarker(mark, colour);
|
makeAndBindMarker(mark, colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//UNCOMMENT THIS TO HIGHLIGHT SUBMARKS 1 and 2 RED AND GREEN RESPECTIVELY FOR DEBUG
|
||||||
|
//(instead of above for loop)
|
||||||
|
// for (Mark mark : cMark.getMarks()) {
|
||||||
|
// if (mark.getSeqID() == 1) {
|
||||||
|
// makeAndBindMarker(mark, Color.RED);
|
||||||
|
// } else {
|
||||||
|
// makeAndBindMarker(mark, Color.GREEN);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
//Create gate line
|
//Create gate line
|
||||||
if (cMark.isGate()) {
|
if (cMark.isGate()) {
|
||||||
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
||||||
gates.add(
|
gates.add(
|
||||||
makeAndBindGate(
|
makeAndBindGate(
|
||||||
markerObjects.get(cMark.getSubMark(i)),
|
markerObjects.get(cMark.getSubMark(i)),
|
||||||
markerObjects.get(cMark.getSubMark(i+1)),
|
markerObjects.get(cMark.getSubMark(i + 1)),
|
||||||
colour
|
colour
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -389,7 +361,7 @@ public class GameView extends Pane {
|
|||||||
boatObjectGroup.getChildren().add(newBoat);
|
boatObjectGroup.getChildren().add(newBoat);
|
||||||
trails.getChildren().add(newBoat.getTrail());
|
trails.getChildren().add(newBoat.getTrail());
|
||||||
// TODO: 1/08/17 Make this less vile to look at.
|
// TODO: 1/08/17 Make this less vile to look at.
|
||||||
clientYacht.addLocationListener((boat, lat, lon, heading, velocity, sailIn) -> {
|
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||||
BoatObject bo = boatObjects.get(boat);
|
BoatObject bo = boatObjects.get(boat);
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
Point2D p2d = findScaledXY(lat, lon);
|
||||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||||
@@ -443,25 +415,25 @@ public class GameView extends Pane {
|
|||||||
annotations.put(clientYacht, newAnnotation);
|
annotations.put(clientYacht, newAnnotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawFps(Double fps){
|
private void drawFps(Double fps) {
|
||||||
Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
|
Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point
|
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
||||||
* with the leftmost point, rightmost point, southern most point and northern most point
|
* the leftmost point, rightmost point, southern most point and northern most point
|
||||||
* respectively.
|
* respectively.
|
||||||
*/
|
*/
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
private void findMinMaxPoint(List<GeoPoint> points) {
|
||||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size()-1);
|
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
||||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
||||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size()-1);
|
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
||||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
||||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
||||||
horizontalInversion = true;
|
horizontalInversion = true;
|
||||||
@@ -483,13 +455,17 @@ public class GameView extends Pane {
|
|||||||
referenceAngle = Math.abs(
|
referenceAngle = Math.abs(
|
||||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
||||||
);
|
);
|
||||||
referencePointX = bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
referencePointX =
|
||||||
|
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||||
|
.getDistance(referencePoint, minLonPoint);
|
||||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
||||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||||
|
.getDistance(referencePoint, maxLatPoint);
|
||||||
referencePointY = referencePointY / 2;
|
referencePointY = referencePointY / 2;
|
||||||
referencePointY += bufferSize;
|
referencePointY += bufferSize;
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility.getDistance(referencePoint, maxLatPoint);
|
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
||||||
|
.getDistance(referencePoint, maxLatPoint);
|
||||||
} else {
|
} else {
|
||||||
referencePointY = canvasHeight - bufferSize;
|
referencePointY = canvasHeight - bufferSize;
|
||||||
referenceAngle = Math.abs(
|
referenceAngle = Math.abs(
|
||||||
@@ -498,10 +474,13 @@ public class GameView extends Pane {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
referencePointX = bufferSize;
|
referencePointX = bufferSize;
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility.getDistance(referencePoint, minLonPoint);
|
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
||||||
referencePointX += ((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor)) / 2;
|
.getDistance(referencePoint, minLonPoint);
|
||||||
|
referencePointX +=
|
||||||
|
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
||||||
|
/ 2;
|
||||||
}
|
}
|
||||||
if(horizontalInversion) {
|
if (horizontalInversion) {
|
||||||
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -545,7 +524,7 @@ public class GameView extends Pane {
|
|||||||
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Point2D findScaledXY (double unscaledLat, double unscaledLon) {
|
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
||||||
double distanceFromReference;
|
double distanceFromReference;
|
||||||
double angleFromReference;
|
double angleFromReference;
|
||||||
double xAxisLocation = referencePointX;
|
double xAxisLocation = referencePointX;
|
||||||
@@ -558,22 +537,30 @@ public class GameView extends Pane {
|
|||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
);
|
);
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation += Math
|
||||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation -= Math
|
||||||
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
} else if (angleFromReference >= 0) {
|
} else if (angleFromReference >= 0) {
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
angleFromReference = angleFromReference - Math.PI / 2;
|
||||||
xAxisLocation += Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
xAxisLocation += Math
|
||||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation += Math
|
||||||
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
angleFromReference = Math.abs(angleFromReference);
|
||||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
xAxisLocation -= Math
|
||||||
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation -= Math
|
||||||
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
} else {
|
} else {
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||||
xAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
xAxisLocation -= Math
|
||||||
yAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
||||||
|
yAxisLocation += Math
|
||||||
|
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
||||||
}
|
}
|
||||||
if(horizontalInversion) {
|
if (horizontalInversion) {
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
||||||
}
|
}
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
return new Point2D(xAxisLocation, yAxisLocation);
|
||||||
@@ -600,7 +587,7 @@ public class GameView extends Pane {
|
|||||||
metersPerPixelY = dVertical / dy;
|
metersPerPixelY = dVertical / dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAnnotationVisibilities (boolean teamName, boolean velocity, boolean estTime,
|
public void setAnnotationVisibilities(boolean teamName, boolean velocity, boolean estTime,
|
||||||
boolean legTime, boolean trail, boolean wake) {
|
boolean legTime, boolean trail, boolean wake) {
|
||||||
for (BoatObject boatObject : boatObjects.values()) {
|
for (BoatObject boatObject : boatObjects.values()) {
|
||||||
boatObject.setVisibility(teamName, velocity, estTime, legTime, trail, wake);
|
boatObject.setVisibility(teamName, velocity, estTime, legTime, trail, wake);
|
||||||
@@ -613,7 +600,7 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFPSVisibility (boolean visibility) {
|
public void setFPSVisibility(boolean visibility) {
|
||||||
fpsDisplay.setVisible(visibility);
|
fpsDisplay.setVisible(visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +610,7 @@ public class GameView extends Pane {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pauseRace () {
|
public void pauseRace() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,8 +619,7 @@ public class GameView extends Pane {
|
|||||||
this.windDir = windDir;
|
this.windDir = windDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startRace() {
|
||||||
public void startRace () {
|
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,9 +627,10 @@ public class GameView extends Pane {
|
|||||||
return playerYacht;
|
return playerYacht;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setBoatAsPlayer (ClientYacht playerYacht) {
|
public void setBoatAsPlayer (ClientYacht playerYacht) {
|
||||||
this.playerYacht = playerYacht;
|
this.playerYacht = playerYacht;
|
||||||
this.playerYacht.toggleClientSail();
|
this.playerYacht.toggleSail();
|
||||||
boatObjects.get(playerYacht).setAsPlayer();
|
boatObjects.get(playerYacht).setAsPlayer();
|
||||||
annotations.get(playerYacht).addAnnotation(
|
annotations.get(playerYacht).addAnnotation(
|
||||||
"velocity",
|
"velocity",
|
||||||
@@ -657,4 +644,40 @@ public class GameView extends Pane {
|
|||||||
gameObjects.add(annotations.get(playerYacht));
|
gameObjects.add(annotations.get(playerYacht));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given yacht geopoint by race view controller, drawCollision will calculate canvas X and Y and
|
||||||
|
* display a flashing red circle on collision point.
|
||||||
|
*
|
||||||
|
* @param collisionPoint yacht collision point
|
||||||
|
*/
|
||||||
|
public void drawCollision(GeoPoint collisionPoint) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Point2D point = findScaledXY(collisionPoint);
|
||||||
|
double circleRadius = 0.0;
|
||||||
|
Circle circle = new Circle(point.getX(), point.getY(), circleRadius, Color.RED);
|
||||||
|
gameObjects.add(circle);
|
||||||
|
|
||||||
|
circle.setFill(Color.TRANSPARENT);
|
||||||
|
circle.setStroke(Color.RED);
|
||||||
|
circle.setStrokeWidth(3);
|
||||||
|
|
||||||
|
Timeline timeline = new Timeline();
|
||||||
|
timeline.setCycleCount(1);
|
||||||
|
|
||||||
|
KeyFrame keyframe1 = new KeyFrame(Duration.ZERO,
|
||||||
|
new KeyValue(circle.radiusProperty(), 0),
|
||||||
|
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
|
||||||
|
KeyFrame keyFrame2 = new KeyFrame(new Duration(1000),
|
||||||
|
new KeyValue(circle.radiusProperty(), 50),
|
||||||
|
new KeyValue(circle.strokeProperty(), Color.RED));
|
||||||
|
KeyFrame keyFrame3 = new KeyFrame(new Duration(1500),
|
||||||
|
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
|
||||||
|
|
||||||
|
timeline.getKeyFrames().addAll(keyframe1, keyFrame2, keyFrame3);
|
||||||
|
timeline.play();
|
||||||
|
|
||||||
|
timeline.setOnFinished(event -> gameObjects.remove(circle));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private GameView gameView;
|
private GameView gameView;
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
|
|
||||||
private Timeline timerTimeline;
|
|
||||||
private Timer timer = new Timer();
|
private Timer timer = new Timer();
|
||||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
private ImportantAnnotationsState importantAnnotations;
|
||||||
@@ -209,9 +208,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to add any new yachts into the race that may have started late or not have had data received yet
|
* Used to add any new yachts into the race that may have started late or not have had data
|
||||||
|
* received yet
|
||||||
*/
|
*/
|
||||||
private void updateSparkLine(){
|
private void updateSparkLine() {
|
||||||
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
|
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
|
||||||
// Collect the racing yachts that aren't already in the chart
|
// Collect the racing yachts that aren't already in the chart
|
||||||
sparkLineData.clear();
|
sparkLineData.clear();
|
||||||
@@ -234,9 +234,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
// Lambda function to sort the series in order of leg (later legs shown more to the right)
|
// Lambda function to sort the series in order of leg (later legs shown more to the right)
|
||||||
sparkLineData.sort((o1, o2) -> {
|
sparkLineData.sort((o1, o2) -> {
|
||||||
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
|
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size() - 1).getXValue());
|
||||||
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
|
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size() - 1).getXValue());
|
||||||
if (leg2 < leg1){
|
if (leg2 < leg1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -249,7 +249,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
.filter(spark -> !raceSparkLine.getData().contains(spark))
|
.filter(spark -> !raceSparkLine.getData().contains(spark))
|
||||||
.forEach(spark -> {
|
.forEach(spark -> {
|
||||||
raceSparkLine.getData().add(spark);
|
raceSparkLine.getData().add(spark);
|
||||||
spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
spark.getNode().lookup(".chart-series-line")
|
||||||
|
.setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -285,26 +286,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the rgb string of the yachts colour to use for the chart via css
|
* gets the rgb string of the yachts colour to use for the chart via css
|
||||||
|
*
|
||||||
* @param yachtId id of yacht passed in to get the yachts colour
|
* @param yachtId id of yacht passed in to get the yachts colour
|
||||||
* @return the colour as an rgb string
|
* @return the colour as an rgb string
|
||||||
*/
|
*/
|
||||||
private String getBoatColorAsRGB(String yachtId){
|
private String getBoatColorAsRGB(String yachtId) {
|
||||||
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
|
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
|
||||||
if (color == null){
|
if (color == null) {
|
||||||
return String.format("#%02X%02X%02X",255,255,255);
|
return String.format("#%02X%02X%02X", 255, 255, 255);
|
||||||
}
|
}
|
||||||
return String.format( "#%02X%02X%02X",
|
return String.format("#%02X%02X%02X",
|
||||||
(int)( color.getRed() * 255 ),
|
(int) (color.getRed() * 255),
|
||||||
(int)( color.getGreen() * 255 ),
|
(int) (color.getGreen() * 255),
|
||||||
(int)( color.getBlue() * 255 )
|
(int) (color.getBlue() * 255)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
|
||||||
* orderings etc.. which are dependent on the info from the stream parser constantly.
|
* orderings etc.. which are dependent on the info from the stream parser constantly. Updates of
|
||||||
* Updates of each of these attributes are called ONCE EACH SECOND
|
* each of these attributes are called ONCE EACH SECOND
|
||||||
*/
|
*/
|
||||||
private void initializeUpdateTimer() {
|
private void initializeUpdateTimer() {
|
||||||
timer.scheduleAtFixedRate(new TimerTask() {
|
timer.scheduleAtFixedRate(new TimerTask() {
|
||||||
@@ -319,9 +321,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
|
* Iterates over all corners until ones SeqID matches with the yachts current leg number. Then
|
||||||
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
|
* it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark Returns
|
||||||
* Returns null if no next mark found.
|
* null if no next mark found.
|
||||||
|
*
|
||||||
* @param bg The BoatGroup to find the next mark of
|
* @param bg The BoatGroup to find the next mark of
|
||||||
* @return The next Mark or null if none found
|
* @return The next Mark or null if none found
|
||||||
*/
|
*/
|
||||||
@@ -396,7 +399,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
textToAdd.setStyle("");
|
textToAdd.setStyle("");
|
||||||
vboxEntries.add(textToAdd);
|
vboxEntries.add(textToAdd);
|
||||||
}
|
}
|
||||||
// System.out.println("finished a loop :))))))))))))");
|
|
||||||
}
|
}
|
||||||
Platform.runLater(() ->
|
Platform.runLater(() ->
|
||||||
positionVbox.getChildren().setAll(vboxEntries)
|
positionVbox.getChildren().setAll(vboxEntries)
|
||||||
@@ -476,9 +478,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Point2D getPointRotation(Point2D ref, Double distance, Double angle){
|
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
|
||||||
Double newX = ref.getX() + (ref.getX() + distance -ref.getX())*Math.cos(angle) - (ref.getY() + distance -ref.getY())*Math.sin(angle);
|
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
|
||||||
Double newY = ref.getY() + (ref.getX() + distance -ref.getX())*Math.sin(angle) + (ref.getY() + distance -ref.getY())*Math.cos(angle);
|
- (ref.getY() + distance - ref.getY()) * Math.sin(angle);
|
||||||
|
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
|
||||||
|
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
|
||||||
|
|
||||||
return new Point2D(newX, newY);
|
return new Point2D(newX, newY);
|
||||||
}
|
}
|
||||||
@@ -503,8 +507,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialised the combo box with any yachts currently in the race and adds the required listener
|
* Initialised the combo box with any yachts currently in the race and adds the required
|
||||||
* for the combobox to take action upon selection
|
* listener for the combobox to take action upon selection
|
||||||
*/
|
*/
|
||||||
private void initialiseBoatSelectionComboBox() {
|
private void initialiseBoatSelectionComboBox() {
|
||||||
yachtSelectionComboBox.setItems(
|
yachtSelectionComboBox.setItems(
|
||||||
@@ -592,11 +596,22 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateRaceData (RaceXMLData raceData) {
|
public void updateRaceData(RaceXMLData raceData) {
|
||||||
this.courseData = raceData;
|
this.courseData = raceData;
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by game client after receiving yacht event packet. Parameter subject id is the
|
||||||
|
* offending yacht. This function in turn will pass the yacht location to game view to display a
|
||||||
|
* collision alert.
|
||||||
|
*
|
||||||
|
* @param subjectId source id of offending yacht
|
||||||
|
*/
|
||||||
|
public void showCollision(Long subjectId) {
|
||||||
|
gameView.drawCollision(participants.get((int) (long) subjectId).getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
public GameView getGameView() {
|
public GameView getGameView() {
|
||||||
return gameView;
|
return gameView;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<BoatConfig>
|
|
||||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
|
||||||
<Version>12</Version>
|
|
||||||
<Snapshot>219</Snapshot>
|
|
||||||
<Settings>
|
|
||||||
<RaceBoatType Type="AC45"/>
|
|
||||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
|
||||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
|
||||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
|
||||||
</Settings>
|
|
||||||
<BoatShapes>
|
|
||||||
<BoatShape ShapeID="0">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="3" Y="25" X="0"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="14">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1"/>
|
|
||||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
|
||||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
|
||||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
|
||||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
|
||||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
|
||||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
|
||||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
|
||||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
|
||||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
|
||||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
|
||||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
|
||||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="1"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="15">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
|
||||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
|
||||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
|
||||||
</Vertices>
|
|
||||||
<Catamaran>
|
|
||||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
|
||||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
|
||||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
|
||||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
|
||||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
|
||||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
|
||||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
|
||||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
|
||||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
|
||||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
|
||||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
|
||||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
|
||||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
|
||||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
|
||||||
</Catamaran>
|
|
||||||
<Bowsprit>
|
|
||||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
|
||||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
|
||||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
|
||||||
</Bowsprit>
|
|
||||||
<Trampoline>
|
|
||||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
|
||||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
|
||||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
|
||||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
|
||||||
</Trampoline>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="18">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
|
||||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
|
||||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
|
||||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
|
||||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
|
||||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
|
||||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
|
||||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
|
||||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
|
||||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
|
||||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
|
||||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
|
||||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
|
||||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
|
||||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
|
||||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
|
||||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
|
||||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
|
||||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="24">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
|
||||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
|
||||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
|
||||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
|
||||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="34">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
|
||||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
|
||||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
|
||||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
|
||||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="35">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
|
||||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
|
||||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
|
||||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
|
||||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
|
||||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
|
||||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
|
||||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
|
||||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
|
||||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
|
||||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
|
||||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
|
||||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
|
||||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
</BoatShapes>
|
|
||||||
<Boats>
|
|
||||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
|
||||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="301" ShapeID="15" StoweName="SWE" ShortName="ARTEMIS" ShorterName="SWE" BoatName="ARTEMIS RACING" HullNum="AC4517" Skipper="OUTTERIDGE" Helmsman="OUTTERIDGE" Country="SWE" PeliID="102" RadioIP="172.20.2.102">
|
|
||||||
<GPSposition Z="1.727" Y="-0.359" X="-0.0121"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
|
||||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
|
||||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="601" ShapeID="15" StoweName="FRA" ShortName="FRANCE" ShorterName="FRA" BoatName="GROUPAMA TEAM FRANCE" HullNum="AC4505" Skipper="CAMMAS" Helmsman="CAMMAS" Country="FRA" PeliID="105" RadioIP="172.20.2.105">
|
|
||||||
<GPSposition Z="1.863" Y="-0.3" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
|
||||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
</Boats>
|
|
||||||
</BoatConfig>
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<BoatConfig>
|
|
||||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
|
||||||
<Version>12</Version>
|
|
||||||
<Snapshot>219</Snapshot>
|
|
||||||
<Settings>
|
|
||||||
<RaceBoatType Type="AC45"/>
|
|
||||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
|
||||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
|
||||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
|
||||||
</Settings>
|
|
||||||
<BoatShapes>
|
|
||||||
<BoatShape ShapeID="0">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="3" Y="25" X="0"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="14">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1"/>
|
|
||||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
|
||||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
|
||||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
|
||||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
|
||||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
|
||||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
|
||||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
|
||||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
|
||||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
|
||||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
|
||||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
|
||||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="1"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="15">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
|
||||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
|
||||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
|
||||||
</Vertices>
|
|
||||||
<Catamaran>
|
|
||||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
|
||||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
|
||||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
|
||||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
|
||||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
|
||||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
|
||||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
|
||||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
|
||||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
|
||||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
|
||||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
|
||||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
|
||||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
|
||||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
|
||||||
</Catamaran>
|
|
||||||
<Bowsprit>
|
|
||||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
|
||||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
|
||||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
|
||||||
</Bowsprit>
|
|
||||||
<Trampoline>
|
|
||||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
|
||||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
|
||||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
|
||||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
|
||||||
</Trampoline>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="18">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
|
||||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
|
||||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
|
||||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
|
||||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
|
||||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
|
||||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
|
||||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
|
||||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
|
||||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
|
||||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
|
||||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
|
||||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
|
||||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
|
||||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
|
||||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
|
||||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
|
||||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
|
||||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="24">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
|
||||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
|
||||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
|
||||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
|
||||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="34">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
|
||||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
|
||||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
|
||||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
|
||||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="35">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
|
||||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
|
||||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
|
||||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
|
||||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
|
||||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
|
||||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
|
||||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
|
||||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
|
||||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
|
||||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
|
||||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
|
||||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
|
||||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
</BoatShapes>
|
|
||||||
<Boats>
|
|
||||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
|
||||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
|
||||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
|
||||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
|
||||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
</Boats>
|
|
||||||
</BoatConfig>
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<BoatConfig>
|
|
||||||
<Modified>2015-08-28T17:32:59+0100</Modified>
|
|
||||||
<Version>12</Version>
|
|
||||||
<Snapshot>219</Snapshot>
|
|
||||||
<Settings>
|
|
||||||
<RaceBoatType Type="AC45"/>
|
|
||||||
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
|
|
||||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
|
|
||||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
|
|
||||||
</Settings>
|
|
||||||
<BoatShapes>
|
|
||||||
<BoatShape ShapeID="0">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="3" Y="25" X="0"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="14">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1"/>
|
|
||||||
<Vtx Seq="2" Y="0.75" X="-1"/>
|
|
||||||
<Vtx Seq="3" Y="0.75" X="-0.25"/>
|
|
||||||
<Vtx Seq="4" Y="3.5" X="-0.25"/>
|
|
||||||
<Vtx Seq="5" Y="4.5" X="-1"/>
|
|
||||||
<Vtx Seq="6" Y="6.5" X="-1"/>
|
|
||||||
<Vtx Seq="7" Y="7" X="-0.5"/>
|
|
||||||
<Vtx Seq="8" Y="7" X="0.5"/>
|
|
||||||
<Vtx Seq="9" Y="6.5" X="1"/>
|
|
||||||
<Vtx Seq="10" Y="4.5" X="1"/>
|
|
||||||
<Vtx Seq="11" Y="3.5" X="0.25"/>
|
|
||||||
<Vtx Seq="12" Y="0.75" X="0.25"/>
|
|
||||||
<Vtx Seq="13" Y="0.75" X="1"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="1"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="15">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-3.46"/>
|
|
||||||
<Vtx Seq="2" Y="13.449" X="-3.46"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="13.449" X="3.46"/>
|
|
||||||
<Vtx Seq="5" Y="0" X="3.46"/>
|
|
||||||
</Vertices>
|
|
||||||
<Catamaran>
|
|
||||||
<Vtx Seq="1" Y="1.769" X="-2.752"/>
|
|
||||||
<Vtx Seq="2" Y="0" X="-2.813"/>
|
|
||||||
<Vtx Seq="3" Y="0" X="-3.34"/>
|
|
||||||
<Vtx Seq="4" Y="5.351" X="-3.46"/>
|
|
||||||
<Vtx Seq="5" Y="10.544" X="-3.387"/>
|
|
||||||
<Vtx Seq="6" Y="13.449" X="-3.075"/>
|
|
||||||
<Vtx Seq="7" Y="10.851" X="-2.793"/>
|
|
||||||
<Vtx Seq="8" Y="6.669" X="-2.699"/>
|
|
||||||
<Vtx Seq="9" Y="6.669" X="2.699"/>
|
|
||||||
<Vtx Seq="10" Y="10.851" X="2.793"/>
|
|
||||||
<Vtx Seq="11" Y="13.449" X="3.075"/>
|
|
||||||
<Vtx Seq="12" Y="10.544" X="3.387"/>
|
|
||||||
<Vtx Seq="13" Y="5.351" X="3.46"/>
|
|
||||||
<Vtx Seq="14" Y="0" X="3.34"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="2.813"/>
|
|
||||||
<Vtx Seq="16" Y="1.769" X="2.752"/>
|
|
||||||
</Catamaran>
|
|
||||||
<Bowsprit>
|
|
||||||
<Vtx Seq="1" Y="6.669" X="-0.2"/>
|
|
||||||
<Vtx Seq="2" Y="11.377" X="-0.2"/>
|
|
||||||
<Vtx Seq="3" Y="14.019" X="0"/>
|
|
||||||
<Vtx Seq="4" Y="11.377" X="0.2"/>
|
|
||||||
<Vtx Seq="5" Y="6.669" X="0.2"/>
|
|
||||||
</Bowsprit>
|
|
||||||
<Trampoline>
|
|
||||||
<Vtx Seq="1" Y="2" X="-2.699"/>
|
|
||||||
<Vtx Seq="2" Y="6.438" X="-2.699"/>
|
|
||||||
<Vtx Seq="3" Y="6.438" X="2.699"/>
|
|
||||||
<Vtx Seq="4" Y="2" X="2.699"/>
|
|
||||||
</Trampoline>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="18">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.04"/>
|
|
||||||
<Vtx Seq="2" Y="0.11" X="-1.18"/>
|
|
||||||
<Vtx Seq="3" Y="0.42" X="-1.28"/>
|
|
||||||
<Vtx Seq="4" Y="3.74" X="-1.29"/>
|
|
||||||
<Vtx Seq="5" Y="5.36" X="-1.21"/>
|
|
||||||
<Vtx Seq="6" Y="6.29" X="-1.08"/>
|
|
||||||
<Vtx Seq="7" Y="7.15" X="-0.84"/>
|
|
||||||
<Vtx Seq="8" Y="7.63" X="-0.62"/>
|
|
||||||
<Vtx Seq="9" Y="7.94" X="-0.34"/>
|
|
||||||
<Vtx Seq="10" Y="8.06" X="0"/>
|
|
||||||
<Vtx Seq="11" Y="7.94" X="0.34"/>
|
|
||||||
<Vtx Seq="12" Y="7.63" X="0.62"/>
|
|
||||||
<Vtx Seq="13" Y="7.15" X="0.84"/>
|
|
||||||
<Vtx Seq="14" Y="6.29" X="1.08"/>
|
|
||||||
<Vtx Seq="15" Y="5.36" X="1.21"/>
|
|
||||||
<Vtx Seq="16" Y="3.74" X="1.29"/>
|
|
||||||
<Vtx Seq="17" Y="0.42" X="1.28"/>
|
|
||||||
<Vtx Seq="18" Y="0.11" X="1.18"/>
|
|
||||||
<Vtx Seq="19" Y="0" X="1.04"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="24">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-2.5"/>
|
|
||||||
<Vtx Seq="2" Y="7" X="-2.5"/>
|
|
||||||
<Vtx Seq="3" Y="12.6" X="-2.2"/>
|
|
||||||
<Vtx Seq="4" Y="12.6" X="2.2"/>
|
|
||||||
<Vtx Seq="5" Y="7" X="2.5"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="2.5"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="34">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.16"/>
|
|
||||||
<Vtx Seq="2" Y="5.51" X="-1.16"/>
|
|
||||||
<Vtx Seq="3" Y="5.846" X="-0.84"/>
|
|
||||||
<Vtx Seq="4" Y="5.846" X="0.84"/>
|
|
||||||
<Vtx Seq="5" Y="5.51" X="1.16"/>
|
|
||||||
<Vtx Seq="6" Y="0" X="1.16"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
<BoatShape ShapeID="35">
|
|
||||||
<Vertices>
|
|
||||||
<Vtx Seq="1" Y="0" X="-1.461"/>
|
|
||||||
<Vtx Seq="2" Y="6" X="-1.461"/>
|
|
||||||
<Vtx Seq="3" Y="7" X="-1.44"/>
|
|
||||||
<Vtx Seq="4" Y="8" X="-1.38"/>
|
|
||||||
<Vtx Seq="5" Y="9" X="-1.17"/>
|
|
||||||
<Vtx Seq="6" Y="10" X="-0.76"/>
|
|
||||||
<Vtx Seq="7" Y="10.6" X="-0.34"/>
|
|
||||||
<Vtx Seq="8" Y="10.61" X="0"/>
|
|
||||||
<Vtx Seq="9" Y="10.6" X="0.34"/>
|
|
||||||
<Vtx Seq="10" Y="10" X="0.76"/>
|
|
||||||
<Vtx Seq="11" Y="9" X="1.17"/>
|
|
||||||
<Vtx Seq="12" Y="8" X="1.38"/>
|
|
||||||
<Vtx Seq="13" Y="7" X="1.44"/>
|
|
||||||
<Vtx Seq="14" Y="6" X="1.461"/>
|
|
||||||
<Vtx Seq="15" Y="0" X="1.461"/>
|
|
||||||
</Vertices>
|
|
||||||
</BoatShape>
|
|
||||||
</BoatShapes>
|
|
||||||
<Boats>
|
|
||||||
<Boat Type="Yacht" SourceID="201" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
|
||||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="301" ShapeID="15" StoweName="SWE" ShortName="ARTEMIS" ShorterName="SWE" BoatName="ARTEMIS RACING" HullNum="AC4517" Skipper="OUTTERIDGE" Helmsman="OUTTERIDGE" Country="SWE" PeliID="102" RadioIP="172.20.2.102">
|
|
||||||
<GPSposition Z="1.727" Y="-0.359" X="-0.0121"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="401" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
|
|
||||||
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="501" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
|
|
||||||
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="601" ShapeID="15" StoweName="FRA" ShortName="FRANCE" ShorterName="FRA" BoatName="GROUPAMA TEAM FRANCE" HullNum="AC4505" Skipper="CAMMAS" Helmsman="CAMMAS" Country="FRA" PeliID="105" RadioIP="172.20.2.105">
|
|
||||||
<GPSposition Z="1.863" Y="-0.3" X="-0.003"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="701" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
|
|
||||||
<GPSposition Z="1.734" Y="-0.352" X="0"/>
|
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
</Boats>
|
|
||||||
</BoatConfig>
|
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
@@ -10,6 +15,7 @@
|
|||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<?import javafx.scene.text.Text?>
|
<?import javafx.scene.text.Text?>
|
||||||
|
|
||||||
<AnchorPane fx:id="holder" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="960.0" prefWidth="1530.0" style="-fx-background-color: #2C2c36;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.StartScreenController">
|
<AnchorPane fx:id="holder" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="960.0" prefWidth="1530.0" style="-fx-background-color: #2C2c36;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.StartScreenController">
|
||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
||||||
@@ -25,7 +31,7 @@
|
|||||||
<Insets left="5.0" right="5.0" />
|
<Insets left="5.0" right="5.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</Button>
|
</Button>
|
||||||
<TextField fx:id="ipTextField" alignment="CENTER" maxWidth="-Infinity" prefHeight="25.0" prefWidth="148.0" promptText="Host IP" text="132.181.14." GridPane.halignment="RIGHT" GridPane.rowIndex="4">
|
<TextField fx:id="ipTextField" alignment="CENTER" maxWidth="-Infinity" prefHeight="25.0" prefWidth="148.0" promptText="Host IP" text="localhost" GridPane.halignment="RIGHT" GridPane.rowIndex="4">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
|
<Insets bottom="10.0" left="5.0" right="85.0" top="10.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ public class ColorsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNextColor() {
|
public void testNextColor() {
|
||||||
Color expectedColors[] = {Color.RED, Color.PERU, Color.SEAGREEN, Color.GREEN, Color.BLUE, Color.PURPLE};
|
Color expectedColors[] = {Color.RED, Color.PERU, Color.GOLD, Color.GREEN, Color.BLUE,
|
||||||
for (int i = 0; i<6; i++)
|
Color.PURPLE, Color.DEEPPINK, Color.GRAY};
|
||||||
{
|
for (int i = 0; i < 8; i++) {
|
||||||
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
Assert.assertEquals(expectedColors[i], Colors.getColor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import seng302.gameServer.GameState;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
|
||||||
|
* meters.
|
||||||
|
*/
|
||||||
|
public class UpdateYachtTest {
|
||||||
|
|
||||||
|
private ServerYacht yacht1 = new ServerYacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1");
|
||||||
|
private ServerYacht yacht2 = new ServerYacht("Yacht", 2, "2", "Yacht" + 2, "Yacht" + 2, "Test2");
|
||||||
|
private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0);
|
||||||
|
private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUpRace() {
|
||||||
|
new GameState("");
|
||||||
|
GameState.addYacht(1, yacht1);
|
||||||
|
GameState.addYacht(2, yacht2);
|
||||||
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateYachtWithCollision() {
|
||||||
|
// Yacht 1 heading towards 90 degrees heading
|
||||||
|
yacht1.setLocation(geoPoint1);
|
||||||
|
|
||||||
|
// Yacht 2 heading towards 270 degrees heading
|
||||||
|
yacht2.setLocation(geoPoint1);
|
||||||
|
|
||||||
|
// Start yacht 1 and rest yacht 2
|
||||||
|
if (!yacht1.getSailIn()) {
|
||||||
|
yacht1.toggleSailIn();
|
||||||
|
}
|
||||||
|
GameState.checkForCollision(yacht1);
|
||||||
|
double moved = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1);
|
||||||
|
Assert.assertEquals(GameState.BOUNCE_DISTANCE_YACHT, moved, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateYachtWithoutCollision() {
|
||||||
|
// Yacht 1 heading towards 90 degrees heading
|
||||||
|
yacht1.setLocation(geoPoint1);
|
||||||
|
|
||||||
|
// Yacht 2 heading towards 270 degrees heading
|
||||||
|
yacht2.setLocation(geoPoint2);
|
||||||
|
|
||||||
|
// Start yacht 1 and rest yacht 2
|
||||||
|
if (!yacht1.getSailIn()) {
|
||||||
|
yacht1.toggleSailIn();
|
||||||
|
}
|
||||||
|
GameState.checkForCollision(yacht1);
|
||||||
|
Assert.assertTrue(
|
||||||
|
GameState.YACHT_COLLISION_DISTANCE < GeoUtility.getDistance(geoPoint1, geoPoint2
|
||||||
|
)
|
||||||
|
); //Check that yachts are actually far enough apart for no collision.
|
||||||
|
Assert.assertEquals(geoPoint1.getLat(), yacht1.getLocation().getLat(), 0.001);
|
||||||
|
Assert.assertEquals(geoPoint1.getLng(), yacht1.getLocation().getLng(), 0.001);
|
||||||
|
Assert.assertEquals(geoPoint2.getLat(), yacht1.getLocation().getLat(), 0.001);
|
||||||
|
Assert.assertEquals(geoPoint2.getLng(), yacht1.getLocation().getLng(), 0.001);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
package seng302.visualiser.ClientToServerTests;
|
package seng302.visualiser.ClientToServerTests;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.gameServer.GameStages;
|
|
||||||
import seng302.gameServer.GameState;
|
|
||||||
import seng302.gameServer.MainServerThread;
|
import seng302.gameServer.MainServerThread;
|
||||||
import seng302.gameServer.server.messages.BoatAction;
|
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,32 +16,32 @@ public class RegularPacketsTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
new GameState("localhost");
|
// new GameState("localhost");
|
||||||
serverThread = new MainServerThread();
|
// serverThread = new MainServerThread();
|
||||||
clientThread = new ClientToServerThread("localhost", 4942);
|
// clientThread = new ClientToServerThread("localhost", 4942);
|
||||||
GameState.setCurrentStage(GameStages.RACING);
|
// GameState.setCurrentStage(GameStages.RACING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void packetsSentAtRegularIntervals () throws Exception {
|
public void packetsSentAtRegularIntervals () throws Exception {
|
||||||
final double TEST_DISTANCE = 10.0;
|
// final double TEST_DISTANCE = 10.0;
|
||||||
serverThread.startGame();
|
// serverThread.startGame();
|
||||||
SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
// ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
||||||
double startAngle = yacht.getHeading();
|
// double startAngle = yacht.getHeading();
|
||||||
long startTime = System.currentTimeMillis();
|
// long startTime = System.currentTimeMillis();
|
||||||
clientThread.sendBoatAction(BoatAction.UPWIND);
|
// clientThread.sendBoatAction(BoatAction.UPWIND);
|
||||||
Thread.sleep(200);
|
// Thread.sleep(200);
|
||||||
while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
// while (Math.abs(yacht.getHeading() - startAngle) < TEST_DISTANCE) {
|
||||||
Thread.sleep(1);
|
// Thread.sleep(1);
|
||||||
}
|
// }
|
||||||
clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
// clientThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||||
long endTime = System.currentTimeMillis();
|
// long endTime = System.currentTimeMillis();
|
||||||
SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
//Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
// //Allowed to be two loops of delay due to loop delay and processing delay at client + server ends.
|
||||||
Assert.assertEquals(
|
// Assert.assertEquals(
|
||||||
TEST_DISTANCE / ServerYacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
// TEST_DISTANCE / ServerYacht.TURN_STEP * ClientToServerThread.PACKET_SENDING_INTERVAL_MS,
|
||||||
(endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
// (endTime - startTime), 2 * ClientToServerThread.PACKET_SENDING_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
// @Test
|
||||||
@@ -72,10 +66,10 @@ public class RegularPacketsTest {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void teardown () throws Exception {
|
public void teardown () throws Exception {
|
||||||
clientThread.setSocketToClose();
|
// clientThread.setSocketToClose();
|
||||||
serverThread.terminate();
|
// serverThread.terminate();
|
||||||
GameState.setCurrentStage(GameStages.LOBBYING);
|
// GameState.setCurrentStage(GameStages.LOBBYING);
|
||||||
for (int i = 0; i<20; i++)
|
// for (int i = 0; i<20; i++)
|
||||||
SleepThreadMaxDelay(); //Make sure socket is closed and toolkit remade.
|
// SleepThreadMaxDelay(); //Make sure socket is closed and toolkit remade.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.visualiser.map;
|
package seng302.visualiser.map;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -21,8 +22,8 @@ public class BoatSailAnimationToggleTest {
|
|||||||
@Test
|
@Test
|
||||||
public void sailToggleTest() throws Exception {
|
public void sailToggleTest() throws Exception {
|
||||||
assertFalse(yacht.getSailIn());
|
assertFalse(yacht.getSailIn());
|
||||||
yacht.toggleClientSail();
|
yacht.toggleSail();
|
||||||
assertFalse(yacht.getSailIn());
|
assertTrue(yacht.getSailIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,10 @@ import seng302.visualiser.ClientToServerThread;
|
|||||||
*/
|
*/
|
||||||
public class ToggleSailSteps {
|
public class ToggleSailSteps {
|
||||||
|
|
||||||
|
|
||||||
MainServerThread mst;
|
MainServerThread mst;
|
||||||
ClientToServerThread client;
|
ClientToServerThread client;
|
||||||
boolean sailsIn = false;
|
|
||||||
long startTime;
|
long startTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Given("^The game is running$")
|
@Given("^The game is running$")
|
||||||
public void the_game_is_running() throws Throwable {
|
public void the_game_is_running() throws Throwable {
|
||||||
mst = new MainServerThread();
|
mst = new MainServerThread();
|
||||||
|
|||||||
Reference in New Issue
Block a user