Compare commits

..

5 Commits

Author SHA1 Message Date
Michael Rausch 562d641703 Fixed alignment on room code label, and room code input
Tags: #story[1281]
2017-09-25 20:19:21 +13:00
Michael Rausch ca320f7fb8 Merge remote-tracking branch 'origin/1273_Changing_Cameras' into 1281_Server_Discovery_Internet 2017-09-25 00:18:35 +13:00
Michael Rausch 5e3ae40d03 Made discovery more reliable & added docs/tests
- Added unit tests
- Added documentation for discovery classes
- Improved error handling

Tags: #story[1281]
2017-09-22 00:01:13 +12:00
Michael Rausch 95ad7a4840 Finished implementing room codes.
- Fixed bug where room code wasn't parsed correctly
- Added room code selection to server list screen.
- Added room code to hosts lobby.
- Implemented communication protocols on the game client.

Tags: #story[1281]
2017-09-21 22:48:33 +12:00
Michael Rausch e17e9749d8 Implemented server to manage a list of available servers on the internet.
- Implemented a server manager that keeps track of servers & room codes, and removes old servers
- Implemented queries to find a server with a specific room code
- Implemented protocol to register servers

#story[1281]
2017-09-20 20:26:14 +12:00
98 changed files with 2002 additions and 2854 deletions
+43 -24
View File
@@ -10,11 +10,13 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServer;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
public class App extends Application { public class App extends Application {
private static Logger logger = LoggerFactory.getLogger(App.class); private static Logger logger = LoggerFactory.getLogger(App.class);
private static boolean isRunningAsCache = false;
public static void parseArgs(String[] args) throws ParseException { public static void parseArgs(String[] args) throws ParseException {
Options options = new Options(); Options options = new Options();
@@ -25,40 +27,52 @@ public class App extends Application {
.getLogger(Logger.ROOT_LOGGER_NAME); .getLogger(Logger.ROOT_LOGGER_NAME);
options.addOption("debugLevel", true, "Set the application debug level"); options.addOption("debugLevel", true, "Set the application debug level");
options.addOption("runAsDiscoveryServer", false, "Run as a discovery server");
options.addOption("discoveryDevMode", false, "Use a local discovery server");
cmd = parser.parse(options, args); cmd = parser.parse(options, args);
if (cmd.hasOption("runAsDiscoveryServer")){
isRunningAsCache = true;
rootLogger.setLevel(Level.ALL);
return;
}
if (cmd.hasOption("discoveryDevMode")) {
DiscoveryServer.DISCOVERY_SERVER = "localhost";
}
if (cmd.hasOption("debugLevel")) { if (cmd.hasOption("debugLevel")) {
switch (cmd.getOptionValue("debugLevel")) { switch (cmd.getOptionValue("debugLevel")) {
case "DEBUG": case "DEBUG":
rootLogger.setLevel(Level.DEBUG); rootLogger.setLevel(Level.DEBUG);
break; break;
case "ALL": case "ALL":
rootLogger.setLevel(Level.ALL); rootLogger.setLevel(Level.ALL);
break; break;
case "WARNING": case "WARNING":
rootLogger.setLevel(Level.WARN); rootLogger.setLevel(Level.WARN);
break; break;
case "ERROR": case "ERROR":
rootLogger.setLevel(Level.ERROR); rootLogger.setLevel(Level.ERROR);
break; break;
case "INFO": case "INFO":
rootLogger.setLevel(Level.INFO); rootLogger.setLevel(Level.INFO);
case "TRACE": case "TRACE":
rootLogger.setLevel(Level.TRACE); rootLogger.setLevel(Level.TRACE);
default: default:
rootLogger.setLevel(Level.ALL); rootLogger.setLevel(Level.ALL);
}
} else {
rootLogger.setLevel(Level.WARN);
} }
} else {
rootLogger.setLevel(Level.WARN);
}
} }
@Override @Override
@@ -67,14 +81,19 @@ public class App extends Application {
} }
public static void main(String[] args) { public static void main(String[] args) throws Exception {
try { try {
parseArgs(args); parseArgs(args);
} catch (ParseException e) { } catch (ParseException e) {
logger.error("Could not parse command line arguments"); logger.error("Could not parse command line arguments");
} }
launch(args); if (!isRunningAsCache){
launch(args);
}
else{
new DiscoveryServer();
}
} }
} }
@@ -0,0 +1,117 @@
package seng302.discoveryServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest;
import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.model.stream.packets.PacketType;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import seng302.discoveryServer.util.ServerTable;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Random;
public class DiscoveryServer {
public static final String ANSI_GREEN = "\u001B[32m";
public static final String ANSI_YELLOW = "\u001B[33m";
public static final String ANSI_BLUE = "\u001B[34m";
public static final String ANSI_RESET = "\u001B[0m";
public static String DISCOVERY_SERVER = "party.sydney.srv.michaelrausch.nz";
private ServerTable serverTable;
public static final Integer PORT_NUMBER = 9969;
private final Logger logger = LoggerFactory.getLogger(DiscoveryServer.class);
private void displayHeader(){
String selectedColor = Arrays.asList(ANSI_BLUE, ANSI_GREEN, ANSI_YELLOW).get(new Random().nextInt(2));
System.out.println(selectedColor);
System.out.println(" .ccccc. \n" +
" .cc;'coooxkl;. \n" +
" .:c:::c:,,,,,;c;;,.'. \n" +
" .clc,',:,..:xxocc;'..c; \n" +
" .c:,';:ox:..:c,,,,,,...cd, \n" +
" .c:'.,oxxxxl::l:.,loll;..;ol. \n" +
" ;Oc..:xxxxxxxxx:.,llll,....oc \n" +
" .,;,',:loxxxxxxxxx:.,llll;.,,.'ld, \n" +
" .lo;..:xxxxxxxxxxxx:.'cllc,.:l:'cO; \n" +
" .:;...'cxxxxxxxxxxxxoc;,::,..cdl;;l' \n" +
" .cl;':,'';oxxxxxxdxxxxxx:....,cooc,cO; \n" +
" .,,,::;,lxoc:,,:lxxxxxxxxxxxo:,,;lxxl;'oNc \n" +
" .cdxo;':lxxxxxxc'';cccccoxxxxxxxxxxxxo,.;lc. " + ANSI_YELLOW + "Party-Parrots-At-Sea Discovery Server v0.1 " + selectedColor +"\n" +
" .loc'.'lxxxxxxxxocc;''''';ccoxxxxxxxxx:..oc \n" +
"olc,..',:cccccccccccc:;;;;;;;;:ccccccccc,.'c, \n" +
"Ol;......................................;l' ");
System.out.println(ANSI_RESET);
}
public DiscoveryServer() throws Exception {
displayHeader();
serverTable = new ServerTable();
ServerSocket serverSocket;
try{
serverSocket = new ServerSocket(PORT_NUMBER);
}
catch(java.net.BindException e){
logger.error("FATAL - Could not bind socket, are you sure there isn't already an instance running?");
System.exit(1);
return;
}
logger.info("Started successfully - Now accepting connections");
while (true){
Socket clientSocket = serverSocket.accept();
parseRequest(clientSocket);
clientSocket.close();
}
}
private void parseRequest(Socket clientSocket) throws Exception {
ServerRepoStreamParser parser = new ServerRepoStreamParser(clientSocket.getInputStream());
if (clientSocket.isConnected() && !clientSocket.isClosed()){
PacketType parsePacketResult = parser.parse();
switch (parsePacketResult){
case SERVER_REGISTRATION:
ServerListing listing = parser.getServerListing();
if (!serverTable.getAllServers().contains(listing)){
listing.setRoomCode(serverTable.getNextRoomCode().toString());
}
serverTable.addServer(listing);
Message serverRegMessage = new RoomCodeRequest(listing.getRoomCode());
clientSocket.getOutputStream().write(serverRegMessage.getBuffer());
break;
case ROOM_CODE_REQUEST:
String desiredRoomCode = parser.getRoomCode();
ServerListing serverListing = serverTable.getServerByRoomCode(desiredRoomCode);
Message response;
if (serverListing != null){
response = new ServerRegistrationMessage(serverListing.getServerName(), serverListing.getMapName(), serverListing.getAddress(), serverListing.getPortNumber(), 0, 0, desiredRoomCode);
}
else{
response = new ServerRegistrationMessage("", "", "", 0, 0, 0, "");
}
clientSocket.getOutputStream().write(response.getBuffer());
break;
}
}
}
}
@@ -0,0 +1,121 @@
package seng302.discoveryServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest;
import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.model.stream.packets.PacketType;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
public class DiscoveryServerClient {
private final Integer UPDATE_INTERVAL_MS = 5000;
private static String roomCode = null;
private Timer serverListingUpdateTimer;
private Logger logger = LoggerFactory.getLogger(DiscoveryServerClient.class);
public DiscoveryServerClient() {
}
/**
* Register the server with the discovery server
* @param serverListing The listing to register
*/
public void register(ServerListing serverListing){
if (serverListingUpdateTimer != null){
serverListingUpdateTimer.cancel();
serverListingUpdateTimer = null;
}
serverListingUpdateTimer = new Timer();
serverListingUpdateTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
sendRegistrationUpdate(serverListing);
} catch (Exception e) {
logger.debug("Could not update server listing");
}
}
}, 0, UPDATE_INTERVAL_MS);
}
/**
* Stop updating the server registration updates
*/
public void unregister(){
serverListingUpdateTimer.cancel();
}
/**
* Gets the connection information for a server given a room code
*
* @param roomCode The room code to search for
* @return The ServerListing, or null if there was an error
* @throws Exception .
*/
public ServerListing getServerForRoomCode(String roomCode) throws Exception {
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
Message request = new RoomCodeRequest(roomCode); //roomCode);
socket.getOutputStream().write(request.getBuffer());
PacketType packetType = parser.parse();
if (packetType != PacketType.SERVER_REGISTRATION){
logger.debug("Wrong packet received in response to a room code request");
return null;
}
socket.close();
return parser.getServerListing();
}
/**
* Sends a registration update to the discovery server.
*
* @param serverListing The server listing to send
* @throws Exception IF there was an error sending the update
*/
private void sendRegistrationUpdate(ServerListing serverListing) throws Exception {
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
Message req = new ServerRegistrationMessage(serverListing);
socket.getOutputStream().write(req.getBuffer());
PacketType packetType = parser.parse();
if (packetType != PacketType.ROOM_CODE_REQUEST){
socket.close();
return;
}
String roomCode = parser.getRoomCode();
if (roomCode.length() != 0){
DiscoveryServerClient.roomCode = roomCode;
}
socket.close();
}
/**
* @return The last room code received by the client
*/
public static String getRoomCode(){
return roomCode;
}
}
@@ -0,0 +1,50 @@
package seng302.discoveryServer.util;
import java.io.InputStream;
public class ReadableByteInputStream {
private InputStream is;
public ReadableByteInputStream(InputStream is){
this.is = is;
}
/**
* Get n bytes from the input stream
* @param n number of bytes
* @return the bytes read
* @throws Exception .
*/
public byte[] getBytes(int n) throws Exception {
byte[] bytes = new byte[n];
for (int i = 0; i < n; i++) {
bytes[i] = (byte) readByte();
}
return bytes;
}
/**
* Skip n bytes
* @param n number of bytes to skip
* @throws Exception
*/
public void skipBytes(long n) throws Exception {
for (int i = 0; i < n; i++) {
readByte();
}
}
/**
* Read the next byte from the stream
* @return The byte that was read
* @throws Exception .
*/
public int readByte() throws Exception {
int currentByte = is.read();
if (currentByte == -1) {
throw new Exception();
}
return currentByte;
}
}
@@ -0,0 +1,113 @@
package seng302.discoveryServer.util;
public class ServerListing {
public final static int SERVER_TTL_DEFAULT = 10;
private String serverName = "";
private String mapName = "";
private String address = "";
private int portNumber = 0;
private int capacity = 0;
private int players = 0;
private String roomCode = "";
private int ttl = SERVER_TTL_DEFAULT;
public ServerListing(String serverName, String mapName, String address, int portNumber, int capacity){
this.serverName = serverName;
this.mapName = mapName;
this.address = address;
this.portNumber = portNumber;
this.capacity = capacity;
}
public ServerListing setNumberOfPlayers(int players){
this.players = players;
return this;
}
public ServerListing setRoomCode(String roomCode){
this.roomCode = roomCode;
return this;
}
public void refreshTtl(){
ttl = SERVER_TTL_DEFAULT;
}
public void decrementTtl(){
ttl--;
}
public boolean hasTtlExpired(){
return ttl < 0;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!ServerListing.class.isAssignableFrom(obj.getClass())) {
return false;
}
final ServerListing other = (ServerListing) obj;
if (this.getPortNumber() != other.getPortNumber()){
return false;
}
if (!this.getMapName().equals(other.getMapName())){
return false;
}
if (!this.getServerName().equals(other.getServerName())){
return false;
}
if (this.getCapacity() != other.getCapacity()){
return false;
}
if (!this.getAddress().equals(other.getAddress())){
return false;
}
return true;
}
@Override
public int hashCode() {
return this.getServerName().hashCode() +
this.getAddress().hashCode() + this.getMapName().hashCode();
}
public String getRoomCode() {
return roomCode;
}
public int getPortNumber() {
return portNumber;
}
public String getMapName() {
return mapName;
}
public String getServerName() {
return serverName;
}
public int getCapacity() {
return capacity;
}
public String getAddress() {
return address;
}
public void setTtl(Integer ttl){
this.ttl = ttl;
}
}
@@ -0,0 +1,109 @@
package seng302.discoveryServer.util;
import seng302.gameServer.messages.Message;
import seng302.model.stream.packets.PacketType;
import java.io.InputStream;
import java.util.Arrays;
public class ServerRepoStreamParser {
private ReadableByteInputStream inputStream;
private String roomCode;
private String mapName;
private ServerListing serverListing;
public ServerRepoStreamParser(InputStream is){
inputStream = new ReadableByteInputStream(is);
}
public PacketType parse() throws Exception {
int sync1 = inputStream.readByte();
int sync2 = inputStream.readByte();
PacketType packetType = null;
if (sync1 == 0x47 && sync2 == 0x83) {
int type = inputStream.readByte();
inputStream.skipBytes(10);
long payloadLength = Message.bytesToLong(inputStream.getBytes(2));
byte[] payload = inputStream.getBytes((int) payloadLength);
inputStream.skipBytes(4);
packetType = PacketType.assignPacketType(type, payload);
switch (packetType) {
case ROOM_CODE_REQUEST:
roomCode = parseRoomCodeRequest(payload);
break;
case LOBBY_REQUEST:
mapName = parseLobbyRequest(payload);
case SERVER_REGISTRATION:
serverListing = parseServerRegistration(payload);
break;
}
}
return packetType;
}
private String parseLobbyRequest(byte[] payload) {
int mapNameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0 ,4));
return new String(Arrays.copyOfRange(payload, 4, 4+mapNameLength));
}
private String parseRoomCodeRequest(byte[] payload) {
int roomCodeLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0 ,6));
return new String(Arrays.copyOfRange(payload, 6, 6+roomCodeLength));
}
public static ServerListing parseServerRegistration(byte[] payload) {
int nameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 0, 6));
int mapNameLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 6, 12));
int addressLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 12, 18));
int roomCodeLength = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 18, 24));
int portNumber = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 24, 28));
int players = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 28, 32));
int capacity = (int) Message.bytesToLong(Arrays.copyOfRange(payload, 32, 36));
int currentPos = 36;
int nextPos = currentPos + nameLength;
String serverName = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + mapNameLength;
String mapName = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + addressLength;
String address = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
currentPos = nextPos;
nextPos = currentPos + roomCodeLength;
String roomCode = new String(Arrays.copyOfRange(payload, currentPos, nextPos));
ServerListing serverListing = new ServerListing(serverName, mapName, address, portNumber, capacity);
serverListing.setNumberOfPlayers(players);
serverListing.setRoomCode(roomCode);
return serverListing;
}
public String getRoomCode() {
return roomCode;
}
public String getMapName() {
return mapName;
}
public ServerListing getServerListing() {
return serverListing;
}
}
@@ -0,0 +1,97 @@
package seng302.discoveryServer.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class ServerTable {
private List<ServerListing> servers;
private int lastRoomCode = 4020;
private Logger logger = LoggerFactory.getLogger(ServerTable.class);
public ServerTable(){
servers = new ArrayList<>();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
updateServers();
}
}, 0, 1000);
}
/**
* Update the servers TTL values, and then remove expired servers
*/
private void updateServers() {
List<ServerListing> serversToRemove = new ArrayList<>();
for (ServerListing server : servers){
server.decrementTtl();
if (server.hasTtlExpired()){
logger.debug("Removed expired server - " + server.getServerName());
serversToRemove.add(server);
}
}
servers.removeAll(serversToRemove);
}
/**
* Add a server to the table
* @param server The server to add
*/
public void addServer(ServerListing server){
if (servers.contains(server)){
updateTtlForServer(server);
return;
}
logger.debug("Added new server - " + server.getServerName());
servers.add(server);
}
/**
* Update the TTL for a given server to the default TTL value
* @param server The server to update
*/
private void updateTtlForServer(ServerListing server) {
for (ServerListing serverListing : servers){
if (server.equals(serverListing)){
serverListing.refreshTtl();
}
}
}
/**
* @return All the servers in the table
*/
public List<ServerListing> getAllServers(){
return Collections.unmodifiableList(servers);
}
/**
* Get a server from the table given its room code
* @param roomCode The room code to search for
* @return The ServerListing of the found server, or null
* the server wasn't found
*/
public ServerListing getServerByRoomCode(String roomCode){
for (ServerListing serverListing : servers){
if (serverListing.getRoomCode().equals(roomCode)){
return serverListing;
}
}
return null;
}
/**
* @return The next available room code
*/
public Integer getNextRoomCode(){
lastRoomCode += 1;
return lastRoomCode;
}
}
+116 -305
View File
@@ -1,47 +1,23 @@
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 java.util.Timer;
import java.util.TimerTask;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.*;
import seng302.gameServer.messages.BoatStatus; import seng302.model.*;
import seng302.gameServer.messages.ChatterMessage;
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.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.RandomSpawn;
import seng302.utilities.XMLParser; import seng302.utilities.XMLParser;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.*;
/** /**
* A Static class to hold information about the current state of the game (model) * A Static class to hold information about the current state of the game (model)
@@ -58,38 +34,25 @@ public class GameState implements Runnable {
private static Logger logger = LoggerFactory.getLogger(GameState.class); private static Logger logger = LoggerFactory.getLogger(GameState.class);
private static final Integer STATE_UPDATES_PER_SECOND = 60;
//Scheduling constants
static final int WARNING_TIME = 10 * -1000; static final int WARNING_TIME = 10 * -1000;
static final int PREPATORY_TIME = 5 * -1000; static final int PREPATORY_TIME = 5 * -1000;
private static final int TIME_TILL_START = 10 * 1000; private static final int TIME_TILL_START = 10 * 1000;
//Wind Constants private static final Long POWERUP_TIMEOUT_MS = 10_000L;
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
//Rounding Constants private static final Integer STATE_UPDATES_PER_SECOND = 60;
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further private static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
//Collision constants
private static final Double MARK_COLLISION_DISTANCE = 15d; private static final Double MARK_COLLISION_DISTANCE = 15d;
public static final Double YACHT_COLLISION_DISTANCE = 25.0; public static final Double YACHT_COLLISION_DISTANCE = 25.0;
private static final Double BOUNCE_DISTANCE_MARK = 20.0; private static final Double BOUNCE_DISTANCE_MARK = 20.0;
public static final Double BOUNCE_DISTANCE_YACHT = 30.0; public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
private static final Double COLLISION_VELOCITY_PENALTY = 0.3; private static final Double COLLISION_VELOCITY_PENALTY = 0.3;
private static final Integer VELOCITY_BOOST_MULTIPLIER = 2;
//Powerup Constants
public static final Double VELOCITY_BOOST_MULTIPLIER = 2d;
public static final Integer HANDLING_BOOST_MULTIPLIER = 2;
private static final Double BAD_RANDOM_SPEED_PENALTY = 0.3;
public static final Long BUMPER_DISABLE_TIME = 5_000L;
private static final Long TOKEN_SPAWN_TIME = 30_000L;
private static Long previousUpdateTime; private static Long previousUpdateTime;
public static Double windDirection; public static Double windDirection;
private static Double windSpeed; private static Double windSpeed;
private static Double serverSpeedMultiplier; private static Double speedMultiplier = 1d;
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;
@@ -101,12 +64,13 @@ public class GameState implements Runnable {
private static GameStages currentStage; private static GameStages currentStage;
private static MarkOrder markOrder; private static MarkOrder markOrder;
private static long startTime; private static long startTime;
private static List<Mark> marks; private static Set<Mark> marks;
private static List<Limit> courseLimit; private static List<Limit> courseLimit;
private static Integer maxPlayers = 8; private static Integer maxPlayers = 8;
private static List<Token> allTokens;
private static List<Token> tokensInPlay; private static List<Token> tokensInPlay;
private static RandomSpawn randomSpawn;
private static List<NewMessageListener> newMessageListeners; private static List<NewMessageListener> newMessageListeners;
@@ -117,22 +81,26 @@ public class GameState implements Runnable {
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>(); yachts = new HashMap<>();
tokensInPlay = new ArrayList<>(); tokensInPlay = new ArrayList<>();
players = new ArrayList<>(); players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress; GameState.hostIpAddress = hostIpAddress;
customizationFlag = false; customizationFlag = false;
playerHasLeftFlag = false; playerHasLeftFlag = false;
serverSpeedMultiplier = 1.0; speedMultiplier = 1.0;
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
//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? markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
newMessageListeners = new ArrayList<>(); newMessageListeners = new ArrayList<>();
marks = new MarkOrder().getAllMarks(); allTokens = makeTokens();
randomSpawn = new RandomSpawn(markOrder.getOrderedUniqueCompoundMarks());
resetStartTime(); resetStartTime();
setCourseLimit("/server_config/race.xml");
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) { private void setCourseLimit(String url) {
@@ -150,10 +118,29 @@ public class GameState implements Runnable {
courseLimit = XMLParser.parseRace(document).getCourseLimit(); courseLimit = XMLParser.parseRace(document).getCourseLimit();
} }
/**
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
* race ideally
*
* @return A list of possible tokensInPlay for this race
*/
private ArrayList<Token> makeTokens() {
Token token1 = new Token(TokenType.BOOST, 57.66946, 11.83154);
Token token2 = new Token(TokenType.BOOST, 57.66877, 11.83382);
Token token3 = new Token(TokenType.BOOST, 57.66914, 11.83965);
Token token4 = new Token(TokenType.BOOST, 57.66684, 11.83214);
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
}
public static String getHostIpAddress() { public static String getHostIpAddress() {
return hostIpAddress; return hostIpAddress;
} }
public static Set<Mark> getMarks() {
return Collections.unmodifiableSet(marks);
}
public static List<Player> getPlayers() { public static List<Player> getPlayers() {
return players; return players;
} }
@@ -254,75 +241,16 @@ public class GameState implements Runnable {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("[GameState] interrupted exception"); System.out.println("[GameState] interrupted exception");
} }
if (currentStage == GameStages.PRE_RACE) { if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
update(); update();
if (System.currentTimeMillis() > startTime) {
startSpawningTokens();
startUpdatingWind();
GameState.setCurrentStage(GameStages.RACING);
}
} }
if (currentStage == GameStages.RACING) { if (currentStage == GameStages.RACING) {
update(); update();
} }
} }
} }
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer("Token Spawning Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
spawnNewToken();
notifyMessageListeners(MessageFactory.getRaceXML());
}
}, 0, TOKEN_SPAWN_TIME);
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind() {
Timer timer = new Timer("Wind Updating Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
private static void updateWind() {
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0) {
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
} else {
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED) {
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED) {
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
public static void updateBoat(Integer sourceId, BoatAction actionType) { public static void updateBoat(Integer sourceId, BoatAction actionType) {
ServerYacht playerYacht = yachts.get(sourceId); ServerYacht playerYacht = yachts.get(sourceId);
switch (actionType) { switch (actionType) {
@@ -344,12 +272,6 @@ 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;
} }
} }
@@ -357,11 +279,14 @@ public class GameState implements Runnable {
* Randomly select a subset of tokensInPlay from a pre defined superset * Randomly select a subset of tokensInPlay from a pre defined superset
* Broadasts a new race status message to show this update * Broadasts a new race status message to show this update
*/ */
private void spawnNewToken() { public static void spawnNewToken() {
Random random = new Random();
tokensInPlay.clear(); tokensInPlay.clear();
Token token = randomSpawn.getRandomTokenLocation();
// token.assignType(TokenType.WIND_WALKER); //Get a random token location with random type
logger.debug("Spawned token of type " + token.getTokenType()); Token token = allTokens.get(random.nextInt(allTokens.size()));
token.assignRandomType();
tokensInPlay.add(token); tokensInPlay.add(token);
} }
@@ -379,12 +304,14 @@ public class GameState implements Runnable {
Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0; Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0;
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
if (System.currentTimeMillis() > startTime) {
GameState.setCurrentStage(GameStages.RACING);
}
for (ServerYacht yacht : yachts.values()) { for (ServerYacht yacht : yachts.values()) {
updateVelocity(yacht); updateVelocity(yacht);
checkPowerUpTimeout(yacht);
yacht.runAutoPilot(); yacht.runAutoPilot();
yacht.updateLocation(timeInterval); yacht.updateLocation(timeInterval);
preformTokenUpdates(yacht); //This update must be done before collision. Sorta hacky
checkCollision(yacht); checkCollision(yacht);
if (yacht.getBoatStatus() != BoatStatus.FINISHED) { if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
checkForLegProgression(yacht); checkForLegProgression(yacht);
@@ -398,136 +325,17 @@ public class GameState implements Runnable {
} }
/**
* All token functionality entry points is taken care of here. So can be disabled and enabled
* easily
*
* @param yacht The yacht to perform token checks on
*/
private void preformTokenUpdates(ServerYacht yacht) {
Token collidedToken = checkTokenPickUp(yacht);
if (collidedToken != null) {
tokensInPlay.remove(collidedToken);
powerUpYacht(yacht, collidedToken);
}
checkPowerUpTimeout(yacht);
TokenType powerUp = yacht.getPowerUp();
if (powerUp != null) {
switch (powerUp) {
case WIND_WALKER:
windWalk(yacht);
break;
case BUMPER:
ServerYacht collidedYacht = checkYachtCollision(yacht, true);
if (collidedYacht != null) {
yacht.powerDown();
boatTempShutDown(collidedYacht);
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
notifyMessageListeners(
MessageFactory.makeStatusEffectMessage(collidedYacht, powerUp));
}
break;
case RANDOM:
yacht.setPowerUpSpeedMultiplier(BAD_RANDOM_SPEED_PENALTY);
}
}
}
/**
* Powers up a thisYacht with the given token type.
*
* @param thisYacht The yacht to be powered up
* @param collidedToken The token which this thisYacht collided with
*/
private void powerUpYacht(ServerYacht thisYacht, Token collidedToken) {
//The random token has a 50% chance of becoming another token else becoming a speed detriment!
if (collidedToken.getTokenType() == TokenType.RANDOM && new Random().nextBoolean()) {
collidedToken.realiseRandom();
}
//If another yacht has the wind walker token, They should be powered down. Only one allowed!
else if (collidedToken.getTokenType() == TokenType.WIND_WALKER) {
for (ServerYacht otherYacht : yachts.values()) {
if (otherYacht != thisYacht && otherYacht.getPowerUp() == TokenType.WIND_WALKER) {
powerDownYacht(otherYacht);
}
}
}
thisYacht.powerUp(collidedToken.getTokenType());
String logMessage =
thisYacht.getBoatName() + " has picked up a " + collidedToken.getTokenType().getName()
+ " token";
notifyMessageListeners(
MessageFactory.makeChatterMessage(thisYacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(MessageFactory.makePickupMessage(thisYacht, collidedToken));
logger.debug(
"Yacht: " + thisYacht.getShortName() + " got powerup " + collidedToken.getTokenType());
}
private void powerDownYacht(ServerYacht yacht) {
String logMessage =
yacht.getBoatName() + "'s " + yacht.getPowerUp().getName() + " expired";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
yacht.powerDown();
}
// TODO: 23/09/17 wmu16 - This is a hacky way to have the boat power down. Need some sort of separation between token and status effect :/
/**
* Disables the given boat for BUMPER_DISABLE_TIME ms.
*
* @param yacht The yacht to disable
*/
private void boatTempShutDown(ServerYacht yacht) {
yacht.setPowerUpSpeedMultiplier(0d);
Timer shutDownTimer = new Timer("Shutdown Timer");
shutDownTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.powerDown(); //Note this actually resets the boat to normal.
}
}, BUMPER_DISABLE_TIME);
}
/**
* Checks how long a powerup has been active for. If it has exceeded its timeout, it powers the
* yacht down.
*
* @param yacht The yacht to check to power down
*/
private void checkPowerUpTimeout(ServerYacht yacht) { private void checkPowerUpTimeout(ServerYacht yacht) {
if (yacht.getPowerUp() != null) { if (yacht.getPowerUp() != null) {
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > yacht.getPowerUp() if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
.getTimeout()) { yacht.powerDown();
powerDownYacht(yacht); sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired");
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
} }
} }
} }
/**
* This function changes the wind to be at an angle that causes the yacht in question to be at
* its fastest velocity
*
* @param yacht The yacht to fix the wind for
*/
private void windWalk(ServerYacht yacht) {
Double optimalAngle = PolarTable.getOptimalAngle();
Double heading = yacht.getHeading();
windDirection = (double) Math.floorMod(Math.round(heading + optimalAngle), 360L);
}
/** /**
* Check if the yacht has crossed the course limit * Check if the yacht has crossed the course limit
* *
@@ -549,15 +357,13 @@ public class GameState implements Runnable {
} }
/** /**
* Checks all tokensInPlay to see if a yacht has picked one up. If so, the yacht is powered up * Checks all tokensInPlay to see if a yacht has picked one up
* in the appropriate way * @return Token which was collided with
* @param yacht The yacht to check for collision with a token * @param serverYacht The yacht to check for collision with a token
*
* @return The token collided with
*/ */
private Token checkTokenPickUp(ServerYacht yacht) { private static Token checkTokenPickUp(ServerYacht serverYacht) {
for (Token token : tokensInPlay) { for (Token token : tokensInPlay) {
Double distance = GeoUtility.getDistance(token, yacht.getLocation()); Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) { if (distance < YACHT_COLLISION_DISTANCE) {
return token; return token;
} }
@@ -580,8 +386,9 @@ public class GameState implements Runnable {
*/ */
public static void checkCollision(ServerYacht serverYacht) { public static void checkCollision(ServerYacht serverYacht) {
//Yacht Collision //Yacht Collision
ServerYacht collidedYacht = checkYachtCollision(serverYacht, false); ServerYacht collidedYacht = checkYachtCollision(serverYacht);
Mark collidedMark = checkMarkCollision(serverYacht); Mark collidedMark = checkMarkCollision(serverYacht);
Token collidedToken = checkTokenPickUp(serverYacht);
if (collidedYacht != null) { if (collidedYacht != null) {
GeoPoint originalLocation = serverYacht.getLocation(); GeoPoint originalLocation = serverYacht.getLocation();
@@ -624,36 +431,50 @@ public class GameState implements Runnable {
); );
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht)); notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
} }
//Token Collision
if (collidedToken != null) {
if (collidedToken.getTokenType() == TokenType.RANDOM) {
collidedToken.realiseRandom();
}
sendServerMessage(serverYacht.getSourceId(),
serverYacht.getBoatName() + " has picked up a " + collidedToken.getTokenType()
.getName() + " token");
tokensInPlay.remove(collidedToken);
serverYacht.powerUp(collidedToken.getTokenType());
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
.getTokenType());
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(MessageFactory.makePickupMessage(serverYacht, collidedToken));
}
} }
private void updateVelocity(ServerYacht yacht) { private void updateVelocity(ServerYacht yacht) {
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
Double maxBoatSpeed = Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier;
GeoUtility.knotsToMMS(boatSpeedInKnots) * serverSpeedMultiplier * yacht if (yacht.getPowerUp() != null) {
.getPowerUpSpeedMultiplier() * yacht.getBoatTypeSpeedMultiplier(); if (yacht.getPowerUp().equals(TokenType.BOOST)) {
maxBoatSpeed *= VELOCITY_BOOST_MULTIPLIER;
}
}
Double currentVelocity = yacht.getCurrentVelocity(); Double currentVelocity = yacht.getCurrentVelocity();
// TODO: 15/08/17 remove magic numbers from these equations. // TODO: 15/08/17 remove magic numbers from these equations.
if (yacht.getSailIn()) { if (yacht.getSailIn()) {
if (currentVelocity < maxBoatSpeed - 500) { if (currentVelocity < maxBoatSpeed - 500) {
yacht.changeVelocity( yacht.changeVelocity(maxBoatSpeed / 100);
(maxBoatSpeed / 100) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > maxBoatSpeed + 500) { } else if (currentVelocity > maxBoatSpeed + 500) {
yacht.changeVelocity( yacht.changeVelocity(-currentVelocity / 200);
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else { } else {
yacht yacht.setCurrentVelocity(maxBoatSpeed);
.setCurrentVelocity((maxBoatSpeed) * yacht.getBoatTypeAccelerationMultiplier());
} }
} else { } else {
if (currentVelocity > 3000) { if (currentVelocity > 3000) {
yacht.changeVelocity( yacht.changeVelocity(-currentVelocity / 200);
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > 100) { } else if (currentVelocity > 100) {
yacht.changeVelocity( yacht.changeVelocity(-currentVelocity / 50);
(-currentVelocity / 50) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity <= 100) { } else if (currentVelocity <= 100) {
yacht.setCurrentVelocity(0d); yacht.setCurrentVelocity(0d);
} }
@@ -716,10 +537,7 @@ public class GameState implements Runnable {
if (hasProgressed) { if (hasProgressed) {
if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) { if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) {
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed leg " + yacht.getLegNumber());
String logMessage = yacht.getBoatName() + " passed leg " + yacht.getLegNumber();
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
} }
yacht.incrementLegNumber(); yacht.incrementLegNumber();
sendMarkRoundingMessage(yacht); sendMarkRoundingMessage(yacht);
@@ -755,9 +573,7 @@ public class GameState implements Runnable {
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) { if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.RACING); yacht.setBoatStatus(BoatStatus.RACING);
String logMessage = yacht.getBoatName() + " passed start line"; sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line");
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -861,10 +677,7 @@ public class GameState implements Runnable {
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) { if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.FINISHED); yacht.setBoatStatus(BoatStatus.FINISHED);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed finish line");
String logMessage = yacht.getBoatName() + " passed finish line";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -887,20 +700,16 @@ public class GameState implements Runnable {
String name = new String(customizeData); String name = new String(customizeData);
playerYacht.setBoatName(name); playerYacht.setBoatName(name);
} else if (requestType.equals(CustomizeRequestType.COLOR)) { } else if (requestType.equals(CustomizeRequestType.COLOR)) {
//This low level stuff shouldnt be here alistair! In fact no logic LIKE THIS should! - wmu16
int red = customizeData[0] & 0xFF; int red = customizeData[0] & 0xFF;
int green = customizeData[1] & 0xFF; int green = customizeData[1] & 0xFF;
int blue = customizeData[2] & 0xFF; int blue = customizeData[2] & 0xFF;
Color yachtColor = Color.rgb(red, green, blue); Color yachtColor = Color.rgb(red, green, blue);
playerYacht.setBoatColor(yachtColor); playerYacht.setBoatColor(yachtColor);
} else if (requestType.equals(CustomizeRequestType.SHAPE)) {
String type = new String(customizeData);
playerYacht.setBoatType(BoatMeshType.valueOf(type));
} }
} }
private static Mark checkMarkCollision(ServerYacht yacht) { private static Mark checkMarkCollision(ServerYacht yacht) {
Set<Mark> marksInRace = new HashSet<>(marks); Set<Mark> marksInRace = GameState.getMarks();
for (Mark mark : marksInRace) { for (Mark mark : marksInRace) {
if (GeoUtility.getDistance(yacht.getLocation(), mark) if (GeoUtility.getDistance(yacht.getLocation(), mark)
<= MARK_COLLISION_DISTANCE) { <= MARK_COLLISION_DISTANCE) {
@@ -929,22 +738,15 @@ public class GameState implements Runnable {
* Collision detection which iterates through all the yachts and check if any yacht collided * Collision detection which iterates through all the yachts and check if any yacht collided
* with this yacht. Return collided yacht or null if no collision. * with this yacht. Return collided yacht or null if no collision.
* *
* UPDATE: HACK!!! wmu16 - forBumperCollision is (the goddamn dirtiest) dirty flag to fix a
* weird bug where the bumper collision would not be registerd but the knock back collision would.
* In other words, only set the 'forBumperCollision' flag true if used for the bumper power up.
*
* @return yacht to compare to all other yachts. * @return yacht to compare to all other yachts.
*/ */
private static ServerYacht checkYachtCollision(ServerYacht yacht, Boolean forBumperCollision) { private static ServerYacht checkYachtCollision(ServerYacht yacht) {
Double collisionDistance =
(forBumperCollision) ? YACHT_COLLISION_DISTANCE + 2.5 : YACHT_COLLISION_DISTANCE;
for (ServerYacht otherYacht : GameState.getYachts().values()) { for (ServerYacht otherYacht : GameState.getYachts().values()) {
if (otherYacht != yacht) { if (otherYacht != yacht) {
Double distance = GeoUtility Double distance = GeoUtility
.getDistance(otherYacht.getLocation(), yacht.getLocation()); .getDistance(otherYacht.getLocation(), yacht.getLocation());
; if (distance < YACHT_COLLISION_DISTANCE) {
if (distance < collisionDistance) {
return otherYacht; return otherYacht;
} }
} }
@@ -980,6 +782,13 @@ public class GameState implements Runnable {
roundingMark.getSourceID())); roundingMark.getSourceID()));
} }
public static void sendServerMessage(Integer messageType, String message) {
notifyMessageListeners(new ChatterMessage(
messageType, "SERVER: " + message
));
}
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) { public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
String chatterText = chatterMessage.getMessage(); String chatterText = chatterMessage.getMessage();
String[] words = chatterText.split("\\s+"); String[] words = chatterText.split("\\s+");
@@ -987,19 +796,17 @@ public class GameState implements Runnable {
switch (words[2].trim()) { switch (words[2].trim()) {
case "/speed": case "/speed":
try { try {
serverSpeedMultiplier = Double.valueOf(words[3]); setSpeedMultiplier(Double.valueOf(words[3]));
String logMessage = "Speed modifier set to x" + words[3]; sendServerMessage(chatterMessage.getMessage_type(),
notifyMessageListeners(MessageFactory "Speed modifier set to x" + words[3]);
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
} catch (Exception e) { } catch (Exception e) {
Logger logger = LoggerFactory.getLogger(GameState.class); Logger logger = LoggerFactory.getLogger(GameState.class);
logger.error("cannot parse >speed value"); logger.error("cannot parse >speed value");
} }
return; return;
case "/finish": case "/finish":
String logMessage = "Game will now finish"; sendServerMessage(chatterMessage.getMessage_type(),
notifyMessageListeners(MessageFactory "Game will now finish");
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
endRace(); endRace();
return; return;
} }
@@ -1056,7 +863,11 @@ public class GameState implements Runnable {
currentStage = GameStages.FINISHED; currentStage = GameStages.FINISHED;
} }
public static double getServerSpeedMultiplier() { public static void setSpeedMultiplier (double multiplier) {
return serverSpeedMultiplier; speedMultiplier = multiplier;
}
public static double getSpeedMultiplier () {
return speedMultiplier;
} }
} }
@@ -37,6 +37,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60; private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
private boolean terminated; private boolean terminated;
private Thread thread; private Thread thread;
@@ -98,6 +101,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
GameState.addMessageEventListener(this::broadcastMessage); GameState.addMessageEventListener(this::broadcastMessage);
terminated = false; terminated = false;
thread = new Thread(this, "MainServer"); thread = new Thread(this, "MainServer");
startUpdatingWind();
startSpawningTokens();
thread.start(); thread.start();
} }
@@ -182,6 +187,63 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
private static void updateWind(){
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0){
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
}
else{
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED){
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED){
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind(){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
GameState.spawnNewToken();
broadcastMessage(MessageFactory.getRaceXML());
}
}, 10000, 60000);
}
/** /**
* A client has tried to connect to the server * A client has tried to connect to the server
* *
@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage; import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.RaceStartNotificationType; import seng302.gameServer.messages.RaceStartNotificationType;
import seng302.gameServer.messages.RaceStartStatusMessage; import seng302.gameServer.messages.RaceStartStatusMessage;
import seng302.gameServer.messages.RaceStatus; import seng302.gameServer.messages.RaceStatus;
@@ -137,14 +136,6 @@ public class MessageFactory {
return new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION); return new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION);
} }
/**
* Constructs a message to be sent out whenever a yacht picks up a boost
*
* @param serverYacht The yacht that has picked up a power up
* @param token The token which they picked up
* @return The corresponding YachtEventCodeMessage
*/
public static YachtEventCodeMessage makePickupMessage(ServerYacht serverYacht, Token token) { public static YachtEventCodeMessage makePickupMessage(ServerYacht serverYacht, Token token) {
YachtEventType yachtEventType = null; YachtEventType yachtEventType = null;
switch (token.getTokenType()) { switch (token.getTokenType()) {
@@ -166,39 +157,4 @@ public class MessageFactory {
} }
return new YachtEventCodeMessage(serverYacht.getSourceId(), yachtEventType); return new YachtEventCodeMessage(serverYacht.getSourceId(), yachtEventType);
} }
/**
* Constructs a message representing a certain buff / debuff for a given yacht. For now this is
* just for the bumper debuff so the affected boat is aware that it has been crashed. This could
* however be extended to render affects for all boats given a certain debuff.
*
* @param yacht The yacht affected by some status
* @param token The token indicating what status they have
* @return A YachtEventCodeMessage
*/
public static YachtEventCodeMessage makeStatusEffectMessage(ServerYacht yacht,
TokenType token) {
YachtEventType yachtEventType = null;
switch (token) {
case BUMPER:
yachtEventType = YachtEventType.BUMPER_CRASH;
break;
}
return new YachtEventCodeMessage(yacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message to be sent out when a given yacht powers down (From a boost of any type)
*
* @param yacht The yacht that is powering down
* @return A YachtEventCodeMessage representing this action
*/
public static YachtEventCodeMessage makePowerDownMessage(ServerYacht yacht) {
return new YachtEventCodeMessage(yacht.getSourceId(), YachtEventType.POWER_DOWN);
}
public static ChatterMessage makeChatterMessage(Integer messageType, String message) {
return new ChatterMessage(messageType, "SERVER: " + message);
}
} }
@@ -1,5 +1,8 @@
package seng302.gameServer; package seng302.gameServer;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.DiscoveryServerClient;
import javax.jmdns.JmDNS; import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceInfo;
import java.io.IOException; import java.io.IOException;
@@ -32,12 +35,15 @@ public class ServerAdvertiser {
private static ServerAdvertiser instance = null; private static ServerAdvertiser instance = null;
private static JmDNS jmdnsInstance = null; private static JmDNS jmdnsInstance = null;
private ServiceInfo serviceInfo; // Note: Whenever this is changed, our service will be re-registered on the network. private ServiceInfo serviceInfo; // Note: Whenever this is changed, our service will be re-registered on the network.
private DiscoveryServerClient repositoryClient;
private Hashtable<String ,String> props; private Hashtable<String ,String> props;
private ServerAdvertiser() throws IOException{ private ServerAdvertiser() throws IOException{
jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp())); jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
repositoryClient = new DiscoveryServerClient();
props = new Hashtable<>(); props = new Hashtable<>();
props.put("map", ""); props.put("map", "");
props.put("spacesLeft", "0"); props.put("spacesLeft", "0");
@@ -126,6 +132,9 @@ public class ServerAdvertiser {
} }
} }
}, 0); }, 0);
ServerListing serverListing = new ServerListing(serverName, props.get("map"), getLocalHostIp(), portNo, Integer.parseInt(props.get("capacity")));
repositoryClient.register(serverListing);
} }
/** /**
@@ -7,6 +7,10 @@ public class ServerDescription {
private String serverName; private String serverName;
private String mapName; private String mapName;
private Integer numPlayers; private Integer numPlayers;
private Long lastUpdated;
private Long lastRefreshed;
private static Long EXPIRY_INTERVAL = 5000L;
public ServerDescription(String serverName, String mapName, Integer numPlayers, Integer capacity, String address, Integer portNum){ public ServerDescription(String serverName, String mapName, Integer numPlayers, Integer capacity, String address, Integer portNum){
this.serverName = serverName; this.serverName = serverName;
@@ -15,6 +19,7 @@ public class ServerDescription {
this.address = address; this.address = address;
this.portNum = portNum; this.portNum = portNum;
this.capacity = capacity; this.capacity = capacity;
lastUpdated = System.currentTimeMillis();
} }
@@ -80,4 +85,20 @@ public class ServerDescription {
return this.getName().hashCode() + this.getAddress().hashCode() + return this.getName().hashCode() + this.getAddress().hashCode() +
this.portNumber().hashCode() + this.getMapName().hashCode(); this.portNumber().hashCode() + this.getMapName().hashCode();
} }
public Boolean hasExpired(){
return System.currentTimeMillis() - lastUpdated > EXPIRY_INTERVAL;
}
public Boolean serverShouldBeRemoved() {
if (lastRefreshed == null) return false;
System.out.println("SBR" + (System.currentTimeMillis() - lastRefreshed > EXPIRY_INTERVAL));
return System.currentTimeMillis() - lastRefreshed > EXPIRY_INTERVAL;
}
public void hasBeenRefreshed(){
System.out.println("Was refreshed");
lastRefreshed = System.currentTimeMillis();
}
} }
@@ -33,7 +33,6 @@ 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.generator.RaceXMLTemplate;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/** /**
* 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
@@ -78,6 +77,7 @@ public class ServerToClientThread implements Runnable {
private List<ConnectionListener> connectionListeners = new ArrayList<>(); private List<ConnectionListener> connectionListeners = new ArrayList<>();
private DisconnectListener disconnectListener; private DisconnectListener disconnectListener;
private ServerYacht yacht;
private Player player; private Player player;
public ServerToClientThread(Socket socket) { public ServerToClientThread(Socket socket) {
@@ -100,12 +100,33 @@ public class ServerToClientThread implements Runnable {
} }
private void setUpPlayer(){ private void setUpPlayer(){
String shortName = "p" + sourceId; BufferedReader fn;
String longName = "player " + sourceId; String fName = "";
BufferedReader ln;
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(), shortName, longName, "NZ"); "Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
player = new Player(socket, yacht); player = new Player(socket, yacht);
GameState.addYacht(sourceId, yacht); GameState.addYacht(sourceId, yacht);
@@ -296,6 +317,10 @@ public class ServerToClientThread implements Runnable {
return socket; return socket;
} }
public ServerYacht getYacht() {
return yacht;
}
public void addConnectionListener(ConnectionListener listener) { public void addConnectionListener(ConnectionListener listener) {
connectionListeners.add(listener); connectionListeners.add(listener);
} }
@@ -14,9 +14,7 @@ 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 = 5; private final int MESSAGE_SIZE = 1;
private BoatAction actionType; private BoatAction actionType;
public BoatActionMessage(BoatAction actionType, int sourceId) { public BoatActionMessage(BoatAction actionType) {
this.actionType = actionType; this.actionType = actionType;
setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // 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
@@ -40,7 +40,7 @@ public class ChatterMessage extends Message {
return message; return message;
} }
public int getMessageType() { public int getMessage_type() {
return message_type; return message_type;
} }
} }
@@ -21,7 +21,10 @@ public enum MessageType {
REGISTRATION_REQUEST(101), REGISTRATION_REQUEST(101),
REGISTRATION_RESPONSE(102), REGISTRATION_RESPONSE(102),
CUSTOMIZATION_REQUEST(103), CUSTOMIZATION_REQUEST(103),
CUSTOMIZATION_RESPONSE(104); CUSTOMIZATION_RESPONSE(104),
REPO_REGISTRATION_REQUEST(201),
ROOM_CODE_REQUEST(202),
LOBBY_REQUEST(203);
private int code; private int code;
@@ -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, int clientID){ public RegistrationRequestMessage(ClientType type){
setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize())); setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize()));
allocateBuffer(); allocateBuffer();
writeHeaderToBuffer(); writeHeaderToBuffer();
@@ -0,0 +1,24 @@
package seng302.gameServer.messages;
public class RoomCodeRequest extends Message{
private int size = 0;
@Override
public int getSize() {
return size;
}
public RoomCodeRequest(String roomCode){
size = roomCode.length() + 6;
setHeader(new Header(MessageType.ROOM_CODE_REQUEST, 0x01, (short)getSize()));
allocateBuffer();
writeHeaderToBuffer();
putInt(roomCode.length(), 6);
putBytes(roomCode.getBytes());
writeCRC();
rewind();
}
}
@@ -0,0 +1,60 @@
package seng302.gameServer.messages;
import seng302.discoveryServer.util.ServerListing;
public class ServerRegistrationMessage extends Message {
private int size;
public ServerRegistrationMessage(ServerListing serverListing) {
String serverName = serverListing.getServerName();
String mapName = serverListing.getMapName();
String address = serverListing.getAddress();
int port = serverListing.getPortNumber();
int players = serverListing.getPortNumber();
int capacity = serverListing.getCapacity();
String roomCode = serverListing.getRoomCode();
createMessage(serverName, mapName, address, port, players, capacity, roomCode);
}
@Override
public int getSize() {
return size;
}
public ServerRegistrationMessage(String serverName, String mapName, String address, int port, int players, int capacity, String roomCode){
createMessage(serverName, mapName, address, port, players, capacity, roomCode);
}
private void createMessage(String serverName, String mapName, String address, int port, int players, int capacity, String roomCode){
size = serverName.getBytes().length + mapName.length() + address.length() + roomCode.length() + 36;
setHeader(new Header(MessageType.REPO_REGISTRATION_REQUEST, 0x01, (short) getSize()));
allocateBuffer();
writeHeaderToBuffer();
int nameLength = serverName.length();
int mapNameLength = mapName.length();
int addressLength = address.length();
int roomCodeLength = roomCode.length();
// Put fields here
putInt(nameLength, 6);
putInt(mapNameLength, 6);
putInt(addressLength, 6);
putInt(roomCodeLength, 6);
putInt(port, 4);
putInt(players, 4);
putInt(capacity, 4);
putBytes(serverName.getBytes());
putBytes(mapName.getBytes());
putBytes(address.getBytes());
putBytes(roomCode.getBytes());
writeCRC();
rewind();
}
}
@@ -1,7 +1,7 @@
package seng302.gameServer.messages; package seng302.gameServer.messages;
/** /**
* Enum for different event types for the yacht * Created by wmu16 on 11/09/17.
*/ */
public enum YachtEventType { public enum YachtEventType {
COLLISION(33), COLLISION(33),
@@ -9,10 +9,7 @@ public enum YachtEventType {
TOKEN_BUMPER(35), TOKEN_BUMPER(35),
TOKEN_HANDLING(36), TOKEN_HANDLING(36),
TOKEN_WIND_WALKER(37), TOKEN_WIND_WALKER(37),
TOKEN_RANDOM(38), TOKEN_RANDOM(38);
POWER_DOWN(39),
BUMPER_CRASH(40);
private int code; private int code;
+5 -65
View File
@@ -6,7 +6,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Timer;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerProperty;
@@ -20,7 +19,6 @@ import jdk.nashorn.internal.objects.annotations.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/** /**
@@ -41,30 +39,15 @@ public class ClientYacht extends Observable {
void notifyRounding(ClientYacht yacht, int legNumber); void notifyRounding(ClientYacht yacht, int legNumber);
} }
@FunctionalInterface
public interface ColorChangeListener {
void notifyColorChange(ClientYacht yacht);
}
//This notifies RaceViewController so it can display icon - wmu16
@FunctionalInterface @FunctionalInterface
public interface PowerUpListener { public interface PowerUpListener {
void notifyPowerUp(ClientYacht yacht, TokenType tokenType); void notifyPowerUp(ClientYacht yacht, TokenType tokenType);
} }
//This notifies RaceViewController so it can remove token icon - wmu16
@FunctionalInterface
public interface PowerDownListener {
void notifyPowerDown(ClientYacht yacht);
}
private Logger logger = LoggerFactory.getLogger(ClientYacht.class); private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
private BoatMeshType boatType; private String boatType;
private Integer sourceId; private Integer sourceId;
private String hullID; //matches HullNum in the XML spec. private String hullID; //matches HullNum in the XML spec.
private String shortName; private String shortName;
@@ -74,7 +57,7 @@ public class ClientYacht extends Observable {
private TokenType powerUp; private TokenType powerUp;
private Long estimateTimeAtFinish; private Long estimateTimeAtFinish;
private Boolean sailIn = true; private Boolean sailIn = false;
private Integer currentMarkSeqID = 0; private Integer currentMarkSeqID = 0;
private Long markRoundTime; private Long markRoundTime;
private Long timeTillNext; private Long timeTillNext;
@@ -84,24 +67,18 @@ public class ClientYacht extends Observable {
private Integer boatStatus; private Integer boatStatus;
private Double currentVelocity; private Double currentVelocity;
Timer t;
private BoatObject boatObject; private BoatObject boatObject;
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>(); private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private List<PowerUpListener> powerUpListeners = new ArrayList<>(); private List<PowerUpListener> powerUpListeners = new ArrayList<>();
private List<PowerDownListener> powerDownListeners = new ArrayList<>();
private List<ColorChangeListener> colorChangeListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper(); private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
private Color colour; private Color colour;
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) { String boatName, String country) {
this.boatType = boatType; this.boatType = boatType;
this.sourceId = sourceId; this.sourceId = sourceId;
@@ -111,7 +88,6 @@ public class ClientYacht extends Observable {
this.country = country; this.country = country;
this.location = new GeoPoint(57.670341, 11.826856); this.location = new GeoPoint(57.670341, 11.826856);
this.heading = 120.0; //In degrees this.heading = 120.0; //In degrees
this.headingProperty.set(this.heading);
this.currentVelocity = 0d; this.currentVelocity = 0d;
this.boatStatus = 1; this.boatStatus = 1;
this.colour = Color.rgb(0, 0, 0, 1.0); this.colour = Color.rgb(0, 0, 0, 1.0);
@@ -126,7 +102,7 @@ public class ClientYacht extends Observable {
super.addObserver(o); super.addObserver(o);
} }
public BoatMeshType getBoatType() { public String getBoatType() {
return boatType; return boatType;
} }
@@ -237,21 +213,6 @@ public class ClientYacht extends Observable {
this.position = position; this.position = position;
} }
/**
* Powers down the boat and notifies the raceViewController to display
*/
public void powerDown() {
this.powerUp = null;
for (PowerDownListener listener : powerDownListeners) {
listener.notifyPowerDown(this);
}
}
/**
* powers up the boat and notifies the raceViewController to display
*
* @param tokenType The type of token that this boat is being powered up with
*/
public void setPowerUp(TokenType tokenType) { public void setPowerUp(TokenType tokenType) {
this.powerUp = tokenType; this.powerUp = tokenType;
for (PowerUpListener listener : powerUpListeners) { for (PowerUpListener listener : powerUpListeners) {
@@ -285,7 +246,6 @@ public class ClientYacht extends Observable {
public void setHeading(Double heading) { public void setHeading(Double heading) {
this.heading = heading; this.heading = heading;
setHeadingProperty();
} }
@Override @Override
@@ -312,15 +272,12 @@ public class ClientYacht extends Observable {
public void setColour(Color colour) { public void setColour(Color colour) {
this.colour = colour; this.colour = colour;
for (ColorChangeListener listener : colorChangeListeners) {
listener.notifyColorChange(this);
}
} }
public void updateLocation(double lat, double lng, double heading, double velocity) { public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng); setLocation(lat, lng);
this.heading = heading; this.heading = heading;
setHeadingProperty();
this.currentVelocity = velocity; this.currentVelocity = velocity;
updateVelocityProperty(velocity); updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) { for (YachtLocationListener yll : locationListeners) {
@@ -328,10 +285,6 @@ public class ClientYacht extends Observable {
} }
} }
private void setHeadingProperty() {
headingProperty.set(heading);
}
public void addLocationListener(YachtLocationListener listener) { public void addLocationListener(YachtLocationListener listener) {
locationListeners.add(listener); locationListeners.add(listener);
} }
@@ -344,14 +297,6 @@ public class ClientYacht extends Observable {
powerUpListeners.add(listener); powerUpListeners.add(listener);
} }
public void addPowerDownListener(PowerDownListener listener) {
powerDownListeners.add(listener);
}
public void addColorChangeListener(ColorChangeListener listener) {
colorChangeListeners.add(listener);
}
public void removeMarkRoundingListener(MarkRoundingListener listener) { public void removeMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.remove(listener); markRoundingListeners.remove(listener);
} }
@@ -380,9 +325,4 @@ public class ClientYacht extends Observable {
public BoatObject getBoatObject() { public BoatObject getBoatObject() {
return this.boatObject; return this.boatObject;
} }
public ReadOnlyDoubleWrapper getHeadingProperty() {
return headingProperty;
}
} }
@@ -1,87 +0,0 @@
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);
keys.add(KeyCode.F1);
keys.add(KeyCode.D);
keys.add(KeyCode.A);
keys.add(KeyCode.W);
keys.add(KeyCode.S);
for (int i = 0; i < 12; 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);
}
public KeyAction getKeyAction(KeyCode keyCode) {
return instance.keyToActionMap.get(keyCode);
}
/**
* 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;
}
}
@@ -1,40 +0,0 @@
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),
VIEW(8),
RIGHT(9),
LEFT(10),
FORWARD(11),
BACKWARD(12);
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;
}
}
+4 -37
View File
@@ -4,9 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
/** /**
* A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised * A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised
@@ -19,7 +17,6 @@ public final class PolarTable {
private static HashMap<Double, HashMap<Double, Double>> polarTable; private static HashMap<Double, HashMap<Double, Double>> polarTable;
private static HashMap<Double, HashMap<Double, Double>> upwindOptimal; private static HashMap<Double, HashMap<Double, Double>> upwindOptimal;
private static HashMap<Double, HashMap<Double, Double>> downwindOptimal; private static HashMap<Double, HashMap<Double, Double>> downwindOptimal;
private static Double optimalAngle;
private static int upTwaIndex; private static int upTwaIndex;
private static int dnTwaIndex; private static int dnTwaIndex;
@@ -36,13 +33,11 @@ public final class PolarTable {
upwindOptimal = new HashMap<>(); upwindOptimal = new HashMap<>();
downwindOptimal = new HashMap<>(); downwindOptimal = new HashMap<>();
String line = null; String line;
String check;
Boolean isHeaderLine = true; Boolean isHeaderLine = true;
try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) { try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) {
while ((check = br.readLine()) != null) { while ((line = br.readLine()) != null) {
line = check;
String[] thisLine = line.split(","); String[] thisLine = line.split(",");
//Initial line in file //Initial line in file
@@ -71,10 +66,7 @@ public final class PolarTable {
upwindOptimal.put(thisWindSpeed, thisUpWindPolar); upwindOptimal.put(thisWindSpeed, thisUpWindPolar);
downwindOptimal.put(thisWindSpeed, thisDnWindPolar); downwindOptimal.put(thisWindSpeed, thisDnWindPolar);
} }
} }
getMaxSpeedAngle(line);
} catch (IOException e) { } catch (IOException e) {
System.out.println("[PolarTable] IO exception"); System.out.println("[PolarTable] IO exception");
@@ -82,27 +74,6 @@ public final class PolarTable {
} }
/**
* Passes the final line of the polar table and iterates over the speeds for each
* angle, velocity pair to find the angle that produces the highest velocity
*
* @param line The last line of the polar file
*/
private static void getMaxSpeedAngle(String line) {
String[] theLastLine = line.split(",");
Double maxWindVal = Double.parseDouble(theLastLine[0]);
Double optimalAngle = Double.parseDouble(theLastLine[1]);
Double maxSpeed = Double.parseDouble(theLastLine[2]);
for (Map.Entry<Double, Double> entry : polarTable.get(maxWindVal).entrySet()) {
if (entry.getValue() > maxSpeed) {
maxSpeed = entry.getValue();
optimalAngle = entry.getKey();
}
}
PolarTable.optimalAngle = optimalAngle;
}
/** /**
* Parses the header line of a polar file * Parses the header line of a polar file
@@ -114,18 +85,14 @@ public final class PolarTable {
String thisItem = thisLine[i]; String thisItem = thisLine[i];
if (thisItem.toLowerCase().startsWith("uptwa")) { if (thisItem.toLowerCase().startsWith("uptwa")) {
upTwaIndex = i; upTwaIndex = i;
} else if (thisItem.toLowerCase().startsWith("dntwa")) { }
else if (thisItem.toLowerCase().startsWith("dntwa")) {
dnTwaIndex = i; dnTwaIndex = i;
} }
} }
} }
public static Double getOptimalAngle() {
return optimalAngle;
}
/** /**
* @return The entire polar table * @return The entire polar table
*/ */
+47 -121
View File
@@ -1,6 +1,5 @@
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;
@@ -9,7 +8,10 @@ import seng302.gameServer.messages.BoatStatus;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;
/** /**
* 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)
@@ -18,14 +20,12 @@ import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
*/ */
public class ServerYacht { public class ServerYacht {
private Logger logger = LoggerFactory.getLogger(ServerYacht.class); private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
public static final Double TURN_STEP = 5.0;
//Boat info //Boat info
private BoatMeshType boatType; private String boatType;
private Double turnStep = 5.0;
private Double boatTypeSpeedMultiplier = 1.0;
private Double boatTypeTurnStepMultiplier = 1.0;
private Double boatTypeAccelerationMultiplier = 1.0;
private Integer sourceId; private Integer sourceId;
private String hullID; //matches HullNum in the XML spec. private String hullID; //matches HullNum in the XML spec.
private String shortName; private String shortName;
@@ -55,15 +55,11 @@ public class ServerYacht {
//PowerUp //PowerUp
private TokenType powerUp; private TokenType powerUp;
private Long powerUpStartTime; private Long powerUpStartTime;
private Double powerUpSpeedMultiplier;
private Integer powerUpHandlingMultiplier;
//turning mode
private Boolean continuouslyTurning;
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) { String boatName, String country) {
setBoatType(boatType); this.boatType = boatType;
this.boatStatus = BoatStatus.PRESTART; this.boatStatus = BoatStatus.PRESTART;
this.sourceId = sourceId; this.sourceId = sourceId;
this.hullID = hullID; this.hullID = hullID;
@@ -80,12 +76,10 @@ public class ServerYacht {
this.legNumber = 0; this.legNumber = 0;
this.boatColor = Colors.getColor(sourceId - 1); this.boatColor = Colors.getColor(sourceId - 1);
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
this.hasEnteredRoundingZone = false; this.hasEnteredRoundingZone = false;
this.hasPassedLine = false; this.hasPassedLine = false;
this.hasPassedThroughGate = false; this.hasPassedThroughGate = false;
this.continuouslyTurning = false;
} }
@@ -112,33 +106,13 @@ public class ServerYacht {
location = geoPoint; location = geoPoint;
} }
/**
* Powers up a yacht with a given yacht, only after powering it down first to avoid double power
* ups
*
* @param powerUp The given power up
*/
public void powerUp(TokenType powerUp) { public void powerUp(TokenType powerUp) {
powerDown();
switch (powerUp) {
case BOOST:
powerUpSpeedMultiplier = GameState.VELOCITY_BOOST_MULTIPLIER;
break;
case HANDLING:
powerUpHandlingMultiplier = GameState.HANDLING_BOOST_MULTIPLIER;
break;
}
this.powerUp = powerUp; this.powerUp = powerUp;
powerUpStartTime = System.currentTimeMillis(); powerUpStartTime = System.currentTimeMillis();
} }
/**
* Powers down a yacht, returning its power multipliers back to 1
*/
public void powerDown() { public void powerDown() {
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
} }
public Long getPowerUpStartTime() { public Long getPowerUpStartTime() {
@@ -155,7 +129,7 @@ public class ServerYacht {
* @param amount the amount by which to adjust the boat heading. * @param amount the amount by which to adjust the boat heading.
*/ */
public void adjustHeading(Double amount) { public void adjustHeading(Double amount) {
Double newVal = heading + amount * powerUpHandlingMultiplier * boatTypeTurnStepMultiplier; Double newVal = heading + amount;
lastHeading = heading; lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L); heading = (double) Math.floorMod(newVal.longValue(), 360L);
} }
@@ -178,11 +152,11 @@ public class ServerYacht {
/** /**
* Enables the boats auto pilot feature, which will move the boat towards a given heading. * Enables the boats auto pilot feature, which will move the boat towards a given heading.
* *
* @param newHeading The heading to move the boat towards. * @param thisHeading The heading to move the boat towards.
*/ */
private void setAutoPilot(Double newHeading) { private void setAutoPilot(Double thisHeading) {
isAuto = true; isAuto = true;
autoHeading = newHeading; autoHeading = thisHeading;
} }
/** /**
@@ -200,9 +174,8 @@ public class ServerYacht {
if (isAuto) { if (isAuto) {
turnTowardsHeading(autoHeading); turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading) if (Math.abs(heading - autoHeading)
<= turnStep*1.5) { <= TURN_STEP) { //Cancel when within 1 turn step of target.
isAuto = false; isAuto = false;
setHeading(autoHeading);
} }
} }
} }
@@ -214,52 +187,44 @@ public class ServerYacht {
public void turnUpwind() { public void turnUpwind() {
disableAutoPilot(); disableAutoPilot();
Double normalizedHeading = normalizeHeading(); Double normalizedHeading = normalizeHeading();
if (continuouslyTurning) { if (normalizedHeading == 0) {
adjustHeading(turnStep); if (lastHeading < 180) {
} else { adjustHeading(-TURN_STEP);
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 { } else {
adjustHeading(turnStep); adjustHeading(TURN_STEP);
} }
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
}
} else if (normalizedHeading < 180) {
adjustHeading(-TURN_STEP);
} else {
adjustHeading(TURN_STEP);
} }
} }
public void turnDownwind() { public void turnDownwind() {
disableAutoPilot(); disableAutoPilot();
Double normalizedHeading = normalizeHeading(); Double normalizedHeading = normalizeHeading();
if (continuouslyTurning) { if (normalizedHeading == 0) {
adjustHeading(-turnStep); if (lastHeading < 180) {
} else { adjustHeading(TURN_STEP);
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 { } else {
adjustHeading(-turnStep); adjustHeading(-TURN_STEP);
} }
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(-TURN_STEP);
} else {
adjustHeading(TURN_STEP);
}
} else if (normalizedHeading < 180) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
} }
} }
@@ -288,7 +253,7 @@ public class ServerYacht {
// Take optimal heading and turn into a boat heading rather than a wind heading. // Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading = optimalHeading =
(optimalHeading + GameState.getWindDirection()) % 360; optimalHeading + GameState.getWindDirection();
setAutoPilot(optimalHeading); setAutoPilot(optimalHeading);
} }
@@ -303,9 +268,9 @@ public class ServerYacht {
private void turnTowardsHeading(Double newHeading) { private void turnTowardsHeading(Double newHeading) {
Double newVal = heading - newHeading; Double newVal = heading - newHeading;
if (Math.floorMod(newVal.longValue(), 360L) > 180) { if (Math.floorMod(newVal.longValue(), 360L) > 180) {
adjustHeading(turnStep / 5); adjustHeading(TURN_STEP / 5);
} else { } else {
adjustHeading(-turnStep / 5); adjustHeading(-TURN_STEP / 5);
} }
} }
@@ -456,43 +421,4 @@ public class ServerYacht {
return boatColor; return boatColor;
} }
public void setBoatType(BoatMeshType boatType) {
this.boatTypeAccelerationMultiplier = boatType.accelerationMultiplier;
this.boatTypeSpeedMultiplier = boatType.maxSpeedMultiplier;
this.boatTypeTurnStepMultiplier = boatType.turnStep;
this.boatType = boatType;
}
public Double getBoatTypeSpeedMultiplier() {
return boatTypeSpeedMultiplier;
}
public Double getBoatTypeAccelerationMultiplier() {
return boatTypeAccelerationMultiplier;
}
public BoatMeshType getBoatType() {
return boatType;
}
public void setContinuouslyTurning(Boolean continuouslyTurning) {
this.continuouslyTurning = continuouslyTurning;
}
public Double getPowerUpSpeedMultiplier() {
return powerUpSpeedMultiplier;
}
public void setPowerUpSpeedMultiplier(Double powerUpSpeedMultiplier) {
this.powerUpSpeedMultiplier = powerUpSpeedMultiplier;
}
public Integer getPowerUpHandlingMultiplier() {
return powerUpHandlingMultiplier;
}
public void setPowerUpHandlingMultiplier(Integer powerUpHandlingMultiplier) {
this.powerUpHandlingMultiplier = powerUpHandlingMultiplier;
}
} }
@@ -24,9 +24,8 @@ import java.util.*;
*/ */
public class MarkOrder { public class MarkOrder {
private List<CompoundMark> raceMarkOrder; private List<CompoundMark> raceMarkOrder;
private List<CompoundMark> orderedUniqueCompoundMarks;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class); private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
private List<Mark> allMarks; private Set<Mark> allMarks;
public MarkOrder(){ public MarkOrder(){
loadRaceProperties(); loadRaceProperties();
@@ -45,10 +44,6 @@ public class MarkOrder {
return Collections.unmodifiableList(raceMarkOrder); return Collections.unmodifiableList(raceMarkOrder);
} }
public List<CompoundMark> getOrderedUniqueCompoundMarks() {
return orderedUniqueCompoundMarks;
}
/** /**
* @param seqID The seqID of the current mark the boat is heading to * @param seqID The seqID of the current mark the boat is heading to
* @return A Boolean indicating if this coming mark is the last one (finish line) * @return A Boolean indicating if this coming mark is the last one (finish line)
@@ -80,8 +75,8 @@ public class MarkOrder {
return raceMarkOrder.get(currentSeqID + 1); return raceMarkOrder.get(currentSeqID + 1);
} }
public List<Mark> getAllMarks() { public Set<Mark> getAllMarks(){
return Collections.unmodifiableList(allMarks); return Collections.unmodifiableSet(allMarks);
} }
/** /**
@@ -94,7 +89,7 @@ public class MarkOrder {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db; DocumentBuilder db;
Document doc; Document doc;
allMarks = new ArrayList<>(); allMarks = new HashSet<>();
try { try {
db = dbf.newDocumentBuilder(); db = dbf.newDocumentBuilder();
@@ -110,7 +105,6 @@ public class MarkOrder {
logger.debug("Loaded RaceXML for mark order"); logger.debug("Loaded RaceXML for mark order");
List<Corner> corners = data.getMarkSequence(); List<Corner> corners = data.getMarkSequence();
Map<Integer, CompoundMark> marks = data.getCompoundMarks(); Map<Integer, CompoundMark> marks = data.getCompoundMarks();
orderedUniqueCompoundMarks = new ArrayList<>(marks.values());
List<CompoundMark> course = new ArrayList<>(); List<CompoundMark> course = new ArrayList<>();
for (Corner corner : corners){ for (Corner corner : corners){
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID()); CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
@@ -20,7 +20,9 @@ public enum PacketType {
RACE_REGISTRATION_REQUEST, RACE_REGISTRATION_REQUEST,
RACE_REGISTRATION_RESPONSE, RACE_REGISTRATION_RESPONSE,
RACE_CUSTOMIZATION_REQUEST, RACE_CUSTOMIZATION_REQUEST,
RACE_CUSTOMIZATION_RESPONSE; RACE_CUSTOMIZATION_RESPONSE,
SERVER_REGISTRATION, ROOM_CODE_REQUEST, LOBBY_REQUEST;
public static PacketType assignPacketType(int packetType, byte[] payload){ public static PacketType assignPacketType(int packetType, byte[] payload){
switch(packetType){ switch(packetType){
@@ -65,6 +67,10 @@ public enum PacketType {
return RACE_CUSTOMIZATION_REQUEST; return RACE_CUSTOMIZATION_REQUEST;
case 104: case 104:
return RACE_CUSTOMIZATION_RESPONSE; return RACE_CUSTOMIZATION_RESPONSE;
case 201:
return SERVER_REGISTRATION;
case 202:
return ROOM_CODE_REQUEST;
default: default:
} }
return OTHER; return OTHER;
+1 -19
View File
@@ -15,24 +15,11 @@ public class Token extends GeoPoint {
private TokenType tokenType; private TokenType tokenType;
private Random random = new Random(); private Random random = new Random();
//Constructor for creating a specific type client side
public Token(TokenType tokenType, double lat, double lng) { public Token(TokenType tokenType, double lat, double lng) {
super(lat, lng); super(lat, lng);
this.tokenType = tokenType; this.tokenType = tokenType;
} }
//Making random type server side
public Token(double lat, double lng) {
super(lat, lng);
assignRandomType();
}
//Making random type server side
public Token(GeoPoint geoPoint) {
super(geoPoint.getLat(), geoPoint.getLng());
assignRandomType();
}
public TokenType getTokenType() { public TokenType getTokenType() {
return tokenType; return tokenType;
} }
@@ -53,10 +40,5 @@ public class Token extends GeoPoint {
tokenType = tokenTypeList.get(random.nextInt(tokenTypeList.size())); tokenType = tokenTypeList.get(random.nextInt(tokenTypeList.size()));
} }
/**
* Exists for testing purposes only
*/
public void assignType(TokenType tokenType) {
this.tokenType = tokenType;
}
} }
@@ -1,63 +0,0 @@
package seng302.utilities;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.token.Token;
/**
* A class for generating and spawning tokens in random locations
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawn {
private static final Integer DEGREES_IN_CIRCLE = 360;
private HashMap<GeoPoint, Double> spawnRadii;
private Random random;
/**
* @param markOrder this must be the ORDERED list of marks. Better yet UNIQUE to avoid over
* computation
*/
public RandomSpawn(List<CompoundMark> markOrder) {
this.spawnRadii = new HashMap<>();
random = new Random();
spawnRadii = generateSpawnRadii(markOrder);
}
private HashMap<GeoPoint, Double> generateSpawnRadii(List<CompoundMark> markOrder) {
HashMap<GeoPoint, Double> spawnRadii = new HashMap<>();
for (int i = 0; i < markOrder.size() - 1; i++) {
GeoPoint spawnCentre = GeoUtility.getDirtyMidPoint(
markOrder.get(i).getMidPoint(),
markOrder.get(i + 1).getMidPoint());
Double distance = GeoUtility.getDistance(spawnCentre, markOrder.get(i).getMidPoint());
spawnRadii.put(spawnCentre, distance);
}
return spawnRadii;
}
/**
* @return A random token type at a random location in a random radii of the set of possible
* radii
*/
public Token getRandomTokenLocation() {
Object[] keys = spawnRadii.keySet().toArray();
GeoPoint randomSpawnCentre = (GeoPoint) keys[random.nextInt(keys.length)];
Double spawnRadius = spawnRadii.get(randomSpawnCentre);
Double randomDistance = spawnRadius * random.nextDouble();
Double randomAngle = random.nextDouble() * DEGREES_IN_CIRCLE;
GeoPoint randomLocation = GeoUtility
.getGeoCoordinate(randomSpawnCentre, randomAngle, randomDistance);
return new Token(randomLocation);
}
}
+7 -15
View File
@@ -14,10 +14,8 @@ public class Sounds {
private static MediaPlayer soundEffect; private static MediaPlayer soundEffect;
private static MediaPlayer soundPlayer; private static MediaPlayer soundPlayer;
private static MediaPlayer hoverSoundPlayer; private static MediaPlayer hoverSoundPlayer;
private static MediaPlayer crashSoundPlayer;
private static boolean hoverInitialized = false; private static boolean hoverInitialized = false;
private static boolean crashInitialized = false;
private static boolean musicMuted = false; private static boolean musicMuted = false;
private static boolean soundEffectsMuted = false; private static boolean soundEffectsMuted = false;
@@ -157,17 +155,11 @@ public class Sounds {
public static void playCrashSound() { public static void playCrashSound() {
if (!soundEffectsMuted) { if (!soundEffectsMuted) {
if (!crashInitialized) { Media crashSound = new Media(
Media pickupSound = new Media( Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3")
Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3") .toString());
.toString()); soundPlayer = new MediaPlayer(crashSound);
crashSoundPlayer = new MediaPlayer(pickupSound); soundPlayer.play();
crashInitialized = true;
}
if (crashSoundPlayer != null) {
crashSoundPlayer.stop();
}
crashSoundPlayer.play();
} }
} }
@@ -184,10 +176,10 @@ public class Sounds {
public static void playHoverSound() { public static void playHoverSound() {
if (!soundEffectsMuted) { if (!soundEffectsMuted) {
if (!hoverInitialized) { if (!hoverInitialized) {
Media hoverSound = new Media( Media crashSound = new Media(
Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3") Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3")
.toString()); .toString());
hoverSoundPlayer = new MediaPlayer(hoverSound); hoverSoundPlayer = new MediaPlayer(crashSound);
hoverInitialized = true; hoverInitialized = true;
} }
hoverSoundPlayer.setVolume(0.5); hoverSoundPlayer.setVolume(0.5);
+14 -30
View File
@@ -4,14 +4,12 @@ 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 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 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;
@@ -20,7 +18,6 @@ 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;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/** /**
* Utilities for parsing XML documents * Utilities for parsing XML documents
@@ -141,27 +138,17 @@ 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, XMLParser.getNodeAttributeString(currentBoat, "Type"),
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); yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color")));
competingBoats.put(yacht.getSourceId(), yacht); if (yacht.getBoatType().equals("Yacht")) {
competingBoats.put(yacht.getSourceId(), yacht);
}
} }
} }
return competingBoats; return competingBoats;
@@ -209,20 +196,17 @@ 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<>();
try { NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); for (int i = 0; i < tokenList.getLength(); i++) {
for (int i = 0; i < tokenList.getLength(); i++) { Node tokenNode = tokenList.item(i);
Node tokenNode = tokenList.item(i); if (tokenNode.getNodeName().equals("Token")) {
if (tokenNode.getNodeName().equals("Token")) { String tokenType = getNodeAttributeString(tokenNode, "TokenType");
String tokenType = getNodeAttributeString(tokenNode, "TokenType"); Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
}
} }
} catch (NullPointerException npe) {
return new ArrayList<>();
} }
return tokens; return tokens;
} }
@@ -175,7 +175,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, clientId); RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER);
try { try {
os.write(requestMessage.getBuffer()); os.write(requestMessage.getBuffer());
@@ -193,6 +193,7 @@ public class ClientToServerThread implements Runnable {
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, 3));
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)){
@@ -242,7 +243,7 @@ public class ClientToServerThread implements Runnable {
new TimerTask() { new TimerTask() {
@Override @Override
public void run() { public void run() {
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId)); sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND));
} }
}, 0, PACKET_SENDING_INTERVAL_MS }, 0, PACKET_SENDING_INTERVAL_MS
); );
@@ -255,14 +256,14 @@ public class ClientToServerThread implements Runnable {
new TimerTask() { new TimerTask() {
@Override @Override
public void run() { public void run() {
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId)); sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND));
} }
}, 0, PACKET_SENDING_INTERVAL_MS }, 0, PACKET_SENDING_INTERVAL_MS
); );
} }
break; break;
default: default:
sendBoatActionMessage(new BoatActionMessage(actionType, clientId)); sendBoatActionMessage(new BoatActionMessage(actionType));
break; break;
} }
} }
@@ -10,16 +10,15 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
@@ -29,8 +28,6 @@ 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;
@@ -48,7 +45,6 @@ import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController; import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
@@ -71,8 +67,6 @@ 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();
/** /**
@@ -82,7 +76,6 @@ public class GameClient {
*/ */
public GameClient(Pane holder) { public GameClient(Pane holder) {
this.holderPane = holder; this.holderPane = holder;
this.gameKeyBind = GameKeyBind.getInstance();
} }
/** /**
@@ -172,12 +165,10 @@ public class GameClient {
private void showConnectionError (String message) { private void showConnectionError (String message) {
Platform.runLater(() -> { Platform.runLater(() -> {
PopupDialogController controller = ViewManager.getInstance().showPopupDialog(); Alert alert = new Alert(AlertType.ERROR);
controller.setHeader("Oops"); alert.setHeaderText("Connection Error");
controller.setContent(message); alert.setContentText(message);
controller.setOptionButtonText("GO HOME"); alert.showAndWait();
controller
.setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView());
}); });
} }
@@ -378,16 +369,16 @@ public class GameClient {
} }
return; return;
} }
switch (e.getCode()) {
if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg case SPACE: // align with vmg
socketThread.sendBoatAction(BoatAction.VMG); socketThread.sendBoatAction(BoatAction.VMG); break;
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind case PAGE_UP: // upwind
socketThread.sendBoatAction(BoatAction.UPWIND); socketThread.sendBoatAction(BoatAction.UPWIND); break;
} else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind case PAGE_DOWN: // downwind
socketThread.sendBoatAction(BoatAction.DOWNWIND); socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
} else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe case ENTER: // 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); socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
} }
} }
@@ -396,17 +387,15 @@ public class GameClient {
if (raceView.isChatInputFocused()) { if (raceView.isChatInputFocused()) {
return; return;
} }
switch (e.getCode()) {
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) { case SHIFT: // sails in/sails out
socketThread.sendBoatAction(BoatAction.SAILS_OUT);
} else {
socketThread.sendBoatAction(BoatAction.SAILS_IN); socketThread.sendBoatAction(BoatAction.SAILS_IN);
} allBoatsMap.get(socketThread.getClientId()).toggleSail();
allBoatsMap.get(socketThread.getClientId()).toggleSail(); break;
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() case PAGE_UP:
|| gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { case PAGE_DOWN:
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
} }
} }
@@ -421,16 +410,9 @@ public class GameClient {
* @param yachtEventData The YachtEvent data packet * @param yachtEventData The YachtEvent data packet
*/ */
private void processYachtEvent(YachtEventData yachtEventData) { private void processYachtEvent(YachtEventData yachtEventData) {
ClientYacht thisYacht = allBoatsMap.get(yachtEventData.getSubjectId().intValue());
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) { if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(thisYacht); showCollisionAlert(yachtEventData);
} else if (yachtEventData.getEventId() == YachtEventType.POWER_DOWN.getCode()) { } else {
thisYacht.powerDown();
Sounds.playTokenPickupSound(); // TODO: 23/09/17 This should be power down sound
} else if (yachtEventData.getEventId() == YachtEventType.BUMPER_CRASH.getCode()) {
showDisableAlert(thisYacht);
} else { //Else all token pickup types
TokenType tokenType = null; TokenType tokenType = null;
if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) { if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) {
tokenType = TokenType.BOOST; tokenType = TokenType.BOOST;
@@ -444,36 +426,36 @@ public class GameClient {
tokenType = TokenType.WIND_WALKER; tokenType = TokenType.WIND_WALKER;
} }
Sounds.playTokenPickupSound(); showTokenPickUp(tokenType);
thisYacht.setPowerUp(tokenType); allBoatsMap.get(yachtEventData.getSubjectId().intValue()).setPowerUp(tokenType);
} }
} }
/**
* Turns a disabled boat black until the bumper affect wears off
*
* @param yacht The yacht to show as disabled
*/
private void showDisableAlert(ClientYacht yacht) {
Color originalColor = yacht.getColour();
yacht.setColour(Color.BLACK);
Timer disableTimer = new Timer("Disable Timer");
disableTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.setColour(originalColor);
}
}, GameState.BUMPER_DISABLE_TIME);
}
/** /**
* Tells race view to show a collision animation. * Tells race view to show a collision animation.
*/ */
private void showCollisionAlert(ClientYacht yacht) { private void showCollisionAlert(YachtEventData yachtEventData) {
Sounds.playCrashSound(); Sounds.playCrashSound();
raceState.storeCollision(yacht); raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
}
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
private void showTokenPickUp(TokenType tokenType) {
Sounds.playTokenPickupSound();
switch (tokenType) {
case BOOST:
break;
case HANDLING:
break;
case WIND_WALKER:
break;
case BUMPER:
break;
}
} }
private void formatAndSendChatMessage(String rawChat) { private void formatAndSendChatMessage(String rawChat) {
@@ -508,14 +490,4 @@ 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,7 +1,6 @@
package seng302.visualiser; package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -10,7 +9,6 @@ import javafx.animation.AnimationTimer;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
@@ -23,9 +21,7 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.GameKeyBind;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.KeyAction;
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;
@@ -51,19 +47,20 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class GameView3D { public class GameView3D {
private final double FOV = 60; private final double FOV = 60;
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 = 155;
private Group root3D; private Group root3D;
private SubScene view; private SubScene view;
// ParallelCamera camera;
private PerspectiveCamera camera;
private PerspectiveCamera camera2;
private PerspectiveCamera camera3;
private Group gameObjects; private Group gameObjects;
// Cameras
private PerspectiveCamera isometricCam;
private PerspectiveCamera topDownCam;
private PerspectiveCamera chaseCam;
private double bufferSize = 0; private double bufferSize = 0;
private double canvasWidth = 200; private double canvasWidth = 200;
private double canvasHeight = 200; private double canvasHeight = 200;
@@ -98,22 +95,28 @@ public class GameView3D {
} }
public GameView3D () { public GameView3D () {
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y); camera = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH);
topDownCam = new TopDownCamera(); camera.setFarClip(600);
chaseCam = new ChaseCamera(); camera.setNearClip(0.1);
camera.setFieldOfView(FOV);
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) { camera2 = new TopDownCamera();
pc.setFarClip(600); camera2.setFarClip(600);
pc.setNearClip(0.1); camera2.setNearClip(0.1);
pc.setFieldOfView(FOV); camera2.setFieldOfView(FOV);
}
camera3 = new ChaseCamera();
camera3.setFarClip(600);
camera3.setNearClip(0.1);
camera3.setFieldOfView(FOV);
gameObjects = new Group(); gameObjects = new Group();
root3D = new Group(isometricCam, gameObjects); root3D = new Group(camera, gameObjects);
view = new SubScene( view = new SubScene(
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
); );
view.setCamera(isometricCam); view.setCamera(camera);
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
gameObjects.getChildren().addAll( gameObjects.getChildren().addAll(
ModelFactory.importModel(ModelType.OCEAN).getAssets(), ModelFactory.importModel(ModelType.OCEAN).getAssets(),
@@ -348,6 +351,7 @@ public class GameView3D {
* it to distanceScaleFactor Returns the max horizontal distance of the map. * it to distanceScaleFactor Returns the max horizontal distance of the map.
*/ */
private double scaleRaceExtremities() { private double scaleRaceExtremities() {
double vertAngle = Math.abs( double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint) GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
); );
@@ -415,44 +419,48 @@ public class GameView3D {
} }
public void cameraMovement(KeyEvent event) { public void cameraMovement(KeyEvent event) {
GameKeyBind keyBinds = GameKeyBind.getInstance(); switch (event.getCode()) {
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode()); case NUMPAD8:
if (keyPressed != null) { view.getCamera().getTransforms().addAll(new Rotate(0.5, new Point3D(1, 0, 0)));
switch (keyPressed) { break;
case ZOOM_IN: case NUMPAD2:
((RaceCamera) view.getCamera()).zoomIn(); view.getCamera().getTransforms().addAll(new Rotate(-0.5, new Point3D(1, 0, 0)));
break; break;
case ZOOM_OUT: case NUMPAD4:
((RaceCamera) view.getCamera()).zoomOut(); view.getCamera().getTransforms().addAll(new Rotate(-0.5, new Point3D(0, 1, 0)));
break; break;
case FORWARD: case NUMPAD6:
((RaceCamera) view.getCamera()).panUp(); view.getCamera().getTransforms().addAll(new Rotate(0.5, new Point3D(0, 1, 0)));
break; break;
case BACKWARD: case Z:
((RaceCamera) view.getCamera()).panDown(); ((RaceCamera) view.getCamera()).zoomIn();
break; break;
case LEFT: case X:
((RaceCamera) view.getCamera()).panLeft(); ((RaceCamera) view.getCamera()).zoomOut();
break; break;
case RIGHT: case W:
((RaceCamera) view.getCamera()).panRight(); view.getCamera().getTransforms().addAll(new Translate(0, -1, 0));
break; break;
case VIEW: case S:
toggleCamera(); view.getCamera().getTransforms().addAll(new Translate(0, 1, 0));
break; break;
} case A:
} view.getCamera().getTransforms().addAll(new Translate(-1, 0, 0));
} break;
case D:
private void toggleCamera() { view.getCamera().getTransforms().addAll(new Translate(1, 0, 0));
Camera currCamera = view.getCamera(); break;
case F1:
if (currCamera.equals(isometricCam)) { if (view.getCamera().equals(camera)) {
view.setCamera(topDownCam); view.setCamera(camera2);
} else if (currCamera.equals(topDownCam)) { if (view.getCamera() instanceof TopDownCamera) {
view.setCamera(chaseCam); ((RaceCamera) view.getCamera()).zoomIn();
} else { }
view.setCamera(isometricCam); } else if (view.getCamera().equals(camera2)) {
view.setCamera(camera3);
} else {
view.setCamera(camera);
}
} }
} }
@@ -478,19 +486,21 @@ public class GameView3D {
final List<Group> wakes = new ArrayList<>(); final List<Group> wakes = new ArrayList<>();
for (ClientYacht clientYacht : yachts) { for (ClientYacht clientYacht : yachts) {
Color colour = clientYacht.getColour(); Color colour = clientYacht.getColour();
newBoat = new BoatObject(clientYacht.getBoatType()); newBoat = new BoatObject();
newBoat.setFill(colour); newBoat.setFill(colour);
boatObjects.put(clientYacht, newBoat); boatObjects.put(clientYacht, newBoat);
wakesGroup.getChildren().add(newBoat.getWake()); wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake()); wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
clientYacht.addLocationListener(this::updateBoatLocation); clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
clientYacht.addColorChangeListener(this::updateBoatColor); BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
});
if (clientYacht.getSourceId().equals( if (clientYacht.getSourceId().equals(
ViewManager.getInstance().getGameClient().getServerThread().getClientId())) { ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
((ChaseCamera) chaseCam).setPlayerBoat(newBoat); ((ChaseCamera) camera3).setPlayerBoat(newBoat);
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
} }
} }
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -503,23 +513,6 @@ public class GameView3D {
return view; return view;
} }
/**
* Updates the boatObjects color with that of the clientYachts object. Used in notification from
* a listener on this attribute in clientYacht to re paint the boat mesh
*
* @param clientYacht The yacht to update the colour for
*/
private void updateBoatColor(ClientYacht clientYacht) {
boatObjects.get(clientYacht).setFill(clientYacht.getColour());
}
private void updateBoatLocation(ClientYacht boat, Double lat, Double lon, Double heading,
Boolean sailIn, Double velocity) {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
}
/** /**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a * 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. * border already exists. Assumes the border is larger than the course.
@@ -627,7 +620,6 @@ public class GameView3D {
} }
public void setBoatAsPlayer (ClientYacht playerYacht) { public void setBoatAsPlayer (ClientYacht playerYacht) {
playerYacht.toggleSail();
playerBoatAnimationTimer = new AnimationTimer() { playerBoatAnimationTimer = new AnimationTimer() {
double count = 60; double count = 60;
@@ -6,11 +6,10 @@ import seng302.gameServer.ServerDescription;
import javax.jmdns.JmDNS; import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener; import javax.jmdns.ServiceListener;
import javax.jmdns.impl.JmDNSImpl;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.ArrayList; import java.util.*;
import java.util.HashSet;
import java.util.Set;
import static seng302.gameServer.ServerAdvertiser.getLocalHostIp; import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
@@ -18,6 +17,7 @@ import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
* Listens for servers on the local network * Listens for servers on the local network
*/ */
public class ServerListener{ public class ServerListener{
private static Integer SERVICE_REFRESH_INTERVAL = 5 * 1000;
private static ServerListener instance; private static ServerListener instance;
private ServerListenerDelegate delegate; private ServerListenerDelegate delegate;
private JmDNS jmdns = null; private JmDNS jmdns = null;
@@ -91,8 +91,16 @@ public class ServerListener{
private ServerListener() throws IOException { private ServerListener() throws IOException {
jmdns = JmDNS.create(InetAddress.getByName(getLocalHostIp())); jmdns = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
listener = new GameServeMonitor(); listener = new GameServeMonitor();
jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener); jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener);
/*new Timer().schedule(new TimerTask() {
@Override
public void run() {
refresh();
}
}, 50, SERVICE_REFRESH_INTERVAL);*/
} }
public static ServerListener getInstance() throws IOException { public static ServerListener getInstance() throws IOException {
@@ -110,4 +118,25 @@ public class ServerListener{
public void setDelegate(ServerListenerDelegate delegate){ public void setDelegate(ServerListenerDelegate delegate){
this.delegate = delegate; this.delegate = delegate;
} }
public void refresh(){
ArrayList<ServerDescription> servers = new ArrayList<>(listener.servers);
for (ServerDescription serverDescription : servers){
if (serverDescription.hasExpired()){
jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverDescription.getName());
}
else{
serverDescription.hasBeenRefreshed();
}
}
for (ServerDescription server : servers){
if (server.serverShouldBeRemoved()){
listener.servers.remove(server);
delegate.serverRemoved(new ArrayList<ServerDescription>(listener.servers));
}
}
}
} }
@@ -1,7 +1,7 @@
package seng302.visualiser.cameras; package seng302.visualiser.cameras;
import java.util.Arrays; import javafx.beans.value.ChangeListener;
import javafx.beans.property.DoubleProperty; import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
@@ -13,118 +13,77 @@ import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class ChaseCamera extends PerspectiveCamera implements RaceCamera { public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
private final Double VERTICAL_PAN_LIMIT = 20.0;
private final Double NEAR_ZOOM_LIMIT = -15.0;
private final Double FAR_ZOOM_LIMIT = -125.0;
private final Double ZOOM_STEP = 2.5;
private final Double PAN_STEP = 2.5;
private ObservableList<Transform> transforms; private ObservableList<Transform> transforms;
private BoatObject playerBoat; private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public ChaseCamera() { public ChaseCamera() {
super(true); super(true);
transforms = this.getTransforms(); transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
this.horizontalPan = 0.0;
this.verticalPan = 0.0;
} }
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) { public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat; this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays this.playerBoat.layoutXProperty().addListener(new ChangeListener<Number>() {
.asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(), @Override
playerBoat.layoutXProperty())) { public void changed(ObservableValue<? extends Number> observable, Number oldValue,
o.addListener((obs, oldVal, newVal) -> repositionCamera()); Number newValue) {
updateCameraX((Double) oldValue, (Double) newValue);
}
});
this.playerBoat.layoutYProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue,
Number newValue) {
updateCameraY((Double) oldValue, (Double) newValue);
}
});
}
private void updateCameraX(Double oldXValue, Double newXValue) {
if (transforms.size() == 0) { // boat is placed and then moved at start,
transforms.addAll(
new Translate(playerBoat.getLayoutX() - 30, playerBoat.getLayoutY() - 30, -125),
new Rotate(80, new Point3D(0, 0, 1))
);
} else {
transforms.addAll(new Translate(newXValue - oldXValue, 0, 0));
} }
} }
/** private void updateCameraY(Double oldYValue, Double newYValue) {
* Moves the camera to a new position after some change (Zooming or Panning) transforms.addAll(new Translate(0, (newYValue - oldYValue), 0));
*/
private void repositionCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), 0),
new Rotate(playerBoat.getRotationProperty().getValue() + horizontalPan,
new Point3D(0, 0, 1)),
new Rotate(60 + verticalPan, new Point3D(1, 0, 0)),
new Translate(0, 0, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
repositionCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -VERTICAL_PAN_LIMIT
&& verticalPan + adjustment <= VERTICAL_PAN_LIMIT) {
verticalPan += adjustment;
repositionCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
this.horizontalPan += adjustment;
repositionCamera();
} }
@Override @Override
public void zoomIn() { public void zoomIn() {
adjustZoomFactor(ZOOM_STEP); transforms.addAll(new Translate(0, 0, 1.5));
} }
@Override @Override
public void zoomOut() { public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP); transforms.addAll(new Translate(0, 0, -1.5));
} }
/*
These have been left intentionally empty for now. it would be cool to be able to pan around the boat and have the camera move around the boat though.
*/
@Override @Override
public void panLeft() { public void panLeft() {
adjustHorizontalPan(-PAN_STEP);
} }
@Override @Override
public void panRight() { public void panRight() {
adjustHorizontalPan(PAN_STEP);
} }
@Override @Override
public void panUp() { public void panUp() {
adjustVerticalPan(-PAN_STEP);
} }
@Override @Override
public void panDown() { public void panDown() {
adjustVerticalPan(PAN_STEP);
} }
} }
@@ -1,113 +1,47 @@
package seng302.visualiser.cameras; package seng302.visualiser.cameras;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform; import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
public class IsometricCamera extends PerspectiveCamera implements RaceCamera { public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
private final Double MIN_X = -120.0; ObservableList<Transform> transforms;
private final Double MAX_X = 125.0;
private final Double MIN_Y = 40.0; public IsometricCamera(Double cameraStartX, Double cameraStartY, Double cameraDepth) {
private final Double MAX_Y = 170.0;
private final Double PAN_LIMIT = 160.0;
private final Double NEAR_ZOOM_LIMIT = -50.0;
private final Double FAR_ZOOM_LIMIT = -160.0;
private Double horizontalPan;
private Double verticalPan;
private Double zoomFactor;
private ObservableList<Transform> transforms;
public IsometricCamera(Double cameraStartX, Double cameraStartY) {
super(true); super(true);
transforms = this.getTransforms(); transforms = this.getTransforms();
transforms.addAll(new Translate(cameraStartX, cameraStartY, cameraDepth));
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = cameraStartX;
verticalPan = cameraStartY;
updateCamera();
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(horizontalPan, verticalPan, zoomFactor),
new Rotate(30, new Point3D(1, 0, 0))
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
*
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= MIN_Y && verticalPan + adjustment <= MAX_Y) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= MIN_X && horizontalPan + adjustment <= MIN_Y) {
this.horizontalPan += adjustment;
updateCamera();
}
} }
@Override @Override
public void zoomIn() { public void zoomIn() {
adjustZoomFactor(-2.5); transforms.addAll(new Translate(0, 0, 1.5));
} }
@Override @Override
public void zoomOut() { public void zoomOut() {
adjustZoomFactor(2.5); transforms.addAll(new Translate(0, 0, -1.5));
} }
@Override @Override
public void panLeft() { public void panLeft() {
adjustHorizontalPan(-2.5); transforms.addAll(new Translate(-1, 0, 0));
} }
@Override @Override
public void panRight() { public void panRight() {
adjustHorizontalPan(2.5); transforms.addAll(new Translate(1, 0, 0));
} }
@Override @Override
public void panUp() { public void panUp() {
adjustVerticalPan(-2.5); transforms.addAll(new Translate(0, -1, 0));
} }
@Override @Override
public void panDown() { public void panDown() {
adjustVerticalPan(2.5); transforms.addAll(new Translate(0, 1, 0));
} }
} }
@@ -1,123 +1,48 @@
package seng302.visualiser.cameras; package seng302.visualiser.cameras;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Transform; import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class TopDownCamera extends PerspectiveCamera implements RaceCamera { public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
private final Double PAN_LIMIT = 30.0; ObservableList<Transform> transforms;
private final Double NEAR_ZOOM_LIMIT = -30.0;
private final Double FAR_ZOOM_LIMIT = -130.0;
private final Double ZOOM_STEP = 2.5;
private ObservableList<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public TopDownCamera() { public TopDownCamera() {
super(true); super(true);
transforms = this.getTransforms(); transforms = this.getTransforms();
transforms.add(new Translate(0, 0, -125));
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = 0.0;
verticalPan = 0.0;
}
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays
.asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
o.addListener((obs, oldVal, newVal) -> updateCamera());
}
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX() + horizontalPan,
playerBoat.getLayoutY() + verticalPan, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= -PAN_LIMIT && horizontalPan + adjustment <= PAN_LIMIT) {
horizontalPan += adjustment;
updateCamera();
}
} }
@Override @Override
public void zoomIn() { public void zoomIn() {
adjustZoomFactor(ZOOM_STEP); transforms.addAll(new Translate(0, 0, 1.5));
} }
@Override @Override
public void zoomOut() { public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP); transforms.addAll(new Translate(0, 0, -1.5));
} }
@Override @Override
public void panLeft() { public void panLeft() {
adjustHorizontalPan(-1.0); transforms.addAll(new Translate(-1, 0, 0));
} }
@Override @Override
public void panRight() { public void panRight() {
adjustHorizontalPan(1.0); transforms.addAll(new Translate(1, 0, 0));
} }
@Override @Override
public void panUp() { public void panUp() {
adjustVerticalPan(-1.0); transforms.addAll(new Translate(0, -1, 0));
} }
@Override @Override
public void panDown() { public void panDown() {
adjustVerticalPan(1.0); transforms.addAll(new Translate(0, 1, 0));
} }
} }
@@ -88,6 +88,7 @@ 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");
} }
@@ -22,6 +22,7 @@ import seng302.model.RaceState;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; 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.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView; import seng302.visualiser.GameView;
import seng302.visualiser.controllers.cells.PlayerCell; import seng302.visualiser.controllers.cells.PlayerCell;
@@ -29,11 +30,7 @@ import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.*;
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 {
@@ -86,21 +83,25 @@ public class LobbyController implements Initializable {
serverName.setText(ViewManager.getInstance().getProperty("serverName")); serverName.setText(ViewManager.getInstance().getProperty("serverName"));
mapName.setText(ViewManager.getInstance().getProperty("mapName")); mapName.setText(ViewManager.getInstance().getProperty("mapName"));
if (DiscoveryServerClient.getRoomCode() != null){
setRoomCode(DiscoveryServerClient.getRoomCode());
}
ViewManager.getInstance().getPlayerList().addListener((ListChangeListener<String>) c -> Platform.runLater(this::refreshPlayerList)); ViewManager.getInstance().getPlayerList().addListener((ListChangeListener<String>) c -> Platform.runLater(this::refreshPlayerList));
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());
@@ -130,8 +131,6 @@ public class LobbyController implements Initializable {
controller.setPlayerName(this.playerBoats controller.setPlayerName(this.playerBoats
.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
.getBoatName()); .getBoatName());
controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId())
.getBoatType().toString());
return customizationDialog; return customizationDialog;
} }
@@ -205,7 +204,7 @@ public class LobbyController implements Initializable {
FXMLLoader loader = new FXMLLoader( FXMLLoader loader = new FXMLLoader(
getClass().getResource("/views/cells/PlayerCell.fxml")); getClass().getResource("/views/cells/PlayerCell.fxml"));
loader.setController(new PlayerCell(playerId, yacht)); loader.setController(new PlayerCell(playerId, yacht.getBoatName(), yacht.getColour()));
try { try {
pane = loader.load(); pane = loader.load();
@@ -245,4 +244,8 @@ public class LobbyController implements Initializable {
public void closeCustomizationDialog() { public void closeCustomizationDialog() {
customizationDialog.close(); customizationDialog.close();
} }
public void setRoomCode(String roomCode) {
roomLabel.setText("Room#" + roomCode);
}
} }
@@ -48,14 +48,12 @@ import javafx.scene.shape.Polyline;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import javax.swing.ImageIcon;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.ClientYacht.PowerUpListener; import seng302.model.ClientYacht.PowerUpListener;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView3D; import seng302.visualiser.GameView3D;
@@ -97,7 +95,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML @FXML
private Label timerLabel; private Label timerLabel;
@FXML @FXML
private StackPane contentStackPane; private StackPane contentAnchorPane;
private GridPane contentGridPane; private GridPane contentGridPane;
@FXML @FXML
@@ -121,7 +119,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML @FXML
private Label positionLabel, boatSpeedLabel, boatHeadingLabel; private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML @FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon; private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon;
//Race Data //Race Data
private Map<Integer, ClientYacht> participants; private Map<Integer, ClientYacht> participants;
@@ -142,14 +140,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private JFXDialog finishScreenDialog; private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController; private FinishDialogController finishDialogController;
//Icon stuff
private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay;
public void initialize() { public void initialize() {
Sounds.stopMusic(); Sounds.stopMusic();
Sounds.playRaceMusic(); Sounds.playRaceMusic();
finishScreenDialog = createFinishDialog();
// Load a default important annotation state // Load a default important annotation state
//importantAnnotations = new ImportantAnnotationsState(); //importantAnnotations = new ImportantAnnotationsState();
@@ -194,10 +190,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> { // chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
// chatHistory.setScrollTop(Double.MAX_VALUE); // chatHistory.setScrollTop(Double.MAX_VALUE);
// }); // });
rvAnchorPane.setOnMouseClicked((event) ->
contentStackPane.setOnMouseClicked(event -> { rvAnchorPane.requestFocus()
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(new ChangeListener<Boolean>() {
@@ -215,27 +210,26 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) { public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
raceState.setRaceStarted(false); raceState.setRaceStarted(false);
createFinishDialog(finishedBoats); finishDialogController.setFinishedBoats(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"));
Platform.runLater(() -> { JFXDialog finishScreenDialog = null;
try {
finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(), try {
JFXDialog.DialogTransition.CENTER); finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(),
finishDialogController = dialog.getController(); JFXDialog.DialogTransition.CENTER);
finishDialogController.setFinishedBoats(finishedBoats); } catch (IOException e) {
finishScreenDialog.show(); e.printStackTrace();
} catch (IOException e) { }
e.printStackTrace();
} finishDialogController = dialog.getController();
});
return finishScreenDialog;
} }
@@ -259,13 +253,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
player.addPowerUpListener(this::displayPowerUpIcon); player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions()); updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D(); gameView = new GameView3D();
// gameView.setFrameRateFXText(fpsDisplay); // gameView.setFrameRateFXText(fpsDisplay);
Platform.runLater(() -> { Platform.runLater(() -> {
contentStackPane.getChildren().add(0, gameView.getAssets()); contentAnchorPane.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()
@@ -308,9 +301,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
*/ */
private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) { private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) {
if (yacht == player) { if (yacht == player) {
if (iconToDisplay != null) { final ImageView iconToDisplay;
iconToDisplay.setVisible(false);
}
switch (tokenType) { switch (tokenType) {
case BOOST: case BOOST:
@@ -325,9 +316,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
case BUMPER: case BUMPER:
iconToDisplay = bumperIcon; iconToDisplay = bumperIcon;
break; break;
case RANDOM:
iconToDisplay = badRandomIcon;
break;
default: default:
iconToDisplay = velocityIcon; iconToDisplay = velocityIcon;
} }
@@ -336,10 +324,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
iconToDisplay.setVisible(true); iconToDisplay.setVisible(true);
//Start blinking icon towards end //Start blinking icon towards end
if (blinkingTimer != null) { Timer blinkingTimer = new Timer();
blinkingTimer.cancel();
}
blinkingTimer = new Timer("Blinking Timer");
blinkingTimer.schedule(new TimerTask() { blinkingTimer.schedule(new TimerTask() {
Boolean isVisible = true; Boolean isVisible = true;
@@ -349,14 +334,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
iconToDisplay.setVisible(isVisible); iconToDisplay.setVisible(isVisible);
} }
}, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD); }, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD);
}
}
public void removeIcon(ClientYacht yacht) { //Turn icon off after the time out
if (yacht == player) { Timer switchOffTimer = new Timer();
blinkingTimer.cancel(); switchOffTimer.schedule(new TimerTask() {
iconToDisplay.setVisible(false); @Override
iconToDisplay = null; public void run() {
blinkingTimer.cancel();
iconToDisplay.setVisible(false);
}
}, tokenType.getTimeout());
} }
} }
@@ -887,7 +874,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();
contentStackPane.requestFocus(); rvAnchorPane.requestFocus();
return chat; return chat;
} }
@@ -7,7 +7,6 @@ import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@@ -16,6 +15,7 @@ import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
@@ -23,12 +23,14 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServer;
import seng302.gameServer.ServerDescription; import seng302.gameServer.ServerDescription;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.DiscoveryServerClient;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListener;
import seng302.visualiser.ServerListenerDelegate; import seng302.visualiser.ServerListenerDelegate;
import seng302.visualiser.controllers.cells.ServerCell; import seng302.visualiser.controllers.cells.ServerCell;
import seng302.visualiser.controllers.dialogs.ServerCreationController;
import seng302.visualiser.validators.HostNameFieldValidator; import seng302.visualiser.validators.HostNameFieldValidator;
import seng302.visualiser.validators.NumberRangeValidator; import seng302.visualiser.validators.NumberRangeValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -53,18 +55,14 @@ public class ServerListController implements Initializable, ServerListenerDelega
private JFXTextField serverHostName; private JFXTextField serverHostName;
@FXML @FXML
private JFXTextField serverPortNumber; private JFXTextField serverPortNumber;
@FXML
private JFXButton roomConnectButton;
@FXML
private JFXTextField roomNumber;
//---------FXML END---------// //---------FXML END---------//
private Label noServersFound; private Label noServersFound;
private Logger logger = LoggerFactory.getLogger(ServerListController.class); private Logger logger = LoggerFactory.getLogger(ServerListController.class);
private JFXDialog serverCreationDialog;
private List<ServerCreationDialogListener> serverCreationDialogListeners = new ArrayList<>();
@FunctionalInterface
public interface ServerCreationDialogListener {
void notifyClosure();
}
// TODO: 12/09/17 ajm412: break this method down, its way too long. // TODO: 12/09/17 ajm412: break this method down, its way too long.
@Override @Override
@@ -74,6 +72,17 @@ public class ServerListController implements Initializable, ServerListenerDelega
// Set Event Bindings // Set Event Bindings
connectButton.setOnMouseEntered(event -> Sounds.playHoverSound()); connectButton.setOnMouseEntered(event -> Sounds.playHoverSound());
serverListHostButton.setOnMouseEntered(event -> Sounds.playHoverSound()); serverListHostButton.setOnMouseEntered(event -> Sounds.playHoverSound());
roomConnectButton.setOnMouseReleased(event -> {
connectToRoomCode(roomNumber.getText());
Sounds.playButtonClick();
});
roomNumber.setOnKeyPressed(event -> {
if (event.getCode().equals(KeyCode.ENTER)) {
connectToRoomCode(roomNumber.getText());
}
});
connectButton.setOnMouseReleased(event -> { connectButton.setOnMouseReleased(event -> {
attemptToDirectConnect(); attemptToDirectConnect();
Sounds.playButtonClick(); Sounds.playButtonClick();
@@ -122,37 +131,22 @@ public class ServerListController implements Initializable, ServerListenerDelega
serverListVBox.getChildren().add(noServersFound); serverListVBox.getChildren().add(noServersFound);
// Set up dialog for server creation // Set up dialog for server creation
serverListHostButton.setOnAction(action -> {
showServerCreationDialog();
});
addServerCreationDialogListener(this::closeServerCreationDialog);
}
/**
* 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 {
serverCreationDialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
DialogTransition.CENTER); DialogTransition.CENTER);
ServerCreationController serverCreationController = dialogContent.getController(); serverListHostButton.setOnAction(action -> {
serverCreationController.setListener(serverCreationDialogListeners); dialog.show();
serverCreationDialog.show(); Sounds.playButtonClick();
Sounds.playButtonClick(); });
} catch (IOException e) { } catch (IOException e) {
logger.warn("Could not create Server Creation Dialog."); logger.warn("Could not create Server Creation Dialog.");
} }
}); });
} }
private void closeServerCreationDialog() {
serverCreationDialog.close();
}
/** /**
* Validates the connection and attempts to connect to a given hostname and port number. * Validates the connection and attempts to connect to a given hostname and port number.
*/ */
@@ -175,6 +169,24 @@ public class ServerListController implements Initializable, ServerListenerDelega
return hostNameValid && portNumberValid; return hostNameValid && portNumberValid;
} }
private void connectToRoomCode(String roomCode){
try {
ServerListing serverListing = new DiscoveryServerClient().getServerForRoomCode(roomCode);
ViewManager.getInstance().getGameClient().runAsClient(serverListing.getAddress(), serverListing.getPortNumber());
}
catch (java.net.ConnectException e){
//TODO Add proper dialog
logger.warn("Couldn't connect to discovery server");
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Couldn't connect to discovery server");
alert.setContentText("Couldn't connect to " + DiscoveryServer.DISCOVERY_SERVER);
alert.showAndWait();
}
catch (Exception e) {
logger.warn("Error discovering room code");
}
}
/** /**
* Connects the user to a lobby via the Direct Connect form. * Connects the user to a lobby via the Direct Connect form.
*/ */
@@ -221,14 +233,4 @@ public class ServerListController implements Initializable, ServerListenerDelega
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) { public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
Platform.runLater(() -> refreshServers(servers)); Platform.runLater(() -> refreshServers(servers));
} }
private void addServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.add(serverCreationDialogListener);
}
private void removeServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.remove(serverCreationDialogListener);
}
} }
@@ -2,9 +2,6 @@ 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;
@@ -18,7 +15,6 @@ 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;
@@ -27,8 +23,6 @@ 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;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
public class ViewManager { public class ViewManager {
@@ -38,9 +32,12 @@ 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<>();
@@ -122,31 +119,12 @@ 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);
@@ -156,13 +134,9 @@ 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()) {
@@ -171,12 +145,9 @@ 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)) {
@@ -186,85 +157,6 @@ public class ViewManager {
} }
}); });
jfxSnackbar = new JFXSnackbar(decorator);
}
/**
* Recursively find JFXDialog given a starting node. Will traverse children of StackPane.
*
* @param nodes children nodes to be check.
* @return true if node contains JFXDialog.
*/
private Boolean checkDialogOpened(ObservableList<Node> nodes) {
boolean foundJFXDialog = false;
for (Node node : nodes) {
if (node instanceof JFXDialog) {
return true;
} else if (node instanceof StackPane) {
foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren());
}
}
return foundJFXDialog;
}
private void showKeyBindingDialog() throws IOException {
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
"/views/dialogs/KeyBindingDialog.fxml"));
for (Node node : decorator.getChildren()) {
if (node instanceof StackPane) {
keyBindingDialog = new JFXDialog((StackPane) node,
dialogContent.load(),
DialogTransition.CENTER);
KeyBindingDialogController keyBindingDialogController = dialogContent
.getController();
keyBindingDialogController.setGameClient(this.gameClient);
keyBindingDialog.show();
decorator.requestFocus();
Sounds.playButtonClick();
}
}
}
public void closeKeyBindingDialog() {
keyBindingDialog.close();
}
public PopupDialogController showPopupDialog() {
FXMLLoader dialogContent = new FXMLLoader(
getClass().getResource("/views/dialogs/PopupDialog.fxml"));
for (Node node : decorator.getChildren()) {
if (node instanceof StackPane) {
try {
JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(),
DialogTransition.CENTER);
PopupDialogController popupDialogController = dialogContent.getController();
popupDialogController.setPopupDialog(dialog);
dialog.show();
return popupDialogController;
} catch (IOException e) {
logger.error("Cannot load Popup dialog");
}
}
}
return null;
}
/**
* Show a snackbar at the bottom of the app for 1 second.
*
* @param snackbarText text to be displayed.
*/
public void showSnackbar(String snackbarText, boolean isWarning) {
if (isWarning) {
decorator.getStylesheets()
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
} else {
if (decorator.getStylesheets().size() > 1) {
decorator.getStylesheets().remove(1);
}
}
jfxSnackbar.show(snackbarText, 1500);
} }
/** /**
@@ -329,7 +221,6 @@ 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.
*/ */
@@ -342,8 +233,9 @@ public class ViewManager {
logger.error("Could not load lobby view"); logger.error("Could not load lobby view");
} }
LobbyController lobbyController = loader.getController();
if (disableReadyButton) { if (disableReadyButton) {
LobbyController lobbyController = loader.getController();
lobbyController.disableReadyButton(); lobbyController.disableReadyButton();
} }
@@ -352,10 +244,8 @@ 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() {
FXMLLoader loader = loadFxml("/views/RaceView.fxml"); FXMLLoader loader = loadFxml("/views/RaceView.fxml");
// have to create a new stage and set the race view maximized as JFoenix decorator has // have to create a new stage and set the race view maximized as JFoenix decorator has
@@ -377,10 +267,17 @@ 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.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
stage.setOnCloseRequest(e -> closeAll()); stage.setOnCloseRequest(e -> closeAll());
stage.setScene(scene); stage.setScene(scene);
stage.show(); stage.show();
@@ -389,7 +286,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) {
@@ -399,9 +296,4 @@ public class ViewManager {
return loader.getController(); return loader.getController();
} }
public Stage getStage() {
return stage;
}
} }
@@ -6,7 +6,6 @@ import javafx.scene.control.Label;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import seng302.model.ClientYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatModel; import seng302.visualiser.fxObjects.assets_3D.BoatModel;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory; import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
@@ -25,13 +24,11 @@ public class PlayerCell {
private String name; private String name;
private Color boatColor; private Color boatColor;
private Integer playerId; private Integer playerId;
private BoatMeshType boatType;
public PlayerCell(Integer playerId, ClientYacht yacht) { public PlayerCell(Integer playerId, String playerName, Color color) {
this.playerId = playerId; this.playerId = playerId;
this.name = yacht.getBoatName(); this.name = playerName;
this.boatColor = yacht.getColour(); this.boatColor = color;
this.boatType = yacht.getBoatType();
} }
public void initialize() { public void initialize() {
@@ -40,7 +37,7 @@ public class PlayerCell {
// Add Rotating Boat to Player Cell with players color on it. // Add Rotating Boat to Player Cell with players color on it.
Group group = new Group(); Group group = new Group();
boatPane.getChildren().add(group); boatPane.getChildren().add(group);
BoatModel bo = ModelFactory.boatIconView(boatType, boatColor); BoatModel bo = ModelFactory.boatIconView(BoatMeshType.DINGHY, this.boatColor);
group.getChildren().add(bo.getAssets()); group.getChildren().add(bo.getAssets());
} }
@@ -6,25 +6,15 @@ 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.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.PointLight;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import seng302.gameServer.messages.CustomizeRequestType; import seng302.gameServer.messages.CustomizeRequestType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.ClientToServerThread; import seng302.visualiser.ClientToServerThread;
import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatModel;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.validators.FieldLengthValidator; import seng302.visualiser.validators.FieldLengthValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -34,35 +24,23 @@ public class BoatCustomizeController implements Initializable{
@FXML @FXML
private JFXColorPicker colorPicker; private JFXColorPicker colorPicker;
@FXML @FXML
private ProgressBar speedBar;
@FXML
private ProgressBar accelBar;
@FXML
private ProgressBar handleBar;
@FXML
private JFXButton submitBtn; private JFXButton submitBtn;
@FXML @FXML
private JFXTextField boatName; private JFXTextField boatName;
@FXML @FXML
private Pane boatPane; void colorChanged(ActionEvent event) {
@FXML Color color = colorPicker.getValue();
void colorChanged() {
refreshBoat();
} }
//---------FXML END---------// //---------FXML END---------//
private ClientToServerThread socketThread; private ClientToServerThread socketThread;
private LobbyController lobbyController; private LobbyController lobbyController;
private BoatMeshType currentBoat;
private Double maxSpeedMultiplier = 1.0;
private Double maxTurnRateMultiplier = 1.0;
private Double maxAccelerationMultiplier = 1.0;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
socketThread = ViewManager.getInstance().getGameClient().getServerThread(); socketThread = ViewManager.getInstance().getGameClient().getServerThread();
findMaxStats();
RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator(); RequiredFieldValidator playerNameReqValidator = new RequiredFieldValidator();
playerNameReqValidator.setMessage("Player name required."); playerNameReqValidator.setMessage("Player name required.");
@@ -70,8 +48,6 @@ public class BoatCustomizeController implements Initializable{
playerNameLengthValidator.setMessage("Player name too long."); playerNameLengthValidator.setMessage("Player name too long.");
boatName.setValidators(playerNameLengthValidator, playerNameReqValidator); boatName.setValidators(playerNameLengthValidator, playerNameReqValidator);
boatPane.setBackground(
new Background(new BackgroundFill(Color.SKYBLUE, CornerRadii.EMPTY, Insets.EMPTY)));
submitBtn.setOnMouseReleased(event -> { submitBtn.setOnMouseReleased(event -> {
Sounds.playButtonClick(); Sounds.playButtonClick();
@@ -102,10 +78,7 @@ public class BoatCustomizeController implements Initializable{
colorArray[2] = (byte) blue; colorArray[2] = (byte) blue;
socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray); socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray);
socketThread.sendCustomizationRequest(CustomizeRequestType.SHAPE, currentBoat.toString().getBytes());
lobbyController.closeCustomizationDialog(); lobbyController.closeCustomizationDialog();
} }
} }
@@ -120,61 +93,4 @@ public class BoatCustomizeController implements Initializable{
public void setParentController(LobbyController lobbyController){ public void setParentController(LobbyController lobbyController){
this.lobbyController = lobbyController; this.lobbyController = lobbyController;
} }
public void setCurrentBoat(String boatType) {
currentBoat = BoatMeshType.valueOf(boatType);
displayCurrentBoat();
refreshStatBars(currentBoat);
}
public void nextBoat() {
currentBoat = BoatMeshType.getNextBoatType(currentBoat);
displayCurrentBoat();
refreshStatBars(currentBoat);
}
public void prevBoat() {
currentBoat = BoatMeshType.getPrevBoatType(currentBoat);
displayCurrentBoat();
refreshStatBars(currentBoat);
}
private void displayCurrentBoat() {
boatPane.getChildren().clear();
Group group = new Group();
boatPane.getChildren().add(group);
BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue());
group.getChildren().add(bo.getAssets());
group.getChildren().add(new PointLight());
}
private void refreshBoat() {
boatPane.getChildren().clear();
Group group = new Group();
boatPane.getChildren().add(group);
BoatModel bo = ModelFactory.boatCustomiseView(currentBoat, colorPicker.getValue());
group.getChildren().add(bo.getAssets());
refreshStatBars(currentBoat);
}
private void findMaxStats() {
for (BoatMeshType bmt: BoatMeshType.values()) {
if (bmt.turnStep > maxTurnRateMultiplier) {
maxTurnRateMultiplier = bmt.turnStep;
}
if (bmt.maxSpeedMultiplier > maxSpeedMultiplier) {
maxSpeedMultiplier = bmt.maxSpeedMultiplier;
}
if (bmt.accelerationMultiplier > maxAccelerationMultiplier) {
maxAccelerationMultiplier = bmt.accelerationMultiplier;
}
}
}
private void refreshStatBars(BoatMeshType bo) {
speedBar.setProgress((bo.maxSpeedMultiplier) / maxSpeedMultiplier);
accelBar.setProgress(bo.accelerationMultiplier / maxAccelerationMultiplier);
handleBar.setProgress(bo.turnStep / maxTurnRateMultiplier);
}
} }
@@ -1,195 +0,0 @@
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
private JFXButton viewButton;
@FXML
private JFXButton rightButton;
@FXML
private JFXButton leftButton;
@FXML
private JFXButton forwardButton;
@FXML
private JFXButton backwardButton;
//---------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,
viewButton, rightButton, leftButton, forwardButton, backwardButton);
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();
showSnackBar("All keys reset!", false);
});
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
}
/**
* 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 < 12; 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;");
keyBindingDialogHeader.requestFocus();
}
/**
* 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,56 +0,0 @@
package seng302.visualiser.controllers.dialogs;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
public class PopupDialogController implements Initializable {
@FXML
private Label headerLabel;
@FXML
private Label contentLabel;
@FXML
private Label closeLabel;
@FXML
private JFXButton optionButton;
@FXML
private JFXDialog popupDialog;
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public void setContent(String content) {
this.contentLabel.setText(content);
}
public void setHeader(String header) {
this.headerLabel.setText(header);
}
public void setOptionButton(JFXButton jfxButton) {
this.optionButton = jfxButton;
}
public void setOptionButtonText(String text) {
this.optionButton.setText(text);
}
public void setOptionButtonEventHandler(EventHandler<? super MouseEvent> eventHandler) {
this.optionButton.setOnMouseClicked(eventHandler);
}
public void setPopupDialog(JFXDialog popupDialog) {
this.popupDialog = popupDialog;
this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close());
}
}
@@ -5,15 +5,14 @@ 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.List;
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 seng302.gameServer.ServerDescription; import seng302.gameServer.ServerDescription;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.controllers.ServerListController.ServerCreationDialogListener;
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;
@@ -29,12 +28,8 @@ public class ServerCreationController implements Initializable {
private Label maxPlayersLabel; private Label maxPlayersLabel;
@FXML @FXML
private JFXButton submitBtn; private JFXButton submitBtn;
@FXML
private Label closeLabel;
//---------FXML END---------// //---------FXML END---------//
private List<ServerCreationDialogListener> serverCreationDialogListeners;
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
updateMaxPlayerLabel(); updateMaxPlayerLabel();
maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> { maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
@@ -54,7 +49,6 @@ public class ServerCreationController implements Initializable {
validateServerSettings(); validateServerSettings();
}); });
closeLabel.setOnMouseClicked(event -> notifyListeners());
} }
/** /**
@@ -93,14 +87,4 @@ public class ServerCreationController implements Initializable {
Sounds.playHoverSound(); Sounds.playHoverSound();
} }
public void setListener(List<ServerCreationDialogListener> serverCreationDialogListeners) {
this.serverCreationDialogListeners = serverCreationDialogListeners;
}
public void notifyListeners() {
for (ServerCreationDialogListener serverCreationDialogListener : serverCreationDialogListeners) {
serverCreationDialogListener.notifyClosure();
}
}
} }
@@ -2,59 +2,21 @@ package seng302.visualiser.fxObjects.assets_3D;
/** /**
* Enum for boat meshes. Enum values should be of the form : * Enum for boat meshes. Enum values should be of the form :
* ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y offset of sail CoR from origin, jib file, fixed sail) * ENUM_VALUE (hull file, mast file, Y offset of mast CoR from origin, sail file, Y offset of sail CoR from origin)
* Files must be valid .stl files. * Files must be valid .stl files.
*/ */
public enum BoatMeshType { public enum BoatMeshType {
DINGHY("dinghy_hull.stl", "dinghy_mast.stl", 1.36653, "dinghy_sail.stl", 1.36653, null, false, 1.8, 1.0, 1.0), DINGHY ("dinghy_hull.stl", "dinghy_mast.stl", -1.36653, "dinghy_sail.stl", -1.36653);
CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl",
0.997, null, false, 1.0, 1.4, 2.0),
PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl",
-0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2);
final String hullFile, mastFile, sailFile, jibFile; final String hullFile, mastFile, sailFile;
final double mastOffset, sailOffset; final double mastOffset, sailOffset;
public final double maxSpeedMultiplier;
public final double accelerationMultiplier;
public final double turnStep;
final boolean fixedSail;
final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP};
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile, double sailOffset) {
double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) {
this.hullFile = hullFile; this.hullFile = hullFile;
this.mastFile = mastFile; this.mastFile = mastFile;
this.mastOffset = mastOffset; this.mastOffset = mastOffset;
this.sailFile = sailFile; this.sailFile = sailFile;
this.sailOffset = sailOffset; this.sailOffset = sailOffset;
this.jibFile = jibFile;
this.fixedSail = fixedSail;
this.maxSpeedMultiplier = maxSpeedMultiplier;
this.accelerationMultiplier = accelerationMultiplier;
this.turnStep = turnStep;
}
public static BoatMeshType getNextBoatType(BoatMeshType boatType) {
for (int i = 0; i < boatTypes.length; i++) {
if (i == boatTypes.length -1) {
return boatTypes[0];
} else if (boatType == boatTypes[i]) {
return boatTypes[i+1];
}
}
return boatType;
}
public static BoatMeshType getPrevBoatType(BoatMeshType boatType) {
for (int i = 0; i < boatTypes.length; i++) {
if (i == 0 && boatType == boatTypes[i]) {
return boatTypes[boatTypes.length -1];
} else if (boatType == boatTypes[i]) {
return boatTypes[i-1];
}
}
return boatType;
} }
} }
@@ -34,16 +34,14 @@ public class BoatModel extends Model {
* @param degrees The rotation of the sail in degrees * @param degrees The rotation of the sail in degrees
*/ */
public void rotateSail(double degrees) { public void rotateSail(double degrees) {
if (!meshType.fixedSail) { MeshView mast = getMeshViewChild(MAST_INDEX);
MeshView mast = getMeshViewChild(MAST_INDEX); MeshView sail = getMeshViewChild(SAIL_INDEX);
MeshView sail = getMeshViewChild(SAIL_INDEX); mast.getTransforms().setAll(
mast.getTransforms().setAll( new Rotate(degrees, -meshType.mastOffset, 0,0, new Point3D(0, 0, 1))
new Rotate(degrees, 0, -meshType.mastOffset, 0, new Point3D(0, 0, 1)) );
); sail.getTransforms().setAll(
sail.getTransforms().setAll( new Rotate(degrees, -meshType.sailOffset, 0,0, new Point3D(0, 0, 1))
new Rotate(degrees, 0, -meshType.sailOffset,0, new Point3D(0, 0, 1)) );
);
}
} }
public void hideSail() { public void hideSail() {
@@ -71,8 +69,4 @@ public class BoatModel extends Model {
private MeshView getMeshViewChild(int index) { private MeshView getMeshViewChild(int index) {
return (MeshView) assets.getChildren().get(index); return (MeshView) assets.getChildren().get(index);
} }
public BoatMeshType getMeshType() {
return meshType;
}
} }
@@ -3,7 +3,6 @@ package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -12,7 +11,7 @@ import javafx.scene.transform.Rotate;
/** /**
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
* dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path, * dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path,
* a wake object and two text labels to annotate the boat teams name and the boatTypes velocity. The * a wake object and two text labels to annotate the boat teams name and the boats velocity. The
* boat will update it's position onscreen everytime UpdatePosition is called unless the window is * boat will update it's position onscreen everytime UpdatePosition is called unless the window is
* minimized in which case it attempts to store animations and apply them when the window is * minimized in which case it attempts to store animations and apply them when the window is
* maximised. * maximised.
@@ -29,18 +28,15 @@ public class BoatObject extends Group {
private Group wake; private Group wake;
private Color colour = Color.BLACK; private Color colour = Color.BLACK;
private Boolean isSelected = false; private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private Rotate rotation = new Rotate(0,0,1);
private ReadOnlyDoubleWrapper rotationProperty;
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>(); private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
*/ */
public BoatObject(BoatMeshType boatMeshType) { public BoatObject() {
rotationProperty = new ReadOnlyDoubleWrapper(0.0); boatAssets = ModelFactory.boatGameView(BoatMeshType.DINGHY, colour);
boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
boatAssets.hideSail(); boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll( boatAssets.getAssets().getTransforms().addAll(
rotation rotation
@@ -70,6 +66,8 @@ public class BoatObject extends Group {
* @param windDir . * @param windDir .
*/ */
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) { public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
Double dx = Math.abs(boatAssets.getAssets().getLayoutX() - x);
Double dy = Math.abs(boatAssets.getAssets().getLayoutY() - y);
Platform.runLater(() -> { Platform.runLater(() -> {
rotateTo(rotation, sailIn, windDir); rotateTo(rotation, sailIn, windDir);
this.layoutXProperty().setValue(x); this.layoutXProperty().setValue(x);
@@ -87,7 +85,6 @@ public class BoatObject extends Group {
private void rotateTo(double heading, boolean sailsIn, double windDir) { private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotationProperty.set(heading);
rotation.setAngle(heading); rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1))); wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) { if (sailsIn) {
@@ -135,8 +132,4 @@ public class BoatObject extends Group {
public void addSelectedBoatListener(SelectedBoatListener sbl) { public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl); selectedBoatListenerListeners.add(sbl);
} }
public ReadOnlyDoubleWrapper getRotationProperty() {
return rotationProperty;
}
} }
@@ -7,7 +7,6 @@ import javafx.geometry.Point3D;
import javafx.scene.AmbientLight; import javafx.scene.AmbientLight;
import javafx.scene.CacheHint; import javafx.scene.CacheHint;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.PointLight;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial; import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
@@ -19,7 +18,7 @@ import javafx.scene.transform.Translate;
/** /**
* Factory class for creating 3D models of boatTypes. * Factory class for creating 3D models of boats.
*/ */
public class ModelFactory { public class ModelFactory {
@@ -52,35 +51,6 @@ public class ModelFactory {
return bo; return bo;
} }
public static BoatModel boatCustomiseView(BoatMeshType boatType, Color primaryColour) {
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
final Rotate animationRotate = new Rotate(0, new Point3D(0,0,1));
boatAssets.getTransforms().addAll(
new Scale(8.0, 8.0, 8.0),
new Rotate(-70, new Point3D(1,0,0)),
new Translate(16,50, 1),
animationRotate
);
boatAssets.getTransforms().add(animationRotate);
BoatModel bo = new BoatModel(boatAssets, null, boatType);
bo.rotateSail(45);
bo.setAnimation(new AnimationTimer() {
double boatAngle = 0;
Rotate rotate = animationRotate;
@Override
public void handle(long now) {
boatAngle += 0.5;
rotate.setAngle(boatAngle);
}
});
boatAssets.getChildren().addAll(
new AmbientLight()
);
return bo;
}
public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) { public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) {
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour); Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
boatAssets.getTransforms().addAll( boatAssets.getTransforms().addAll(
@@ -114,29 +84,20 @@ public class ModelFactory {
} }
private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) { private static Group getUnmodifiedBoatModel(BoatMeshType boatType, Color primaryColour) {
Group boatAssets = new Group(); Group boatAssets = new Group();
MeshView hull = importSTL(boatType.hullFile); MeshView hull = importFile(boatType.hullFile);
hull.setMaterial(new PhongMaterial(primaryColour)); hull.setMaterial(new PhongMaterial(primaryColour));
MeshView mast = importSTL(boatType.mastFile); MeshView mast = importFile(boatType.mastFile);
mast.setMaterial(new PhongMaterial(primaryColour)); mast.setMaterial(new PhongMaterial(primaryColour));
MeshView sail = importSTL(boatType.sailFile); MeshView sail = importFile(boatType.sailFile);
sail.setMaterial(new PhongMaterial(Color.WHITE)); sail.setMaterial(new PhongMaterial(Color.WHITE));
boatAssets.getChildren().addAll(hull, mast, sail);
if (boatType.jibFile != null) {
MeshView jib = importSTL(boatType.jibFile);
sail.setMaterial(new PhongMaterial(Color.WHITE));
boatAssets.getChildren().addAll(hull, mast, sail, jib);
} else {
boatAssets.getChildren().addAll(hull, mast, sail);
}
return boatAssets; return boatAssets;
} }
private static MeshView importSTL(String fileName) { private static MeshView importFile(String fileName) {
StlMeshImporter importer = new StlMeshImporter(); StlMeshImporter importer = new StlMeshImporter();
importer.read(ModelFactory.class.getResource("/meshes/boatSTLs/" + fileName)); importer.read(ModelFactory.class.getResource("/meshes/" + fileName));
MeshView importedFile = new MeshView(importer.getImport()); MeshView importedFile = new MeshView(importer.getImport());
importedFile.setCache(true); importedFile.setCache(true);
importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE); importedFile.setCacheHint(CacheHint.SCALE_AND_ROTATE);
@@ -0,0 +1,108 @@
package seng302.visualiser;
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.MeshView;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
/**
* Created by cir27 on 7/09/17.
*/
public class test3d extends Application {
Group root = new Group();
Scene scene;
@Override
public void start(Stage primaryStage) throws Exception {
// camera = new PerspectiveCamera();
// gameObjects = new Group();
// root3D = new Group(camera, gameObjects);
scene = new Scene(
root, 1000, 1000, true, SceneAntialiasing.BALANCED
);
gameView3DTest();
primaryStage.setScene(scene);
primaryStage.show();
// scene.setCamera(camera);
// primaryStage.setScene(scene);
// primaryStage.show();
//
// StlMeshImporter importer = new StlMeshImporter();
// importer.read(test3d.class.getResource("/meshes/dinghy_hull.stl").toString());
// MeshView boat = new MeshView(importer.getImport());
// boat.setMaterial(new PhongMaterial(Color.GREENYELLOW));
//
// importer = new StlMeshImporter();
// importer.read(getClass().getResource("/meshes/dinghy_mast.stl").toString());
// MeshView mast = new MeshView(importer.getImport());
// mast.setMaterial(new PhongMaterial(Color.GREENYELLOW));
//
// importer = new StlMeshImporter();
// importer.read(getClass().getResource("/meshes/dinghy_sail.stl").toString());
// MeshView sail = new MeshView(importer.getImport());
// sail.setMaterial(new PhongMaterial(Color.LIGHTGREY));
//
// gameObjects.getChildren().addAll(boat, mast, sail);
//
// gameObjects.getTransforms().add(new Scale(25, 25,25));
// gameObjects.getTransforms().add(new Translate(15, 20,0));
// gameObjects.getTransforms().addAll(
// new Rotate(90, new Point3D(0,0,1)),
// new Rotate(90, new Point3D(0, 1, 0))
// );
//
//// PointLight light = new PointLight();
//// light.setLightOn(true);
//// light.getTransforms().add(new Translate(15, 20, 0));
////
//// PointLight light2 = new PointLight();
//// light2.setLightOn(true);
//// light2.getTransforms().add(new Translate(30, 40, 0));
//
//// root3D.getChildren().addAll(light);
//
// scene.setOnKeyPressed(event -> {
// switch (event.getCode()) {
// case UP:
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,0,1)));
// break;
// case DOWN:
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,0,1)));
// break;
// case LEFT:
// gameObjects.getTransforms().add(new Rotate(-5, new Point3D(0,1,0)));
// break;
// case RIGHT:
// gameObjects.getTransforms().add(new Rotate(5, new Point3D(0,1,0)));
// break;
// }
// });
//
// AnimationTimer animationTimer = new AnimationTimer() {
// @Override
// public void handle(long now) {
// sail.getTransforms().add(new Rotate(0.5, 0, -1.36653, 0, new Point3D(0, 0, 1)));
// }
// };
//
//// animationTimer.start();
}
private void gameView3DTest() {
GameView3D gameView3D = new GameView3D();
root.getChildren().add(gameView3D.getAssets());
}
}
-22
View File
@@ -44,18 +44,8 @@
-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 ***********/
.scroll-pane {
-fx-focus-traversable: false;
-fx-border-style: none;
}
/* The main scrollbar **track** CSS class */ /* The main scrollbar **track** CSS class */
.scroll-bar:horizontal .track, .scroll-bar:horizontal .track,
.scroll-bar:vertical .track { .scroll-bar:vertical .track {
@@ -110,15 +100,3 @@
.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;
}
-1
View File
@@ -48,7 +48,6 @@ 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 {
+6 -6
View File
@@ -38,30 +38,30 @@
-fx-font-size: 23px; -fx-font-size: 23px;
} }
#connectButton { #connectButton, #roomConnectButton {
-fx-background-color: -fx-pp-light-text-color; /* inverted */ -fx-background-color: -fx-pp-light-text-color; /* inverted */
-fx-text-fill: -fx-pp-theme-color; /* inverted */ -fx-text-fill: -fx-pp-theme-color; /* inverted */
-fx-font-size: 20px; -fx-font-size: 20px;
-fx-pref-height: 65px; -fx-pref-height: 45px;
} }
#connectButton:hover { #connectButton:hover, #roomConnectButton:hover {
-fx-font-size: 23px; -fx-font-size: 23px;
} }
#connectLabel, #serverPortNumber, #serverHostName { #connectLabel, #connectLabel1, #serverPortNumber, #roomNumber, #serverHostName {
-fx-text-fill: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-light-text-color;
-fx-font-size: 18px; -fx-font-size: 18px;
} }
#serverHostName, #serverPortNumber { #serverHostName, #serverPortNumber, #roomNumber {
-jfx-focus-color: -fx-pp-light-text-color; -jfx-focus-color: -fx-pp-light-text-color;
-jfx-unfocus-color: -fx-pp-light-text-color; -jfx-unfocus-color: -fx-pp-light-text-color;
-fx-prompt-text-fill: -fx-pp-light-text-color; -fx-prompt-text-fill: -fx-pp-light-text-color;
} }
#serverHostName .error-label, #serverPortNumber .error-label { #serverHostName .error-label, #serverPortNumber .error-label, #roomNumber .error-label {
-fx-font-size: 12px; -fx-font-size: 12px;
-fx-text-fill: lightblue; -fx-text-fill: lightblue;
} }
@@ -2,7 +2,6 @@
-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 {
@@ -1,59 +0,0 @@
#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: red;
-fx-font-size: 33px;
}
.sectionLabel {
-fx-text-fill: -fx-pp-dark-text-color;
-fx-font-size: 20px;
}
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;
}
-33
View File
@@ -1,33 +0,0 @@
#headerLabel {
-fx-font-size: 20px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-font-size: 24px;
-fx-text-fill: red;
}
#contentLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#optionButton {
-fx-background-color: -fx-pp-theme-color;
-fx-text-fill: -fx-pp-light-text-color;
-fx-font-size: 18px;
-fx-effect: -fx-pp-dropshadow-light;
-fx-max-height: 55;
-fx-focus-traversable: false;
}
#optionButton:hover {
-fx-font-size: 20px !important;
-fx-background-color: -fx-pp-light-theme-color;
}
@@ -45,13 +45,3 @@
.maxPlayers { .maxPlayers {
-fx-font-size: 13px; -fx-font-size: 13px;
} }
#closeLabel {
-fx-font-size: 30;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-text-fill: red;
-fx-font-size: 33px;
}
@@ -1,4 +0,0 @@
/* a separate file to dynamically change snackbar's color */
.jfx-snackbar-toast {
-fx-text-fill: red !important;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -7
View File
@@ -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-26T19:13:35</created> <created>2017-09-19T15:45:46</created>
<modified>2017-09-26T19:13:35</modified> <modified>2017-09-19T15:45:46</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>
@@ -23,10 +23,10 @@
<color sid="ambient">0 0 0 1</color> <color sid="ambient">0 0 0 1</color>
</ambient> </ambient>
<diffuse> <diffuse>
<color sid="diffuse">0.01630632 0.52949 0.0134405 1</color> <color sid="diffuse">0.004555753 0.0885511 0.003947978 1</color>
</diffuse> </diffuse>
<specular> <specular>
<color sid="specular">0.125 0.125 0.125 1</color> <color sid="specular">0.25 0.25 0.25 1</color>
</specular> </specular>
<shininess> <shininess>
<float sid="shininess">50</float> <float sid="shininess">50</float>
@@ -49,10 +49,10 @@
<color sid="ambient">0 0 0 1</color> <color sid="ambient">0 0 0 1</color>
</ambient> </ambient>
<diffuse> <diffuse>
<color sid="diffuse">0.64 0.5334254 0 1</color> <color sid="diffuse">0.64 0.1458963 0.001825521 1</color>
</diffuse> </diffuse>
<specular> <specular>
<color sid="specular">0.125 0.125 0.125 1</color> <color sid="specular">0.25 0.25 0.25 1</color>
</specular> </specular>
<shininess> <shininess>
<float sid="shininess">50</float> <float sid="shininess">50</float>
@@ -87,7 +87,7 @@
</technique_common> </technique_common>
</source> </source>
<source id="Icosphere_001-mesh-normals"> <source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284252 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616992 0.7240421 0.1947362 0.6616954 0.4911194 0.356821 0.7946576 0.4089462 0.6284253 0.6616984 -0.1875943 0.5773454 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875943 -0.5773454 0.7946577 0.03853034 -0.7487788 0.6616992 0.4911193 -0.356821 0.7946577 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875943 0.5773454 -0.7946577 -0.0385304 0.7487789 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911193 0.356821 -0.7946577 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911194 -0.356821 -0.7946576 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487789 -0.6616991 0.1875943 -0.5773454 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150898 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150899 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array> <float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616991 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.1875942 0.5773453 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common> <technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3"> <accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/> <param name="X" type="float"/>
@@ -12,7 +12,7 @@
</BoatShapes> </BoatShapes>
<Boats> <Boats>
<#list boats as boat> <#list boats as boat>
<Boat Type="${boat.boatType}" SourceID="${boat.sourceId}" ShapeID="4" HullNum="${boat.hullID}" StoweName="${boat.shortName}" ShortName="${boat.shortName}" <Boat Type="Yacht" SourceID="${boat.sourceId}" ShapeID="4" HullNum="${boat.hullID}" StoweName="${boat.shortName}" ShortName="${boat.shortName}"
BoatName="${boat.boatName}" Country="${boat.country}" Color="${boat.boatColor}"> BoatName="${boat.boatName}" Country="${boat.country}" Color="${boat.boatColor}">
<GPSposition Z="0" Y="3.7" X="0" /> <GPSposition Z="0" Y="3.7" X="0" />
<MastTop Z="0" Y="6.2" X="0" /> <MastTop Z="0" Y="6.2" X="0" />
+11 -2
View File
@@ -52,10 +52,19 @@
<Insets left="35.0" top="-15.0" /> <Insets left="35.0" top="-15.0" />
</padding> </padding>
</Label> </Label>
<Label fx:id="roomLabel" text="Room: 2145" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<font>
<Font size="31.0" />
</font>
<GridPane.margin>
<Insets right="20.0" top="10.0" />
</GridPane.margin>
</Label>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="732.0" minWidth="10.0" prefWidth="507.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="10000.0" minWidth="10.0" prefWidth="155.0" />
<ColumnConstraints halignment="RIGHT" hgrow="NEVER" maxWidth="445.0" minWidth="10.0" prefWidth="238.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="50.0" prefHeight="74.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="1.7976931348623157E308" minHeight="50.0" prefHeight="74.0" vgrow="SOMETIMES" />
+278 -269
View File
@@ -16,6 +16,7 @@
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?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.Pane?>
@@ -23,277 +24,285 @@
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308" <AnchorPane fx:id="rvAnchorPane" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8.0.111" prefWidth="1200.0" style="-fx-background-color: lightblue;" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.RaceViewController"> fx:controller="seng302.visualiser.controllers.RaceViewController">
<children> <children>
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" <StackPane fx:id="contentAnchorPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="800.0" prefWidth="1200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
prefHeight="800.0" prefWidth="1200.0"> <children>
<columnConstraints> <GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0" prefHeight="800.0" prefWidth="1200.0">
prefWidth="250.0"/> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0"
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0" prefWidth="250.0"/>
prefWidth="400.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints> <ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0"
<rowConstraints> prefWidth="400.0"/>
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0" </columnConstraints>
vgrow="SOMETIMES"/> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/> <RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0"
<RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0" vgrow="SOMETIMES"/>
valignment="BOTTOM" vgrow="SOMETIMES"/> <RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
</rowConstraints> <RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0"
<children> valignment="BOTTOM" vgrow="SOMETIMES"/>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer"> </rowConstraints>
<columnConstraints> <children>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0" <GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0"
prefWidth="50.0"/> styleClass="timer">
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0" <columnConstraints>
prefWidth="135.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
</columnConstraints> prefWidth="50.0"/>
<rowConstraints> <ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0"
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> minWidth="135.0" prefWidth="135.0"/>
</rowConstraints> </columnConstraints>
<opaqueInsets> <rowConstraints>
<Insets/> <RowConstraints minHeight="10.0" prefHeight="30.0"
</opaqueInsets> vgrow="SOMETIMES"/>
<GridPane.margin> </rowConstraints>
<Insets left="10.0" right="200.0" top="10.0"/> <opaqueInsets>
</GridPane.margin> <Insets/>
<children> </opaqueInsets>
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true" <GridPane.margin>
preserveRatio="true" GridPane.halignment="CENTER" <Insets left="10.0" right="200.0" top="10.0"/>
GridPane.valignment="CENTER"> </GridPane.margin>
<image> <children>
<Image url="@../images/timer.png"/> <ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true"
</image> preserveRatio="true" GridPane.halignment="CENTER"
<GridPane.margin> GridPane.valignment="CENTER">
<Insets/> <image>
</GridPane.margin> <Image url="@../images/timer.png"/>
</ImageView> </image>
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1" <GridPane.margin>
GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <Insets/>
<font> </GridPane.margin>
<Font size="21.0"/> </ImageView>
</font> <Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1"
<GridPane.margin> GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<Insets/> <font>
</GridPane.margin> <Font size="21.0"/>
</Label> </font>
</children> <GridPane.margin>
</GridPane> <Insets/>
<GridPane GridPane.columnIndex="2"> </GridPane.margin>
<columnConstraints> </Label>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </children>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </GridPane>
</columnConstraints> <GridPane GridPane.columnIndex="2">
<rowConstraints> <columnConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
</rowConstraints> prefWidth="100.0"/>
</GridPane> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2"> prefWidth="100.0"/>
<columnConstraints> </columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0" <rowConstraints>
prefWidth="390.0"/> <RowConstraints minHeight="10.0" prefHeight="30.0"
</columnConstraints> vgrow="SOMETIMES"/>
<rowConstraints> </rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/> </GridPane>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" <GridPane fx:id="chatGridPane" GridPane.columnIndex="2"
vgrow="SOMETIMES"/> GridPane.rowIndex="2">
</rowConstraints> <columnConstraints>
<children> <ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0"
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0" minWidth="390.0" prefWidth="390.0"/>
GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM" </columnConstraints>
GridPane.vgrow="ALWAYS"> <rowConstraints>
<GridPane.margin> <RowConstraints maxHeight="1.7976931348623157E308"
<Insets/> vgrow="SOMETIMES"/>
</GridPane.margin> <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
<padding> vgrow="SOMETIMES"/>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> </rowConstraints>
</padding> <children>
</Pane> <Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0"
<GridPane fx:id="chatInputHolder" GridPane.rowIndex="1"> GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM"
<columnConstraints> GridPane.vgrow="ALWAYS">
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" <GridPane.margin>
prefWidth="100.0"/> <Insets/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" </GridPane.margin>
minWidth="90.0" prefWidth="90.0"/> <padding>
</columnConstraints> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
<rowConstraints> </padding>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" </Pane>
valignment="CENTER" vgrow="SOMETIMES"/> <GridPane fx:id="chatInputHolder" GridPane.rowIndex="1">
</rowConstraints> <columnConstraints>
<children> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
<JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED" prefWidth="100.0"/>
focusTraversable="false" maxHeight="-Infinity" <ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="90.0" prefWidth="90.0"/>
minWidth="-Infinity" prefHeight="35.0" text="SEND" </columnConstraints>
GridPane.columnIndex="1"> <rowConstraints>
<GridPane.margin> <RowConstraints maxHeight="50.0" minHeight="50.0"
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> prefHeight="50.0" valignment="CENTER" vgrow="SOMETIMES"/>
</GridPane.margin> </rowConstraints>
</JFXButton> <children>
<JFXTextField fx:id="chatInput" focusTraversable="false" <JFXButton fx:id="chatSend" alignment="CENTER"
maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0"> buttonType="RAISED" maxHeight="-Infinity"
<GridPane.margin> maxWidth="1.7976931348623157E308" minHeight="-Infinity"
<Insets bottom="10.0" left="20.0" right="10.0"/> minWidth="-Infinity" prefHeight="35.0" text="SEND"
</GridPane.margin> GridPane.columnIndex="1">
<padding> <GridPane.margin>
<Insets right="15.0"/> <Insets bottom="10.0" left="10.0" right="10.0"
</padding> top="10.0"/>
</JFXTextField> </GridPane.margin>
</children> </JFXButton>
<GridPane.margin> <JFXTextField fx:id="chatInput" maxHeight="35.0"
<Insets top="10.0"/> minHeight="-Infinity" prefHeight="35.0">
</GridPane.margin> <GridPane.margin>
</GridPane> <Insets bottom="10.0" left="20.0" right="10.0"/>
</children> </GridPane.margin>
<GridPane.margin> <padding>
<Insets bottom="10.0" right="10.0"/> <Insets right="15.0"/>
</GridPane.margin> </padding>
</GridPane> </JFXTextField>
<GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity" </children>
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER" <GridPane.margin>
GridPane.rowIndex="2" GridPane.valignment="BOTTOM"> <Insets top="10.0"/>
<columnConstraints> </GridPane.margin>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0" </GridPane>
prefWidth="110.0"/> </children>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0" <GridPane.margin>
prefWidth="132.0"/> <Insets bottom="10.0" right="10.0"/>
</columnConstraints> </GridPane.margin>
<rowConstraints> </GridPane>
<RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0" <GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity"
vgrow="SOMETIMES"/> prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
vgrow="SOMETIMES"/> <columnConstraints>
</rowConstraints> <ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0"
<children> minWidth="110.0" prefWidth="110.0"/>
<Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1" <ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP"> prefWidth="132.0"/>
<padding> </columnConstraints>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <rowConstraints>
</padding> <RowConstraints maxHeight="120.0" minHeight="120.0"
</Label> prefHeight="120.0" vgrow="SOMETIMES"/>
<Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
GridPane.halignment="LEFT" GridPane.rowSpan="2" vgrow="SOMETIMES"/>
GridPane.valignment="CENTER"> </rowConstraints>
<opaqueInsets> <children>
<Insets/> <Label fx:id="positionLabel" text="Position:"
</opaqueInsets> GridPane.columnIndex="1" GridPane.halignment="LEFT"
<padding> GridPane.rowSpan="2" GridPane.valignment="TOP">
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <padding>
</padding> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</Label> </padding>
<Label fx:id="boatHeadingLabel" text="Boat Heading:" </Label>
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2" <Label fx:id="boatSpeedLabel" text="Boat Speed:"
GridPane.valignment="BOTTOM"> GridPane.columnIndex="1" GridPane.halignment="LEFT"
<padding> GridPane.rowSpan="2" GridPane.valignment="CENTER">
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <opaqueInsets>
</padding> <Insets/>
</Label> </opaqueInsets>
<GridPane fx:id="windHolder" GridPane.rowSpan="2"> <padding>
<columnConstraints> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" </padding>
prefWidth="100.0"/> </Label>
</columnConstraints> <Label fx:id="boatHeadingLabel" text="Boat Heading:"
<rowConstraints> GridPane.columnIndex="1" GridPane.halignment="LEFT"
<RowConstraints maxHeight="120.0" minHeight="120.0" GridPane.rowSpan="2" GridPane.valignment="BOTTOM">
prefHeight="120.0" vgrow="SOMETIMES"/> <padding>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
vgrow="SOMETIMES"/> </padding>
</rowConstraints> </Label>
<children> <GridPane fx:id="windHolder" GridPane.rowSpan="2">
<ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0" <columnConstraints>
pickOnBounds="true" preserveRatio="true" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
GridPane.halignment="CENTER" GridPane.rowSpan="2" prefWidth="100.0"/>
GridPane.valignment="CENTER"/> </columnConstraints>
<Label fx:id="windSpeedLabel" text="0.0 Knots" <rowConstraints>
GridPane.halignment="RIGHT" GridPane.rowIndex="1" <RowConstraints maxHeight="120.0" minHeight="120.0"
GridPane.valignment="CENTER"> prefHeight="120.0" vgrow="SOMETIMES"/>
<GridPane.margin> <RowConstraints maxHeight="30.0" minHeight="30.0"
<Insets right="5.0"/> prefHeight="30.0" vgrow="SOMETIMES"/>
</GridPane.margin> </rowConstraints>
</Label> <children>
<Label fx:id="windDirectionLabel" text="180.0°" <ImageView fx:id="windImageView" fitHeight="92.0"
GridPane.halignment="LEFT" GridPane.rowIndex="1" fitWidth="109.0" pickOnBounds="true" preserveRatio="true"
GridPane.valignment="CENTER"> GridPane.halignment="CENTER" GridPane.rowSpan="2"
<GridPane.margin> GridPane.valignment="CENTER"/>
<Insets left="5.0"/> <Label fx:id="windSpeedLabel" text="0.0 Knots"
</GridPane.margin> GridPane.halignment="RIGHT" GridPane.rowIndex="1"
</Label> GridPane.valignment="CENTER">
</children> <GridPane.margin>
</GridPane> <Insets right="5.0"/>
</children> </GridPane.margin>
<opaqueInsets> </Label>
<Insets/> <Label fx:id="windDirectionLabel" text="180.0°"
</opaqueInsets> GridPane.halignment="LEFT" GridPane.rowIndex="1"
<GridPane.margin> GridPane.valignment="CENTER">
<Insets bottom="10.0" left="10.0" top="40.0"/> <GridPane.margin>
</GridPane.margin> <Insets left="5.0"/>
</GridPane> </GridPane.margin>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2"> </Label>
<columnConstraints> </children>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </GridPane>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </children>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> <opaqueInsets>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> <Insets/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </opaqueInsets>
</columnConstraints> <GridPane.margin>
<rowConstraints> <Insets bottom="10.0" left="10.0" top="40.0"/>
<RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0" </GridPane.margin>
vgrow="SOMETIMES"/> </GridPane>
<RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0" <GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
vgrow="SOMETIMES"/> <columnConstraints>
</rowConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
<children> prefWidth="100.0"/>
<ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
pickOnBounds="true" preserveRatio="true" visible="false" prefWidth="100.0"/>
GridPane.halignment="CENTER" GridPane.rowIndex="1"> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
<image> prefWidth="100.0"/>
<Image url="@../icons/velocity.png"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
</image> prefWidth="100.0"/>
</ImageView> </columnConstraints>
<ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0" <rowConstraints>
pickOnBounds="true" preserveRatio="true" visible="false" <RowConstraints minHeight="10.0" prefHeight="30.0"
GridPane.columnIndex="1" GridPane.halignment="CENTER" vgrow="SOMETIMES"/>
GridPane.rowIndex="1"> <RowConstraints minHeight="10.0" prefHeight="30.0"
<image> vgrow="SOMETIMES"/>
<Image url="@../icons/handlingIcon.png"/> </rowConstraints>
</image> <children>
</ImageView> <ImageView fx:id="velocityIcon" fitHeight="123.0" fitWidth="139.0"
<ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" visible="false"
pickOnBounds="true" preserveRatio="true" visible="false" GridPane.halignment="CENTER" GridPane.rowIndex="1">
GridPane.columnIndex="2" GridPane.halignment="CENTER" <image>
GridPane.rowIndex="1"> <Image url="@../icons/velocity.png"/>
<image> </image>
<Image url="@../icons/windWalkerIcon.png"/> </ImageView>
</image> <ImageView fx:id="handlingIcon" fitHeight="123.0" fitWidth="139.0"
</ImageView> pickOnBounds="true" preserveRatio="true" visible="false"
<ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0" GridPane.columnIndex="1" GridPane.halignment="CENTER"
pickOnBounds="true" preserveRatio="true" visible="false" GridPane.rowIndex="1">
GridPane.columnIndex="3" GridPane.halignment="CENTER" <image>
GridPane.rowIndex="1"> <Image url="@../icons/handlingIcon.png"/>
<image> </image>
<Image url="@../icons/bumperIcon.png"/> </ImageView>
</image> <ImageView fx:id="windWalkerIcon" fitHeight="123.0" fitWidth="139.0"
</ImageView> pickOnBounds="true" preserveRatio="true" visible="false"
<ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0" GridPane.columnIndex="2" GridPane.halignment="CENTER"
pickOnBounds="true" preserveRatio="true" visible="false" GridPane.rowIndex="1">
GridPane.columnIndex="4" GridPane.halignment="CENTER" <image>
GridPane.rowIndex="1" GridPane.valignment="CENTER"> <Image url="@../icons/windWalkerIcon.png"/>
<image> </image>
<Image url="@../icons/ayy_lmao.gif"/> </ImageView>
</image> <ImageView fx:id="bumperIcon" fitHeight="123.0" fitWidth="139.0"
</ImageView> pickOnBounds="true" preserveRatio="true" visible="false"
</children> GridPane.columnIndex="3" GridPane.halignment="CENTER"
</GridPane> GridPane.rowIndex="1">
</children> <image>
</GridPane> <Image url="@../icons/bumperIcon.png"/>
</children> </image>
</ImageView>
</children>
</GridPane>
</children>
</GridPane>
</children>
</StackPane>
</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>
</StackPane> </AnchorPane>
+32 -15
View File
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.lang.String?> <?import java.lang.String?>
@@ -12,35 +18,48 @@
<?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" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.ServerListController"> <StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.ServerListController">
<children> <children>
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"> <GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<children> <children>
<GridPane fx:id="connectGridPane" GridPane.rowIndex="2"> <GridPane fx:id="connectGridPane" GridPane.rowIndex="2">
<children> <children>
<JFXButton fx:id="connectButton" buttonType="RAISED" prefHeight="45.0" <JFXButton fx:id="connectButton" buttonType="RAISED" prefHeight="45.0" prefWidth="220.0" ripplerFill="#3493e3" text="CONNECT" textFill="WHITE" GridPane.columnIndex="5" GridPane.halignment="RIGHT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
prefWidth="220.0" ripplerFill="#3493e3" text="CONNECT" textFill="WHITE"
GridPane.columnIndex="5" GridPane.halignment="RIGHT"
GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets right="50.0" /> <Insets right="50.0" />
</GridPane.margin> </GridPane.margin>
</JFXButton> </JFXButton>
<JFXTextField fx:id="serverHostName" maxHeight="30.0" minHeight="30.0" prefHeight="30.0" promptText="Host Name" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <JFXTextField fx:id="serverHostName" maxHeight="30.0" minHeight="30.0" prefHeight="30.0" promptText="Host Name" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets left="20.0" right="20.0" /> <Insets left="20.0" right="20.0" />
</GridPane.margin> </GridPane.margin>
</JFXTextField> </JFXTextField>
<JFXTextField fx:id="serverPortNumber" maxHeight="30.0" minHeight="30.0" prefHeight="30.0" promptText="Port Number" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <JFXTextField fx:id="serverPortNumber" maxHeight="30.0" minHeight="30.0" prefHeight="30.0" promptText="Port Number" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets left="20.0" right="20.0" /> <Insets left="20.0" right="20.0" />
</GridPane.margin> </GridPane.margin>
</JFXTextField> </JFXTextField>
<Label fx:id="connectLabel" text="Direct Connect:" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.valignment="CENTER"> <Label fx:id="connectLabel" text="Direct Connect:" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets right="45.0" /> <Insets right="45.0" />
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<Label fx:id="connectLabel1" text="Connect to Room:" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="45.0" top="5.0" />
</GridPane.margin>
</Label>
<JFXButton fx:id="roomConnectButton" buttonType="RAISED" prefHeight="45.0" prefWidth="220.0" text="CONNECT" GridPane.columnIndex="5" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets right="50.0" top="5.0" />
</GridPane.margin>
</JFXButton>
<JFXTextField fx:id="roomNumber" maxHeight="30.0" minHeight="30.0" prefHeight="30.0" promptText="Room Number" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="20.0" right="20.0" top="5.0" />
</GridPane.margin>
</JFXTextField>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" /> <ColumnConstraints hgrow="SOMETIMES" />
@@ -51,6 +70,7 @@
<ColumnConstraints hgrow="SOMETIMES" maxWidth="273.0" minWidth="250.0" prefWidth="273.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="273.0" minWidth="250.0" prefWidth="273.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <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> </rowConstraints>
</GridPane> </GridPane>
@@ -76,12 +96,9 @@
<Insets left="35.0" top="5.0" /> <Insets left="35.0" top="5.0" />
</padding> </padding>
</Label> </Label>
<JFXButton id="hostButton" fx:id="serverListHostButton" buttonType="RAISED" <JFXButton id="hostButton" fx:id="serverListHostButton" buttonType="RAISED" prefHeight="45.0" prefWidth="220.0" text="HOST" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
prefHeight="45.0" prefWidth="220.0"
text="HOST" GridPane.columnIndex="1" GridPane.halignment="RIGHT"
GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets right="50.0"/> <Insets right="50.0" />
</GridPane.margin> </GridPane.margin>
</JFXButton> </JFXButton>
</children> </children>
@@ -99,11 +116,11 @@
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="400.0" prefHeight="400.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="1.7976931348623157E308" minHeight="400.0" prefHeight="465.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<stylesheets> <stylesheets>
<String fx:value="/css/Master.css"/> <String fx:value="/css/Master.css" />
<String fx:value="/css/ServerListView.css" /> <String fx:value="/css/ServerListView.css" />
</stylesheets> </stylesheets>
</GridPane> </GridPane>
@@ -1,11 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXColorPicker?> <?import com.jfoenix.controls.JFXColorPicker?>
<?import com.jfoenix.controls.JFXDialogLayout?> <?import com.jfoenix.controls.JFXDialogLayout?>
@@ -16,45 +10,54 @@
<?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?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.BoatCustomizeController"> minWidth="-Infinity" prefWidth="400.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.BoatCustomizeController">
<children> <children>
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="90.0" minHeight="48.0" prefHeight="48.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="207.0" minHeight="93.0" prefHeight="181.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="207.0" minHeight="93.0" prefHeight="181.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="125.0" minHeight="61.0" prefHeight="99.0"
<RowConstraints maxHeight="145.0" minHeight="66.0" prefHeight="109.0" vgrow="SOMETIMES" /> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="125.0" minHeight="24.0" prefHeight="72.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="126.0"
<RowConstraints maxHeight="164.0" minHeight="100.0" prefHeight="105.0" vgrow="SOMETIMES" /> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER" GridPane.valignment="CENTER" /> <Label fx:id="hostDialogHeader" text="Customize Boat" GridPane.halignment="CENTER"
<JFXButton fx:id="submitBtn" prefHeight="45.0" prefWidth="220.0" text="Customize Boat" GridPane.halignment="CENTER" GridPane.rowIndex="5" GridPane.valignment="CENTER" /> GridPane.valignment="CENTER"/>
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name" unFocusColor="#6b6b6b" GridPane.rowIndex="3"> <JFXButton fx:id="submitBtn" prefHeight="45.0" prefWidth="220.0" text="Customize Boat" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
<JFXTextField fx:id="boatName" focusColor="#6c6c6c" promptText="Boat Name"
unFocusColor="#6b6b6b" GridPane.rowIndex="1">
<GridPane.margin> <GridPane.margin>
<Insets left="30.0" right="30.0" /> <Insets left="30.0" right="30.0" />
</GridPane.margin></JFXTextField> </GridPane.margin></JFXTextField>
<GridPane GridPane.halignment="CENTER" GridPane.rowIndex="4" GridPane.valignment="CENTER"> <GridPane GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0" prefWidth="94.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="139.0" minWidth="10.0"
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0" prefWidth="198.0" /> prefWidth="94.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="203.0" minWidth="10.0"
prefWidth="198.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints percentHeight="100.0" valignment="CENTER" vgrow="SOMETIMES" /> <RowConstraints percentHeight="100.0" valignment="CENTER" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0" text="Boat Color" GridPane.valignment="CENTER"> <Label fx:id="boatColorLabel" prefHeight="25.0" prefWidth="96.0"
text="Boat Color" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets top="-10.0" /> <Insets top="-10.0" />
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<JFXColorPicker fx:id="colorPicker" onAction="#colorChanged" GridPane.columnIndex="1" GridPane.valignment="CENTER"> <JFXColorPicker fx:id="colorPicker" onAction="#colorChanged"
GridPane.columnIndex="1" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets left="30.0" top="-10.0" /> <Insets left="30.0" top="-10.0"/>
</GridPane.margin> </GridPane.margin>
</JFXColorPicker> </JFXColorPicker>
</children> </children>
@@ -62,45 +65,11 @@
<Insets left="30.0" right="30.0" /> <Insets left="30.0" right="30.0" />
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="50.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="256.0" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane fx:id="boatPane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" />
<JFXButton buttonType="RAISED" onAction="#prevBoat" prefHeight="200.0" prefWidth="50.0" text="&lt;" />
<JFXButton buttonType="RAISED" onAction="#nextBoat" prefHeight="200.0" prefWidth="50.0" text="&gt;" GridPane.columnIndex="2" />
</children>
</GridPane>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Max Speed:" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Acceleration:" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Handling:" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
<ProgressBar fx:id="speedBar" focusTraversable="false" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" />
<ProgressBar fx:id="accelBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<ProgressBar fx:id="handleBar" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
</children> </children>
<stylesheets> <stylesheets>
<String fx:value="/css/dialogs/BoatCustomize.css" /> <String fx:value="/css/dialogs/BoatCustomize.css"/>
<String fx:value="/css/Master.css" /> <String fx:value="/css/Master.css"/>
</stylesheets> </stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -1,231 +0,0 @@
<?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.control.ScrollPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<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">
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<ScrollPane prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
<content>
<StackPane prefHeight="150.0" prefWidth="200.0">
<children>
<GridPane>
<children>
<JFXButton fx:id="viewButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="F1"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
<Label text="VIEW ASPECT" GridPane.halignment="CENTER"
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
<JFXButton fx:id="rightButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="D"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<Label text="RIGHT" GridPane.halignment="CENTER"
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<JFXButton fx:id="leftButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="A"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
<Label text="LEFT" GridPane.halignment="CENTER"
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
<JFXButton fx:id="forwardButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="W"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
<Label text="FORWARD" GridPane.halignment="CENTER"
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
<JFXButton fx:id="backwardButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="S"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
<Label text="BACKWARD" GridPane.halignment="CENTER"
GridPane.rowIndex="11" 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>
<Label styleClass="sectionLabel" text="BOAT ACTIONS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
<Label styleClass="sectionLabel" text="CAMERA SETTINGS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="250.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="150.0"/>
</columnConstraints>
<rowConstraints>
<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="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>
</GridPane>
</children>
</StackPane>
</content>
</ScrollPane>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBINDING" GridPane.columnSpan="2"
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
<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="2" GridPane.valignment="CENTER"/>
</children>
</GridPane>
</children>
</JFXDialogLayout>
@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?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 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.PopupDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
prefHeight="80.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
prefWidth="150.0" GridPane.halignment="RIGHT" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</JFXButton>
<Label fx:id="contentLabel" text="Popup content goes here ..."
GridPane.rowIndex="1"/>
<Label fx:id="headerLabel" text="Popup header"/>
<Label fx:id="closeLabel" text="✖" translateY="-10.0" GridPane.halignment="RIGHT"/>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/Popup.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
</JFXDialogLayout>
@@ -4,18 +4,14 @@
<?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.net.URL?> <?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.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">
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8.0.111"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
<children> <children>
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
@@ -63,13 +59,11 @@
</VBox> </VBox>
</children> </children>
</GridPane> </GridPane>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
</children> </children>
</GridPane> </GridPane>
</children> </children>
<stylesheets> <stylesheets>
<URL value="@../../css/dialogs/ServerCreation.css"/> <String fx:value="/css/dialogs/ServerCreation.css" />
<URL value="@../../css/Master.css"/> <String fx:value="/css/Master.css"/>
</stylesheets> </stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -110,7 +110,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(5.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(5.0, GameState.getSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
try { try {
Thread.sleep(200); Thread.sleep(200);
@@ -150,7 +150,7 @@ public class ChatCommandsTest {
ie.printStackTrace(); ie.printStackTrace();
} }
mst.terminate(); mst.terminate();
Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
try { try {
Thread.sleep(2000); Thread.sleep(2000);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
@@ -194,7 +194,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
host.setSocketToClose(); host.setSocketToClose();
client.setSocketToClose(); client.setSocketToClose();
@@ -5,7 +5,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import static seng302.gameServer.GameState.checkCollision; import static seng302.gameServer.GameState.checkCollision;
@@ -15,10 +14,8 @@ import static seng302.gameServer.GameState.checkCollision;
*/ */
public class UpdateYachtTest { public class UpdateYachtTest {
private ServerYacht yacht1 = new ServerYacht(BoatMeshType.DINGHY, 1, "1", "Yacht" + 1, private ServerYacht yacht1 = new ServerYacht("Yacht", 1, "1", "Yacht" + 1, "Yacht" + 1, "Test1");
"Yacht" + 1, "Test1"); private ServerYacht yacht2 = new ServerYacht("Yacht", 2, "2", "Yacht" + 2, "Yacht" + 2, "Test2");
private ServerYacht yacht2 = new ServerYacht(BoatMeshType.DINGHY, 2, "2", "Yacht" + 2,
"Yacht" + 2, "Test2");
private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0); private GeoPoint geoPoint1 = new GeoPoint(50.0, 50.0);
private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0); private GeoPoint geoPoint2 = GeoUtility.getGeoCoordinate(geoPoint1, 90.0, 50.0);
+1 -2
View File
@@ -4,7 +4,6 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; 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;
public class YachtTest { public class YachtTest {
@@ -18,7 +17,7 @@ public class YachtTest {
@BeforeClass @BeforeClass
public static void setUp() { public static void setUp() {
new GameState("localhost"); new GameState("localhost");
y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1"); y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1");
gs = new GameState("localhost"); gs = new GameState("localhost");
} }
@@ -0,0 +1,57 @@
package seng302.serverDiscovery;
import org.junit.BeforeClass;
import org.junit.Test;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerTable;
import java.util.Objects;
import static org.junit.Assert.assertTrue;
public class ServerTableTest {
private static ServerTable serverTable;
@BeforeClass
public static void setup(){
serverTable = new ServerTable();
}
@Test
public void testAddServer(){
ServerListing listing = new ServerListing("", "", "", 12, 12);
serverTable.addServer(listing);
assertTrue(serverTable.getAllServers().contains(listing));
}
@Test
public void testGetNextRoomCodeIsUnique(){
assertTrue(!Objects.equals(serverTable.getNextRoomCode(), serverTable.getNextRoomCode()));
}
@Test
public void testGetServerRoomCode(){
ServerListing listing = new ServerListing("123", "", "", 12, 12);
listing.setRoomCode(serverTable.getNextRoomCode().toString());
serverTable.addServer(listing);
ServerListing result = serverTable.getServerByRoomCode(listing.getRoomCode());
assertTrue(result.equals(listing));
}
@Test
public void testServersRemovedOnExpiry() throws InterruptedException {
ServerListing listing = new ServerListing("432", "221", "", 12, 12);
listing.setTtl(1);
serverTable.addServer(listing);
listing.decrementTtl();
Thread.sleep(1000);
assertTrue(!serverTable.getAllServers().contains(listing));
}
}
@@ -0,0 +1,31 @@
package seng302.serverDiscovery;
import org.junit.Test;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest;
import seng302.model.stream.packets.PacketType;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.Assert.assertTrue;
public class testStreamParser {
private static ServerRepoStreamParser parser;
private static InputStream inputStream;
private static void setupWithByteArray(byte[] bytes){
inputStream = new ByteArrayInputStream(bytes);
parser = new ServerRepoStreamParser(inputStream);
}
@Test
public void testParseRoomCodeRequest() throws Exception {
Message roomCodeMsg = new RoomCodeRequest("1234");
setupWithByteArray(roomCodeMsg.getBuffer());
assertTrue(parser.parse() == PacketType.ROOM_CODE_REQUEST);
assertTrue(parser.getRoomCode().equals("1234"));
}
}
@@ -1,28 +0,0 @@
package seng302.utilities;
import org.junit.Assert;
import org.junit.Test;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/**
* Basic tests for the next and previous methods
* Created by kre39 on 20/09/17.
*/
public class BoatMeshTypeTest {
@Test
public void testNextBoatMeshType() {
BoatMeshType currentBoat = BoatMeshType.DINGHY;
BoatMeshType nextBoat = BoatMeshType.getNextBoatType(currentBoat);
Assert.assertEquals(BoatMeshType.CATAMARAN, nextBoat);
}
@Test
public void testPreviousBoatMeshType() {
BoatMeshType currentBoat = BoatMeshType.CATAMARAN;
BoatMeshType prevBoat = BoatMeshType.getPrevBoatType(currentBoat);
Assert.assertEquals(BoatMeshType.DINGHY, prevBoat);
}
}
@@ -1,50 +0,0 @@
package seng302.utilities;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.token.Token;
/**
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawnTest {
private RandomSpawn randomSpawn;
Mark mark1 = new Mark("mark1", 0, 57.670333, 11.827833, 0);
Mark mark2 = new Mark("mark2", 1, 57.671829, 11.842049, 1);
CompoundMark compoundMark1 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark1)));
CompoundMark compoundMark2 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark2)));
List<CompoundMark> markOrder = new ArrayList<>(Arrays.asList(compoundMark1, compoundMark2));
@Before
public void setup() {
randomSpawn = new RandomSpawn(markOrder);
}
@Test
public void testGetRandomTokenLocation() {
GeoPoint testMidPoint = GeoUtility
.getDirtyMidPoint(compoundMark1.getMidPoint(), compoundMark2.getMidPoint());
Double maxDistance = GeoUtility.getDistance(testMidPoint, compoundMark2.getMidPoint());
for (int i = 0; i < 1000; i++) {
Token token = randomSpawn.getRandomTokenLocation();
Double distanceFromCentreRadius = GeoUtility.getDistance(testMidPoint, token);
assertTrue("Out of bounds token", distanceFromCentreRadius <= maxDistance);
}
}
}
@@ -6,7 +6,6 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/** /**
* Created by kre39 on 6/08/17. * Created by kre39 on 6/08/17.
@@ -17,7 +16,7 @@ public class BoatSailAnimationToggleTest {
@Before @Before
public void setup() throws Exception{ public void setup() throws Exception{
yacht = new ClientYacht(BoatMeshType.DINGHY, 1, "YACHT", "YAC", "Test Yacht", "NZ"); yacht = new ClientYacht("Yacht", 1, "YACHT", "YAC", "Test Yacht", "NZ");
} }
@Test @Test
-1
View File
@@ -13,7 +13,6 @@ import seng302.model.ServerYacht;
import seng302.visualiser.ClientToServerThread; import seng302.visualiser.ClientToServerThread;
/** /**
*
* Created by kre39 on 7/08/17. * Created by kre39 on 7/08/17.
*/ */
public class ToggleSailSteps { public class ToggleSailSteps {