Merge branch 'story1275_host_customization' into 1273_Skybox
# Conflicts: # src/main/java/seng302/visualiser/GameView3D.java # src/main/java/seng302/visualiser/controllers/LobbyController.java # src/main/java/seng302/visualiser/controllers/ViewManager.java # src/main/resources/views/LobbyView.fxml # src/main/resources/views/RaceView.fxml
@@ -1,23 +1,39 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
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 org.w3c.dom.Document;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import org.xml.sax.InputSource;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
import seng302.gameServer.messages.*;
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.model.*;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
|
import seng302.gameServer.messages.MarkRoundingMessage;
|
||||||
|
import seng302.gameServer.messages.MarkType;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RoundingBoatStatus;
|
||||||
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.PolarTable;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLParser;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import java.util.*;
|
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,7 +74,6 @@ public class GameState implements Runnable {
|
|||||||
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
||||||
private static Boolean playerHasLeftFlag;
|
private static Boolean playerHasLeftFlag;
|
||||||
|
|
||||||
private static String hostIpAddress;
|
|
||||||
private static List<Player> players;
|
private static List<Player> players;
|
||||||
private static Map<Integer, ServerYacht> yachts;
|
private static Map<Integer, ServerYacht> yachts;
|
||||||
private static Boolean isRaceStarted;
|
private static Boolean isRaceStarted;
|
||||||
@@ -77,14 +92,13 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
|
|
||||||
public GameState(String hostIpAddress) {
|
public GameState() {
|
||||||
windDirection = 180d;
|
windDirection = 180d;
|
||||||
windSpeed = 10000d;
|
windSpeed = 10000d;
|
||||||
yachts = new HashMap<>();
|
yachts = new HashMap<>();
|
||||||
tokensInPlay = new ArrayList<>();
|
tokensInPlay = new ArrayList<>();
|
||||||
|
marks = new HashSet<>();
|
||||||
players = new ArrayList<>();
|
players = new ArrayList<>();
|
||||||
GameState.hostIpAddress = hostIpAddress;
|
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
playerHasLeftFlag = false;
|
playerHasLeftFlag = false;
|
||||||
speedMultiplier = 1.0;
|
speedMultiplier = 1.0;
|
||||||
@@ -92,34 +106,20 @@ public class GameState implements Runnable {
|
|||||||
isRaceStarted = false;
|
isRaceStarted = false;
|
||||||
//set this when game stage changes to prerace
|
//set this when game stage changes to prerace
|
||||||
previousUpdateTime = System.currentTimeMillis();
|
previousUpdateTime = System.currentTimeMillis();
|
||||||
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
|
||||||
newMessageListeners = new ArrayList<>();
|
newMessageListeners = new ArrayList<>();
|
||||||
allTokens = makeTokens();
|
allTokens = makeTokens();
|
||||||
|
|
||||||
resetStartTime();
|
resetStartTime();
|
||||||
|
|
||||||
new Thread(this, "GameState").start(); //Run the auto updates on the game state
|
new Thread(this, "GameState").start(); //Run the auto updates on the game state
|
||||||
|
|
||||||
marks = new MarkOrder().getAllMarks();
|
|
||||||
setCourseLimit("/server_config/race.xml");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCourseLimit(String url) {
|
public static void setRace(RaceXMLData raceXMLData) {
|
||||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
markOrder = new MarkOrder(raceXMLData);
|
||||||
documentBuilderFactory.setNamespaceAware(true);
|
for (CompoundMark compoundMark : raceXMLData.getCompoundMarks().values()){
|
||||||
DocumentBuilder documentBuilder;
|
marks.addAll(compoundMark.getMarks());
|
||||||
Document document = null;
|
|
||||||
try {
|
|
||||||
documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
|
||||||
document = documentBuilder.parse(new InputSource(getClass().getResourceAsStream(url)));
|
|
||||||
} catch (Exception e) {
|
|
||||||
// sorry, we have to catch general one, otherwise we have to catch five different exceptions.
|
|
||||||
logger.trace("Failed to load course limit for boundary collision detection.", e);
|
|
||||||
}
|
}
|
||||||
courseLimit = XMLParser.parseRace(document).getCourseLimit();
|
courseLimit = raceXMLData.getCourseLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
|
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
|
||||||
* race ideally
|
* race ideally
|
||||||
@@ -134,10 +134,6 @@ public class GameState implements Runnable {
|
|||||||
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
|
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getHostIpAddress() {
|
|
||||||
return hostIpAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<Mark> getMarks() {
|
public static Set<Mark> getMarks() {
|
||||||
return Collections.unmodifiableSet(marks);
|
return Collections.unmodifiableSet(marks);
|
||||||
}
|
}
|
||||||
@@ -245,10 +241,6 @@ public class GameState implements Runnable {
|
|||||||
if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
|
if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStage == GameStages.RACING) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +265,12 @@ public class GameState implements Runnable {
|
|||||||
case DOWNWIND:
|
case DOWNWIND:
|
||||||
playerYacht.turnDownwind();
|
playerYacht.turnDownwind();
|
||||||
break;
|
break;
|
||||||
|
case CONTINUOUSLY_TURNING:
|
||||||
|
playerYacht.setContinuouslyTurning(true);
|
||||||
|
break;
|
||||||
|
case DEFAULT_TURNING:
|
||||||
|
playerYacht.setContinuouslyTurning(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,22 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.model.GeoPoint;
|
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.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLGenerator;
|
|
||||||
import seng302.utilities.XMLParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -45,29 +37,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();;
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
private static Integer capacity;
|
private static Integer capacity;
|
||||||
|
private RaceXMLData raceXMLData;
|
||||||
|
private RegattaXMLData regattaXMLData;
|
||||||
|
|
||||||
private void startAdvertisingServer() {
|
private void startAdvertisingServer() {
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder db;
|
|
||||||
Document doc;
|
|
||||||
XMLGenerator generator = new XMLGenerator();
|
|
||||||
|
|
||||||
try {
|
|
||||||
db = dbf.newDocumentBuilder();
|
|
||||||
String regatta = generator.getRegattaAsXml();
|
|
||||||
StringReader stringReader = new StringReader(regatta);
|
|
||||||
InputSource is = new InputSource(stringReader);
|
|
||||||
doc = db.parse(is);
|
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
|
||||||
logger.warn("Couldn't load race regatta");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc);
|
|
||||||
|
|
||||||
|
|
||||||
Integer capacity = GameState.getCapacity();
|
Integer capacity = GameState.getCapacity();
|
||||||
Integer numPlayers = GameState.getNumberOfPlayers();
|
Integer numPlayers = GameState.getNumberOfPlayers();
|
||||||
Integer spacesLeft = capacity - numPlayers;
|
Integer spacesLeft = capacity - numPlayers;
|
||||||
@@ -79,33 +54,40 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
|
|
||||||
// Start advertising server
|
// Start advertising server
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setCapacity(capacity).setNumberOfPlayers(numPlayers);
|
ServerAdvertiser.getInstance()
|
||||||
ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName());
|
.setMapName(regattaXMLData.getCourseName())
|
||||||
|
.setCapacity(capacity)
|
||||||
|
.setNumberOfPlayers(numPlayers)
|
||||||
|
.registerGame(PORT, regattaXMLData.getRegattaName());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Could not register server");
|
logger.warn("Could not register server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainServerThread() {
|
public MainServerThread() {
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
try {
|
try {
|
||||||
serverSocket = new ServerSocket(PORT);
|
serverSocket = new ServerSocket(PORT);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
startAdvertisingServer();
|
|
||||||
|
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
|
||||||
GameState.addMessageEventListener(this::broadcastMessage);
|
|
||||||
terminated = false;
|
terminated = false;
|
||||||
thread = new Thread(this, "MainServer");
|
thread = new Thread(this, "MainServer");
|
||||||
startUpdatingWind();
|
|
||||||
startSpawningTokens();
|
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startServer() {
|
||||||
|
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
||||||
|
GameState.setRace(raceXMLData);
|
||||||
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
|
startAdvertisingServer();
|
||||||
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
||||||
|
GameState.addMessageEventListener(this::broadcastMessage);
|
||||||
|
startUpdatingWind();
|
||||||
|
startSpawningTokens();
|
||||||
|
sendSetupMessages();
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
@@ -133,8 +115,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
||||||
}
|
}
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
|
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
|
||||||
.getCustomizationFlag()) {
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
GameState.resetCustomizationFlag();
|
GameState.resetCustomizationFlag();
|
||||||
}
|
}
|
||||||
@@ -254,11 +236,28 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
||||||
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
||||||
serverToClientThread.setAsHost();
|
serverToClientThread.setAsHost();
|
||||||
|
serverToClientThread.raceXMLProperty().addListener((obs, oldVal, race) -> {
|
||||||
|
if (race != null) {
|
||||||
|
raceXMLData = race;
|
||||||
|
}
|
||||||
|
if (regattaXMLData != null) {
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
serverToClientThread.regattaXMLProperty().addListener((obs, oldVal, regatta) -> {
|
||||||
|
if (regatta != null) {
|
||||||
|
regattaXMLData = regatta;
|
||||||
|
}
|
||||||
|
if (raceXMLData != null) {
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
||||||
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
}
|
}
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import seng302.model.Player;
|
|||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
@@ -38,6 +40,47 @@ Ideally this class would be created with an instance of the GameState (I tried i
|
|||||||
public class MessageFactory {
|
public class MessageFactory {
|
||||||
|
|
||||||
private static XMLGenerator xmlGenerator = new XMLGenerator();
|
private static XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
private static XMLMessage race;
|
||||||
|
private static XMLMessage regatta;
|
||||||
|
private static XMLMessage boats;
|
||||||
|
|
||||||
|
public static void updateXMLGenerator(RaceXMLData race, RegattaXMLData regatta) {
|
||||||
|
xmlGenerator.setRegattaTemplate(
|
||||||
|
new RegattaXMLTemplate(
|
||||||
|
regatta.getRegattaName(),
|
||||||
|
regatta.getCourseName(),
|
||||||
|
regatta.getCentralLat(),
|
||||||
|
regatta.getCentralLng()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
xmlGenerator.setRaceTemplate(
|
||||||
|
new RaceXMLTemplate(
|
||||||
|
new ArrayList<>(),
|
||||||
|
new ArrayList<>(),
|
||||||
|
race.getMarkSequence(),
|
||||||
|
race.getCourseLimit(),
|
||||||
|
new ArrayList<>(race.getCompoundMarks().values())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
String xmlStr = xmlGenerator.getRaceAsXml();
|
||||||
|
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
|
||||||
|
xmlStr = xmlGenerator.getRegattaAsXml();
|
||||||
|
MessageFactory.regatta = new XMLMessage(xmlStr, XMLMessageSubType.REGATTA, xmlStr.length());
|
||||||
|
xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateBoats(List<ServerYacht> yachts) {
|
||||||
|
xmlGenerator.getRace().setBoats(yachts);
|
||||||
|
String xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateTokens(List<Token> tokens) {
|
||||||
|
xmlGenerator.getRace().setTokens(tokens);
|
||||||
|
String xmlStr = xmlGenerator.getRaceAsXml();
|
||||||
|
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static RaceStartStatusMessage getRaceStartStatusMessage() {
|
public static RaceStartStatusMessage getRaceStartStatusMessage() {
|
||||||
@@ -98,38 +141,15 @@ public class MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getRaceXML() {
|
public static XMLMessage getRaceXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
return race;
|
||||||
List<Token> tokens = GameState.getTokensInPlay();
|
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
|
||||||
|
|
||||||
XMLMessage raceXMLMessage = new XMLMessage(
|
|
||||||
xmlGenerator.getRaceAsXml(),
|
|
||||||
XMLMessageSubType.RACE,
|
|
||||||
xmlGenerator.getRaceAsXml().length());
|
|
||||||
|
|
||||||
return raceXMLMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getRegattaXML() {
|
public static XMLMessage getRegattaXML() {
|
||||||
//@TODO calculate lat/lng values
|
return regatta;
|
||||||
|
|
||||||
return new XMLMessage(
|
|
||||||
xmlGenerator.getRegattaAsXml(),
|
|
||||||
XMLMessageSubType.REGATTA,
|
|
||||||
xmlGenerator.getRegattaAsXml().length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XMLMessage getBoatXML() {
|
public static XMLMessage getBoatXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
return boats;
|
||||||
List<Token> tokens = GameState.getTokensInPlay();
|
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
|
||||||
|
|
||||||
return new XMLMessage(
|
|
||||||
xmlGenerator.getBoatsAsXml(),
|
|
||||||
XMLMessageSubType.BOAT,
|
|
||||||
xmlGenerator.getBoatsAsXml().length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
|
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
@@ -25,15 +22,16 @@ import seng302.gameServer.messages.CustomizeRequestType;
|
|||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RegistrationResponseMessage;
|
import seng302.gameServer.messages.RegistrationResponseMessage;
|
||||||
import seng302.gameServer.messages.RegistrationResponseStatus;
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
import seng302.gameServer.messages.XMLMessage;
|
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
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.xml.generator.RaceXMLTemplate;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.utilities.StreamParser;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -81,6 +79,9 @@ public class ServerToClientThread implements Runnable {
|
|||||||
private ServerYacht yacht;
|
private ServerYacht yacht;
|
||||||
private Player player;
|
private Player player;
|
||||||
|
|
||||||
|
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
|
||||||
|
private SimpleObjectProperty<RegattaXMLData> regattaXMLProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public ServerToClientThread(Socket socket) {
|
public ServerToClientThread(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
seqNo = 0;
|
seqNo = 0;
|
||||||
@@ -101,30 +102,8 @@ public class ServerToClientThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setUpPlayer(){
|
private void setUpPlayer(){
|
||||||
BufferedReader fn;
|
String fName = "Player" + GameState.getNumberOfPlayers().toString();
|
||||||
String fName = "";
|
|
||||||
BufferedReader ln;
|
|
||||||
String lName = "";
|
String lName = "";
|
||||||
|
|
||||||
fn = new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
ServerToClientThread.class.getResourceAsStream(
|
|
||||||
"/server_config/CSV_Database_of_First_Names.csv"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
List<String> all = fn.lines().collect(Collectors.toList());
|
|
||||||
fName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
|
||||||
ln = new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
ServerToClientThread.class.getResourceAsStream(
|
|
||||||
"/server_config/CSV_Database_of_Last_Names.csv"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
all = ln.lines().collect(Collectors.toList());
|
|
||||||
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
|
||||||
|
|
||||||
ServerYacht yacht = new ServerYacht(
|
ServerYacht yacht = new ServerYacht(
|
||||||
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
||||||
);
|
);
|
||||||
@@ -186,37 +165,51 @@ public class ServerToClientThread implements Runnable {
|
|||||||
long computedCrc = checksum.getValue();
|
long computedCrc = checksum.getValue();
|
||||||
long packetCrc = Message.bytesToLong(getBytes(4));
|
long packetCrc = Message.bytesToLong(getBytes(4));
|
||||||
if (computedCrc == packetCrc) {
|
if (computedCrc == packetCrc) {
|
||||||
|
StreamPacket packet = new StreamPacket(type, payloadLength, timeStamp, payload);
|
||||||
switch (PacketType.assignPacketType(type, payload)) {
|
switch (PacketType.assignPacketType(type, payload)) {
|
||||||
case BOAT_ACTION:
|
case BOAT_ACTION:
|
||||||
BoatAction actionType = ServerPacketParser
|
BoatAction actionType = ServerPacketParser.extractBoatAction(packet);
|
||||||
.extractBoatAction(
|
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.updateBoat(sourceId, actionType);
|
GameState.updateBoat(sourceId, actionType);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RACE_REGISTRATION_REQUEST:
|
case RACE_REGISTRATION_REQUEST:
|
||||||
ClientType requestedType = ServerPacketParser.extractClientType(
|
ClientType requestedType = ServerPacketParser
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
.extractClientType(packet);
|
||||||
|
|
||||||
completeRegistration(requestedType);
|
completeRegistration(requestedType);
|
||||||
break;
|
break;
|
||||||
case CHATTER_TEXT:
|
case CHATTER_TEXT:
|
||||||
ChatterMessage chatterMessage = ServerPacketParser
|
ChatterMessage chatterMessage = ServerPacketParser
|
||||||
.extractChatterText(
|
.extractChatterText(packet);
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.processChatter(chatterMessage, isHost);
|
GameState.processChatter(chatterMessage, isHost);
|
||||||
break;
|
break;
|
||||||
case RACE_CUSTOMIZATION_REQUEST:
|
case RACE_CUSTOMIZATION_REQUEST:
|
||||||
Long sourceID = Message
|
Long sourceID = Message.bytesToLong(
|
||||||
.bytesToLong(Arrays.copyOfRange(payload, 0, 3));
|
Arrays.copyOfRange(payload, 0, 3)
|
||||||
|
);
|
||||||
CustomizeRequestType requestType = ServerPacketParser
|
CustomizeRequestType requestType = ServerPacketParser
|
||||||
.extractCustomizationType(
|
.extractCustomizationType(packet);
|
||||||
new StreamPacket(type, payloadLength, timeStamp, payload));
|
|
||||||
GameState.customizePlayer(sourceID, requestType,
|
GameState.customizePlayer(sourceID, requestType,
|
||||||
Arrays.copyOfRange(payload, 6, payload.length));
|
Arrays.copyOfRange(payload, 6, payload.length)
|
||||||
|
);
|
||||||
GameState.setCustomizationFlag();
|
GameState.setCustomizationFlag();
|
||||||
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
|
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
|
||||||
break;
|
break;
|
||||||
|
case RACE_XML:
|
||||||
|
raceXMLProperty.set(
|
||||||
|
XMLParser.parseRace(
|
||||||
|
StreamParser.extractXmlMessage(packet)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case REGATTA_XML:
|
||||||
|
regattaXMLProperty.set(
|
||||||
|
XMLParser.parseRegatta(
|
||||||
|
StreamParser.extractXmlMessage(packet)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Packet has been dropped", 1);
|
logger.warn("Packet has been dropped", 1);
|
||||||
@@ -233,23 +226,9 @@ public class ServerToClientThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendSetupMessages() {
|
public void sendSetupMessages() {
|
||||||
xmlGenerator = new XMLGenerator();
|
sendMessage(MessageFactory.getRegattaXML());
|
||||||
RaceXMLTemplate race = new RaceXMLTemplate(new ArrayList<>(GameState.getYachts().values()), new ArrayList<>());
|
sendMessage(MessageFactory.getBoatXML());
|
||||||
|
sendMessage(MessageFactory.getRaceXML());
|
||||||
xmlGenerator.setRaceTemplate(race);
|
|
||||||
|
|
||||||
XMLMessage xmlMessage;
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getRegattaAsXml(), XMLMessageSubType.REGATTA,
|
|
||||||
xmlGenerator.getRegattaAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getBoatsAsXml(), XMLMessageSubType.BOAT,
|
|
||||||
xmlGenerator.getBoatsAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xmlGenerator.getRaceAsXml(), XMLMessageSubType.RACE,
|
|
||||||
xmlGenerator.getRaceAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeSocket() {
|
private void closeSocket() {
|
||||||
@@ -345,4 +324,12 @@ public class ServerToClientThread implements Runnable {
|
|||||||
public void setAsHost() {
|
public void setAsHost() {
|
||||||
isHost = true;
|
isHost = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SimpleObjectProperty<RaceXMLData> raceXMLProperty() {
|
||||||
|
return raceXMLProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleObjectProperty<RegattaXMLData> regattaXMLProperty() {
|
||||||
|
return regattaXMLProperty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ public enum BoatAction {
|
|||||||
TACK_GYBE(4),
|
TACK_GYBE(4),
|
||||||
UPWIND(5),
|
UPWIND(5),
|
||||||
DOWNWIND(6),
|
DOWNWIND(6),
|
||||||
MAINTAIN_HEADING(7);
|
MAINTAIN_HEADING(7),
|
||||||
|
CONTINUOUSLY_TURNING(8),
|
||||||
|
DEFAULT_TURNING(9);
|
||||||
|
|
||||||
private final int type;
|
private final int type;
|
||||||
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
|
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ package seng302.gameServer.messages;
|
|||||||
*/
|
*/
|
||||||
public class BoatActionMessage extends Message{
|
public class BoatActionMessage extends Message{
|
||||||
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
|
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
|
||||||
private final int MESSAGE_SIZE = 1;
|
private final int MESSAGE_SIZE = 5;
|
||||||
private BoatAction actionType;
|
private BoatAction actionType;
|
||||||
|
|
||||||
public BoatActionMessage(BoatAction actionType) {
|
public BoatActionMessage(BoatAction actionType, int sourceId) {
|
||||||
this.actionType = actionType;
|
this.actionType = actionType;
|
||||||
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
|
setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
// Write message fields
|
// Write message fields
|
||||||
putInt(actionType.getValue(), 1);
|
putInt(actionType.getValue(), 1);
|
||||||
|
putInt(sourceId, 4);
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ package seng302.gameServer.messages;
|
|||||||
public class RegistrationRequestMessage extends Message {
|
public class RegistrationRequestMessage extends Message {
|
||||||
private static int MESSAGE_LENGTH = 2;
|
private static int MESSAGE_LENGTH = 2;
|
||||||
|
|
||||||
public RegistrationRequestMessage(ClientType type){
|
public RegistrationRequestMessage(ClientType type, int clientID){
|
||||||
setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize()));
|
setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize()));
|
||||||
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
|
||||||
|
public class GameKeyBind {
|
||||||
|
|
||||||
|
private static GameKeyBind instance;
|
||||||
|
private Map<KeyCode, KeyAction> keyToActionMap;
|
||||||
|
private Map<KeyAction, KeyCode> actionToKeyMap;
|
||||||
|
private Boolean continuouslyTurning;
|
||||||
|
|
||||||
|
|
||||||
|
private GameKeyBind() {
|
||||||
|
setToDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToDefault() {
|
||||||
|
actionToKeyMap = new HashMap<>();
|
||||||
|
keyToActionMap = new HashMap<>();
|
||||||
|
continuouslyTurning = false;
|
||||||
|
// default key bindings
|
||||||
|
ArrayList<KeyCode> keys = new ArrayList<>();
|
||||||
|
keys.add(KeyCode.Z);
|
||||||
|
keys.add(KeyCode.X);
|
||||||
|
keys.add(KeyCode.SPACE);
|
||||||
|
keys.add(KeyCode.SHIFT);
|
||||||
|
keys.add(KeyCode.ENTER);
|
||||||
|
keys.add(KeyCode.PAGE_UP);
|
||||||
|
keys.add(KeyCode.PAGE_DOWN);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
|
||||||
|
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameKeyBind getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new GameKeyBind();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyCode getKeyCode(KeyAction keyAction) {
|
||||||
|
return instance.actionToKeyMap.get(keyAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a key to a key action
|
||||||
|
*
|
||||||
|
* @return true if successfully bind
|
||||||
|
*/
|
||||||
|
public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) {
|
||||||
|
if (instance.keyToActionMap.containsKey(keyCode)) {
|
||||||
|
// if the key has been bound to other action, return false
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
instance.keyToActionMap.put(keyCode, keyAction); // add key -> action
|
||||||
|
KeyCode oldKeyCode = instance.actionToKeyMap
|
||||||
|
.get(keyAction); // get old key for the action
|
||||||
|
instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action
|
||||||
|
instance.actionToKeyMap
|
||||||
|
.replace(keyAction, keyCode); // replace the old key by the newer one
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleTurningMode() {
|
||||||
|
continuouslyTurning = !continuouslyTurning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isContinuouslyTurning() {
|
||||||
|
return continuouslyTurning;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum KeyAction {
|
||||||
|
ZOOM_IN(1),
|
||||||
|
ZOOM_OUT(2),
|
||||||
|
VMG(3),
|
||||||
|
SAILS_STATE(4),
|
||||||
|
TACK_GYBE(5),
|
||||||
|
UPWIND(6),
|
||||||
|
DOWNWIND(7);
|
||||||
|
|
||||||
|
private final int type;
|
||||||
|
private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (KeyAction type : KeyAction.values()) {
|
||||||
|
intToTypeMap.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyAction(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyAction getType(int value) {
|
||||||
|
return intToTypeMap.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,4 +15,9 @@ public class Limit extends GeoPoint {
|
|||||||
public Integer getSeqID() {
|
public Integer getSeqID() {
|
||||||
return seqID;
|
return seqID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "Limit = {seqID=" + seqID + ", lat=" + getLat() + ", lng=" + getLng() + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information on a scaled lat lon point for use with mapping geographical elements to a 2d plane.
|
||||||
|
*/
|
||||||
|
public class ScaledPoint extends GeoPoint {
|
||||||
|
|
||||||
|
public enum ScaleDirection {
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL
|
||||||
|
}
|
||||||
|
|
||||||
|
private double x, y, scaleFactor;
|
||||||
|
private ScaleDirection scaleDirection;
|
||||||
|
|
||||||
|
private ScaledPoint(double lat, double lng, double x, double y, double scaleFactor, ScaleDirection direction) {
|
||||||
|
super(lat, lng);
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.scaleFactor = scaleFactor;
|
||||||
|
this.scaleDirection = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScaleFactor() {
|
||||||
|
return scaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScaleDirection getScaleDirection() {
|
||||||
|
return scaleDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point2D findScaledXY(GeoPoint unscaled) {
|
||||||
|
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
||||||
|
double distanceFromReference;
|
||||||
|
double angleFromReference;
|
||||||
|
double xReference = this.getX();
|
||||||
|
double yReference = this.getY();
|
||||||
|
|
||||||
|
angleFromReference = GeoUtility.getBearingRad(
|
||||||
|
this, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
|
);
|
||||||
|
distanceFromReference = GeoUtility.getDistance(
|
||||||
|
this, new GeoPoint(unscaledLat, unscaledLon)
|
||||||
|
);
|
||||||
|
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
||||||
|
xReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
} else if (angleFromReference >= 0) {
|
||||||
|
angleFromReference = angleFromReference - Math.PI / 2;
|
||||||
|
xReference += scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
||||||
|
angleFromReference = Math.abs(angleFromReference);
|
||||||
|
xReference -= scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
} else {
|
||||||
|
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
||||||
|
xReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
||||||
|
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
||||||
|
}
|
||||||
|
return new Point2D(xReference, yReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScaledPoint makeScaledPoint(double width, double height,
|
||||||
|
List<? extends GeoPoint> points, boolean centered) {
|
||||||
|
|
||||||
|
double referencePointX, referencePointY, scaleFactor, lat, lng;
|
||||||
|
ScaleDirection scaleDirection;
|
||||||
|
points = new ArrayList<>(points);
|
||||||
|
points.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
||||||
|
GeoPoint minLatPoint = points.get(0);
|
||||||
|
GeoPoint maxLatPoint = points.get(points.size() - 1);
|
||||||
|
|
||||||
|
points.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
||||||
|
GeoPoint minLonPoint = points.get(0);
|
||||||
|
GeoPoint maxLonPoint = points.get(points.size() - 1);
|
||||||
|
|
||||||
|
referencePointX = centered ? 0 : width / 2;
|
||||||
|
referencePointY = centered ? 0 : height / 2;
|
||||||
|
|
||||||
|
lat = (maxLatPoint.getLat() - minLatPoint.getLat()) / 2 + minLatPoint.getLat();
|
||||||
|
lng = (maxLonPoint.getLng() - minLonPoint.getLng()) / 2 + minLonPoint.getLng();
|
||||||
|
|
||||||
|
GeoPoint ref = new GeoPoint(lat, lng);
|
||||||
|
|
||||||
|
double vertDistance = GeoUtility.getDistance(
|
||||||
|
ref, new GeoPoint(ref.getLat(), maxLonPoint.getLng())
|
||||||
|
) * 2.1;
|
||||||
|
|
||||||
|
double horiDistance = GeoUtility.getDistance(
|
||||||
|
ref, new GeoPoint(maxLatPoint.getLat(), ref.getLng())
|
||||||
|
) * 2.1;
|
||||||
|
|
||||||
|
double vertScale = height / vertDistance;
|
||||||
|
|
||||||
|
if (horiDistance * vertScale > width) {
|
||||||
|
scaleFactor = width / horiDistance;
|
||||||
|
scaleDirection = ScaleDirection.HORIZONTAL;
|
||||||
|
} else {
|
||||||
|
scaleFactor = vertScale;
|
||||||
|
scaleDirection = ScaleDirection.VERTICAL;
|
||||||
|
}
|
||||||
|
return new ScaledPoint(lat, lng, referencePointX, referencePointY, scaleFactor, scaleDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package seng302.model;
|
package seng302.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
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;
|
||||||
@@ -10,12 +11,6 @@ import seng302.model.token.TokenType;
|
|||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Observable;
|
|
||||||
import java.util.Observer;
|
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
* 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
|
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
||||||
@@ -61,6 +56,8 @@ public class ServerYacht {
|
|||||||
private TokenType powerUp;
|
private TokenType powerUp;
|
||||||
private Long powerUpStartTime;
|
private Long powerUpStartTime;
|
||||||
|
|
||||||
|
//turning mode
|
||||||
|
private Boolean continuouslyTurning;
|
||||||
|
|
||||||
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
|
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
|
||||||
String boatName, String country) {
|
String boatName, String country) {
|
||||||
@@ -85,6 +82,8 @@ public class ServerYacht {
|
|||||||
this.hasEnteredRoundingZone = false;
|
this.hasEnteredRoundingZone = false;
|
||||||
this.hasPassedLine = false;
|
this.hasPassedLine = false;
|
||||||
this.hasPassedThroughGate = false;
|
this.hasPassedThroughGate = false;
|
||||||
|
|
||||||
|
this.continuouslyTurning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -192,44 +191,52 @@ public class ServerYacht {
|
|||||||
public void turnUpwind() {
|
public void turnUpwind() {
|
||||||
disableAutoPilot();
|
disableAutoPilot();
|
||||||
Double normalizedHeading = normalizeHeading();
|
Double normalizedHeading = normalizeHeading();
|
||||||
if (normalizedHeading == 0) {
|
if (continuouslyTurning) {
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(-turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(turnStep);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-turnStep);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(-turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(turnStep);
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
if (normalizedHeading == 0) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading == 180) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void turnDownwind() {
|
public void turnDownwind() {
|
||||||
disableAutoPilot();
|
disableAutoPilot();
|
||||||
Double normalizedHeading = normalizeHeading();
|
Double normalizedHeading = normalizeHeading();
|
||||||
if (normalizedHeading == 0) {
|
if (continuouslyTurning) {
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-turnStep);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading == 180) {
|
|
||||||
if (lastHeading < 180) {
|
|
||||||
adjustHeading(-turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(turnStep);
|
|
||||||
}
|
|
||||||
} else if (normalizedHeading < 180) {
|
|
||||||
adjustHeading(turnStep);
|
|
||||||
} else {
|
|
||||||
adjustHeading(-turnStep);
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
if (normalizedHeading == 0) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading == 180) {
|
||||||
|
if (lastHeading < 180) {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
}
|
||||||
|
} else if (normalizedHeading < 180) {
|
||||||
|
adjustHeading(turnStep);
|
||||||
|
} else {
|
||||||
|
adjustHeading(-turnStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,4 +452,8 @@ public class ServerYacht {
|
|||||||
public BoatMeshType getBoatType() {
|
public BoatMeshType getBoatType() {
|
||||||
return boatType;
|
return boatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setContinuouslyTurning(Boolean continuouslyTurning) {
|
||||||
|
this.continuouslyTurning = continuouslyTurning;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package seng302.model.mark;
|
package seng302.model.mark;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
@@ -10,13 +10,13 @@ public class CompoundMark {
|
|||||||
|
|
||||||
private int compoundMarkId;
|
private int compoundMarkId;
|
||||||
private String name;
|
private String name;
|
||||||
private List<Mark> marks = new ArrayList<>();
|
private List<Mark> marks;
|
||||||
private GeoPoint midPoint;
|
private GeoPoint midPoint;
|
||||||
|
|
||||||
public CompoundMark(int markID, String name, List<Mark> marks) {
|
public CompoundMark(int markID, String name, List<Mark> marks) {
|
||||||
this.compoundMarkId = markID;
|
this.compoundMarkId = markID;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.marks.addAll(marks);
|
this.marks = Collections.unmodifiableList(marks);
|
||||||
if (marks.size() > 1) {
|
if (marks.size() > 1) {
|
||||||
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
|
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -32,4 +32,10 @@ public class Corner {
|
|||||||
public Integer getZoneSize() {
|
public Integer getZoneSize() {
|
||||||
return zoneSize;
|
return zoneSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Corner = {seqID=" + seqID + ", compoundMarkID=" + compoundMarkID + ", rounding="
|
||||||
|
+ rounding +", zoneSize=" + zoneSize + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,12 @@
|
|||||||
package seng302.model.mark;
|
package seng302.model.mark;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.ArrayList;
|
||||||
import java.io.StringReader;
|
import java.util.Collections;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import java.util.List;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.token.Token;
|
|
||||||
import seng302.utilities.XMLGenerator;
|
|
||||||
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.
|
||||||
@@ -25,10 +14,17 @@ import java.util.*;
|
|||||||
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(){
|
|
||||||
loadRaceProperties();
|
public MarkOrder(RaceXMLData raceXMLData){
|
||||||
|
raceMarkOrder = new ArrayList<>();
|
||||||
|
for (Corner corner : raceXMLData.getMarkSequence()){
|
||||||
|
CompoundMark compoundMark = raceXMLData.getCompoundMarks().get(corner.getCompoundMarkID());
|
||||||
|
compoundMark.setRoundingSide(
|
||||||
|
RoundingSide.getRoundingSide(corner.getRounding())
|
||||||
|
);
|
||||||
|
raceMarkOrder.add(compoundMark);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +36,6 @@ public class MarkOrder {
|
|||||||
logger.warn("Race order accessed but not instantiated");
|
logger.warn("Race order accessed but not instantiated");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableList(raceMarkOrder);
|
return Collections.unmodifiableList(raceMarkOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,70 +69,4 @@ public class MarkOrder {
|
|||||||
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
|
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
|
||||||
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
|
|
||||||
* @param xml An AC35 RaceXML
|
|
||||||
* @return An ordered list of marks in the race
|
|
||||||
*/
|
|
||||||
private List<CompoundMark> loadRaceOrderFromXML(String xml) {
|
|
||||||
|
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder db;
|
|
||||||
Document doc;
|
|
||||||
allMarks = new HashSet<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
db = dbf.newDocumentBuilder();
|
|
||||||
doc = db.parse(new InputSource(new StringReader(xml)));
|
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
|
||||||
logger.error("Failed to read generated race XML");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
RaceXMLData data = XMLParser.parseRace(doc);
|
|
||||||
|
|
||||||
if (data != null){
|
|
||||||
logger.debug("Loaded RaceXML for mark order");
|
|
||||||
List<Corner> corners = data.getMarkSequence();
|
|
||||||
Map<Integer, CompoundMark> marks = data.getCompoundMarks();
|
|
||||||
List<CompoundMark> course = new ArrayList<>();
|
|
||||||
for (Corner corner : corners){
|
|
||||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
|
||||||
compoundMark.setRoundingSide(
|
|
||||||
RoundingSide.getRoundingSide(corner.getRounding())
|
|
||||||
);
|
|
||||||
course.add(compoundMark);
|
|
||||||
allMarks.addAll(compoundMark.getMarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
return course;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the raceXML and mark order
|
|
||||||
*/
|
|
||||||
private void loadRaceProperties(){
|
|
||||||
XMLGenerator generator = new XMLGenerator();
|
|
||||||
|
|
||||||
// TODO: 29/08/17 wmu16 - This is terrible, having to make a template just to receive constant data
|
|
||||||
generator.setRaceTemplate(new RaceXMLTemplate(
|
|
||||||
new ArrayList<>(),
|
|
||||||
new ArrayList<>()));
|
|
||||||
|
|
||||||
String raceXML = generator.getRaceAsXml();
|
|
||||||
|
|
||||||
if (raceXML == null){
|
|
||||||
logger.error("Failed to generate raceXML (for race properties)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
raceMarkOrder = loadRaceOrderFromXML(raceXML);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package seng302.model.stream.xml.generator;
|
package seng302.model.stream.xml.generator;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import seng302.model.Limit;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,10 +17,17 @@ public class RaceXMLTemplate {
|
|||||||
private List<ServerYacht> yachts;
|
private List<ServerYacht> yachts;
|
||||||
private LocalDateTime startTime;
|
private LocalDateTime startTime;
|
||||||
private List<Token> tokens;
|
private List<Token> tokens;
|
||||||
|
private List<Corner> roundings;
|
||||||
|
private List<Limit> courseLimit;
|
||||||
|
private List<CompoundMark> course;
|
||||||
|
|
||||||
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens) {
|
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens, List<Corner> roundings,
|
||||||
|
List<Limit> limit, List<CompoundMark> course) {
|
||||||
this.yachts = yachts;
|
this.yachts = yachts;
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
|
this.roundings = roundings;
|
||||||
|
this.courseLimit = limit;
|
||||||
|
this.course = course;
|
||||||
startTime = LocalDateTime.now();
|
startTime = LocalDateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +48,18 @@ public class RaceXMLTemplate {
|
|||||||
return Collections.unmodifiableList(tokens);
|
return Collections.unmodifiableList(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<CompoundMark> getCompoundMarks() {
|
||||||
|
return Collections.unmodifiableList(course);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Limit> getCourseLimit() {
|
||||||
|
return Collections.unmodifiableList(courseLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Corner> getRoundings() {
|
||||||
|
return Collections.unmodifiableList(roundings);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time until the race starts
|
* Set the time until the race starts
|
||||||
* @param seconds The time in seconds until the race starts
|
* @param seconds The time in seconds until the race starts
|
||||||
@@ -54,4 +75,12 @@ public class RaceXMLTemplate {
|
|||||||
public String getRaceStartTime(){
|
public String getRaceStartTime(){
|
||||||
return startTime.toString();
|
return startTime.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBoats(List<ServerYacht> boats) {
|
||||||
|
yachts = boats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTokens(List<Token> tokens) {
|
||||||
|
this.tokens = tokens;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,4 +179,8 @@ public class XMLGenerator {
|
|||||||
public RegattaXMLTemplate getRegatta() {
|
public RegattaXMLTemplate getRegatta() {
|
||||||
return regatta;
|
return regatta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RaceXMLTemplate getRace() {
|
||||||
|
return race;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,29 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
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.Random;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.Colors;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
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.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
@@ -139,14 +149,26 @@ public class XMLParser {
|
|||||||
Node currentBoat = boatsList.item(i);
|
Node currentBoat = boatsList.item(i);
|
||||||
if (currentBoat.getNodeName().equals("Boat")) {
|
if (currentBoat.getNodeName().equals("Boat")) {
|
||||||
// Boat boat = new Boat(currentBoat);
|
// Boat boat = new Boat(currentBoat);
|
||||||
|
BoatMeshType boatMeshType;
|
||||||
|
try {
|
||||||
|
boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type"));
|
||||||
|
} catch (IllegalArgumentException e){
|
||||||
|
boatMeshType = BoatMeshType.DINGHY;
|
||||||
|
}
|
||||||
|
Color color;
|
||||||
|
try {
|
||||||
|
color = Color.web(getNodeAttributeString(currentBoat, "Color"));
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
color = Colors.getColor(new Random().nextInt(8));
|
||||||
|
}
|
||||||
ClientYacht yacht = new ClientYacht(
|
ClientYacht yacht = new ClientYacht(
|
||||||
BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")),
|
boatMeshType,
|
||||||
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
|
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
|
XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
|
XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
|
XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
|
||||||
XMLParser.getNodeAttributeString(currentBoat, "Country"));
|
XMLParser.getNodeAttributeString(currentBoat, "Country"));
|
||||||
yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color")));
|
yacht.setColour(color);
|
||||||
competingBoats.put(yacht.getSourceId(), yacht);
|
competingBoats.put(yacht.getSourceId(), yacht);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +204,7 @@ public class XMLParser {
|
|||||||
public static RaceXMLData parseRace(Document doc) {
|
public static RaceXMLData parseRace(Document doc) {
|
||||||
Element docEle = doc.getDocumentElement();
|
Element docEle = doc.getDocumentElement();
|
||||||
return new RaceXMLData(
|
return new RaceXMLData(
|
||||||
extractParticpantIDs(docEle),
|
extractParticipantIDs(docEle),
|
||||||
extractTokens(docEle),
|
extractTokens(docEle),
|
||||||
extractCompoundMarks(docEle),
|
extractCompoundMarks(docEle),
|
||||||
extractMarkOrder(docEle),
|
extractMarkOrder(docEle),
|
||||||
@@ -195,17 +217,20 @@ public class XMLParser {
|
|||||||
*/
|
*/
|
||||||
private static List<Token> extractTokens(Element docEle) {
|
private static List<Token> extractTokens(Element docEle) {
|
||||||
List<Token> tokens = new ArrayList<>();
|
List<Token> tokens = new ArrayList<>();
|
||||||
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
|
try {
|
||||||
for (int i = 0; i < tokenList.getLength(); i++) {
|
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
|
||||||
Node tokenNode = tokenList.item(i);
|
for (int i = 0; i < tokenList.getLength(); i++) {
|
||||||
if (tokenNode.getNodeName().equals("Token")) {
|
Node tokenNode = tokenList.item(i);
|
||||||
String tokenType = getNodeAttributeString(tokenNode, "TokenType");
|
if (tokenNode.getNodeName().equals("Token")) {
|
||||||
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
|
String tokenType = getNodeAttributeString(tokenNode, "TokenType");
|
||||||
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
|
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
|
||||||
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
|
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
|
||||||
|
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,13 +243,11 @@ public class XMLParser {
|
|||||||
for (int i = 0; i < limitList.getLength(); i++) {
|
for (int i = 0; i < limitList.getLength(); i++) {
|
||||||
Node limitNode = limitList.item(i);
|
Node limitNode = limitList.item(i);
|
||||||
if (limitNode.getNodeName().equals("Limit")) {
|
if (limitNode.getNodeName().equals("Limit")) {
|
||||||
courseLimit.add(
|
courseLimit.add(new Limit(
|
||||||
new Limit(
|
XMLParser.getNodeAttributeInt(limitNode, "SeqID"),
|
||||||
XMLParser.getNodeAttributeInt(limitNode, "SeqID"),
|
XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
||||||
XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
XMLParser.getNodeAttributeDouble(limitNode, "Lon")
|
||||||
XMLParser.getNodeAttributeDouble(limitNode, "Lon")
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return courseLimit;
|
return courseLimit;
|
||||||
@@ -256,7 +279,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* Extracts course participants data
|
* Extracts course participants data
|
||||||
*/
|
*/
|
||||||
private static List<Integer> extractParticpantIDs (Element docEle) {
|
private static List<Integer> extractParticipantIDs(Element docEle) {
|
||||||
List<Integer> boatIDs = new ArrayList<>();
|
List<Integer> boatIDs = new ArrayList<>();
|
||||||
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
|
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
|
||||||
for (int i = 0; i < pList.getLength(); i++) {
|
for (int i = 0; i < pList.getLength(); i++) {
|
||||||
@@ -278,10 +301,11 @@ public class XMLParser {
|
|||||||
for (int i = 0; i < cMarkList.getLength(); i++) {
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
Node cMarkNode = cMarkList.item(i);
|
Node cMarkNode = cMarkList.item(i);
|
||||||
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
|
String name = XMLParser.getNodeAttributeString(cMarkNode, "Name");
|
||||||
|
name = (name == null || name.equals("")) ? "Mark " + i+1: name;
|
||||||
cMark = new CompoundMark(
|
cMark = new CompoundMark(
|
||||||
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
|
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
|
||||||
XMLParser.getNodeAttributeString(cMarkNode, "Name"),
|
name, createMarks(cMarkNode)
|
||||||
createMarks(cMarkNode)
|
|
||||||
);
|
);
|
||||||
allMarks.add(cMark);
|
allMarks.add(cMark);
|
||||||
}
|
}
|
||||||
@@ -302,14 +326,156 @@ public class XMLParser {
|
|||||||
Node markNode = childMarks.item(i);
|
Node markNode = childMarks.item(i);
|
||||||
if (markNode.getNodeName().equals("Mark")) {
|
if (markNode.getNodeName().equals("Mark")) {
|
||||||
Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID");
|
Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID");
|
||||||
|
seqID = (seqID == null) ? i+1 : seqID;
|
||||||
|
|
||||||
Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID");
|
Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID");
|
||||||
|
sourceID = (sourceID == null) ? i+1 : sourceID;
|
||||||
|
|
||||||
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
String markName = XMLParser.getNodeAttributeString(markNode, "Name");
|
||||||
|
markName = (markName == null || markName.equals("")) ? cMarkName + " " + i+1: markName;
|
||||||
|
|
||||||
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
|
||||||
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
|
||||||
|
|
||||||
Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID);
|
Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID);
|
||||||
subMarks.add(mark);
|
subMarks.add(mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subMarks;
|
return subMarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
||||||
|
* Look upon it and despair.
|
||||||
|
* @param url the location of the race def file
|
||||||
|
* @param serverName the name of the server
|
||||||
|
* @param repetitions the repetitions of a segment of the race def file.
|
||||||
|
* @return a pair which contains regatta string, race string as key, value pair.
|
||||||
|
*/
|
||||||
|
public static Pair<String, String> parseRaceDef(String url, String serverName, int repetitions) {
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db;
|
||||||
|
Document doc = null;
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
doc = db.parse(url);
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Element docEle = doc.getDocumentElement();
|
||||||
|
|
||||||
|
RegattaXMLTemplate regattaXMLTemplate = new RegattaXMLTemplate(
|
||||||
|
serverName, XMLParser.getElementString(docEle, "CourseName"),
|
||||||
|
XMLParser.getElementDouble(docEle, "CentralLat"),
|
||||||
|
XMLParser.getElementDouble(docEle, "CentralLng")
|
||||||
|
);
|
||||||
|
XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
xmlGenerator.setRegattaTemplate(regattaXMLTemplate);
|
||||||
|
|
||||||
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(new ArrayList<>(), new ArrayList<>(),
|
||||||
|
XMLParser.extractMarkOrderRaceDef(docEle, repetitions),
|
||||||
|
XMLParser.extractCourseLimitRaceDef(docEle),
|
||||||
|
XMLParser.extractCompoundMarksRaceDef(docEle)
|
||||||
|
);
|
||||||
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
return new Pair<>(xmlGenerator.getRegattaAsXml(), xmlGenerator.getRaceAsXml());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Corner> extractMarkOrderRaceDef(Element docEle, int repitions){
|
||||||
|
List<Corner> compoundMarkSequence = new ArrayList<>();
|
||||||
|
NodeList cornerList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
|
||||||
|
|
||||||
|
int seqId = 1;
|
||||||
|
final int zoneSize = 3;
|
||||||
|
|
||||||
|
for (int i=0; i<cornerList.getLength(); i++) {
|
||||||
|
Node segment = cornerList.item(i);
|
||||||
|
if (segment.getNodeName().equals("OpeningSegment") ||
|
||||||
|
segment.getNodeName().equals("ClosingSegment")) {
|
||||||
|
|
||||||
|
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
|
||||||
|
|
||||||
|
} else if (segment.getNodeName().equals("RepeatingSegment")) {
|
||||||
|
for (int k = 0; k < repitions; k++) {
|
||||||
|
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compoundMarkSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a segment of the course adding new Corners to the given list.
|
||||||
|
* @param segment Segment to parse
|
||||||
|
* @param seqID initial sequence ID
|
||||||
|
* @param course course to add corners to
|
||||||
|
* @return the last sequence id.
|
||||||
|
*/
|
||||||
|
private static int parseCourseSegment(Node segment, int seqID, List<Corner> course) {
|
||||||
|
NodeList segmentList = segment.getChildNodes();
|
||||||
|
for (int j = 0; j < segmentList.getLength(); j++) {
|
||||||
|
Node corner = segmentList.item(j);
|
||||||
|
if (corner.getNodeName().equals("Corner")) {
|
||||||
|
String rounding = XMLParser.getNodeAttributeString(corner, "Rounding");
|
||||||
|
rounding = //Converting "P" to "Port" and "S" to "Stbd"
|
||||||
|
rounding.equals("P") ? "Port" :
|
||||||
|
rounding.equals("S") ? "Stbd" : rounding;
|
||||||
|
course.add(new Corner(
|
||||||
|
seqID++, XMLParser.getNodeAttributeInt(corner, "CompoundMarkID"),
|
||||||
|
rounding, 3
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seqID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Limit> extractCourseLimitRaceDef(Element docEle) {
|
||||||
|
List<Limit> courseLimit = new ArrayList<>();
|
||||||
|
NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes();
|
||||||
|
int seqId = 1;
|
||||||
|
for (int i = 0; i < limitList.getLength(); i++) {
|
||||||
|
Node limitNode = limitList.item(i);
|
||||||
|
if (limitNode.getNodeName().equals("Limit")) {
|
||||||
|
courseLimit.add(new Limit(
|
||||||
|
seqId++, XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
|
||||||
|
XMLParser.getNodeAttributeDouble(limitNode, "Lng")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return courseLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CompoundMark> extractCompoundMarksRaceDef(Element docEle){
|
||||||
|
List<CompoundMark> allMarks = new ArrayList<>();
|
||||||
|
NodeList cMarkList = docEle.getElementsByTagName("Marks").item(0).getChildNodes();
|
||||||
|
CompoundMark cMark;
|
||||||
|
int markCount = 200;
|
||||||
|
for (int i = 0; i < cMarkList.getLength(); i++) {
|
||||||
|
Node cMarkNode = cMarkList.item(i);
|
||||||
|
if (cMarkNode.getNodeName().equals("CompoundMark")) {
|
||||||
|
Integer id = XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID");
|
||||||
|
List<Mark> subMarks = createMarksRaceDef(cMarkNode, markCount,"Mark " + id);
|
||||||
|
markCount += subMarks.size();
|
||||||
|
allMarks.add(new CompoundMark(id, "Mark " + id, subMarks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allMarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Mark> createMarksRaceDef(Node compoundMark, int markCount, String markName) {
|
||||||
|
List<Mark> subMarks = new ArrayList<>();
|
||||||
|
NodeList childMarks = compoundMark.getChildNodes();
|
||||||
|
int seqID = 1;
|
||||||
|
for (int i = 0; i < childMarks.getLength(); i++) {
|
||||||
|
Node markNode = childMarks.item(i);
|
||||||
|
if (markNode.getNodeName().equals("Mark")) {
|
||||||
|
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "Lat");
|
||||||
|
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "Lng");
|
||||||
|
Mark mark = new Mark(markName + " subMark " + seqID, seqID, targetLat, targetLng, markCount++);
|
||||||
|
subMarks.add(mark);
|
||||||
|
seqID += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subMarks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ import java.util.TimerTask;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
|
import javafx.util.Pair;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
@@ -25,8 +26,11 @@ import seng302.gameServer.messages.CustomizeRequestType;
|
|||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RegistrationRequestMessage;
|
import seng302.gameServer.messages.RegistrationRequestMessage;
|
||||||
import seng302.gameServer.messages.RegistrationResponseStatus;
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
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.utilities.XMLParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
||||||
@@ -44,7 +48,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface DisconnectedFromHostListener {
|
public interface DisconnectedFromHostListener {
|
||||||
void notifYDisconnection (String message);
|
void notifyDisconnection(String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ByteReadException extends Exception {
|
private class ByteReadException extends Exception {
|
||||||
@@ -68,7 +72,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private Timer upWindPacketTimer = new Timer();
|
private Timer upWindPacketTimer = new Timer();
|
||||||
private Timer downWindPacketTimer = new Timer();
|
private Timer downWindPacketTimer = new Timer();
|
||||||
private boolean upwindTimerFlag = false, downwindTimerFlag = false;
|
private boolean upwindTimerFlag = false, downwindTimerFlag = false;
|
||||||
static public final int PACKET_SENDING_INTERVAL_MS = 100;
|
public static final int PACKET_SENDING_INTERVAL_MS = 100;
|
||||||
|
|
||||||
private int clientId = -1;
|
private int clientId = -1;
|
||||||
|
|
||||||
@@ -166,7 +170,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private void notifyDisconnectListeners (String message) {
|
private void notifyDisconnectListeners (String message) {
|
||||||
if (socketOpen) {
|
if (socketOpen) {
|
||||||
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
||||||
listener.notifYDisconnection(message);
|
listener.notifyDisconnection(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +179,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* Sends a request to the server asking for a source ID
|
* Sends a request to the server asking for a source ID
|
||||||
*/
|
*/
|
||||||
private void sendRegistrationRequest() {
|
private void sendRegistrationRequest() {
|
||||||
RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER);
|
RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
os.write(requestMessage.getBuffer());
|
os.write(requestMessage.getBuffer());
|
||||||
@@ -191,9 +195,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* @param packet The registration requests packet
|
* @param packet The registration requests packet
|
||||||
*/
|
*/
|
||||||
private void processRegistrationResponse(StreamPacket packet){
|
private void processRegistrationResponse(StreamPacket packet){
|
||||||
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3));
|
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 4));
|
||||||
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
|
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
|
||||||
|
|
||||||
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
|
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
|
||||||
|
|
||||||
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
|
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
|
||||||
@@ -243,7 +246,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND));
|
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId));
|
||||||
}
|
}
|
||||||
}, 0, PACKET_SENDING_INTERVAL_MS
|
}, 0, PACKET_SENDING_INTERVAL_MS
|
||||||
);
|
);
|
||||||
@@ -256,14 +259,14 @@ public class ClientToServerThread implements Runnable {
|
|||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND));
|
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId));
|
||||||
}
|
}
|
||||||
}, 0, PACKET_SENDING_INTERVAL_MS
|
}, 0, PACKET_SENDING_INTERVAL_MS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sendBoatActionMessage(new BoatActionMessage(actionType));
|
sendBoatActionMessage(new BoatActionMessage(actionType, clientId));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,4 +372,20 @@ public class ClientToServerThread implements Runnable {
|
|||||||
public int getClientId () {
|
public int getClientId () {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendXML(String path, String serverName, int legRepeats) {
|
||||||
|
Pair<String, String> regattaRace = XMLParser.parseRaceDef(path, serverName, legRepeats);
|
||||||
|
|
||||||
|
sendByteBuffer(
|
||||||
|
new XMLMessage(
|
||||||
|
regattaRace.getKey(), XMLMessageSubType.REGATTA, regattaRace.getKey().length()
|
||||||
|
).getBuffer()
|
||||||
|
);
|
||||||
|
|
||||||
|
sendByteBuffer(
|
||||||
|
new XMLMessage(
|
||||||
|
regattaRace.getValue(), XMLMessageSubType.RACE, regattaRace.getValue().length()
|
||||||
|
).getBuffer()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import seng302.gameServer.messages.BoatAction;
|
|||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
import seng302.gameServer.messages.YachtEventType;
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.GameKeyBind;
|
||||||
|
import seng302.model.KeyAction;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.parser.MarkRoundingData;
|
import seng302.model.stream.parser.MarkRoundingData;
|
||||||
@@ -67,6 +69,8 @@ public class GameClient {
|
|||||||
|
|
||||||
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
|
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
|
||||||
|
|
||||||
|
private GameKeyBind gameKeyBind; // all the key binding setting.
|
||||||
|
|
||||||
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,6 +80,7 @@ public class GameClient {
|
|||||||
*/
|
*/
|
||||||
public GameClient(Pane holder) {
|
public GameClient(Pane holder) {
|
||||||
this.holderPane = holder;
|
this.holderPane = holder;
|
||||||
|
this.gameKeyBind = GameKeyBind.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,18 +123,18 @@ public class GameClient {
|
|||||||
* @param ipAddress IP to connect to.
|
* @param ipAddress IP to connect to.
|
||||||
* @param portNumber Port to connect to.
|
* @param portNumber Port to connect to.
|
||||||
*/
|
*/
|
||||||
public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers) {
|
public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race, Integer numLegs) {
|
||||||
XMLGenerator.setDefaultRaceName(serverName);
|
XMLGenerator.setDefaultRaceName(serverName);
|
||||||
GameState.setMaxPlayers(maxPlayers);
|
|
||||||
|
|
||||||
server = new MainServerThread();
|
server = new MainServerThread();
|
||||||
|
GameState.setMaxPlayers(maxPlayers);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, 4942);
|
startClientToServerThread(ipAddress, 4942);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
showConnectionError("Cannot connect to server as host");
|
showConnectionError("Cannot connect to server as host");
|
||||||
}
|
}
|
||||||
|
socketThread.sendXML(race, serverName, numLegs);
|
||||||
while (regattaData == null){
|
while (regattaData == null){
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
@@ -369,16 +374,16 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (e.getCode()) {
|
|
||||||
case SPACE: // align with vmg
|
if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg
|
||||||
socketThread.sendBoatAction(BoatAction.VMG); break;
|
socketThread.sendBoatAction(BoatAction.VMG);
|
||||||
case PAGE_UP: // upwind
|
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind
|
||||||
socketThread.sendBoatAction(BoatAction.UPWIND); break;
|
socketThread.sendBoatAction(BoatAction.UPWIND);
|
||||||
case PAGE_DOWN: // downwind
|
} else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind
|
||||||
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
|
socketThread.sendBoatAction(BoatAction.DOWNWIND);
|
||||||
case ENTER: // tack/gybe
|
} else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe
|
||||||
// if chat box is active take whatever is in there and send it to server
|
// if chat box is active take whatever is in there and send it to server
|
||||||
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
|
socketThread.sendBoatAction(BoatAction.TACK_GYBE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,15 +392,17 @@ public class GameClient {
|
|||||||
if (raceView.isChatInputFocused()) {
|
if (raceView.isChatInputFocused()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (e.getCode()) {
|
|
||||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out
|
||||||
case SHIFT: // sails in/sails out
|
if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) {
|
||||||
|
socketThread.sendBoatAction(BoatAction.SAILS_OUT);
|
||||||
|
} else {
|
||||||
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
}
|
||||||
break;
|
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
||||||
case PAGE_UP:
|
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()
|
||||||
case PAGE_DOWN:
|
|| gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) {
|
||||||
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,4 +497,14 @@ public class GameClient {
|
|||||||
public Map<Integer, ClientYacht> getAllBoatsMap() {
|
public Map<Integer, ClientYacht> getAllBoatsMap() {
|
||||||
return allBoatsMap;
|
return allBoatsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendToggleTurningModePacket() {
|
||||||
|
if (socketThread != null) {
|
||||||
|
if (gameKeyBind.isContinuouslyTurning()) {
|
||||||
|
socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING);
|
||||||
|
} else {
|
||||||
|
socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,443 +1,31 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import java.util.ArrayList;
|
||||||
import javafx.collections.ObservableList;
|
import java.util.List;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.scene.Group;
|
||||||
import javafx.scene.*;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.image.ImageView;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.shape.Polygon;
|
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.utilities.GeoUtility;
|
|
||||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
|
||||||
import seng302.visualiser.fxObjects.assets_2D.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by cir27 on 20/07/17.
|
* Created by cir27 on 26/09/17.
|
||||||
*/
|
*/
|
||||||
public class GameView extends Pane {
|
public abstract class GameView {
|
||||||
|
|
||||||
private double bufferSize = 50;
|
double canvasWidth, canvasHeight;
|
||||||
private double horizontalBuffer = 0;
|
ScaledPoint scaledPoint;
|
||||||
|
|
||||||
private double canvasWidth = 1100;
|
List<Limit> borderPoints;
|
||||||
private double canvasHeight = 920;
|
Group gameObjects = new Group();
|
||||||
private boolean horizontalInversion = false;
|
Group markers = new Group();
|
||||||
|
Group tokens = new Group();
|
||||||
|
List<CompoundMark> course = new ArrayList<>();
|
||||||
|
List<CompoundMark> compoundMarks = new ArrayList<>();
|
||||||
|
List<Corner> courseOrder = new ArrayList<>();
|
||||||
|
|
||||||
private double distanceScaleFactor;
|
public abstract Node getAssets();
|
||||||
private ScaleDirection scaleDirection;
|
public abstract void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence);
|
||||||
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
|
public abstract void updateBorder(List<Limit> border);
|
||||||
private double referencePointX, referencePointY;
|
|
||||||
|
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
|
||||||
|
|
||||||
/* Note that if either of these is null then values for it have not been added and the other
|
|
||||||
should be used as the limits of the map. */
|
|
||||||
private List<Limit> borderPoints;
|
|
||||||
private Map<Mark, Marker2D> markerObjects;
|
|
||||||
|
|
||||||
private ObservableList<Node> gameObjects;
|
|
||||||
private Group markers = new Group();
|
|
||||||
private Group tokens = new Group();
|
|
||||||
private List<CompoundMark> course = new ArrayList<>();
|
|
||||||
|
|
||||||
private ImageView mapImage = new ImageView();
|
|
||||||
|
|
||||||
private enum ScaleDirection {
|
|
||||||
HORIZONTAL,
|
|
||||||
VERTICAL
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameView () {
|
|
||||||
gameObjects = this.getChildren();
|
|
||||||
gameObjects.addAll(mapImage, raceBorder, markers, tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
|
|
||||||
* case the course is added relative ot the border.
|
|
||||||
*
|
|
||||||
* @param newCourse the mark objects that make up the course.
|
|
||||||
* @param sequence The sequence the marks travel through
|
|
||||||
*/
|
|
||||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
|
||||||
markerObjects = new HashMap<>();
|
|
||||||
|
|
||||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
|
||||||
for (CompoundMark compoundMark : newCourse) {
|
|
||||||
if (corner.getCompoundMarkID() == compoundMark.getId()) {
|
|
||||||
course.add(compoundMark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
|
|
||||||
for (Corner corner : sequence){
|
|
||||||
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
|
|
||||||
compoundMark.setRoundingSide(
|
|
||||||
RoundingSide.getRoundingSide(corner.getRounding())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Gate> gates = new ArrayList<>();
|
|
||||||
Paint colour = Color.BLACK;
|
|
||||||
//Creates new markers
|
|
||||||
for (CompoundMark cMark : newCourse) {
|
|
||||||
//Set start and end colour
|
|
||||||
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
|
||||||
colour = Color.GREEN;
|
|
||||||
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
|
||||||
colour = Color.RED;
|
|
||||||
}
|
|
||||||
//Create mark dots
|
|
||||||
for (Mark mark : cMark.getMarks()) {
|
|
||||||
makeAndBindMarker(mark, colour);
|
|
||||||
}
|
|
||||||
//Create gate line
|
|
||||||
if (cMark.isGate()) {
|
|
||||||
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
|
||||||
gates.add(
|
|
||||||
makeAndBindGate(
|
|
||||||
markerObjects.get(cMark.getSubMark(i)),
|
|
||||||
markerObjects.get(cMark.getSubMark(i + 1)),
|
|
||||||
colour
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
colour = Color.BLACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
createMarkArrows(sequence);
|
|
||||||
|
|
||||||
//Scale race to markers if there is no border.
|
|
||||||
if (borderPoints == null) {
|
|
||||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
|
||||||
}
|
|
||||||
//Move the Markers to initial position.
|
|
||||||
markerObjects.forEach(((mark, marker2D) -> {
|
|
||||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
|
||||||
marker2D.setLayoutX(p2d.getX());
|
|
||||||
marker2D.setLayoutY(p2d.getY());
|
|
||||||
}));
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
markers.getChildren().clear();
|
|
||||||
markers.getChildren().addAll(gates);
|
|
||||||
markers.getChildren().addAll(markerObjects.values());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates all the data needed for to create mark arrows. Requires that a course has been
|
|
||||||
* added to the gameview.
|
|
||||||
* @param sequence The order in which marks are traversed.
|
|
||||||
*/
|
|
||||||
private void createMarkArrows (List<Corner> sequence) {
|
|
||||||
for (int i=1; i < sequence.size()-1; i++) { //General case.
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
int numMarks = course.get(i-1).getMarks().size();
|
|
||||||
for (Mark mark : course.get(i-1).getMarks()) {
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
numMarks = course.get(i+1).getMarks().size();
|
|
||||||
averageLat = 0;
|
|
||||||
averageLng = 0;
|
|
||||||
for (Mark mark : course.get(i+1).getMarks()) {
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
|
|
||||||
for (Mark mark : course.get(i).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
GeoUtility.getBearing(lastMarkAv, mark),
|
|
||||||
GeoUtility.getBearing(mark, nextMarkAv)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createStartLineArrows();
|
|
||||||
createFinishLineArrows();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createStartLineArrows () {
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
int numMarks = 0;
|
|
||||||
for (Mark mark : course.get(1).getMarks()) {
|
|
||||||
numMarks += 1;
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
for (Mark mark : course.get(0).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
0d, //90
|
|
||||||
GeoUtility.getBearing(mark, firstMarkAv)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createFinishLineArrows () {
|
|
||||||
double numMarks = 0;
|
|
||||||
double averageLat = 0;
|
|
||||||
double averageLng = 0;
|
|
||||||
for (Mark mark : course.get(course.size()-2).getMarks()) {
|
|
||||||
numMarks += 1;
|
|
||||||
averageLat += mark.getLat();
|
|
||||||
averageLng += mark.getLng();
|
|
||||||
}
|
|
||||||
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
|
||||||
for (Mark mark : course.get(course.size()-1).getMarks()) {
|
|
||||||
markerObjects.get(mark).addArrows(
|
|
||||||
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
|
||||||
GeoUtility.getBearing(secondToLastMarkAv, mark),
|
|
||||||
GeoUtility.getBearing(mark, mark)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Marker and binds it's position to the given Mark.
|
|
||||||
*
|
|
||||||
* @param observableMark The mark to bind the marker to.
|
|
||||||
* @param colour The desired colour of the mark
|
|
||||||
*/
|
|
||||||
private void makeAndBindMarker(Mark observableMark, Paint colour) {
|
|
||||||
Marker2D marker2D = new Marker2D(colour);
|
|
||||||
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
|
|
||||||
markerObjects.put(observableMark, marker2D);
|
|
||||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
|
||||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
|
||||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new gate connecting the given marks.
|
|
||||||
*
|
|
||||||
* @param m1 The first Mark of the gate.
|
|
||||||
* @param m2 The second Mark of the gate.
|
|
||||||
* @param colour The desired colour of the gate.
|
|
||||||
* @return the new gate.
|
|
||||||
*/
|
|
||||||
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
|
|
||||||
Gate gate = new Gate(colour);
|
|
||||||
gate.startXProperty().bind(
|
|
||||||
m1.layoutXProperty()
|
|
||||||
);
|
|
||||||
gate.startYProperty().bind(
|
|
||||||
m1.layoutYProperty()
|
|
||||||
);
|
|
||||||
gate.endXProperty().bind(
|
|
||||||
m2.layoutXProperty()
|
|
||||||
);
|
|
||||||
gate.endYProperty().bind(
|
|
||||||
m2.layoutYProperty()
|
|
||||||
);
|
|
||||||
return gate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
|
|
||||||
* border already exists. Assumes the border is larger than the course.
|
|
||||||
*
|
|
||||||
* @param border the race border to be drawn.
|
|
||||||
*/
|
|
||||||
public void updateBorder(List<Limit> border) {
|
|
||||||
if (borderPoints == null) {
|
|
||||||
borderPoints = border;
|
|
||||||
rescaleRace(new ArrayList<>(borderPoints));
|
|
||||||
}
|
|
||||||
|
|
||||||
rescaleRace(new ArrayList<>(border));
|
|
||||||
|
|
||||||
List<Double> boundaryPoints = new ArrayList<>();
|
|
||||||
for (Limit limit : border) {
|
|
||||||
Point2D location = findScaledXY(limit.getLat(), limit.getLng());
|
|
||||||
boundaryPoints.add(location.getX());
|
|
||||||
boundaryPoints.add(location.getY());
|
|
||||||
}
|
|
||||||
raceBorder.getPoints().setAll(boundaryPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rescales the race to the size of the window.
|
|
||||||
*
|
|
||||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
|
||||||
*/
|
|
||||||
public void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
|
||||||
findMinMaxPoint(limitingCoordinates);
|
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
|
||||||
* the leftmost point, rightmost point, southern most point and northern most point
|
|
||||||
* respectively.
|
|
||||||
*/
|
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
|
||||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
|
||||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
|
||||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
|
||||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
|
||||||
horizontalInversion = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the location of a reference point, this is always the point with minimum latitude,
|
|
||||||
* in relation to the canvas.
|
|
||||||
*
|
|
||||||
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
|
|
||||||
* maximum longitude.
|
|
||||||
*/
|
|
||||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
|
||||||
GeoPoint referencePoint = minLatPoint;
|
|
||||||
double referenceAngle;
|
|
||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
|
||||||
);
|
|
||||||
referencePointX =
|
|
||||||
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
|
||||||
referencePointY = canvasHeight - (bufferSize + bufferSize);
|
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
referencePointY = referencePointY / 2;
|
|
||||||
referencePointY += bufferSize;
|
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
} else {
|
|
||||||
referencePointY = canvasHeight - bufferSize;
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
Math.toRadians(
|
|
||||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
referencePointX = bufferSize;
|
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referencePointX +=
|
|
||||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
|
||||||
/ 2;
|
|
||||||
referencePointX += horizontalBuffer;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
|
|
||||||
* it to distanceScaleFactor Returns the max horizontal distance of the map.
|
|
||||||
*/
|
|
||||||
private double scaleRaceExtremities() {
|
|
||||||
|
|
||||||
double vertAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
|
||||||
);
|
|
||||||
double vertDistance =
|
|
||||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
|
||||||
double horiAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
|
||||||
);
|
|
||||||
if (horiAngle <= (Math.PI / 2)) {
|
|
||||||
horiAngle = (Math.PI / 2) - horiAngle;
|
|
||||||
} else {
|
|
||||||
horiAngle = horiAngle - (Math.PI / 2);
|
|
||||||
}
|
|
||||||
double horiDistance =
|
|
||||||
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
|
||||||
|
|
||||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
|
||||||
|
|
||||||
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
|
|
||||||
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
|
|
||||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
|
||||||
} else {
|
|
||||||
distanceScaleFactor = vertScale;
|
|
||||||
scaleDirection = ScaleDirection.VERTICAL;
|
|
||||||
}
|
|
||||||
return horiDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
|
||||||
double distanceFromReference;
|
|
||||||
double angleFromReference;
|
|
||||||
double xAxisLocation = referencePointX;
|
|
||||||
double yAxisLocation = referencePointY;
|
|
||||||
|
|
||||||
angleFromReference = GeoUtility.getBearingRad(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
distanceFromReference = GeoUtility.getDistance(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
|
||||||
xAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
} else if (angleFromReference >= 0) {
|
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
|
||||||
xAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
|
||||||
xAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
} else {
|
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
|
||||||
xAxisLocation -= Math
|
|
||||||
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
|
|
||||||
yAxisLocation += Math
|
|
||||||
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
|
||||||
}
|
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setSize(Double width, Double height){
|
|
||||||
this.canvasWidth = width;
|
|
||||||
this.canvasHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHorizontalBuffer(Double buff){
|
|
||||||
this.horizontalBuffer = buff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,8 +22,8 @@ import javafx.scene.transform.Translate;
|
|||||||
import org.fxyz3d.scene.Skybox;
|
import org.fxyz3d.scene.Skybox;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
@@ -39,21 +38,24 @@ import seng302.visualiser.cameras.TopDownCamera;
|
|||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.*;
|
import seng302.visualiser.fxObjects.assets_3D.*;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of animated3D assets that displays a race.
|
* Collection of animated3D assets that displays a race.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class GameView3D {
|
public class GameView3D extends GameView{
|
||||||
|
|
||||||
private final double FOV = 60;
|
private final double FOV = 60;
|
||||||
private final double DEFAULT_CAMERA_DEPTH = -125;
|
private final double DEFAULT_CAMERA_DEPTH = -125;
|
||||||
private final double DEFAULT_CAMERA_X = 0;
|
private final double DEFAULT_CAMERA_X = 0;
|
||||||
private final double DEFAULT_CAMERA_Y = 155;
|
private final double DEFAULT_CAMERA_Y = 100;
|
||||||
|
|
||||||
private Group root3D;
|
private Group root3D;
|
||||||
private SubScene view;
|
private SubScene view;
|
||||||
// ParallelCamera camera;
|
|
||||||
private PerspectiveCamera camera;
|
private PerspectiveCamera camera;
|
||||||
private PerspectiveCamera camera2;
|
private PerspectiveCamera camera2;
|
||||||
private PerspectiveCamera camera3;
|
private PerspectiveCamera camera3;
|
||||||
@@ -72,28 +74,20 @@ public class GameView3D {
|
|||||||
|
|
||||||
/* Note that if either of these is null then values for it have not been added and the other
|
/* Note that if either of these is null then values for it have not been added and the other
|
||||||
should be used as the limits of the map. */
|
should be used as the limits of the map. */
|
||||||
private List<Limit> borderPoints;
|
|
||||||
private Map<Mark, Marker3D> markerObjects;
|
private Map<Mark, Marker3D> markerObjects;
|
||||||
|
|
||||||
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
||||||
private BoatObject selectedBoat = null;
|
private BoatObject selectedBoat = null;
|
||||||
private Group wakesGroup = new Group();
|
private Group wakesGroup = new Group();
|
||||||
private Group boatObjectGroup = new Group();
|
private Group boatObjectGroup = new Group();
|
||||||
private Group markers = new Group();
|
|
||||||
private Group tokens = new Group();
|
|
||||||
private List<CompoundMark> course = new ArrayList<>();
|
|
||||||
private List<Node> mapTokens;
|
private List<Node> mapTokens;
|
||||||
private AnimationTimer playerBoatAnimationTimer;
|
private AnimationTimer playerBoatAnimationTimer;
|
||||||
private Group trail = new Group();
|
private Group trail = new Group();
|
||||||
private Double windDir;
|
private Double windDir;
|
||||||
private Skybox skybox;
|
private Skybox skybox;
|
||||||
|
|
||||||
private enum ScaleDirection {
|
|
||||||
HORIZONTAL,
|
|
||||||
VERTICAL
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameView3D () {
|
public GameView3D () {
|
||||||
|
canvasWidth = canvasHeight = 220;
|
||||||
|
|
||||||
camera = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH);
|
camera = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH);
|
||||||
camera.setFarClip(100000);
|
camera.setFarClip(100000);
|
||||||
camera.setNearClip(0.1);
|
camera.setNearClip(0.1);
|
||||||
@@ -135,8 +129,10 @@ public class GameView3D {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||||
markerObjects = new HashMap<>();
|
markerObjects = new HashMap<>();
|
||||||
|
compoundMarks = newCourse;
|
||||||
|
|
||||||
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
for (Corner corner : sequence) { //Makes course out of all compound marks.
|
||||||
for (CompoundMark compoundMark : newCourse) {
|
for (CompoundMark compoundMark : newCourse) {
|
||||||
@@ -187,11 +183,13 @@ public class GameView3D {
|
|||||||
|
|
||||||
//Scale race to markers if there is no border.
|
//Scale race to markers if there is no border.
|
||||||
if (borderPoints == null) {
|
if (borderPoints == null) {
|
||||||
rescaleRace(new ArrayList<>(markerObjects.keySet()));
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
//Move the Markers to initial position.
|
//Move the Markers to initial position.
|
||||||
markerObjects.forEach(((mark, marker) -> {
|
markerObjects.forEach(((mark, marker) -> {
|
||||||
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
|
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
|
||||||
marker.setLayoutX(p2d.getX());
|
marker.setLayoutX(p2d.getX());
|
||||||
marker.setLayoutY(p2d.getY());
|
marker.setLayoutY(p2d.getY());
|
||||||
}));
|
}));
|
||||||
@@ -211,7 +209,7 @@ public class GameView3D {
|
|||||||
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
|
||||||
markerObjects.put(observableMark, new Marker3D(markerType));
|
markerObjects.put(observableMark, new Marker3D(markerType));
|
||||||
observableMark.addPositionListener((mark, lat, lon) -> {
|
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||||
Point2D p2d = findScaledXY(lat, lon);
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
markerObjects.get(mark).setLayoutX(p2d.getX());
|
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||||
markerObjects.get(mark).setLayoutY(p2d.getY());
|
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||||
});
|
});
|
||||||
@@ -226,8 +224,8 @@ public class GameView3D {
|
|||||||
* @return the new gate.
|
* @return the new gate.
|
||||||
*/
|
*/
|
||||||
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
|
||||||
Point2D m1Location = findScaledXY(m1);
|
Point2D m1Location = scaledPoint.findScaledXY(m1);
|
||||||
Point2D m2Location = findScaledXY(m2);
|
Point2D m2Location = scaledPoint.findScaledXY(m2);
|
||||||
|
|
||||||
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
Group barrier = ModelFactory.importModel(gateType).getAssets();
|
||||||
barrier.getTransforms().addAll(
|
barrier.getTransforms().addAll(
|
||||||
@@ -285,145 +283,6 @@ public class GameView3D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
|
|
||||||
* the leftmost point, rightmost point, southern most point and northern most point
|
|
||||||
* respectively.
|
|
||||||
*/
|
|
||||||
private void findMinMaxPoint(List<GeoPoint> points) {
|
|
||||||
List<GeoPoint> sortedPoints = new ArrayList<>(points);
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
|
|
||||||
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
|
|
||||||
|
|
||||||
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
|
|
||||||
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
|
|
||||||
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
|
|
||||||
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
|
|
||||||
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
|
|
||||||
horizontalInversion = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the location of a reference point, this is always the point with minimum latitude,
|
|
||||||
* in relation to the canvas.
|
|
||||||
*
|
|
||||||
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
|
|
||||||
* maximum longitude.
|
|
||||||
*/
|
|
||||||
private void calculateReferencePointLocation(double minLonToMaxLon) {
|
|
||||||
GeoPoint referencePoint = minLatPoint;
|
|
||||||
double referenceAngle;
|
|
||||||
|
|
||||||
if (scaleDirection == ScaleDirection.HORIZONTAL) {
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(referencePoint, minLonPoint)
|
|
||||||
);
|
|
||||||
referencePointX =
|
|
||||||
-100 + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
|
|
||||||
referencePointY = -100 + canvasHeight - (bufferSize + bufferSize);
|
|
||||||
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
referencePointY = referencePointY / 2;
|
|
||||||
referencePointY += bufferSize;
|
|
||||||
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, maxLatPoint);
|
|
||||||
} else {
|
|
||||||
referencePointY = -100 + canvasHeight - bufferSize;
|
|
||||||
referenceAngle = Math.abs(
|
|
||||||
Math.toRadians(
|
|
||||||
GeoUtility.getDistance(referencePoint, minLonPoint)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
referencePointX = -100 + bufferSize;
|
|
||||||
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
|
|
||||||
.getDistance(referencePoint, minLonPoint);
|
|
||||||
referencePointX +=
|
|
||||||
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
|
|
||||||
/ 2;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
referencePointX = -100 + canvasWidth - bufferSize - (referencePointX - bufferSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
|
|
||||||
* it to distanceScaleFactor Returns the max horizontal distance of the map.
|
|
||||||
*/
|
|
||||||
private double scaleRaceExtremities() {
|
|
||||||
|
|
||||||
double vertAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
|
|
||||||
);
|
|
||||||
double vertDistance =
|
|
||||||
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
|
|
||||||
double horiAngle = Math.abs(
|
|
||||||
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
|
|
||||||
);
|
|
||||||
if (horiAngle <= (Math.PI / 2)) {
|
|
||||||
horiAngle = (Math.PI / 2) - horiAngle;
|
|
||||||
} else {
|
|
||||||
horiAngle = horiAngle - (Math.PI / 2);
|
|
||||||
}
|
|
||||||
double horiDistance =
|
|
||||||
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
|
|
||||||
|
|
||||||
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
|
|
||||||
|
|
||||||
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
|
|
||||||
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
|
|
||||||
scaleDirection = ScaleDirection.HORIZONTAL;
|
|
||||||
} else {
|
|
||||||
distanceScaleFactor = vertScale;
|
|
||||||
scaleDirection = ScaleDirection.VERTICAL;
|
|
||||||
}
|
|
||||||
return horiDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(GeoPoint unscaled) {
|
|
||||||
return findScaledXY(unscaled.getLat(), unscaled.getLng());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
|
|
||||||
double distanceFromReference;
|
|
||||||
double angleFromReference;
|
|
||||||
double xAxisLocation = referencePointX;
|
|
||||||
double yAxisLocation = referencePointY;
|
|
||||||
|
|
||||||
angleFromReference = GeoUtility.getBearingRad(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
distanceFromReference = GeoUtility.getDistance(
|
|
||||||
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
|
|
||||||
);
|
|
||||||
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
|
|
||||||
xAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
} else if (angleFromReference >= 0) {
|
|
||||||
angleFromReference = angleFromReference - Math.PI / 2;
|
|
||||||
xAxisLocation += distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
|
|
||||||
angleFromReference = Math.abs(angleFromReference);
|
|
||||||
xAxisLocation -= distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
} else {
|
|
||||||
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
|
|
||||||
xAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
|
|
||||||
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
|
|
||||||
}
|
|
||||||
if (horizontalInversion) {
|
|
||||||
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
|
|
||||||
}
|
|
||||||
return new Point2D(xAxisLocation, yAxisLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cameraMovement(KeyEvent event) {
|
public void cameraMovement(KeyEvent event) {
|
||||||
switch (event.getCode()) {
|
switch (event.getCode()) {
|
||||||
case NUMPAD8:
|
case NUMPAD8:
|
||||||
@@ -470,19 +329,6 @@ public class GameView3D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Rescales the race to the size of the window.
|
|
||||||
*
|
|
||||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
|
||||||
*/
|
|
||||||
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
|
||||||
findMinMaxPoint(limitingCoordinates);
|
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
|
||||||
// drawGoogleMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws all the boats.
|
* Draws all the boats.
|
||||||
* @param yachts The yachts to set in the race
|
* @param yachts The yachts to set in the race
|
||||||
@@ -500,7 +346,7 @@ public class GameView3D {
|
|||||||
boatObjectGroup.getChildren().add(newBoat);
|
boatObjectGroup.getChildren().add(newBoat);
|
||||||
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
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 = scaledPoint.findScaledXY(lat, lon);
|
||||||
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -529,18 +375,20 @@ public class GameView3D {
|
|||||||
public void updateBorder(List<Limit> border) {
|
public void updateBorder(List<Limit> border) {
|
||||||
if (borderPoints == null) {
|
if (borderPoints == null) {
|
||||||
borderPoints = border;
|
borderPoints = border;
|
||||||
rescaleRace(new ArrayList<>(borderPoints));
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(borderPoints), true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
List<Node> boundaryAssets = new ArrayList<>();
|
List<Node> boundaryAssets = new ArrayList<>();
|
||||||
|
|
||||||
Point2D lastLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
Point2D lastLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||||
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||||
pylon.setLayoutX(lastLocation.getX());
|
pylon.setLayoutX(lastLocation.getX());
|
||||||
pylon.setLayoutY(lastLocation.getY());
|
pylon.setLayoutY(lastLocation.getY());
|
||||||
boundaryAssets.add(pylon);
|
boundaryAssets.add(pylon);
|
||||||
|
|
||||||
for (int i=1; i<border.size(); i++) {
|
for (int i=1; i<border.size(); i++) {
|
||||||
Point2D location = findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
Point2D location = scaledPoint.findScaledXY(border.get(i).getLat(), border.get(i).getLng());
|
||||||
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
|
||||||
pylon.setLayoutX(location.getX());
|
pylon.setLayoutX(location.getX());
|
||||||
pylon.setLayoutY(location.getY());
|
pylon.setLayoutY(location.getY());
|
||||||
@@ -566,7 +414,7 @@ public class GameView3D {
|
|||||||
boundaryAssets.add(pylon);
|
boundaryAssets.add(pylon);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2D firstLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
Point2D firstLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
|
||||||
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
|
||||||
barrier.getTransforms().addAll(
|
barrier.getTransforms().addAll(
|
||||||
new Rotate(
|
new Rotate(
|
||||||
@@ -630,19 +478,17 @@ public class GameView3D {
|
|||||||
playerYacht.toggleSail();
|
playerYacht.toggleSail();
|
||||||
playerBoatAnimationTimer = new AnimationTimer() {
|
playerBoatAnimationTimer = new AnimationTimer() {
|
||||||
|
|
||||||
double count = 60;
|
Point2D lastLocation = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
Point2D lastLocation = findScaledXY(playerYacht.getLocation());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
if (--count == 0) {
|
Point2D location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
count = 60;
|
if (Math.abs(lastLocation.distance(location)) > 2) {
|
||||||
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
|
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
|
||||||
Point2D location = findScaledXY(playerYacht.getLocation());
|
location = scaledPoint.findScaledXY(playerYacht.getLocation());
|
||||||
segment.getTransforms().addAll(
|
segment.getTransforms().addAll(
|
||||||
new Translate(location.getX(), location.getY(), 0),
|
new Translate(location.getX(), location.getY(), 0),
|
||||||
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)),
|
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1))
|
||||||
new Scale(1, lastLocation.distance(location) / 5, 1)
|
|
||||||
);
|
);
|
||||||
trail.getChildren().add(segment);
|
trail.getChildren().add(segment);
|
||||||
if (trail.getChildren().size() > 50) {
|
if (trail.getChildren().size() > 50) {
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes maps from map definition xml files.
|
||||||
|
*/
|
||||||
|
public class MapMaker {
|
||||||
|
|
||||||
|
private List<MapPreview> mapPreviews = new ArrayList<>();
|
||||||
|
private List<RaceXMLData> races = new ArrayList<>();
|
||||||
|
private List<RegattaXMLData> regattas = new ArrayList<>();
|
||||||
|
private List<String> filePaths = new ArrayList<>();
|
||||||
|
private static MapMaker instance;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
public static MapMaker getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new MapMaker();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapMaker() {
|
||||||
|
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
|
||||||
|
File[] directoryListing = dir.listFiles();
|
||||||
|
if (directoryListing != null) {
|
||||||
|
for (File child : directoryListing) {
|
||||||
|
Pair<String, String> regattaRace = XMLParser.parseRaceDef(
|
||||||
|
child.getAbsolutePath(), "", 1
|
||||||
|
);
|
||||||
|
filePaths.add(child.getAbsolutePath());
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db;
|
||||||
|
Document doc = null;
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
doc = db.parse(new InputSource(new StringReader(regattaRace.getKey())));
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
regattas.add(XMLParser.parseRegatta(doc));
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
doc = db.parse(new InputSource(new StringReader(regattaRace.getValue())));
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
RaceXMLData race = XMLParser.parseRace(doc);
|
||||||
|
MapPreview mapPreview = new MapPreview(
|
||||||
|
new ArrayList<>(race.getCompoundMarks().values()),
|
||||||
|
race.getMarkSequence(), race.getCourseLimit()
|
||||||
|
);
|
||||||
|
mapPreviews.add(mapPreview);
|
||||||
|
races.add(race);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
index += 1;
|
||||||
|
if (index >= mapPreviews.size()) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void previous() {
|
||||||
|
index -= 1;
|
||||||
|
if (index < 0) {
|
||||||
|
index = mapPreviews.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getCurrentGameView() {
|
||||||
|
return mapPreviews.get(index).getAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RaceXMLData getCurrentRace() {
|
||||||
|
return races.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegattaXMLData getCurrentRegatta() {
|
||||||
|
return regattas.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentRacePath() {
|
||||||
|
return filePaths.get(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.ScaledPoint;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.CourseBoundary;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.Gate;
|
||||||
|
import seng302.visualiser.fxObjects.assets_2D.Marker2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by cir27 on 20/07/17.
|
||||||
|
*/
|
||||||
|
public class MapPreview extends GameView {
|
||||||
|
|
||||||
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
|
private Map<Mark, Marker2D> markerObjects;
|
||||||
|
|
||||||
|
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
||||||
|
this.compoundMarks = marks;
|
||||||
|
this.courseOrder = course;
|
||||||
|
this.borderPoints = border;
|
||||||
|
gameObjects.getChildren().addAll(raceBorder, markers, tokens);
|
||||||
|
gameObjects.parentProperty().addListener((obs, old, parent) -> {
|
||||||
|
if (parent != null) {
|
||||||
|
canvasWidth = parent.prefWidth(1);
|
||||||
|
canvasHeight = parent.prefHeight(1);
|
||||||
|
updateBorder(borderPoints);
|
||||||
|
updateCourse(compoundMarks, courseOrder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getAssets() {
|
||||||
|
return gameObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(double width, double height) {
|
||||||
|
canvasHeight = height;
|
||||||
|
canvasWidth = width;
|
||||||
|
updateBorder(borderPoints);
|
||||||
|
updateCourse(compoundMarks, courseOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
|
||||||
|
* case the course is added relative ot the border.
|
||||||
|
*
|
||||||
|
* @param newCourse the mark objects that make up the course.
|
||||||
|
* @param sequence The sequence the marks travel through
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
|
||||||
|
|
||||||
|
if (newCourse.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compoundMarks = newCourse;
|
||||||
|
markerObjects = new HashMap<>();
|
||||||
|
courseOrder = sequence;
|
||||||
|
|
||||||
|
for (Corner corner : courseOrder) { //Makes course out of all compound marks.
|
||||||
|
for (CompoundMark compoundMark : newCourse) {
|
||||||
|
if (corner.getCompoundMarkID() == compoundMark.getId()) {
|
||||||
|
course.add(compoundMark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
|
||||||
|
for (Corner corner : sequence){
|
||||||
|
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
|
||||||
|
compoundMark.setRoundingSide(
|
||||||
|
RoundingSide.getRoundingSide(corner.getRounding())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Gate> gates = new ArrayList<>();
|
||||||
|
Paint colour = Color.BLACK;
|
||||||
|
//Creates new markers
|
||||||
|
for (CompoundMark cMark : newCourse) {
|
||||||
|
//Set start and end colour
|
||||||
|
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
|
||||||
|
colour = Color.GREEN;
|
||||||
|
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
|
||||||
|
colour = Color.RED;
|
||||||
|
}
|
||||||
|
//Create mark dots
|
||||||
|
for (Mark mark : cMark.getMarks()) {
|
||||||
|
makeAndBindMarker(mark, colour);
|
||||||
|
}
|
||||||
|
//Create gate line
|
||||||
|
if (cMark.isGate()) {
|
||||||
|
for (int i = 1; i < cMark.getMarks().size(); i++) {
|
||||||
|
gates.add(
|
||||||
|
makeAndBindGate(
|
||||||
|
markerObjects.get(cMark.getSubMark(i)),
|
||||||
|
markerObjects.get(cMark.getSubMark(i + 1)),
|
||||||
|
colour
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colour = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
createMarkArrows(sequence);
|
||||||
|
|
||||||
|
//Scale race to markers if there is no border.
|
||||||
|
if (borderPoints == null) {
|
||||||
|
scaledPoint = ScaledPoint.makeScaledPoint(
|
||||||
|
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//Move the Markers to initial position.
|
||||||
|
markerObjects.forEach(((mark, marker2D) -> {
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
|
||||||
|
marker2D.setLayoutX(p2d.getX());
|
||||||
|
marker2D.setLayoutY(p2d.getY());
|
||||||
|
}));
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
markers.getChildren().clear();
|
||||||
|
markers.getChildren().addAll(gates);
|
||||||
|
markers.getChildren().addAll(markerObjects.values());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates all the data needed for to create mark arrows. Requires that a course has been
|
||||||
|
* added to the gameview.
|
||||||
|
* @param sequence The order in which marks are traversed.
|
||||||
|
*/
|
||||||
|
private void createMarkArrows (List<Corner> sequence) {
|
||||||
|
for (int i=1; i < sequence.size()-1; i++) { //General case.
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
int numMarks = course.get(i-1).getMarks().size();
|
||||||
|
for (Mark mark : course.get(i-1).getMarks()) {
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
numMarks = course.get(i+1).getMarks().size();
|
||||||
|
averageLat = 0;
|
||||||
|
averageLng = 0;
|
||||||
|
for (Mark mark : course.get(i+1).getMarks()) {
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
|
||||||
|
for (Mark mark : course.get(i).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
GeoUtility.getBearing(lastMarkAv, mark),
|
||||||
|
GeoUtility.getBearing(mark, nextMarkAv)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createStartLineArrows();
|
||||||
|
createFinishLineArrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createStartLineArrows () {
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
int numMarks = 0;
|
||||||
|
for (Mark mark : course.get(1).getMarks()) {
|
||||||
|
numMarks += 1;
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
for (Mark mark : course.get(0).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
0d, //90
|
||||||
|
GeoUtility.getBearing(mark, firstMarkAv)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFinishLineArrows () {
|
||||||
|
double numMarks = 0;
|
||||||
|
double averageLat = 0;
|
||||||
|
double averageLng = 0;
|
||||||
|
for (Mark mark : course.get(course.size()-2).getMarks()) {
|
||||||
|
numMarks += 1;
|
||||||
|
averageLat += mark.getLat();
|
||||||
|
averageLng += mark.getLng();
|
||||||
|
}
|
||||||
|
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
|
||||||
|
for (Mark mark : course.get(course.size()-1).getMarks()) {
|
||||||
|
markerObjects.get(mark).addArrows(
|
||||||
|
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
|
||||||
|
GeoUtility.getBearing(secondToLastMarkAv, mark),
|
||||||
|
GeoUtility.getBearing(mark, mark)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Marker and binds it's position to the given Mark.
|
||||||
|
*
|
||||||
|
* @param observableMark The mark to bind the marker to.
|
||||||
|
* @param colour The desired colour of the mark
|
||||||
|
*/
|
||||||
|
private void makeAndBindMarker(Mark observableMark, Paint colour) {
|
||||||
|
Marker2D marker2D = new Marker2D(colour);
|
||||||
|
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
|
||||||
|
markerObjects.put(observableMark, marker2D);
|
||||||
|
observableMark.addPositionListener((mark, lat, lon) -> {
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
|
markerObjects.get(mark).setLayoutX(p2d.getX());
|
||||||
|
markerObjects.get(mark).setLayoutY(p2d.getY());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new gate connecting the given marks.
|
||||||
|
*
|
||||||
|
* @param m1 The first Mark of the gate.
|
||||||
|
* @param m2 The second Mark of the gate.
|
||||||
|
* @param colour The desired colour of the gate.
|
||||||
|
* @return the new gate.
|
||||||
|
*/
|
||||||
|
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
|
||||||
|
Gate gate = new Gate(colour);
|
||||||
|
gate.startXProperty().bind(
|
||||||
|
m1.layoutXProperty()
|
||||||
|
);
|
||||||
|
gate.startYProperty().bind(
|
||||||
|
m1.layoutYProperty()
|
||||||
|
);
|
||||||
|
gate.endXProperty().bind(
|
||||||
|
m2.layoutXProperty()
|
||||||
|
);
|
||||||
|
gate.endYProperty().bind(
|
||||||
|
m2.layoutYProperty()
|
||||||
|
);
|
||||||
|
return gate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
|
||||||
|
* border already exists. Assumes the border is larger than the course.
|
||||||
|
*
|
||||||
|
* @param border the race border to be drawn.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateBorder(List<Limit> border) {
|
||||||
|
if (border.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
borderPoints = border;
|
||||||
|
scaledPoint = ScaledPoint.makeScaledPoint(canvasWidth, canvasHeight, border, false);
|
||||||
|
|
||||||
|
List<Double> boundaryPoints = new ArrayList<>();
|
||||||
|
for (Limit limit : border) {
|
||||||
|
Point2D location = scaledPoint.findScaledXY(limit.getLat(), limit.getLng());
|
||||||
|
boundaryPoints.add(location.getX());
|
||||||
|
boundaryPoints.add(location.getY());
|
||||||
|
}
|
||||||
|
raceBorder.getPoints().setAll(boundaryPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
|
|
||||||
public void switchToStartScreenView() {
|
public void switchToStartScreenView() {
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
//TODO merge fix
|
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ package seng302.visualiser.controllers;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDialog;
|
import com.jfoenix.controls.JFXDialog;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@@ -9,7 +15,7 @@ import javafx.fxml.FXMLLoader;
|
|||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
@@ -24,21 +30,16 @@ import seng302.model.mark.Corner;
|
|||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.discoveryServer.DiscoveryServerClient;
|
import seng302.discoveryServer.DiscoveryServerClient;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameView;
|
import seng302.visualiser.MapPreview;
|
||||||
import seng302.visualiser.controllers.cells.PlayerCell;
|
import seng302.visualiser.controllers.cells.PlayerCell;
|
||||||
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
||||||
import seng302.visualiser.controllers.dialogs.DirectConnectController;
|
import seng302.visualiser.controllers.dialogs.DirectConnectController;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
|
||||||
|
|
||||||
public class LobbyController implements Initializable {
|
public class LobbyController implements Initializable {
|
||||||
|
|
||||||
|
private final double INITIAL_MAP_HEIGHT = 770d;
|
||||||
|
private final double INITIAL_MAP_WIDTH = 574d;
|
||||||
|
|
||||||
//--------FXML BEGIN--------//
|
//--------FXML BEGIN--------//
|
||||||
@FXML
|
@FXML
|
||||||
private VBox playerListVBox;
|
private VBox playerListVBox;
|
||||||
@@ -53,7 +54,7 @@ public class LobbyController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private Label mapName;
|
private Label mapName;
|
||||||
@FXML
|
@FXML
|
||||||
private Pane serverMap;
|
private AnchorPane serverMap;
|
||||||
@FXML
|
@FXML
|
||||||
private Label roomLabel;
|
private Label roomLabel;
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
@@ -62,8 +63,8 @@ public class LobbyController implements Initializable {
|
|||||||
private JFXDialog customizationDialog;
|
private JFXDialog customizationDialog;
|
||||||
public Color playersColor;
|
public Color playersColor;
|
||||||
private Map<Integer, ClientYacht> playerBoats;
|
private Map<Integer, ClientYacht> playerBoats;
|
||||||
private Double mapWidth, mapHeight;
|
private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT;
|
||||||
private GameView gameView;
|
private MapPreview mapPreview;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
@@ -99,16 +100,16 @@ public class LobbyController implements Initializable {
|
|||||||
ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted());
|
ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
customizeButton.setOnMouseReleased(event -> {
|
||||||
|
customizationDialog = createCustomizeDialog();
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
customizationDialog.show();
|
||||||
|
});
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId();
|
Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId();
|
||||||
|
|
||||||
playersColor = Colors.getColor(playerId - 1);
|
playersColor = Colors.getColor(playerId - 1);
|
||||||
customizationDialog = createCustomizeDialog();
|
|
||||||
|
|
||||||
customizeButton.setOnMouseReleased(event -> {
|
|
||||||
Sounds.playButtonClick();
|
|
||||||
customizationDialog.show();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
||||||
@@ -145,44 +146,29 @@ public class LobbyController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void refreshMapView(){
|
|
||||||
RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
|
|
||||||
List<Limit> border = raceData.getCourseLimit();
|
|
||||||
List<CompoundMark> marks = new ArrayList<CompoundMark>(raceData.getCompoundMarks().values());
|
|
||||||
List<Corner> corners = raceData.getMarkSequence();
|
|
||||||
|
|
||||||
gameView.setSize(mapWidth, mapHeight);
|
|
||||||
|
|
||||||
// Update game view
|
|
||||||
gameView.updateBorder(border);
|
|
||||||
gameView.updateCourse(marks, corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a top down preview of the race course map.
|
* Initializes a top down preview of the race course map.
|
||||||
*/
|
*/
|
||||||
private void initMapPreview() {
|
private void initMapPreview() {
|
||||||
gameView = new GameView();
|
RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
|
||||||
gameView.setHorizontalBuffer(330d);
|
List<Limit> border = raceData.getCourseLimit();
|
||||||
|
List<CompoundMark> marks = new ArrayList<>(raceData.getCompoundMarks().values());
|
||||||
|
List<Corner> corners = raceData.getMarkSequence();
|
||||||
|
|
||||||
mapWidth = 770d;
|
mapPreview = new MapPreview(marks, corners, border);
|
||||||
mapHeight = 574d;
|
|
||||||
|
|
||||||
// Add game view
|
|
||||||
serverMap.getChildren().clear();
|
serverMap.getChildren().clear();
|
||||||
serverMap.getChildren().add(gameView);
|
serverMap.getChildren().add(mapPreview.getAssets());
|
||||||
|
|
||||||
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
|
|
||||||
serverMap.widthProperty().addListener((observable, oldValue, newValue) -> {
|
serverMap.widthProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
mapWidth = newValue.doubleValue();
|
mapWidth = newValue.doubleValue();
|
||||||
refreshMapView();
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
});
|
});
|
||||||
|
//
|
||||||
serverMap.heightProperty().addListener((observable, oldValue, newValue) -> {
|
serverMap.heightProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
mapHeight = newValue.doubleValue();
|
mapHeight = newValue.doubleValue();
|
||||||
refreshMapView();
|
mapPreview.setSize(mapWidth, mapHeight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@@ -26,8 +24,6 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.SubScene;
|
import javafx.scene.SubScene;
|
||||||
import javafx.scene.chart.LineChart;
|
import javafx.scene.chart.LineChart;
|
||||||
import javafx.scene.chart.NumberAxis;
|
import javafx.scene.chart.NumberAxis;
|
||||||
import javafx.scene.chart.XYChart;
|
|
||||||
import javafx.scene.chart.XYChart.Data;
|
|
||||||
import javafx.scene.chart.XYChart.Series;
|
import javafx.scene.chart.XYChart.Series;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
@@ -95,7 +91,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
@FXML
|
@FXML
|
||||||
private Label timerLabel;
|
private Label timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private StackPane contentAnchorPane;
|
private StackPane contentStackPane;
|
||||||
|
|
||||||
private GridPane contentGridPane;
|
private GridPane contentGridPane;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -144,34 +140,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Sounds.stopMusic();
|
Sounds.stopMusic();
|
||||||
Sounds.playRaceMusic();
|
Sounds.playRaceMusic();
|
||||||
|
|
||||||
finishScreenDialog = createFinishDialog();
|
|
||||||
|
|
||||||
// Load a default important annotation state
|
|
||||||
//importantAnnotations = new ImportantAnnotationsState();
|
|
||||||
|
|
||||||
//Formatting the y axis of the sparkline
|
|
||||||
// raceSparkLine.getYAxis().setRotate(180);
|
|
||||||
// raceSparkLine.getYAxis().setTickLabelRotation(180);
|
|
||||||
// raceSparkLine.getYAxis().setTranslateX(-5);
|
|
||||||
//raceSparkLine.visibleProperty().setValue(false);
|
|
||||||
//raceSparkLine.getYAxis().setAutoRanging(false);
|
|
||||||
//sparklineYAxis.setTickMarkVisible(false);
|
|
||||||
|
|
||||||
//positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
// raceSparkLine.visibleProperty().setValue(false);
|
|
||||||
// raceSparkLine.getYAxis().setAutoRanging(false);
|
|
||||||
// sparklineYAxis.setTickMarkVisible(false);
|
|
||||||
// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
|
|
||||||
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
// rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
|
|
||||||
// rvAnchorPane.prefHeightProperty().bind(ViewManager.getInstance().getDecorator().heightProperty());
|
|
||||||
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
// windArrowHolder.getChildren().addAll(windArrow);
|
|
||||||
// windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
|
|
||||||
// windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
|
|
||||||
|
|
||||||
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
|
||||||
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
|
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
|
||||||
if (newLen.intValue() > CHAT_LIMIT) {
|
if (newLen.intValue() > CHAT_LIMIT) {
|
||||||
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
|
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
|
||||||
@@ -185,51 +153,44 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
chatHistory.prefHeightProperty().bind(
|
chatHistory.prefHeightProperty().bind(
|
||||||
chatHistoryHolder.heightProperty()
|
chatHistoryHolder.heightProperty()
|
||||||
);
|
);
|
||||||
// chatHistory.setFitToWidth(true);
|
|
||||||
// chatHistory.setFitToHeight(true);
|
|
||||||
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
|
|
||||||
// chatHistory.setScrollTop(Double.MAX_VALUE);
|
|
||||||
// });
|
|
||||||
rvAnchorPane.setOnMouseClicked((event) ->
|
|
||||||
rvAnchorPane.requestFocus()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
contentStackPane.setOnMouseClicked(event -> {
|
||||||
|
contentStackPane.requestFocus();
|
||||||
|
});
|
||||||
|
Platform.runLater(contentStackPane::requestFocus);
|
||||||
//Makes the chat history non transparent when clicked on
|
//Makes the chat history non transparent when clicked on
|
||||||
chatInput.focusedProperty().addListener(new ChangeListener<Boolean>() {
|
chatInput.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
@Override
|
if (newValue) {
|
||||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
|
chatHistory.increaseOpacity();
|
||||||
Boolean newValue) {
|
} else {
|
||||||
if (newValue) {
|
chatHistory.decreaseOpacity();
|
||||||
chatHistory.increaseOpacity();
|
|
||||||
} else {
|
|
||||||
chatHistory.decreaseOpacity();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
||||||
raceState.setRaceStarted(false);
|
raceState.setRaceStarted(false);
|
||||||
finishDialogController.setFinishedBoats(finishedBoats);
|
createFinishDialog(finishedBoats);
|
||||||
finishScreenDialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JFXDialog createFinishDialog() {
|
/**
|
||||||
|
* Create finishScreenDialog and set up finishDialogController.
|
||||||
|
*/
|
||||||
|
private void createFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
||||||
FXMLLoader dialog = new FXMLLoader(
|
FXMLLoader dialog = new FXMLLoader(
|
||||||
getClass().getResource("/views/dialogs/RaceFinishDialog.fxml"));
|
getClass().getResource("/views/dialogs/RaceFinishDialog.fxml"));
|
||||||
|
|
||||||
JFXDialog finishScreenDialog = null;
|
Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
try {
|
finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(),
|
||||||
finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(),
|
JFXDialog.DialogTransition.CENTER);
|
||||||
JFXDialog.DialogTransition.CENTER);
|
finishDialogController = dialog.getController();
|
||||||
} catch (IOException e) {
|
finishDialogController.setFinishedBoats(finishedBoats);
|
||||||
e.printStackTrace();
|
finishScreenDialog.show();
|
||||||
}
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
finishDialogController = dialog.getController();
|
}
|
||||||
|
});
|
||||||
return finishScreenDialog;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -247,7 +208,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
if (c.wasPermutated()) {
|
if (c.wasPermutated()) {
|
||||||
updateOrder(raceState.getPlayerPositions());
|
updateOrder(raceState.getPlayerPositions());
|
||||||
updateSparkLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -256,9 +216,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
updateOrder(raceState.getPlayerPositions());
|
||||||
gameView = new GameView3D();
|
gameView = new GameView3D();
|
||||||
// gameView.setFrameRateFXText(fpsDisplay);
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
contentAnchorPane.getChildren().add(0, gameView.getAssets());
|
contentStackPane.getChildren().add(0, gameView.getAssets());
|
||||||
((SubScene) gameView.getAssets()).widthProperty()
|
((SubScene) gameView.getAssets()).widthProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().widthProperty());
|
.bind(ViewManager.getInstance().getStage().widthProperty());
|
||||||
((SubScene) gameView.getAssets()).heightProperty()
|
((SubScene) gameView.getAssets()).heightProperty()
|
||||||
@@ -270,11 +229,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
gameView.updateCourse(
|
gameView.updateCourse(
|
||||||
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
||||||
);
|
);
|
||||||
// gameView.enableZoom();
|
|
||||||
gameView.setBoatAsPlayer(player);
|
gameView.setBoatAsPlayer(player);
|
||||||
// gameView.startRace();
|
|
||||||
|
|
||||||
// raceState.addCollisionListener(gameView::drawCollision);
|
// raceState.addCollisionListener(gameView::drawCollision);
|
||||||
|
|
||||||
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
||||||
gameView.setWindDir(newDirection.doubleValue());
|
gameView.setWindDir(newDirection.doubleValue());
|
||||||
Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
|
Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
|
||||||
@@ -287,9 +245,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
updateWindSpeed(raceState.getWindSpeed());
|
updateWindSpeed(raceState.getWindSpeed());
|
||||||
});
|
});
|
||||||
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(this::initializeUpdateTimer);
|
||||||
initializeUpdateTimer();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -386,137 +342,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseFPSCheckBox() {
|
|
||||||
// toggleFps.selectedProperty().addListener((obs, oldVal, newVal) ->
|
|
||||||
// gameView.setFPSVisibility(toggleFps.isSelected())
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialiseAnnotationSlider() {
|
|
||||||
// annotationSlider.setLabelFormatter(new StringConverter<Double>() {
|
|
||||||
// @Override
|
|
||||||
// public String toString(Double n) {
|
|
||||||
// if (n == 0) {
|
|
||||||
// return "None";
|
|
||||||
// }
|
|
||||||
// if (n == 1) {
|
|
||||||
// return "Important";
|
|
||||||
// }
|
|
||||||
// if (n == 2) {
|
|
||||||
// return "All";
|
|
||||||
// }
|
|
||||||
// return "All";
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Double fromString(String s) {
|
|
||||||
// switch (s) {
|
|
||||||
// case "None":
|
|
||||||
// return 0d;
|
|
||||||
// case "Important":
|
|
||||||
// return 1d;
|
|
||||||
// case "All":
|
|
||||||
// return 2d;
|
|
||||||
//
|
|
||||||
// default:
|
|
||||||
// return 2d;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// annotationSlider.setValue(2);
|
|
||||||
// annotationSlider.valueProperty().addListener((obs, oldVal, newVal) ->
|
|
||||||
// setAnnotations((int) annotationSlider.getValue())
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to add any new yachts into the race that may have started late or not have had data received yet
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
// // Collect the racing yachts that aren't already in the chart
|
|
||||||
// sparkLineData.clear();
|
|
||||||
// List<ClientYacht> sparkLineCandidates = new ArrayList<>(participants.values());
|
|
||||||
// // Create a new data series for new yachts
|
|
||||||
// sparkLineCandidates
|
|
||||||
// .stream()
|
|
||||||
// .filter(yacht -> yacht.getPosition() != null)
|
|
||||||
// .forEach(yacht -> {
|
|
||||||
// Series<String, Double> yachtData = new Series<>();
|
|
||||||
// yachtData.setName(yacht.getSourceId().toString());
|
|
||||||
// yachtData.getData().add(
|
|
||||||
// new Data<>(
|
|
||||||
// Integer.toString(yacht.getLegNumber()),
|
|
||||||
// 1.0 + participants.size() - yacht.getPosition()
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// sparkLineData.add(yachtData);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // Lambda function to sort the series in order of leg (later legs shown more to the right)
|
|
||||||
// sparkLineData.sort((o1, o2) -> {
|
|
||||||
// Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
|
|
||||||
// Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
|
|
||||||
// if (leg2 < leg1){
|
|
||||||
// return 1;
|
|
||||||
// } else {
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// // Adds the new data series to the sparkline (and set the colour of the series)
|
|
||||||
// Platform.runLater(() -> {
|
|
||||||
// sparkLineData
|
|
||||||
// .stream()
|
|
||||||
// .filter(spark -> !raceSparkLine.getData().contains(spark))
|
|
||||||
// .forEach(spark -> {
|
|
||||||
// raceSparkLine.getData().add(spark);
|
|
||||||
// spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialiseSparkLine() {
|
|
||||||
// sparklineYAxis.setUpperBound(participants.size() + 1);
|
|
||||||
// raceSparkLine.setCreateSymbols(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the yachts sparkline of the desired yacht and using the new leg number
|
|
||||||
* @param yacht The yacht to be updated on the sparkline
|
|
||||||
* @param legNumber the leg number that the position will be assigned to
|
|
||||||
*/
|
|
||||||
void updateYachtPositionSparkline(ClientYacht yacht, Integer legNumber){
|
|
||||||
for (XYChart.Series<String, Double> positionData : sparkLineData) {
|
|
||||||
positionData.getData().add(
|
|
||||||
new Data<>(
|
|
||||||
Integer.toString(legNumber),
|
|
||||||
1.0 + participants.size() - yacht.getPlacing()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* @return the colour as an rgb string
|
|
||||||
*/
|
|
||||||
private String getBoatColorAsRGB(String yachtId){
|
|
||||||
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
|
|
||||||
if (color == null){
|
|
||||||
return String.format("#%02X%02X%02X",255,255,255);
|
|
||||||
}
|
|
||||||
return String.format( "#%02X%02X%02X",
|
|
||||||
(int)( color.getRed() * 255 ),
|
|
||||||
(int)( color.getGreen() * 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.
|
||||||
@@ -874,7 +699,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
public String readChatInput() {
|
public String readChatInput() {
|
||||||
String chat = chatInput.getText();
|
String chat = chatInput.getText();
|
||||||
chatInput.clear();
|
chatInput.clear();
|
||||||
rvAnchorPane.requestFocus();
|
contentStackPane.requestFocus();
|
||||||
return chat;
|
return chat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,17 +139,25 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set up dialog for server creation
|
// Set up dialog for server creation
|
||||||
|
serverListHostButton.setOnAction(action -> {
|
||||||
|
showServerCreationDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows Server Creation Dialog when "Host" button is clicked.
|
||||||
|
*/
|
||||||
|
private void showServerCreationDialog() {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
||||||
"/views/dialogs/ServerCreationDialog.fxml"));
|
"/views/dialogs/ServerCreationDialog.fxml"));
|
||||||
try {
|
try {
|
||||||
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
||||||
DialogTransition.CENTER);
|
DialogTransition.CENTER);
|
||||||
serverListHostButton.setOnAction(action -> {
|
dialog.show();
|
||||||
dialog.show();
|
Sounds.playButtonClick();
|
||||||
Sounds.playButtonClick();
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
logger.warn("Could not create Server Creation Dialog.");
|
logger.warn("Could not create Server Creation Dialog.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package seng302.visualiser.controllers;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDecorator;
|
import com.jfoenix.controls.JFXDecorator;
|
||||||
|
import com.jfoenix.controls.JFXDialog;
|
||||||
|
import com.jfoenix.controls.JFXDialog.DialogTransition;
|
||||||
|
import com.jfoenix.controls.JFXSnackbar;
|
||||||
import com.jfoenix.svg.SVGGlyph;
|
import com.jfoenix.svg.SVGGlyph;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -15,6 +18,7 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.SceneAntialiasing;
|
import javafx.scene.SceneAntialiasing;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -23,6 +27,7 @@ import seng302.gameServer.ServerAdvertiser;
|
|||||||
import seng302.utilities.BonjourInstallChecker;
|
import seng302.utilities.BonjourInstallChecker;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameClient;
|
import seng302.visualiser.GameClient;
|
||||||
|
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
|
||||||
|
|
||||||
public class ViewManager {
|
public class ViewManager {
|
||||||
|
|
||||||
@@ -32,12 +37,9 @@ public class ViewManager {
|
|||||||
private HashMap<String, String> properties; //TODO is this the best way to do this??
|
private HashMap<String, String> properties; //TODO is this the best way to do this??
|
||||||
private ObservableList<String> playerList;
|
private ObservableList<String> playerList;
|
||||||
private Logger logger = LoggerFactory.getLogger(ViewManager.class);
|
private Logger logger = LoggerFactory.getLogger(ViewManager.class);
|
||||||
|
|
||||||
public Stage getStage() {
|
|
||||||
return stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
private JFXSnackbar jfxSnackbar;
|
||||||
|
private JFXDialog keyBindingDialog;
|
||||||
|
|
||||||
private ViewManager() {
|
private ViewManager() {
|
||||||
properties = new HashMap<>();
|
properties = new HashMap<>();
|
||||||
@@ -99,6 +101,8 @@ public class ViewManager {
|
|||||||
gameClient.stopGame();
|
gameClient.stopGame();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jfxSnackbar = new JFXSnackbar(decorator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,12 +123,31 @@ public class ViewManager {
|
|||||||
//Get the button box
|
//Get the button box
|
||||||
HBox btns = (HBox) decorator.getChildren().get(0);
|
HBox btns = (HBox) decorator.getChildren().get(0);
|
||||||
|
|
||||||
|
//Create settings button -- [WIP]
|
||||||
|
JFXButton btnKeyBinding = new JFXButton();
|
||||||
|
btnKeyBinding.setText(" Key Bindings");
|
||||||
|
btnKeyBinding.setStyle("-fx-text-fill:#fff");
|
||||||
|
btnKeyBinding.getStyleClass().add("jfx-decorator-button");
|
||||||
|
btnKeyBinding.setCursor(Cursor.HAND);
|
||||||
|
btnKeyBinding.setFocusTraversable(false);
|
||||||
|
|
||||||
|
btnKeyBinding.setOnMouseClicked(event -> Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
|
if (!checkDialogOpened(decorator.getChildren())) {
|
||||||
|
showKeyBindingDialog();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Something went wrong when opening key bind dialog");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
//Create new button
|
//Create new button
|
||||||
JFXButton btnMute = new JFXButton();
|
JFXButton btnMute = new JFXButton();
|
||||||
btnMute.setText(" Toggle Sound");
|
btnMute.setText(" Toggle Sound");
|
||||||
btnMute.setStyle("-fx-text-fill:#fff");
|
btnMute.setStyle("-fx-text-fill:#fff");
|
||||||
btnMute.getStyleClass().add("jfx-decorator-button");
|
btnMute.getStyleClass().add("jfx-decorator-button");
|
||||||
btnMute.setCursor(Cursor.HAND);
|
btnMute.setCursor(Cursor.HAND);
|
||||||
|
btnMute.setFocusTraversable(false);
|
||||||
|
|
||||||
//Create Graphics
|
//Create Graphics
|
||||||
SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE);
|
SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE);
|
||||||
@@ -134,9 +157,13 @@ public class ViewManager {
|
|||||||
SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON",
|
SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON",
|
||||||
"M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z",
|
"M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z",
|
||||||
Color.WHITE);
|
Color.WHITE);
|
||||||
|
SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING",
|
||||||
|
"M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z",
|
||||||
|
Color.WHITE);
|
||||||
volumeOn.setSize(16, 16);
|
volumeOn.setSize(16, 16);
|
||||||
volumeOff.setSize(16, 16);
|
volumeOff.setSize(16, 16);
|
||||||
spacer.setSize(40, 16);
|
spacer.setSize(40, 16);
|
||||||
|
keyBindingGlyph.setSize(24, 16);
|
||||||
|
|
||||||
// Determine which graphic should go on the button
|
// Determine which graphic should go on the button
|
||||||
if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) {
|
if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) {
|
||||||
@@ -145,9 +172,12 @@ public class ViewManager {
|
|||||||
btnMute.setGraphic(volumeOn);
|
btnMute.setGraphic(volumeOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btnKeyBinding.setGraphic(keyBindingGlyph);
|
||||||
|
|
||||||
// Add Buttons
|
// Add Buttons
|
||||||
btns.getChildren().add(0, spacer);
|
btns.getChildren().add(0, spacer);
|
||||||
btns.getChildren().add(0, btnMute);
|
btns.getChildren().add(0, btnMute);
|
||||||
|
btns.getChildren().add(0, btnKeyBinding);
|
||||||
btnMute.setOnAction((action) -> {
|
btnMute.setOnAction((action) -> {
|
||||||
Sounds.toggleAllSounds();
|
Sounds.toggleAllSounds();
|
||||||
if (btnMute.getGraphic().equals(volumeOff)) {
|
if (btnMute.getGraphic().equals(volumeOff)) {
|
||||||
@@ -212,6 +242,7 @@ public class ViewManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the view to the Lobby Screen
|
* Change the view to the Lobby Screen
|
||||||
|
*
|
||||||
* @param disableReadyButton Boolean value so that clients can't try start a game.
|
* @param disableReadyButton Boolean value so that clients can't try start a game.
|
||||||
* @return A LobbyController object for the Lobby Screen.
|
* @return A LobbyController object for the Lobby Screen.
|
||||||
*/
|
*/
|
||||||
@@ -235,6 +266,7 @@ public class ViewManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the view for the race. Creating a new decorator and destroying the old one.
|
* Sets up the view for the race. Creating a new decorator and destroying the old one.
|
||||||
|
*
|
||||||
* @return A RaceViewController for the race view screen.
|
* @return A RaceViewController for the race view screen.
|
||||||
*/
|
*/
|
||||||
public RaceViewController loadRaceView() {
|
public RaceViewController loadRaceView() {
|
||||||
@@ -258,15 +290,6 @@ public class ViewManager {
|
|||||||
scene.setOnKeyPressed(gameClient::keyPressed);
|
scene.setOnKeyPressed(gameClient::keyPressed);
|
||||||
scene.setOnKeyReleased(gameClient::keyReleased);
|
scene.setOnKeyReleased(gameClient::keyReleased);
|
||||||
|
|
||||||
// uncomment to make it full screen
|
|
||||||
// Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
|
|
||||||
// stage.setX(visualBounds.getMinX());
|
|
||||||
// stage.setY(visualBounds.getMinY());
|
|
||||||
// stage.setWidth(visualBounds.getWidth());
|
|
||||||
// stage.setHeight(visualBounds.getHeight());
|
|
||||||
// stage.setMaximized(true);
|
|
||||||
// stage.setFullScreen(true);
|
|
||||||
|
|
||||||
stage.setMinHeight(500);
|
stage.setMinHeight(500);
|
||||||
stage.setMinWidth(800);
|
stage.setMinWidth(800);
|
||||||
stage.setTitle("Party Parrots At Sea");
|
stage.setTitle("Party Parrots At Sea");
|
||||||
@@ -279,7 +302,7 @@ public class ViewManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
while (loader.getController() == null){
|
while (loader.getController() == null) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -289,4 +312,9 @@ public class ViewManager {
|
|||||||
|
|
||||||
return loader.getController();
|
return loader.getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stage getStage() {
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXToggleButton;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import seng302.model.GameKeyBind;
|
||||||
|
import seng302.model.KeyAction;
|
||||||
|
import seng302.visualiser.GameClient;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
|
||||||
|
public class KeyBindingDialogController implements Initializable {
|
||||||
|
|
||||||
|
//--------FXML BEGIN--------//
|
||||||
|
@FXML
|
||||||
|
private Label keyBindingDialogHeader;
|
||||||
|
@FXML
|
||||||
|
private Label closeLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXButton zoomInbtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton zoomOutBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton vmgBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton sailInOutBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton tackGybeBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton upwindBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton downwindBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton resetBtn;
|
||||||
|
@FXML
|
||||||
|
private Label upwindLabel;
|
||||||
|
@FXML
|
||||||
|
private Label downwindLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXToggleButton turningToggle;
|
||||||
|
//---------FXML END---------//
|
||||||
|
|
||||||
|
private GameKeyBind gameKeyBind;
|
||||||
|
private List<JFXButton> buttons = new ArrayList<>();
|
||||||
|
private Map<Button, KeyAction> buttonActionMap;
|
||||||
|
private GameClient gameClient; // to send turning mode packet
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
gameKeyBind = GameKeyBind.getInstance();
|
||||||
|
buttons = new ArrayList<>();
|
||||||
|
Collections.addAll(buttons,
|
||||||
|
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn);
|
||||||
|
bindButtonWithAction();
|
||||||
|
loadKeyBind();
|
||||||
|
|
||||||
|
buttons.forEach(button -> {
|
||||||
|
button.setOnMouseEntered(event -> mouseEnter(button));
|
||||||
|
button.setOnMousePressed(event -> buttonPressed(button));
|
||||||
|
button.setOnMouseExited(event -> mouseExit(button));
|
||||||
|
button.setOnKeyPressed(event -> keyPressed(event, button));
|
||||||
|
});
|
||||||
|
|
||||||
|
turningToggle.setOnMouseClicked(event -> toggleTurningMode());
|
||||||
|
|
||||||
|
resetBtn.setOnMouseClicked(event -> {
|
||||||
|
gameKeyBind.setToDefault();
|
||||||
|
loadKeyBind();
|
||||||
|
});
|
||||||
|
|
||||||
|
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
|
||||||
|
|
||||||
|
keyBindingDialogHeader.setFocusTraversable(true);
|
||||||
|
keyBindingDialogHeader.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set buttons' label according to GameKeyBind settings
|
||||||
|
*/
|
||||||
|
private void loadKeyBind() {
|
||||||
|
buttons.forEach(
|
||||||
|
button -> button
|
||||||
|
.setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName()));
|
||||||
|
turningToggle.setSelected(gameKeyBind.isContinuouslyTurning());
|
||||||
|
if (gameKeyBind.isContinuouslyTurning()) {
|
||||||
|
upwindLabel.setText("ClOCKWISE TURNING");
|
||||||
|
downwindLabel.setText("ANTICLOCKWISE TURNING");
|
||||||
|
} else {
|
||||||
|
upwindLabel.setText("UPWIND");
|
||||||
|
downwindLabel.setText("DOWNWIND");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind buttons with specific action in a map.
|
||||||
|
*/
|
||||||
|
private void bindButtonWithAction() {
|
||||||
|
buttonActionMap = new HashMap<>();
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt success / failure message for reassigning key action
|
||||||
|
*/
|
||||||
|
private void showSnackBar(String message, Boolean isWarning) {
|
||||||
|
ViewManager.getInstance().showSnackbar(message, isWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a mouse enters the button, the color and font size should change to highlight
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void mouseEnter(Button button) {
|
||||||
|
button.setStyle(""
|
||||||
|
+ "-fx-background-color: -fx-pp-theme-color;"
|
||||||
|
+ "-fx-text-fill: -fx-pp-front-color;"
|
||||||
|
+ "-fx-font-size: 15;");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt "press key..." to inform users assign a new key bind by pressing a key
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void buttonPressed(Button button) {
|
||||||
|
button.setText("PRESS KEY...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When mouse leaves the button, return the button to the normal state in terms of text,
|
||||||
|
* color and font size
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void mouseExit(Button button) {
|
||||||
|
button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName());
|
||||||
|
button.setStyle(""
|
||||||
|
+ "-fx-background-color: -fx-pp-front-color; "
|
||||||
|
+ "-fx-text-fill: -fx-pp-theme-color; "
|
||||||
|
+ "-fx-font-size: 13;");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a key is pressed, check if the new binding conflicts to any existed settings, if not
|
||||||
|
* assign the selected action with the new key binding to GameKeyBind.
|
||||||
|
* @param event
|
||||||
|
* @param button
|
||||||
|
*/
|
||||||
|
private void keyPressed(KeyEvent event, Button button) {
|
||||||
|
event.consume();
|
||||||
|
KeyAction buttonAction = buttonActionMap.get(button);
|
||||||
|
if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) {
|
||||||
|
showSnackBar(button.getId() + " is set to " + event.getCode().getName(), false);
|
||||||
|
button.setText(gameKeyBind.getKeyCode(buttonAction).getName());
|
||||||
|
} else {
|
||||||
|
loadKeyBind();
|
||||||
|
showSnackBar(event.getCode().getName() + " is already in use", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the turning mode is toggled, update gameKeyBind and send out packet to notify the server
|
||||||
|
*/
|
||||||
|
private void toggleTurningMode() {
|
||||||
|
gameKeyBind.toggleTurningMode();
|
||||||
|
gameClient.sendToggleTurningModePacket();
|
||||||
|
loadKeyBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameClient(GameClient gameClient) {
|
||||||
|
this.gameClient = gameClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
package seng302.visualiser.controllers.dialogs;
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXCheckBox;
|
||||||
import com.jfoenix.controls.JFXSlider;
|
import com.jfoenix.controls.JFXSlider;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
import com.jfoenix.validation.RequiredFieldValidator;
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.MapMaker;
|
||||||
import seng302.visualiser.controllers.ViewManager;
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
import seng302.visualiser.validators.FieldLengthValidator;
|
import seng302.visualiser.validators.FieldLengthValidator;
|
||||||
import seng302.visualiser.validators.ValidationTools;
|
import seng302.visualiser.validators.ValidationTools;
|
||||||
@@ -28,13 +30,35 @@ public class ServerCreationController implements Initializable {
|
|||||||
private Label maxPlayersLabel;
|
private Label maxPlayersLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton submitBtn;
|
private JFXButton submitBtn;
|
||||||
|
@FXML
|
||||||
|
private JFXButton nextMapButton;
|
||||||
|
@FXML
|
||||||
|
private JFXButton lastMapButton;
|
||||||
|
@FXML
|
||||||
|
private Label mapNameLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXSlider legsSlider;
|
||||||
|
@FXML
|
||||||
|
private Label legsSliderLabel;
|
||||||
|
@FXML
|
||||||
|
private JFXCheckBox pickupsCheckBox;
|
||||||
|
@FXML
|
||||||
|
private AnchorPane mapHolder;
|
||||||
|
|
||||||
|
private MapMaker mapMaker = MapMaker.getInstance();
|
||||||
|
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
legsSlider.setMax(10);
|
||||||
|
maxPlayersSlider.valueProperty().addListener(
|
||||||
|
(observable, oldValue, newValue) -> updateMaxPlayerLabel()
|
||||||
|
);
|
||||||
|
legsSlider.valueProperty().addListener(
|
||||||
|
(obs, oldVal, newVal) -> updateLegSliderLabel()
|
||||||
|
);
|
||||||
updateMaxPlayerLabel();
|
updateMaxPlayerLabel();
|
||||||
maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
|
updateLegSliderLabel();
|
||||||
updateMaxPlayerLabel();
|
|
||||||
});
|
|
||||||
|
|
||||||
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
|
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
|
||||||
fieldLengthValidator.setMessage("Server name too long.");
|
fieldLengthValidator.setMessage("Server name too long.");
|
||||||
@@ -49,6 +73,18 @@ public class ServerCreationController implements Initializable {
|
|||||||
validateServerSettings();
|
validateServerSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
nextMapButton.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
nextMap();
|
||||||
|
});
|
||||||
|
|
||||||
|
lastMapButton.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
lastMap();
|
||||||
|
});
|
||||||
|
|
||||||
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +105,7 @@ public class ServerCreationController implements Initializable {
|
|||||||
private void createServer() {
|
private void createServer() {
|
||||||
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
|
||||||
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
||||||
.getValue());
|
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue());
|
||||||
|
|
||||||
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
||||||
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
||||||
@@ -80,11 +116,31 @@ public class ServerCreationController implements Initializable {
|
|||||||
*/
|
*/
|
||||||
private void updateMaxPlayerLabel() {
|
private void updateMaxPlayerLabel() {
|
||||||
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
||||||
maxPlayersLabel.setText(String.format("YOU SELECTED: %.0f", maxPlayersSlider.getValue()));
|
maxPlayersLabel.setText(String.format("Max players: %.0f", maxPlayersSlider.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLegSliderLabel() {
|
||||||
|
legsSlider.setValue(Math.floor(legsSlider.getValue()));
|
||||||
|
legsSliderLabel.setText(
|
||||||
|
String.format("A section of the race will repeat %.0f times", legsSlider.getValue())
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
Sounds.playHoverSound();
|
Sounds.playHoverSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void nextMap() {
|
||||||
|
mapMaker.next();
|
||||||
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lastMap() {
|
||||||
|
mapMaker.previous();
|
||||||
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<configurations>
|
|
||||||
<race-name>AC35</race-name>
|
|
||||||
<race-size>6</race-size>
|
|
||||||
<time-scale>10.0</time-scale>
|
|
||||||
<windDir-direction>135</windDir-direction>
|
|
||||||
</configurations>
|
|
||||||
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<markers>
|
|
||||||
<marks>
|
|
||||||
<gate>
|
|
||||||
<name type="start-line">Start</name>
|
|
||||||
<mark>
|
|
||||||
<name>Start1</name>
|
|
||||||
<latitude>57.6703330</latitude>
|
|
||||||
<longitude>11.8278330</longitude>
|
|
||||||
<id>122</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Start2</name>
|
|
||||||
<latitude>57.6703330</latitude>
|
|
||||||
<longitude>11.8271333</longitude>
|
|
||||||
<id>123</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<mark>
|
|
||||||
<name>Mid Mark</name>
|
|
||||||
<latitude>57.6675700</latitude>
|
|
||||||
<longitude>11.8359880</longitude>
|
|
||||||
<id>131</id>
|
|
||||||
</mark>
|
|
||||||
<gate>
|
|
||||||
<name>Leeward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate1</name>
|
|
||||||
<latitude>57.6708220</latitude>
|
|
||||||
<longitude>11.8433900</longitude>
|
|
||||||
<id>124</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate2</name>
|
|
||||||
<latitude>57.6711220</latitude>
|
|
||||||
<longitude>11.8436900</longitude>
|
|
||||||
<id>125</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate>
|
|
||||||
<name>Windward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate1</name>
|
|
||||||
<latitude>57.6650170</latitude>
|
|
||||||
<longitude>11.8279170</longitude>
|
|
||||||
<id>126</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate2</name>
|
|
||||||
<latitude>57.6653170</latitude>
|
|
||||||
<longitude>11.8282170</longitude>
|
|
||||||
<id>127</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate type="finish-line">
|
|
||||||
<name>Finish</name>
|
|
||||||
<mark>
|
|
||||||
<name>Finish1</name>
|
|
||||||
<latitude>57.6715240</latitude>
|
|
||||||
<longitude>11.8444950</longitude>
|
|
||||||
<id>128</id>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Finish2</name>
|
|
||||||
<latitude>57.6718240</latitude>
|
|
||||||
<longitude>11.8447950</longitude>
|
|
||||||
<id>129</id>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
</marks>
|
|
||||||
<order>
|
|
||||||
<one>Start</one>
|
|
||||||
<two>Mid Mark</two>
|
|
||||||
<three>Leeward Gate</three>
|
|
||||||
<four>Windward Gate</four>
|
|
||||||
<five>Leeward Gate</five>
|
|
||||||
<six>Finish</six>
|
|
||||||
</order>
|
|
||||||
</markers>
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<course>
|
|
||||||
<marks>
|
|
||||||
<gate>
|
|
||||||
<name type="start-line">Start</name>
|
|
||||||
<mark>
|
|
||||||
<name>Start1</name>
|
|
||||||
<latitude>32.296577</latitude>
|
|
||||||
<longitude>-64.854304</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Start2</name>
|
|
||||||
<latitude>32.293771</latitude>
|
|
||||||
<longitude>-64.855242</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<mark>
|
|
||||||
<name>Mid Mark</name>
|
|
||||||
<latitude>32.293039</latitude>
|
|
||||||
<longitude>-64.843983</longitude>
|
|
||||||
</mark>
|
|
||||||
<gate>
|
|
||||||
<name>Leeward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate1</name>
|
|
||||||
<latitude>32.284680</latitude>
|
|
||||||
<longitude>-64.850045</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Leeward Gate2</name>
|
|
||||||
<latitude>32.280164</latitude>
|
|
||||||
<longitude>-64.847591</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate>
|
|
||||||
<name>Windward Gate</name>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate1</name>
|
|
||||||
<latitude>32.309693</latitude>
|
|
||||||
<longitude>-64.835249</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Windward Gate2</name>
|
|
||||||
<latitude>32.308046</latitude>
|
|
||||||
<longitude>-64.831785</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
<gate type="finish-line">
|
|
||||||
<name>Finish</name>
|
|
||||||
<mark>
|
|
||||||
<name>Finish1</name>
|
|
||||||
<latitude>32.317379</latitude>
|
|
||||||
<longitude>-64.839291</longitude>
|
|
||||||
</mark>
|
|
||||||
<mark>
|
|
||||||
<name>Finish2</name>
|
|
||||||
<latitude>32.317257</latitude>
|
|
||||||
<longitude>-64.836260</longitude>
|
|
||||||
</mark>
|
|
||||||
</gate>
|
|
||||||
</marks>
|
|
||||||
<order>
|
|
||||||
<one>Start</one>
|
|
||||||
<two>Mid Mark</two>
|
|
||||||
<three>Leeward Gate</three>
|
|
||||||
<four>Windward Gate</four>
|
|
||||||
<five>Leeward Gate</five>
|
|
||||||
<six>Finish</six>
|
|
||||||
</order>
|
|
||||||
</course>
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<teams>
|
|
||||||
<team>
|
|
||||||
<name>Oracle Team USA</name>
|
|
||||||
<alias>USA</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>102</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Artemis Racing</name>
|
|
||||||
<alias>ART</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>101</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Emirates Team New Zealand</name>
|
|
||||||
<alias>NZL</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>103</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Land Rover BAR</name>
|
|
||||||
<alias>BAR</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>104</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>SoftBank Team Japan</name>
|
|
||||||
<alias>JAP</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>105</id>
|
|
||||||
</team>
|
|
||||||
<team>
|
|
||||||
<name>Groupama Team France</name>
|
|
||||||
<alias>FRC</alias>
|
|
||||||
<currentVelocity>0.0</currentVelocity>
|
|
||||||
<id>106</id>
|
|
||||||
</team>
|
|
||||||
</teams>
|
|
||||||
@@ -44,6 +44,11 @@
|
|||||||
-fx-border-color: -fx-decorator-color;
|
-fx-border-color: -fx-decorator-color;
|
||||||
-fx-border-width: 0 4 4 4;
|
-fx-border-width: 0 4 4 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jfx-decorator-button {
|
||||||
|
-fx-focus-traversable: false; /* so decorator button will not be focused */
|
||||||
|
}
|
||||||
|
|
||||||
/********* customised scroll bar for scroll pane ***********/
|
/********* customised scroll bar for scroll pane ***********/
|
||||||
|
|
||||||
/* The main scrollbar **track** CSS class */
|
/* The main scrollbar **track** CSS class */
|
||||||
@@ -100,3 +105,15 @@
|
|||||||
.slider .track {
|
.slider .track {
|
||||||
-fx-background-color: -fx-pp-dark-text-color;
|
-fx-background-color: -fx-pp-dark-text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-content {
|
||||||
|
-fx-background-color: -fx-pp-front-color;
|
||||||
|
-fx-padding: 0 5 0 5;
|
||||||
|
-fx-spacing: 0 5 0 5;
|
||||||
|
-fx-font-size: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-font-size: 15;
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ GridPane .timer * {
|
|||||||
-fx-text-fill: -fx-pp-theme-color;
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
-fx-font-size: 13px;
|
-fx-font-size: 13px;
|
||||||
-fx-pref-height: 35px;
|
-fx-pref-height: 35px;
|
||||||
|
-fx-focus-traversable: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chatSend:hover {
|
#chatSend:hover {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
-fx-font-size: 20px;
|
-fx-font-size: 20px;
|
||||||
-fx-text-fill: -fx-pp-light-text-color;
|
-fx-text-fill: -fx-pp-light-text-color;
|
||||||
-fx-background-color: -fx-pp-theme-color;
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-focus-traversable: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jfx-rippler {
|
.jfx-rippler {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#keyBindingDialogHeader {
|
||||||
|
-fx-font-size: 27px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel {
|
||||||
|
-fx-font-size: 30;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#closeLabel:hover {
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-font-size: 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXButton {
|
||||||
|
-fx-background-color: -fx-pp-light-text-color;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
-fx-font-size: 15px;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXToggleButton {
|
||||||
|
-jfx-toggle-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetBtn {
|
||||||
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-front-color;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
|
-fx-font-size: 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetBtn:hover {
|
||||||
|
-fx-font-size: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-content {
|
||||||
|
-fx-background-color: #323232;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-snackbar-action {
|
||||||
|
-fx-text-fill: #ff4081;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/* a separate file to dynamically change snackbar's color */
|
||||||
|
.jfx-snackbar-toast {
|
||||||
|
-fx-text-fill: red !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RaceDefinition>
|
||||||
|
|
||||||
|
<CourseName> El Classico </CourseName>
|
||||||
|
|
||||||
|
<CentralLat> 57.6679590 </CentralLat>
|
||||||
|
<CentralLng> 11.8503233 </CentralLng>
|
||||||
|
|
||||||
|
<Marks>
|
||||||
|
<CompoundMark CompoundMarkID="1">
|
||||||
|
<Mark Lat="57.670603" Lng="11.828262"/>
|
||||||
|
<Mark Lat="57.669445" Lng="11.826413"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2">
|
||||||
|
<Mark Lat="57.6675700" Lng="11.8359880"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3">
|
||||||
|
<Mark Lat="57.6708220" Lng="11.8433900"/>
|
||||||
|
<Mark Lat="57.671629" Lng="11.840951"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4">
|
||||||
|
<Mark Lat="57.664190" Lng="11.829576"/>
|
||||||
|
<Mark Lat="57.665316" Lng="11.827184"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5">
|
||||||
|
<Mark Lat="57.672350" Lng="11.842535"/>
|
||||||
|
<Mark Lat="57.6715240" Lng="11.8444950"/>
|
||||||
|
</CompoundMark>
|
||||||
|
</Marks>
|
||||||
|
|
||||||
|
<Course>
|
||||||
|
<OpeningSegment>
|
||||||
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="P"/>
|
||||||
|
</OpeningSegment>
|
||||||
|
|
||||||
|
<RepeatingSegment>
|
||||||
|
<Corner CompoundMarkID="3" Rounding="SP"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
</RepeatingSegment>
|
||||||
|
|
||||||
|
<ClosingSegment>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="PS"/>
|
||||||
|
</ClosingSegment>
|
||||||
|
</Course>
|
||||||
|
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit Lat="57.6739450" Lng="11.8417100" />
|
||||||
|
<Limit Lat="57.6709520" Lng="11.8485010" />
|
||||||
|
<Limit Lat="57.6690260" Lng="11.8472790" />
|
||||||
|
<Limit Lat="57.6693140" Lng="11.8457610" />
|
||||||
|
<Limit Lat="57.6665370" Lng="11.8432910" />
|
||||||
|
<Limit Lat="57.6641400" Lng="11.8385840" />
|
||||||
|
<Limit Lat="57.6629430" Lng="11.8332030" />
|
||||||
|
<Limit Lat="57.6629480" Lng="11.8249660" />
|
||||||
|
<Limit Lat="57.6686890" Lng="11.8250920" />
|
||||||
|
<Limit Lat="57.6692230" Lng="11.8231430" />
|
||||||
|
<Limit Lat="57.6725370" Lng="11.8272480" />
|
||||||
|
<Limit Lat="57.6708220" Lng="11.8321340" />
|
||||||
|
</CourseLimit>
|
||||||
|
|
||||||
|
</RaceDefinition>
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RaceDefinition>
|
||||||
|
|
||||||
|
<CourseName> HorseShoe </CourseName>
|
||||||
|
|
||||||
|
<CentralLat> -14.6457 </CentralLat>
|
||||||
|
<CentralLng> 47.612855 </CentralLng>
|
||||||
|
|
||||||
|
<Marks>
|
||||||
|
<CompoundMark CompoundMarkID="1">
|
||||||
|
<Mark Lat="-14.071412" Lng="47.05756"/>
|
||||||
|
<Mark Lat="-14.070814" Lng="47.058041"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2">
|
||||||
|
<Mark Lat="-14.067194" Lng="47.053818" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3">
|
||||||
|
<Mark Lat="-14.061248" Lng="47.058556" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4">
|
||||||
|
<Mark Lat="-14.060584" Lng="47.063088"/>
|
||||||
|
<Mark Lat="-14.060617" Lng="47.06374" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5">
|
||||||
|
<Mark Lat="-14.064637" Lng="47.060307"/>
|
||||||
|
<Mark Lat="-14.06477" Lng="47.061165"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="6">
|
||||||
|
<Mark Lat="-14.063839" Lng="47.06762"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="7">
|
||||||
|
<Mark Lat="-14.068954" Lng="47.066349"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="8">
|
||||||
|
<Mark Lat="-14.07025" Lng="47.060238"/>
|
||||||
|
<Mark Lat="-14.071047" Lng="47.060307"/>
|
||||||
|
</CompoundMark>
|
||||||
|
</Marks>
|
||||||
|
|
||||||
|
<Course>
|
||||||
|
|
||||||
|
<OpeningSegment>
|
||||||
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="3" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="SP"/>
|
||||||
|
</OpeningSegment>
|
||||||
|
|
||||||
|
<RepeatingSegment>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="SP"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
</RepeatingSegment>
|
||||||
|
|
||||||
|
<ClosingSegment>
|
||||||
|
<Corner CompoundMarkID="6" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="7" Rounding="S"/>
|
||||||
|
<Corner CompoundMarkID="8" Rounding="SP" />
|
||||||
|
</ClosingSegment>
|
||||||
|
|
||||||
|
</Course>
|
||||||
|
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit Lat="-14.073371" Lng="47.058213" />
|
||||||
|
<Limit Lat="-14.06653" Lng="47.051003" />
|
||||||
|
<Limit Lat="-14.059022" Lng="47.057286" />
|
||||||
|
<Limit Lat="-14.058723" Lng="47.064358" />
|
||||||
|
<Limit Lat="-14.06261" Lng="47.071293" />
|
||||||
|
<Limit Lat="-14.070814" Lng="47.06762" />
|
||||||
|
<Limit Lat="-14.072773" Lng="47.059689" />
|
||||||
|
<Limit Lat="-14.068323" Lng="47.059449" />
|
||||||
|
<Limit Lat="-14.064969" Lng="47.065113" />
|
||||||
|
<Limit Lat="-14.066131" Lng="47.05986" />
|
||||||
|
<Limit Lat="-14.063441" Lng="47.058419" />
|
||||||
|
<Limit Lat="-14.068091" Lng="47.059174" />
|
||||||
|
</CourseLimit>
|
||||||
|
|
||||||
|
</RaceDefinition>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
<author>Blender User</author>
|
<author>Blender User</author>
|
||||||
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
|
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
|
||||||
</contributor>
|
</contributor>
|
||||||
<created>2017-09-11T16:51:03</created>
|
<created>2017-09-26T01:05:25</created>
|
||||||
<modified>2017-09-11T16:51:03</modified>
|
<modified>2017-09-26T01:05:25</modified>
|
||||||
<unit name="meter" meter="1"/>
|
<unit name="meter" meter="1"/>
|
||||||
<up_axis>Z_UP</up_axis>
|
<up_axis>Z_UP</up_axis>
|
||||||
</asset>
|
</asset>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<geometry id="Plane_004-mesh" name="Plane.004">
|
<geometry id="Plane_004-mesh" name="Plane.004">
|
||||||
<mesh>
|
<mesh>
|
||||||
<source id="Plane_004-mesh-positions">
|
<source id="Plane_004-mesh-positions">
|
||||||
<float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554524 1 -0.09999954 0.01554524 -1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 -0.09999954 0.01554524 1.019509 -0.09807801 0.01554524 1.038269 -0.09238743 0.01554524 1.055557 -0.08314645 0.01554524 1.070711 -0.07071018 0.01554524 1.083147 -0.05555653 0.01554524 1.092388 -0.03826785 0.01554524 1.098079 -0.01950848 0.01554524 1.1 5.96046e-7 0.01554524 1.098079 0.01950955 0.01554524 1.092388 0.03826892 0.01554524 1.083147 0.0555576 0.01554524 1.070711 0.07071125 0.01554524 1.055557 0.08314752 0.01554524 1.038269 0.09238851 0.01554524 1.019509 0.09807896 0.01554524 -1 0.1000005 0.01554524 -1.019509 0.0980789 0.01554524 -1.038268 0.09238833 0.01554524 -1.055557 0.08314734 0.01554524 -1.070711 0.07071107 0.01554524 -1.083147 0.05555742 0.01554524 -1.092388 0.03826874 0.01554524 -1.098078 0.01950937 0.01554524 -1.1 4.56348e-7 0.01554524 -1.098078 -0.0195086 0.01554524 -1.092388 -0.03826785 0.01554524 -1.083147 -0.05555653 0.01554524 -1.070711 -0.07071018 0.01554524 -1.055557 -0.08314645 0.01554524 -1.038268 -0.09238755 0.01554524 -1.019509 -0.09807813 0.01554524 -0.9999997 -0.09999954 0.01554524 1 4.76837e-7 0.01554524 -1 4.76837e-7 0.01554524 -1 4.76837e-7 0.04452204 -1 0.1000005 0.04452204 -1 -0.09999954 0.04452204 1 -0.09999954 0.04452204 1 0.1000005 0.04452204 1.019509 -0.09807801 0.04452204 1 -0.09999954 0.04452204 1.038269 -0.09238743 0.04452204 1.055557 -0.08314645 0.04452204 1.070711 -0.07071018 0.04452204 1.083147 -0.05555653 0.04452204 1.092388 -0.03826785 0.04452204 1.098079 -0.01950848 0.04452204 1.1 5.96046e-7 0.04452204 1.098079 0.01950955 0.04452204 1.092388 0.03826892 0.04452204 1.083147 0.0555576 0.04452204 1.070711 0.07071125 0.04452204 1.055557 0.08314752 0.04452204 1.038269 0.09238851 0.04452204 1.019509 0.09807896 0.04452204 1 0.1000005 0.04452204 -1.019509 0.0980789 0.04452204 -1 0.1000005 0.04452204 -1.038268 0.09238833 0.04452204 -1.055557 0.08314734 0.04452204 -1.070711 0.07071107 0.04452204 -1.083147 0.05555742 0.04452204 -1.092388 0.03826874 0.04452204 -1.098078 0.01950937 0.04452204 -1.1 4.56348e-7 0.04452204 -1.098078 -0.0195086 0.04452204 -1.092388 -0.03826785 0.04452204 -1.083147 -0.05555653 0.04452204 -1.070711 -0.07071018 0.04452204 -1.055557 -0.08314645 0.04452204 -1.038268 -0.09238755 0.04452204 -1.019509 -0.09807813 0.04452204 -0.9999997 -0.09999954 0.04452204 1 4.76837e-7 0.04452204</float_array>
|
<float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554518 1 -0.09999954 0.01554518 -1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 -0.09999954 0.01554518 1.019509 -0.09807801 0.01554518 1.038269 -0.09238743 0.01554518 1.055557 -0.08314645 0.01554518 1.070711 -0.07071018 0.01554518 1.083147 -0.05555647 0.01554518 1.092388 -0.03826785 0.01554518 1.098079 -0.01950848 0.01554518 1.1 5.96046e-7 0.01554518 1.098079 0.01950955 0.01554518 1.092388 0.03826892 0.01554518 1.083147 0.05555754 0.01554518 1.070711 0.07071125 0.01554518 1.055557 0.08314752 0.01554518 1.038269 0.09238851 0.01554518 1.019509 0.09807896 0.01554518 -1 0.1000005 0.01554518 -1.019509 0.0980789 0.01554518 -1.038268 0.09238833 0.01554518 -1.055557 0.08314734 0.01554518 -1.070711 0.07071107 0.01554518 -1.083147 0.05555737 0.01554518 -1.092388 0.03826874 0.01554518 -1.098078 0.01950937 0.01554518 -1.1 4.56348e-7 0.01554518 -1.098078 -0.0195086 0.01554518 -1.092388 -0.03826785 0.01554518 -1.083147 -0.05555647 0.01554518 -1.070711 -0.07071018 0.01554518 -1.055557 -0.08314645 0.01554518 -1.038268 -0.09238755 0.01554518 -1.019509 -0.09807813 0.01554518 -0.9999997 -0.09999954 0.01554518 1 4.76837e-7 0.01554518 -1 4.76837e-7 0.01554518 -1 4.76837e-7 0.04452198 -1 0.1000005 0.04452198 -1 -0.09999954 0.04452198 1 -0.09999954 0.04452198 1 0.1000005 0.04452198 1.019509 -0.09807801 0.04452198 1 -0.09999954 0.04452198 1.038269 -0.09238743 0.04452198 1.055557 -0.08314645 0.04452198 1.070711 -0.07071018 0.04452198 1.083147 -0.05555647 0.04452198 1.092388 -0.03826785 0.04452198 1.098079 -0.01950848 0.04452198 1.1 5.96046e-7 0.04452198 1.098079 0.01950955 0.04452198 1.092388 0.03826892 0.04452198 1.083147 0.05555754 0.04452198 1.070711 0.07071125 0.04452198 1.055557 0.08314752 0.04452198 1.038269 0.09238851 0.04452198 1.019509 0.09807896 0.04452198 1 0.1000005 0.04452198 -1.019509 0.0980789 0.04452198 -1 0.1000005 0.04452198 -1.038268 0.09238833 0.04452198 -1.055557 0.08314734 0.04452198 -1.070711 0.07071107 0.04452198 -1.083147 0.05555737 0.04452198 -1.092388 0.03826874 0.04452198 -1.098078 0.01950937 0.04452198 -1.1 4.56348e-7 0.04452198 -1.098078 -0.0195086 0.04452198 -1.092388 -0.03826785 0.04452198 -1.083147 -0.05555647 0.04452198 -1.070711 -0.07071018 0.04452198 -1.055557 -0.08314645 0.04452198 -1.038268 -0.09238755 0.04452198 -1.019509 -0.09807813 0.04452198 -0.9999997 -0.09999954 0.04452198 1 4.76837e-7 0.04452198</float_array>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
|
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
|
||||||
<param name="X" type="float"/>
|
<param name="X" type="float"/>
|
||||||
@@ -58,9 +58,9 @@
|
|||||||
</technique_common>
|
</technique_common>
|
||||||
</source>
|
</source>
|
||||||
<source id="Plane_004-mesh-normals">
|
<source id="Plane_004-mesh-normals">
|
||||||
<float_array id="Plane_004-mesh-normals-array" count="342">0 0 -1 0 0 -1 0 0 -1 0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 0 0 1 -1.19345e-7 0 1 0 0 1 1.19344e-7 0 1 -4.77372e-7 0 1 0 0 1 0 0 1 0 0 1 -2.38688e-7 0 1 0 0 1 2.3869e-7 0 1 1.19345e-7 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 -2.3869e-7 0 1 0 0 1 -0.6343874 0.7730153 0 -1 0 0 0.9569399 -0.2902863 0 1 0 0 -0.7730182 0.6343839 0 0.9951848 -0.09801703 0 -0.8819218 0.4713957 0 0.9951835 0.09803056 0 -1 -5.14244e-6 0 -0.9569436 0.2902743 0 0.9569399 0.2902863 0 -0.9951834 0.09803056 0 0.8819165 0.4714059 0 0.9238785 0.3826861 0 -0.9951835 -0.09802997 0 0.7730053 0.6343997 0 0.3826843 -0.9238792 0 0 -1 0 -0.9569393 -0.2902879 0 0.6344003 0.7730048 0 0 1 0 -0.8819164 -0.4714059 0 0.4713947 0.8819224 0 0.09802103 -0.9951844 0 -0.7730182 -0.6343839 0 1 3.85683e-6 0 0.2902728 0.9569441 0 -0.2902856 0.9569401 0 -0.6343874 -0.7730153 0 0.09802168 0.9951844 0 -0.4713947 0.8819224 0 -0.4713994 -0.8819198 0 -0.09802168 0.9951844 0 0.6344003 -0.7730048 0 -0.2902857 -0.9569401 0 1 2.57122e-6 0 -0.2902857 0.9569401 0 0.7730085 -0.6343957 0 -0.0980131 -0.9951851 0 -0.4713975 0.881921 0 0.8819219 -0.4713957 0 0.9569398 -0.2902863 0 -0.7730182 0.634384 0 0.9951835 -0.09802997 0 -0.8819165 0.4714059 0 0.9951847 0.09801757 0 -1 -3.85683e-6 0 -0.9569399 0.2902863 0 0.9569398 0.2902863 0 -0.9951834 0.09803056 0 0.8819218 0.4713957 0 0.9238789 0.3826851 0 0.7730085 0.6343957 0 0.3826831 -0.9238798 0 -0.956943 -0.2902759 0 0.6344001 0.7730049 0 -0.8819219 -0.4713957 0 0.4713975 0.881921 0 0.09802103 -0.9951844 0 -0.7730182 -0.634384 0 1 3.85683e-6 0 -0.2902855 0.9569401 0 0.09802103 0.9951844 0 -0.4714021 -0.8819184 0 -0.09802103 0.9951844 0 0.6344001 -0.7730049 0 -0.2902856 -0.9569401 0 1 2.57122e-6 0 -0.2902856 0.9569401 0 0.7730054 -0.6343996 0 -0.09801179 -0.9951853 0 -0.4713947 0.8819224 0 0.8819164 -0.471406 0</float_array>
|
<float_array id="Plane_004-mesh-normals-array" count="270">0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 -1.19343e-7 0 -1 0 0 -1 0 0 -1 -1.19343e-7 0 -1 0 0 1 1.19345e-7 0 1 0 0 1 -4.77394e-7 0 1 -1.19344e-7 0 1 -4.77375e-7 0 1 4.77387e-7 0 1 0 0 1 -1.19345e-7 0 1 2.38692e-7 0 1 2.38687e-7 0 1 -2.38687e-7 0 1 -0.6343871 0.7730156 0 -1 0 0 0.9569398 -0.2902864 0 1 0 0 -0.7730116 0.6343919 0 0.9951861 -0.09800404 0 -0.8819217 0.4713962 0 0.9951872 0.09799164 0 -0.9569509 0.2902504 0 0.9569326 0.2903105 0 -0.9951821 0.09804385 0 0.8819217 0.471396 0 0.923877 0.3826896 0 -0.9951823 -0.09804314 0 0.773018 0.6343841 0 0.3826818 -0.9238802 0 0 -1 0 -0.9569467 -0.2902641 0 0.6343807 0.7730209 0 0 1 0 -0.8819217 -0.4713962 0 0.4714139 0.8819121 0 0.09802061 -0.9951844 0 -0.7730181 -0.6343839 0 1 3.85683e-6 0 0.2902668 0.9569458 0 -0.2902731 0.9569439 0 -0.6343807 -0.7730209 0 0.09802073 0.9951844 0 -0.4714134 0.8819125 0 -0.4713908 -0.8819245 0 -0.09802436 0.995184 0 0.6343871 -0.7730156 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730117 -0.6343918 0 -0.09801268 -0.9951853 0 -0.4713921 0.8819237 0 0.8819217 -0.4713962 0 -0.6343807 0.7730209 0 0.9569326 -0.2903105 0 -0.7730181 0.634384 0 0.9951873 -0.0979911 0 0.995186 0.09800463 0 -0.9569472 0.2902624 0 0.9569398 0.2902864 0 -0.9951821 0.09804385 0 0.923877 0.3826897 0 0.7730115 0.634392 0 0.3826841 -0.9238793 0 -0.9569503 -0.2902522 0 0.6343871 0.7730156 0 0.4714112 0.8819137 0 0.09801995 -0.9951846 0 -0.7730117 -0.6343919 0 1 2.57122e-6 0 0.2902686 0.9569453 0 -0.2902749 0.9569434 0 -0.6343871 -0.7730156 0 0.09802132 0.9951844 0 -0.4714105 0.8819139 0 -0.4713962 -0.8819217 0 -0.09802371 0.9951841 0 0.6343807 -0.7730209 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730181 -0.634384 0 -0.09801262 -0.9951853 0 -0.4713866 0.8819267 0</float_array>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
<accessor source="#Plane_004-mesh-normals-array" count="114" stride="3">
|
<accessor source="#Plane_004-mesh-normals-array" count="90" stride="3">
|
||||||
<param name="X" type="float"/>
|
<param name="X" type="float"/>
|
||||||
<param name="Y" type="float"/>
|
<param name="Y" type="float"/>
|
||||||
<param name="Z" type="float"/>
|
<param name="Z" type="float"/>
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
|
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
|
||||||
<input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/>
|
<input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/>
|
||||||
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
|
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
|
||||||
<p>38 0 0 0 39 0 6 0 5 0 38 0 8 1 6 1 38 1 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 4 38 4 19 4 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 5 36 5 39 5 35 6 39 6 36 6 21 7 39 7 22 7 34 8 39 8 35 8 33 9 39 9 34 9 32 10 39 10 33 10 31 11 39 11 32 11 30 12 39 12 31 12 29 13 39 13 30 13 28 14 39 14 29 14 27 15 39 15 28 15 26 16 39 16 27 16 25 17 39 17 26 17 22 18 39 18 23 18 23 19 39 19 24 19 24 20 39 20 25 20 40 21 43 21 79 21 45 21 79 21 46 21 48 21 79 21 45 21 49 21 50 21 79 21 48 21 49 21 79 21 50 22 51 22 79 22 51 21 52 21 79 21 52 23 53 23 79 23 61 21 79 21 60 21 59 21 60 21 79 21 58 21 59 21 79 21 57 21 58 21 79 21 56 21 57 21 79 21 55 21 56 21 79 21 54 24 55 24 79 24 53 21 54 21 79 21 78 25 40 25 77 25 76 26 77 26 40 26 63 27 62 27 40 27 75 28 76 28 40 28 74 29 75 29 40 29 73 30 74 30 40 30 72 31 73 31 40 31 71 32 72 32 40 32 70 33 71 33 40 33 69 34 70 34 40 34 68 35 69 35 40 35 67 36 68 36 40 36 66 37 67 37 40 37 62 38 64 38 40 38 64 39 65 39 40 39 65 40 66 40 40 40 25 41 65 41 24 41 38 42 61 42 4 42 12 43 51 43 11 43 38 44 43 44 1 44 26 45 66 45 25 45 13 46 52 46 12 46 0 42 40 42 39 42 27 47 67 47 26 47 14 48 53 48 13 48 5 49 79 49 38 49 28 50 68 50 27 50 15 51 54 51 14 51 29 52 69 52 28 52 16 53 55 53 15 53 38 54 47 54 7 54 39 42 41 42 2 42 30 55 70 55 29 55 17 56 56 56 16 56 8 57 45 57 6 57 1 58 42 58 0 58 31 59 71 59 30 59 18 60 57 60 17 60 2 61 44 61 3 61 32 62 72 62 31 62 19 63 58 63 18 63 6 64 46 64 5 64 33 65 73 65 32 65 37 66 40 66 78 66 20 67 59 67 19 67 6 68 47 68 7 68 34 69 74 69 33 69 4 70 60 70 20 70 7 71 48 71 8 71 35 72 75 72 34 72 22 73 63 73 21 73 9 74 48 74 8 74 36 75 76 75 35 75 21 76 40 76 39 76 23 77 62 77 22 77 10 78 49 78 9 78 37 79 77 79 36 79 24 80 64 80 23 80 11 81 50 81 10 81 3 44 79 44 38 44 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 21 41 21 40 21 40 21 42 21 43 21 79 21 44 21 40 21 25 41 66 41 65 41 38 42 79 42 61 42 12 82 52 82 51 82 38 44 79 44 43 44 26 83 67 83 66 83 13 84 53 84 52 84 0 42 42 42 40 42 27 85 68 85 67 85 14 86 54 86 53 86 5 87 46 87 79 87 28 88 69 88 68 88 15 89 55 89 54 89 29 90 70 90 69 90 16 91 56 91 55 91 38 92 79 92 47 92 39 42 40 42 41 42 30 55 71 55 70 55 17 93 57 93 56 93 8 94 48 94 45 94 1 58 43 58 42 58 31 95 72 95 71 95 18 96 58 96 57 96 2 61 41 61 44 61 32 97 73 97 72 97 19 98 59 98 58 98 6 99 45 99 46 99 33 100 74 100 73 100 37 101 39 101 40 101 20 67 60 67 59 67 6 102 45 102 47 102 34 69 75 69 74 69 4 103 61 103 60 103 7 80 47 80 48 80 35 104 76 104 75 104 22 105 62 105 63 105 9 106 49 106 48 106 36 107 77 107 76 107 21 108 63 108 40 108 23 109 64 109 62 109 10 110 50 110 49 110 37 111 78 111 77 111 24 112 65 112 64 112 11 113 51 113 50 113 3 44 44 44 79 44</p>
|
<p>38 0 0 0 39 0 6 1 5 1 38 1 8 0 6 0 38 0 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 0 38 0 19 0 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 4 36 4 39 4 35 0 39 0 36 0 21 0 39 0 22 0 34 0 39 0 35 0 33 5 39 5 34 5 32 0 39 0 33 0 31 0 39 0 32 0 30 0 39 0 31 0 29 0 39 0 30 0 28 6 39 6 29 6 27 0 39 0 28 0 26 0 39 0 27 0 25 7 39 7 26 7 22 0 39 0 23 0 23 0 39 0 24 0 24 8 39 8 25 8 40 9 43 9 79 9 45 9 79 9 46 9 48 9 79 9 45 9 49 9 50 9 79 9 48 9 49 9 79 9 50 10 51 10 79 10 51 9 52 9 79 9 52 11 53 11 79 11 61 9 79 9 60 9 59 9 60 9 79 9 58 12 59 12 79 12 57 9 58 9 79 9 56 9 57 9 79 9 55 9 56 9 79 9 54 13 55 13 79 13 53 9 54 9 79 9 78 14 40 14 77 14 76 15 77 15 40 15 63 9 62 9 40 9 75 9 76 9 40 9 74 9 75 9 40 9 73 9 74 9 40 9 72 9 73 9 40 9 71 9 72 9 40 9 70 9 71 9 40 9 69 16 70 16 40 16 68 9 69 9 40 9 67 17 68 17 40 17 66 18 67 18 40 18 62 9 64 9 40 9 64 19 65 19 40 19 65 20 66 20 40 20 25 21 65 21 24 21 38 22 61 22 4 22 12 23 51 23 11 23 38 24 43 24 1 24 26 25 66 25 25 25 13 26 52 26 12 26 0 22 40 22 39 22 27 27 67 27 26 27 14 28 53 28 13 28 5 22 79 22 38 22 28 29 68 29 27 29 15 30 54 30 14 30 29 31 69 31 28 31 16 32 55 32 15 32 38 33 47 33 7 33 39 22 41 22 2 22 30 34 70 34 29 34 17 35 56 35 16 35 8 36 45 36 6 36 1 37 42 37 0 37 31 38 71 38 30 38 18 39 57 39 17 39 2 40 44 40 3 40 32 41 72 41 31 41 19 42 58 42 18 42 6 43 46 43 5 43 33 44 73 44 32 44 37 45 40 45 78 45 20 46 59 46 19 46 6 47 47 47 7 47 34 48 74 48 33 48 4 49 60 49 20 49 7 50 48 50 8 50 35 51 75 51 34 51 22 52 63 52 21 52 9 53 48 53 8 53 36 54 76 54 35 54 21 24 40 24 39 24 23 55 62 55 22 55 10 56 49 56 9 56 37 57 77 57 36 57 24 58 64 58 23 58 11 59 50 59 10 59 3 24 79 24 38 24 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 9 41 9 40 9 40 9 42 9 43 9 79 9 44 9 40 9 25 60 66 60 65 60 38 22 79 22 61 22 12 61 52 61 51 61 38 24 79 24 43 24 26 62 67 62 66 62 13 63 53 63 52 63 0 22 42 22 40 22 27 27 68 27 67 27 14 64 54 64 53 64 5 22 46 22 79 22 28 65 69 65 68 65 15 66 55 66 54 66 29 67 70 67 69 67 16 32 56 32 55 32 38 68 79 68 47 68 39 22 40 22 41 22 30 34 71 34 70 34 17 69 57 69 56 69 8 70 48 70 45 70 1 37 43 37 42 37 31 71 72 71 71 71 18 72 58 72 57 72 2 40 41 40 44 40 32 41 73 41 72 41 19 73 59 73 58 73 6 74 45 74 46 74 33 75 74 75 73 75 37 76 39 76 40 76 20 77 60 77 59 77 6 78 45 78 47 78 34 79 75 79 74 79 4 80 61 80 60 80 7 81 47 81 48 81 35 82 76 82 75 82 22 83 62 83 63 83 9 84 49 84 48 84 36 85 77 85 76 85 21 24 63 24 40 24 23 86 64 86 62 86 10 87 50 87 49 87 37 88 78 88 77 88 24 89 65 89 64 89 11 59 51 59 50 59 3 24 44 24 79 24</p>
|
||||||
</polylist>
|
</polylist>
|
||||||
</mesh>
|
</mesh>
|
||||||
</geometry>
|
</geometry>
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
<library_visual_scenes>
|
<library_visual_scenes>
|
||||||
<visual_scene id="Scene" name="Scene">
|
<visual_scene id="Scene" name="Scene">
|
||||||
<node id="Plane" name="Plane" type="NODE">
|
<node id="Plane" name="Plane" type="NODE">
|
||||||
<matrix sid="transform">1 0 0 0 0 1 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix>
|
<matrix sid="transform">0.4856636 0 0 0 0 0.6802911 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix>
|
||||||
<instance_geometry url="#Plane_004-mesh" name="Plane">
|
<instance_geometry url="#Plane_004-mesh" name="Plane">
|
||||||
<bind_material>
|
<bind_material>
|
||||||
<technique_common>
|
<technique_common>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 59 KiB |
@@ -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="101" 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="102" 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="103" 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="104" 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="105" 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="106" 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,105 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Race>
|
|
||||||
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
|
|
||||||
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False"/>
|
|
||||||
<RaceID>15082901</RaceID>
|
|
||||||
<RaceType>Fleet</RaceType>
|
|
||||||
<Participants>
|
|
||||||
<Yacht SourceID="101"/>
|
|
||||||
<Yacht SourceID="102"/>
|
|
||||||
<Yacht SourceID="103"/>
|
|
||||||
<Yacht SourceID="104"/>
|
|
||||||
<Yacht SourceID="105"/>
|
|
||||||
<Yacht SourceID="106"/>
|
|
||||||
</Participants>
|
|
||||||
<Course>
|
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330"
|
|
||||||
SourceID="122"/>
|
|
||||||
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.6703330" TargetLng="11.8278330"
|
|
||||||
SourceID="123"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="2" Name="Mark1">
|
|
||||||
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="3" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="4" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="5" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="6" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="7" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="8" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="9" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="124"/>
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
|
|
||||||
SourceID="125"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="10" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="126"/>
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
|
|
||||||
SourceID="127"/>
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="11" Name="Mark4">
|
|
||||||
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.6715240" TargetLng="11.8444950"
|
|
||||||
SourceID="128"/>
|
|
||||||
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950"
|
|
||||||
SourceID="129"/>
|
|
||||||
</CompoundMark>
|
|
||||||
</Course>
|
|
||||||
<CompoundMarkSequence>
|
|
||||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="6" CompoundMarkID="6" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="7" CompoundMarkID="7" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="8" CompoundMarkID="8" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="9" CompoundMarkID="9" Rounding="SP" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="10" CompoundMarkID="10" Rounding="PS" ZoneSize="3"/>
|
|
||||||
<Corner SeqID="11" CompoundMarkID="11" Rounding="PS" ZoneSize="3"/>
|
|
||||||
</CompoundMarkSequence>
|
|
||||||
<CourseLimit>
|
|
||||||
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100"/>
|
|
||||||
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010"/>
|
|
||||||
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790"/>
|
|
||||||
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610"/>
|
|
||||||
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910"/>
|
|
||||||
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840"/>
|
|
||||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030"/>
|
|
||||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660"/>
|
|
||||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920"/>
|
|
||||||
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340"/>
|
|
||||||
</CourseLimit>
|
|
||||||
</Race>
|
|
||||||
@@ -4,62 +4,39 @@
|
|||||||
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
||||||
<RaceID>15082901</RaceID>
|
<RaceID>15082901</RaceID>
|
||||||
<RaceType>Fleet</RaceType>
|
<RaceType>Fleet</RaceType>
|
||||||
|
|
||||||
<Participants>
|
<Participants>
|
||||||
<#list boats as boat>
|
<#list boats as boat>
|
||||||
<Yacht SourceID="${boat.sourceId}"/>
|
<Yacht SourceID="${boat.sourceId}"/>
|
||||||
</#list>
|
</#list>
|
||||||
</Participants>
|
</Participants>
|
||||||
|
|
||||||
<Tokens>
|
<Tokens>
|
||||||
<#list tokens as token>
|
<#list tokens as token>
|
||||||
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
|
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
|
||||||
</#list>
|
</#list>
|
||||||
</Tokens>
|
</Tokens>
|
||||||
|
|
||||||
<Course>
|
<Course>
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
<#list compoundMarks as compoundMark>
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.670603" TargetLng="11.828262" SourceID="122" />
|
<CompoundMark CompoundMarkID="${compoundMark.id?c}" Name="${compoundMark.name}">
|
||||||
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.669445" TargetLng="11.826413" SourceID="123" />
|
<#list compoundMark.marks as mark>
|
||||||
</CompoundMark>
|
<Mark SeqID="${mark.seqID?c}" Name="${mark.name}" TargetLat="${mark.lat?c}" TargetLng="${mark.lng?c}" SourceID="${mark.sourceID?c}" />
|
||||||
<CompoundMark CompoundMarkID="2" Name="Mark1">
|
</#list>
|
||||||
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131" />
|
</CompoundMark>
|
||||||
</CompoundMark>
|
</#list>
|
||||||
<CompoundMark CompoundMarkID="3" Name="Mark2">
|
|
||||||
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900" SourceID="124" />
|
|
||||||
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.671629" TargetLng="11.840951" SourceID="125" />
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="4" Name="Mark3">
|
|
||||||
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.664190" TargetLng="11.829576" SourceID="126" />
|
|
||||||
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.665316" TargetLng="11.827184" SourceID="127" />
|
|
||||||
</CompoundMark>
|
|
||||||
<CompoundMark CompoundMarkID="5" Name="Mark4">
|
|
||||||
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.672350" TargetLng="11.842535" SourceID="128" />
|
|
||||||
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950" SourceID="129" />
|
|
||||||
</CompoundMark>
|
|
||||||
</Course>
|
</Course>
|
||||||
|
|
||||||
<CompoundMarkSequence>
|
<CompoundMarkSequence>
|
||||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3" />
|
<#list roundings as corner>
|
||||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" />
|
<Corner SeqID="${corner.seqID?c}" CompoundMarkID="${corner.compoundMarkID?c}" Rounding="${corner.rounding}" ZoneSize="${corner.zoneSize?c}" />
|
||||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
</#list>
|
||||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="5" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="6" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="7" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="8" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="9" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
|
|
||||||
<Corner SeqID="10" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
|
|
||||||
<Corner SeqID="11" CompoundMarkID="5" Rounding="PS" ZoneSize="3" />
|
|
||||||
</CompoundMarkSequence>
|
</CompoundMarkSequence>
|
||||||
|
|
||||||
<CourseLimit>
|
<CourseLimit>
|
||||||
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100" />
|
<#list courseLimit as limit>
|
||||||
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010" />
|
<Limit SeqID="${limit.seqID?c}" Lat="${limit.lat?c}" Lon="${limit.lng?c}" />
|
||||||
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790" />
|
</#list>
|
||||||
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610" />
|
|
||||||
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910" />
|
|
||||||
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840" />
|
|
||||||
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030" />
|
|
||||||
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660" />
|
|
||||||
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920" />
|
|
||||||
<Limit SeqID="10" Lat="57.6692230" Lon="11.8231430" />
|
|
||||||
<Limit SeqID="11" Lat="57.6725370" Lon="11.8272480" />
|
|
||||||
<Limit SeqID="12" Lat="57.6708220" Lon="11.8321340" />
|
|
||||||
</CourseLimit>
|
</CourseLimit>
|
||||||
|
|
||||||
</Race>
|
</Race>
|
||||||
@@ -5,15 +5,15 @@
|
|||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.ScrollPane?>
|
<?import javafx.scene.control.ScrollPane?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.Pane?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||||
<children>
|
<children>
|
||||||
@@ -86,11 +86,14 @@
|
|||||||
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
<Pane fx:id="serverMap" style="-fx-background-color: skyblue;">
|
<AnchorPane fx:id="serverMap" style="-fx-background-color: skyblue;">
|
||||||
<GridPane.margin>
|
<opaqueInsets>
|
||||||
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
|
<Insets />
|
||||||
</GridPane.margin>
|
</opaqueInsets>
|
||||||
</Pane>
|
<GridPane.margin>
|
||||||
|
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</AnchorPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
|
|||||||
@@ -302,7 +302,7 @@
|
|||||||
</StackPane>
|
</StackPane>
|
||||||
</children>
|
</children>
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/Master.css" />
|
<String fx:value="/css/Master.css"/>
|
||||||
<String fx:value="/css/RaceView.css" />
|
<String fx:value="/css/RaceView.css"/>
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
</AnchorPane>
|
</StackPane>
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
|
<?import com.jfoenix.controls.JFXToggleButton?>
|
||||||
|
<?import java.net.URL?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity"
|
||||||
|
minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0"
|
||||||
|
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController">
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="70.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBIND" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
|
<Label text="ZOOM IN" GridPane.halignment="CENTER" GridPane.rowIndex="1"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label text="ZOOM OUT" GridPane.halignment="CENTER" GridPane.rowIndex="2"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label text="VMG" GridPane.halignment="CENTER" GridPane.rowIndex="3"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label text="SAILS IN/OUT" GridPane.halignment="CENTER" GridPane.rowIndex="4"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label text="TACK/GYBE" GridPane.halignment="CENTER" GridPane.rowIndex="5"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label fx:id="upwindLabel" text="UPWIND" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="6" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<Label fx:id="downwindLabel" text="DOWNWIND" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="7" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin></Label>
|
||||||
|
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="Z"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1"
|
||||||
|
GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="X"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2"
|
||||||
|
GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
|
||||||
|
text="SPACE" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn" buttonType="RAISED"
|
||||||
|
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
|
||||||
|
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="4" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
|
||||||
|
text="ENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="5" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
|
||||||
|
text="PAGE_UP" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXButton id="DOWNWIND" fx:id="downwindBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
|
||||||
|
text="PAGE_DOWN" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="7" GridPane.valignment="CENTER"/>
|
||||||
|
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity" prefHeight="35.0"
|
||||||
|
text="OFF / ON" GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="8"/>
|
||||||
|
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER" GridPane.rowIndex="8"
|
||||||
|
GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
|
||||||
|
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
|
||||||
|
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="9" GridPane.valignment="CENTER"/>
|
||||||
|
<Label fx:id="closeLabel" text="✖" translateY="-5.0" GridPane.columnIndex="1"
|
||||||
|
GridPane.halignment="RIGHT" GridPane.valignment="TOP"/>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../../css/dialogs/KeyBindingDialog.css" />
|
||||||
|
<URL value="@../../css/Master.css" />
|
||||||
|
</stylesheets>
|
||||||
|
</JFXDialogLayout>
|
||||||
@@ -1,69 +1,178 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXCheckBox?>
|
||||||
<?import com.jfoenix.controls.JFXDialogLayout?>
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
<?import com.jfoenix.controls.JFXSlider?>
|
<?import com.jfoenix.controls.JFXSlider?>
|
||||||
<?import com.jfoenix.controls.JFXTextField?>
|
<?import com.jfoenix.controls.JFXTextField?>
|
||||||
<?import java.lang.String?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
|
<?import javafx.scene.text.Font?>
|
||||||
<children>
|
|
||||||
<GridPane>
|
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
|
||||||
<columnConstraints>
|
<children>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<GridPane>
|
||||||
</columnConstraints>
|
<children>
|
||||||
<rowConstraints>
|
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER">
|
||||||
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
|
<font>
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
<Font name="System Bold" size="13.0" />
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
</font></JFXButton>
|
||||||
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
<GridPane GridPane.rowIndex="1">
|
||||||
</rowConstraints>
|
|
||||||
<children>
|
|
||||||
<Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
|
||||||
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
|
|
||||||
<JFXTextField fx:id="serverName" promptText="SERVER NAME" GridPane.rowIndex="1">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="30.0" right="30.0" />
|
|
||||||
</GridPane.margin></JFXTextField>
|
|
||||||
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="2">
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
<GridPane>
|
||||||
<GridPane.margin>
|
<columnConstraints>
|
||||||
<Insets right="30.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
</GridPane.margin></Label>
|
</columnConstraints>
|
||||||
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
|
<rowConstraints>
|
||||||
<GridPane.margin>
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
<Insets left="30.0" top="20.0" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</GridPane.margin>
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</Label>
|
</rowConstraints>
|
||||||
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
<children>
|
||||||
<children>
|
<JFXTextField fx:id="serverName" promptText="SERVER NAME">
|
||||||
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
<padding>
|
||||||
</children>
|
<Insets left="15.0" right="15.0" />
|
||||||
<GridPane.margin>
|
</padding>
|
||||||
<Insets bottom="10.0" right="30.0" />
|
<GridPane.margin>
|
||||||
</GridPane.margin>
|
<Insets left="35.0" right="35.0" />
|
||||||
</VBox>
|
</GridPane.margin>
|
||||||
|
</JFXTextField>
|
||||||
|
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="30.0" top="20.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<children>
|
||||||
|
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
||||||
|
</children>
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets bottom="10.0" right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
<GridPane fx:id="maxPlayersGridPane1" GridPane.rowIndex="2">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="legsSliderLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</Label>
|
||||||
|
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<children>
|
||||||
|
<JFXSlider fx:id="legsSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
|
||||||
|
</children>
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets bottom="10.0" right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</VBox>
|
||||||
|
<GridPane>
|
||||||
|
<children>
|
||||||
|
<Label alignment="CENTER" text="NUMBER OF" GridPane.halignment="CENTER" />
|
||||||
|
<Label alignment="CENTER" text="REPEATING LEGS" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
<JFXCheckBox fx:id="pickupsCheckBox" text="Enable Pickups" GridPane.rowIndex="1">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="5.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXCheckBox>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
<GridPane GridPane.columnIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" prefWidth="35.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" minWidth="35.0" prefWidth="35.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<JFXButton fx:id="lastMapButton" maxHeight="300.0" minHeight="300.0" prefHeight="300.0" prefWidth="35.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text="<" textFill="#5b5b5b" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font></JFXButton>
|
||||||
|
<JFXButton fx:id="nextMapButton" maxHeight="300.0" minHeight="300.0" minWidth="35.0" prefHeight="300.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text=">" textFill="#5b5b5b" GridPane.columnIndex="2" GridPane.valignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font></JFXButton>
|
||||||
|
<GridPane style="-fx-background-color: lightblue; -fx-border-color: grey; -fx-border-radius: 5; -fx-background-radius: 5;" GridPane.columnIndex="1">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="25.0" minHeight="25.0" prefHeight="25.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="342.0" minHeight="10.0" prefHeight="336.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label fx:id="mapNameLabel" text="MAP NAME" GridPane.halignment="CENTER" />
|
||||||
|
<AnchorPane fx:id="mapHolder" prefHeight="333.0" prefWidth="404.0" GridPane.rowIndex="1" />
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
<Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER">
|
||||||
</GridPane>
|
<font>
|
||||||
</children>
|
<Font size="20.0" />
|
||||||
<stylesheets>
|
</font></Label>
|
||||||
<String fx:value="/css/dialogs/ServerCreation.css" />
|
</children>
|
||||||
<String fx:value="/css/Master.css"/>
|
<columnConstraints>
|
||||||
</stylesheets>
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="511.0" minHeight="90.0" prefHeight="370.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="102.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
</JFXDialogLayout>
|
</JFXDialogLayout>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class ChatCommandsTest {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dcSent = false;
|
dcSent = false;
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
mst = new MainServerThread();
|
mst = new MainServerThread();
|
||||||
host = new ClientToServerThread("localhost", 4942);
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
host.addStreamObserver(() -> {
|
host.addStreamObserver(() -> {
|
||||||
@@ -85,7 +85,7 @@ public class ChatCommandsTest {
|
|||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
ie.printStackTrace();
|
ie.printStackTrace();
|
||||||
}
|
}
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
mst = new MainServerThread();
|
mst = new MainServerThread();
|
||||||
host = null;
|
host = null;
|
||||||
try {
|
try {
|
||||||
@@ -129,7 +129,7 @@ public class ChatCommandsTest {
|
|||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
ie.printStackTrace();
|
ie.printStackTrace();
|
||||||
}
|
}
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
mst = new MainServerThread();
|
mst = new MainServerThread();
|
||||||
host = null;
|
host = null;
|
||||||
try {
|
try {
|
||||||
@@ -212,7 +212,7 @@ public class ChatCommandsTest {
|
|||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
ie.printStackTrace();
|
ie.printStackTrace();
|
||||||
}
|
}
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
dcSent = false;
|
dcSent = false;
|
||||||
mst = new MainServerThread();
|
mst = new MainServerThread();
|
||||||
host = null;
|
host = null;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package seng302.model;
|
package seng302.model;
|
||||||
|
|
||||||
|
import static seng302.gameServer.GameState.checkCollision;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -7,8 +9,6 @@ import seng302.gameServer.GameState;
|
|||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
import static seng302.gameServer.GameState.checkCollision;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
|
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
|
||||||
* meters.
|
* meters.
|
||||||
@@ -24,10 +24,10 @@ public class UpdateYachtTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUpRace() {
|
public void setUpRace() {
|
||||||
new GameState("");
|
new GameState();
|
||||||
GameState.addYacht(1, yacht1);
|
GameState.addYacht(1, yacht1);
|
||||||
GameState.addYacht(2, yacht2);
|
GameState.addYacht(2, yacht2);
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ import static junit.framework.TestCase.assertTrue;
|
|||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.utilities.StreamParser;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
public class MarkOrderTest {
|
public class MarkOrderTest {
|
||||||
private static MarkOrder markOrder;
|
private static MarkOrder markOrder;
|
||||||
@@ -16,7 +20,32 @@ public class MarkOrderTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup(){
|
public static void setup(){
|
||||||
markOrder = new MarkOrder();
|
/*
|
||||||
|
%%%%%%
|
||||||
|
%%%% = =
|
||||||
|
%%C >
|
||||||
|
_)' _( .' ,
|
||||||
|
__/ |_/\ " *. o
|
||||||
|
/` \_\ \/ %`= '_ .
|
||||||
|
/ ) \/| .^',*. ,
|
||||||
|
/' /- o/ - " % '_
|
||||||
|
/\_/ < = , ^ ~ .
|
||||||
|
)_o|----'| .` '
|
||||||
|
___// (_ - (\
|
||||||
|
///-( \' \\
|
||||||
|
|
||||||
|
*/
|
||||||
|
markOrder = new MarkOrder(
|
||||||
|
XMLParser.parseRace(
|
||||||
|
StreamParser.extractXmlMessage(
|
||||||
|
new StreamPacket(
|
||||||
|
XMLMessageSubType.RACE.getType(),
|
||||||
|
XMLParser.parseRaceDef("/maps/default.xml", "test", 2).getValue().length(),
|
||||||
|
0, XMLParser.parseRaceDef("/maps/default.xml", "test", 2).getValue().getBytes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
currentSeqID = 0;
|
currentSeqID = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.junit.BeforeClass;
|
|||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
|
|
||||||
public class YachtTest {
|
public class YachtTest {
|
||||||
@@ -17,9 +18,9 @@ public class YachtTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() {
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1");
|
y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1");
|
||||||
gs = new GameState("localhost");
|
gs = new GameState();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Commented out until can fix the weird non-deterministic bug.
|
//Commented out until can fix the weird non-deterministic bug.
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
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.GameStages;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.gameServer.MainServerThread;
|
import seng302.gameServer.MainServerThread;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,7 +18,7 @@ public class RegularPacketsTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
new GameState("localhost");
|
new GameState();
|
||||||
serverThread = new MainServerThread();
|
serverThread = new MainServerThread();
|
||||||
clientThread = new ClientToServerThread("localhost", 4942);
|
clientThread = new ClientToServerThread("localhost", 4942);
|
||||||
GameState.setCurrentStage(GameStages.RACING);
|
GameState.setCurrentStage(GameStages.RACING);
|
||||||
|
|||||||