Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e1ebbc71c1 | |||
| c98297ea79 | |||
| a5eea10c87 | |||
| 597fbe935f | |||
| 7cfad28d6b | |||
| 3345734efd | |||
| 9795083d4d | |||
| f02208ba3a | |||
| b9a2d60115 | |||
| 076c4c9a40 | |||
| 8d74c3b756 | |||
| 3f666fa092 | |||
| 55d82298b6 | |||
| 909407fe63 | |||
| cb4e47f71a | |||
| 499acb9733 | |||
| 5688e10e6f | |||
| 5cbd729214 | |||
| ddf5a96e0f | |||
| 81b2d285e9 | |||
| 5d7f307260 | |||
| 4ec23a1785 | |||
| 37e4fe4ce7 | |||
| e87931a8fc | |||
| d1edbc4b8a | |||
| 275a2cbab7 | |||
| 705669ad07 | |||
| 71f6b9accb | |||
| caf04e1e99 | |||
| b9cb6fa5b4 | |||
| 0b8e2499a7 | |||
| 9075d2a909 | |||
| 00e2af9c14 | |||
| ba768deabc | |||
| 73861b2ef3 | |||
| 4018dd783e | |||
| 8b7407bf89 | |||
| 00ddf117b2 | |||
| a266779709 | |||
| df24fe072a | |||
| a1a34b9bd7 | |||
| 42d490d6fd | |||
| cd4a2f8da3 | |||
| 287cfd77d0 | |||
| a08a38c985 | |||
| 810dde6a21 | |||
| 7a76efa2ce | |||
| ff4c2cd5b6 | |||
| c5e6302f86 | |||
| cd199767ae | |||
| 5cc4898ab5 | |||
| 22e1e57c24 | |||
| c5d2016733 | |||
| efc71f2003 | |||
| be72062c8e | |||
| 0d212a4a1d | |||
| 0e9b818071 | |||
| 452e83c1c3 | |||
| aded794a67 | |||
| 2b3a972ed5 | |||
| 2a523a5664 | |||
| 67f3124cfb | |||
| 7db387bdec | |||
| 2ceca2fd42 | |||
| 00ff771fc3 | |||
| d963785679 | |||
| 78f64557c3 | |||
| 982fac38a0 | |||
| edbfb2f84f | |||
| c01111038f | |||
| fd53fd52a4 | |||
| 6f62efcc93 | |||
| daf3867433 | |||
| e5af7bf666 | |||
| 85ca91db96 | |||
| 2eb7e603f1 | |||
| 658a342118 | |||
| ea52977aeb | |||
| 10fa51a105 | |||
| c54a1e141d | |||
| 6d51ea3574 | |||
| d56468e4aa | |||
| 330ccd272d | |||
| 4b7dfe38c4 | |||
| ab07c7f298 | |||
| b5076bc976 | |||
| 671efcaf08 | |||
| 8ba44d7476 | |||
| 98abe64f00 | |||
| 870d7a6e82 | |||
| 7a4cdbe0c9 | |||
| 735699dc85 | |||
| 81e791bd1a | |||
| 06e5f4ae00 | |||
| cd2b4cb93c | |||
| dde1c82dbb | |||
| d9c832168b | |||
| 9cfb3b9e5d | |||
| d0844e861d | |||
| 5d32d76d9d | |||
| 9ca39d1a7c | |||
| 30dad8509e | |||
| 0211f2df38 | |||
| dba5a5680f | |||
| 29b97a194d | |||
| 8a0ad8d6a9 | |||
| ca320f7fb8 | |||
| 78259f8e33 | |||
| c47e5b1450 | |||
| 8c7f9a878d | |||
| ecb3d4ecbf | |||
| e61b6d50a1 | |||
| 061e49bab9 | |||
| a3c555d5fe | |||
| 5e3ae40d03 | |||
| 95ad7a4840 | |||
| e17e9749d8 | |||
| 3be8cd264d | |||
| 66d9a06f9e | |||
| 034e4c252a | |||
| 6cde016401 | |||
| 52d3cea592 | |||
| 78596ea111 |
@@ -109,6 +109,12 @@
|
|||||||
<version>3.4.2</version>
|
<version>3.4.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.fxyz3d</groupId>
|
||||||
|
<artifactId>fxyz3d</artifactId>
|
||||||
|
<version>0.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ 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;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
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,9 +30,21 @@ 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")) {
|
||||||
@@ -63,19 +80,45 @@ public class App extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
ViewManager.getInstance().initialStartView(primaryStage);
|
ViewManager.getInstance().initialiseSplashScreen(primaryStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void runDiscoveryServer() throws Exception {
|
||||||
|
while (true){
|
||||||
|
try {
|
||||||
|
new DiscoveryServer();
|
||||||
|
}
|
||||||
|
catch (Exception ignored){
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
/*
|
||||||
|
* Do not trust Java to do garbage collection
|
||||||
|
*/
|
||||||
|
new Timer().schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}, 0, 1200);
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isRunningAsCache){
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
runDiscoveryServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
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 seng302.visualiser.ServerListener;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Timer;
|
||||||
|
|
||||||
|
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";
|
||||||
|
private static final int MAX_SERVER_TRIES = 10;
|
||||||
|
public static String DISCOVERY_SERVER = "party.sydney.srv.michaelrausch.nz";
|
||||||
|
|
||||||
|
private ServerTable serverTable;
|
||||||
|
public static final Integer PORT_NUMBER = 9969;
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
try{
|
||||||
|
while (true){
|
||||||
|
Socket clientSocket = serverSocket.accept();
|
||||||
|
|
||||||
|
parseRequest(clientSocket);
|
||||||
|
|
||||||
|
clientSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (desiredRoomCode.equals("0000")){
|
||||||
|
serverListing = getRandomFreeServer();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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 = ServerRegistrationMessage.getEmptyRegistration();
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSocket.getOutputStream().write(response.getBuffer());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerListing getRandomFreeServer() {
|
||||||
|
ServerListing serverToJoin;
|
||||||
|
|
||||||
|
List<ServerListing> servers = serverTable.getAllServers();
|
||||||
|
|
||||||
|
if (servers.size() <= 0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (servers.size() == 1){
|
||||||
|
return servers.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverToJoin = servers.get(new Random().nextInt(servers.size()));
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
while (serverToJoin != null && serverToJoin.isMaxPlayersReached() && tries < MAX_SERVER_TRIES){
|
||||||
|
serverToJoin = servers.get(new Random().nextInt(servers.size()));
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverToJoin != null && serverToJoin.isMaxPlayersReached()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverToJoin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close(){
|
||||||
|
try {
|
||||||
|
serverSocket.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
package seng302.discoveryServer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.discoveryServer.util.ServerListing;
|
||||||
|
import seng302.discoveryServer.util.ServerRepoStreamParser;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RoomCodeRequest;
|
||||||
|
import seng302.gameServer.messages.ServerRegistrationMessage;
|
||||||
|
import seng302.model.stream.packets.PacketType;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URL;
|
||||||
|
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);
|
||||||
|
private String ip = "";
|
||||||
|
private Boolean isInInvalidState = false;
|
||||||
|
|
||||||
|
public DiscoveryServerClient() {
|
||||||
|
try {
|
||||||
|
ip = getInetIpAddr();
|
||||||
|
} catch (Exception e) {
|
||||||
|
failError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInetIp(){
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void failError() {
|
||||||
|
isInInvalidState = true;
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("You do not appear to be able to connect to the internet. Matchmaking will be unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean didFail(){
|
||||||
|
return isInInvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the server with the discovery server
|
||||||
|
* @param serverListing The listing to register
|
||||||
|
*/
|
||||||
|
public void register(ServerListing serverListing){
|
||||||
|
if (isInInvalidState) return;
|
||||||
|
|
||||||
|
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(){
|
||||||
|
if (serverListingUpdateTimer != null)
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerListing getRandomServer() throws Exception {
|
||||||
|
Socket socket = new Socket(DiscoveryServer.DISCOVERY_SERVER, DiscoveryServer.PORT_NUMBER);
|
||||||
|
ServerRepoStreamParser parser = new ServerRepoStreamParser(socket.getInputStream());
|
||||||
|
|
||||||
|
Message request = new RoomCodeRequest("0000");
|
||||||
|
socket.getOutputStream().write(request.getBuffer());
|
||||||
|
|
||||||
|
PacketType packetType = parser.parse();
|
||||||
|
|
||||||
|
if (packetType != PacketType.SERVER_REGISTRATION){
|
||||||
|
logger.error("Incorrect packet type received");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.close();
|
||||||
|
|
||||||
|
ServerListing serverListing = parser.getServerListing();
|
||||||
|
|
||||||
|
if (serverListing == null || serverListing.equals(ServerRegistrationMessage.getEmptyRegistration())){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverListing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getInetIpAddr() throws Exception {
|
||||||
|
URL myIp = new URL("http://checkip.amazonaws.com");
|
||||||
|
BufferedReader in = null;
|
||||||
|
try {
|
||||||
|
in = new BufferedReader(new InputStreamReader(
|
||||||
|
myIp.openStream()));
|
||||||
|
String ip = in.readLine();
|
||||||
|
return ip;
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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,117 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMaxPlayersReached() {
|
||||||
|
return players >= capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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() + " at address: " + server.getAddress() + ":" + server.getPortNumber());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -9,6 +9,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
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;
|
||||||
@@ -20,8 +22,6 @@ import seng302.gameServer.messages.MarkRoundingMessage;
|
|||||||
import seng302.gameServer.messages.MarkType;
|
import seng302.gameServer.messages.MarkType;
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RoundingBoatStatus;
|
import seng302.gameServer.messages.RoundingBoatStatus;
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
|
||||||
import seng302.gameServer.messages.YachtEventType;
|
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
@@ -34,6 +34,7 @@ import seng302.model.stream.xml.parser.RaceXMLData;
|
|||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
import seng302.model.token.TokenType;
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.utilities.RandomSpawn;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,63 +52,75 @@ 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;
|
||||||
|
|
||||||
private static final Long POWERUP_TIMEOUT_MS = 10_000L;
|
//Wind Constants
|
||||||
|
private static final int MAX_WIND_SPEED = 12000;
|
||||||
|
private static final int MIN_WIND_SPEED = 8000;
|
||||||
|
|
||||||
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
//Rounding Constants
|
||||||
private static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
private static final 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;
|
||||||
|
|
||||||
|
//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 speedMultiplier = 1d;
|
private static Double serverSpeedMultiplier;
|
||||||
|
|
||||||
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
||||||
private static Boolean playerHasLeftFlag;
|
private static Boolean playerHasLeftFlag;
|
||||||
|
|
||||||
|
private static String hostIpAddress;
|
||||||
private static List<Player> players;
|
private static List<Player> players;
|
||||||
private static Map<Integer, ServerYacht> yachts;
|
private static Map<Integer, ServerYacht> yachts;
|
||||||
private static Boolean isRaceStarted;
|
|
||||||
private static GameStages currentStage;
|
private static GameStages currentStage;
|
||||||
private static MarkOrder markOrder;
|
private static MarkOrder markOrder;
|
||||||
private static long startTime;
|
private static long startTime;
|
||||||
private static Set<Mark> marks;
|
private static Set<Mark> marks = new HashSet<>();
|
||||||
private static List<Limit> courseLimit;
|
private static List<Limit> courseLimit = new ArrayList<>();
|
||||||
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;
|
||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
|
private static boolean tokensEnabled = false;
|
||||||
|
|
||||||
public GameState() {
|
public GameState() {
|
||||||
windDirection = 180d;
|
windDirection = 180d;
|
||||||
windSpeed = 10000d;
|
windSpeed = 10000d;
|
||||||
yachts = new HashMap<>();
|
yachts = new HashMap<>();
|
||||||
tokensInPlay = new ArrayList<>();
|
tokensInPlay = new ArrayList<>();
|
||||||
marks = new HashSet<>();
|
|
||||||
players = new ArrayList<>();
|
players = new ArrayList<>();
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
playerHasLeftFlag = false;
|
playerHasLeftFlag = false;
|
||||||
speedMultiplier = 1.0;
|
serverSpeedMultiplier = 1.0;
|
||||||
currentStage = GameStages.LOBBYING;
|
currentStage = GameStages.LOBBYING;
|
||||||
isRaceStarted = false;
|
|
||||||
//set this when game stage changes to prerace
|
|
||||||
previousUpdateTime = System.currentTimeMillis();
|
previousUpdateTime = System.currentTimeMillis();
|
||||||
newMessageListeners = new ArrayList<>();
|
newMessageListeners = new ArrayList<>();
|
||||||
allTokens = makeTokens();
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,27 +129,10 @@ public class GameState implements Runnable {
|
|||||||
for (CompoundMark compoundMark : raceXMLData.getCompoundMarks().values()){
|
for (CompoundMark compoundMark : raceXMLData.getCompoundMarks().values()){
|
||||||
marks.addAll(compoundMark.getMarks());
|
marks.addAll(compoundMark.getMarks());
|
||||||
}
|
}
|
||||||
|
randomSpawn = new RandomSpawn(markOrder.getOrderedUniqueCompoundMarks());
|
||||||
courseLimit = raceXMLData.getCourseLimit();
|
courseLimit = raceXMLData.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 Set<Mark> getMarks() {
|
|
||||||
return Collections.unmodifiableSet(marks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Player> getPlayers() {
|
public static List<Player> getPlayers() {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
@@ -145,6 +141,10 @@ public class GameState implements Runnable {
|
|||||||
return tokensInPlay;
|
return tokensInPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<Mark> getMarks() {
|
||||||
|
return Collections.unmodifiableSet(marks);
|
||||||
|
}
|
||||||
|
|
||||||
public static void addPlayer(Player player) {
|
public static void addPlayer(Player player) {
|
||||||
players.add(player);
|
players.add(player);
|
||||||
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
|
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
|
||||||
@@ -165,10 +165,6 @@ public class GameState implements Runnable {
|
|||||||
yachts.remove(yachtId);
|
yachts.remove(yachtId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Boolean getIsRaceStarted() {
|
|
||||||
return isRaceStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GameStages getCurrentStage() {
|
public static GameStages getCurrentStage() {
|
||||||
return currentStage;
|
return currentStage;
|
||||||
}
|
}
|
||||||
@@ -237,12 +233,77 @@ 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 || currentStage == GameStages.RACING) {
|
if (currentStage == GameStages.PRE_RACE) {
|
||||||
|
update();
|
||||||
|
if (System.currentTimeMillis() > startTime) {
|
||||||
|
startSpawningTokens();
|
||||||
|
startUpdatingWind();
|
||||||
|
GameState.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() {
|
||||||
|
if (tokensEnabled) {
|
||||||
|
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.windSpeed = Double.valueOf(windSpeed);
|
||||||
|
GameState.windDirection = 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) {
|
||||||
@@ -277,10 +338,13 @@ 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
|
||||||
*/
|
*/
|
||||||
public static void spawnNewToken() {
|
private void spawnNewToken() {
|
||||||
Random random = new Random();
|
|
||||||
tokensInPlay.clear();
|
tokensInPlay.clear();
|
||||||
tokensInPlay.add(allTokens.get(random.nextInt(allTokens.size())));
|
Token token = randomSpawn.getRandomToken();
|
||||||
|
// token.assignType(TokenType.WIND_WALKER);
|
||||||
|
logger.debug("Spawned token of type " + token.getTokenType());
|
||||||
|
tokensInPlay.add(token);
|
||||||
|
MessageFactory.updateTokens(tokensInPlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,14 +361,12 @@ 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);
|
||||||
@@ -318,17 +380,138 @@ 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);
|
||||||
|
MessageFactory.updateTokens(tokensInPlay);
|
||||||
|
notifyMessageListeners(MessageFactory.getRaceXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
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() > POWERUP_TIMEOUT_MS) {
|
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > yacht.getPowerUp()
|
||||||
yacht.powerDown();
|
.getTimeout()) {
|
||||||
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired");
|
powerDownYacht(yacht);
|
||||||
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
|
||||||
*
|
*
|
||||||
@@ -342,6 +525,7 @@ public class GameState implements Runnable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GeoUtility.checkCrossedLine(courseLimit.get(courseLimit.size() - 1), courseLimit.get(0),
|
if (GeoUtility.checkCrossedLine(courseLimit.get(courseLimit.size() - 1), courseLimit.get(0),
|
||||||
yacht.getLastLocation(), yacht.getLocation()) != 0) {
|
yacht.getLastLocation(), yacht.getLocation()) != 0) {
|
||||||
return true;
|
return true;
|
||||||
@@ -350,13 +534,15 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks all tokensInPlay to see if a yacht has picked one up
|
* Checks all tokensInPlay to see if a yacht has picked one up. If so, the yacht is powered up
|
||||||
* @return Token which was collided with
|
* in the appropriate way
|
||||||
* @param serverYacht The yacht to check for collision with a token
|
* @param yacht The yacht to check for collision with a token
|
||||||
|
*
|
||||||
|
* @return The token collided with
|
||||||
*/
|
*/
|
||||||
private static Token checkTokenPickUp(ServerYacht serverYacht) {
|
private Token checkTokenPickUp(ServerYacht yacht) {
|
||||||
for (Token token : tokensInPlay) {
|
for (Token token : tokensInPlay) {
|
||||||
Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
|
Double distance = GeoUtility.getDistance(token, yacht.getLocation());
|
||||||
if (distance < YACHT_COLLISION_DISTANCE) {
|
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -379,7 +565,7 @@ 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);
|
ServerYacht collidedYacht = checkYachtCollision(serverYacht, false);
|
||||||
Mark collidedMark = checkMarkCollision(serverYacht);
|
Mark collidedMark = checkMarkCollision(serverYacht);
|
||||||
|
|
||||||
if (collidedYacht != null) {
|
if (collidedYacht != null) {
|
||||||
@@ -396,9 +582,7 @@ public class GameState implements Runnable {
|
|||||||
collidedYacht.setCurrentVelocity(
|
collidedYacht.setCurrentVelocity(
|
||||||
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mark Collision
|
//Mark Collision
|
||||||
@@ -410,9 +594,7 @@ public class GameState implements Runnable {
|
|||||||
serverYacht.setCurrentVelocity(
|
serverYacht.setCurrentVelocity(
|
||||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Boundary Collision
|
//Boundary Collision
|
||||||
@@ -425,23 +607,7 @@ public class GameState implements Runnable {
|
|||||||
serverYacht.setCurrentVelocity(
|
serverYacht.setCurrentVelocity(
|
||||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Token Collision
|
|
||||||
Token collidedToken = checkTokenPickUp(serverYacht);
|
|
||||||
if (collidedToken != null) {
|
|
||||||
sendServerMessage(serverYacht.getSourceId(), serverYacht.getBoatName() + " has picked speed-up token");
|
|
||||||
tokensInPlay.remove(collidedToken);
|
|
||||||
serverYacht.powerUp(collidedToken.getTokenType());
|
|
||||||
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
|
|
||||||
.getTokenType());
|
|
||||||
System.out.println("AGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
|
|
||||||
notifyMessageListeners(MessageFactory.getRaceXML());
|
|
||||||
notifyMessageListeners(
|
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,29 +615,30 @@ public class GameState implements Runnable {
|
|||||||
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 = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier();
|
Double maxBoatSpeed =
|
||||||
if (yacht.getPowerUp() != null) {
|
GeoUtility.knotsToMMS(boatSpeedInKnots) * serverSpeedMultiplier * yacht
|
||||||
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
.getPowerUpSpeedMultiplier() * yacht.getBoatTypeSpeedMultiplier();
|
||||||
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
|
|
||||||
maxBoatSpeed *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier());
|
yacht.changeVelocity(
|
||||||
|
(maxBoatSpeed / 100) * yacht.getBoatTypeAccelerationMultiplier());
|
||||||
} else if (currentVelocity > maxBoatSpeed + 500) {
|
} else if (currentVelocity > maxBoatSpeed + 500) {
|
||||||
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
|
yacht.changeVelocity(
|
||||||
|
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
|
||||||
} else {
|
} else {
|
||||||
yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier());
|
yacht
|
||||||
|
.setCurrentVelocity((maxBoatSpeed) * yacht.getBoatTypeAccelerationMultiplier());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (currentVelocity > 3000) {
|
if (currentVelocity > 3000) {
|
||||||
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
|
yacht.changeVelocity(
|
||||||
|
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
|
||||||
} else if (currentVelocity > 100) {
|
} else if (currentVelocity > 100) {
|
||||||
yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier());
|
yacht.changeVelocity(
|
||||||
|
(-currentVelocity / 50) * yacht.getBoatTypeAccelerationMultiplier());
|
||||||
} else if (currentVelocity <= 100) {
|
} else if (currentVelocity <= 100) {
|
||||||
yacht.setCurrentVelocity(0d);
|
yacht.setCurrentVelocity(0d);
|
||||||
}
|
}
|
||||||
@@ -534,7 +701,10 @@ 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);
|
||||||
@@ -555,6 +725,10 @@ public class GameState implements Runnable {
|
|||||||
* @param yacht The current yacht to check for
|
* @param yacht The current yacht to check for
|
||||||
*/
|
*/
|
||||||
private Boolean checkStartLineCrossing(ServerYacht yacht) {
|
private Boolean checkStartLineCrossing(ServerYacht yacht) {
|
||||||
|
long timeTillStart = System.currentTimeMillis() - this.getStartTime();
|
||||||
|
if (timeTillStart < 0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
|
Integer currentMarkSeqID = yacht.getCurrentMarkSeqID();
|
||||||
CompoundMark currentMark = markOrder.getCurrentMark(currentMarkSeqID);
|
CompoundMark currentMark = markOrder.getCurrentMark(currentMarkSeqID);
|
||||||
GeoPoint lastLocation = yacht.getLastLocation();
|
GeoPoint lastLocation = yacht.getLastLocation();
|
||||||
@@ -570,7 +744,9 @@ 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);
|
||||||
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line");
|
String logMessage = yacht.getBoatName() + " passed start line";
|
||||||
|
notifyMessageListeners(
|
||||||
|
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -674,7 +850,10 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,6 +876,7 @@ 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;
|
||||||
@@ -709,7 +889,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Mark checkMarkCollision(ServerYacht yacht) {
|
private static Mark checkMarkCollision(ServerYacht yacht) {
|
||||||
Set<Mark> marksInRace = GameState.getMarks();
|
Set<Mark> marksInRace = new HashSet<>(marks);
|
||||||
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) {
|
||||||
@@ -738,15 +918,22 @@ 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) {
|
private static ServerYacht checkYachtCollision(ServerYacht yacht, Boolean forBumperCollision) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -782,13 +969,6 @@ 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+");
|
||||||
@@ -796,17 +976,19 @@ public class GameState implements Runnable {
|
|||||||
switch (words[2].trim()) {
|
switch (words[2].trim()) {
|
||||||
case "/speed":
|
case "/speed":
|
||||||
try {
|
try {
|
||||||
setSpeedMultiplier(Double.valueOf(words[3]));
|
serverSpeedMultiplier = Double.valueOf(words[3]);
|
||||||
sendServerMessage(chatterMessage.getMessage_type(),
|
String logMessage = "Speed modifier set to x" + words[3];
|
||||||
"Speed modifier set to x" + words[3]);
|
notifyMessageListeners(MessageFactory
|
||||||
|
.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":
|
||||||
sendServerMessage(chatterMessage.getMessage_type(),
|
String logMessage = "Game will now finish";
|
||||||
"Game will now finish");
|
notifyMessageListeners(MessageFactory
|
||||||
|
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
|
||||||
endRace();
|
endRace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -856,6 +1038,12 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
public static void setMaxPlayers(Integer newMax){
|
public static void setMaxPlayers(Integer newMax){
|
||||||
maxPlayers = newMax;
|
maxPlayers = newMax;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerAdvertiser.getInstance().setCapacity(newMax);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Couldn't update max players");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void endRace () {
|
public static void endRace () {
|
||||||
@@ -863,11 +1051,11 @@ public class GameState implements Runnable {
|
|||||||
currentStage = GameStages.FINISHED;
|
currentStage = GameStages.FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setSpeedMultiplier (double multiplier) {
|
public static double getServerSpeedMultiplier() {
|
||||||
speedMultiplier = multiplier;
|
return serverSpeedMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getSpeedMultiplier () {
|
public static void setTokensEnabled (boolean tokensEnabled) {
|
||||||
return speedMultiplier;
|
GameState.tokensEnabled = tokensEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ import seng302.model.stream.xml.parser.RaceXMLData;
|
|||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing the overall server, which creates and collects server threads for each client
|
* A class describing the overall server, which creates and collects server threads for each client
|
||||||
* Created by wmu16 on 13/07/17.
|
* Created by wmu16 on 13/07/17.
|
||||||
@@ -30,12 +37,10 @@ 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;
|
||||||
|
private boolean hasStarted = false;
|
||||||
|
|
||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocket = null;
|
||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
@@ -59,7 +64,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
ServerAdvertiser.getInstance()
|
ServerAdvertiser.getInstance()
|
||||||
.setMapName(regattaXMLData.getCourseName())
|
.setMapName(regattaXMLData.getCourseName())
|
||||||
.setCapacity(capacity)
|
.setCapacity(capacity)
|
||||||
.setNumberOfPlayers(numPlayers)
|
.setNumberOfPlayers(numPlayers - 1)
|
||||||
.registerGame(PORT, regattaXMLData.getRegattaName());
|
.registerGame(PORT, regattaXMLData.getRegattaName());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Could not register server");
|
logger.warn("Could not register server");
|
||||||
@@ -80,16 +85,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startServer() {
|
private void startServer() {
|
||||||
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
||||||
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
|
||||||
GameState.setRace(raceXMLData);
|
GameState.setRace(raceXMLData);
|
||||||
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
startAdvertisingServer();
|
startAdvertisingServer();
|
||||||
PolarTable
|
|
||||||
.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
|
|
||||||
GameState.addMessageEventListener(this::broadcastMessage);
|
GameState.addMessageEventListener(this::broadcastMessage);
|
||||||
startUpdatingWind();
|
|
||||||
startSpawningTokens();
|
|
||||||
System.out.println("SAAAANNNNNNNNNDDDDDDDDDDDDDDDDDDDDDDDDDDdd");
|
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +99,14 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
new HeartbeatThread(this);
|
new HeartbeatThread(this);
|
||||||
new ServerListenThread(serverSocket, this);
|
new ServerListenThread(serverSocket, this);
|
||||||
|
|
||||||
|
hasStarted = true;
|
||||||
|
|
||||||
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
|
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
if (GameState.getPlayerHasLeftFlag()) {
|
if (GameState.getPlayerHasLeftFlag()) {
|
||||||
for (ServerToClientThread stc : serverToClientThreads) {
|
for (ServerToClientThread stc : serverToClientThreads) {
|
||||||
if (!stc.isSocketOpen()) {
|
if (!stc.isSocketOpen()) {
|
||||||
GameState.getYachts().remove(stc.getSourceId());
|
GameState.getYachts().remove(stc.getSourceId());
|
||||||
System.out.println("AAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
try {
|
try {
|
||||||
stc.getSocket().close();
|
stc.getSocket().close();
|
||||||
@@ -122,7 +124,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
|
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
|
||||||
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
System.out.println("gfdgfdgfdg");
|
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
GameState.resetCustomizationFlag();
|
GameState.resetCustomizationFlag();
|
||||||
}
|
}
|
||||||
@@ -148,9 +149,11 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
synchronized (this){
|
||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
serverToClientThread.terminate();
|
serverToClientThread.terminate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("IO error in server thread handler upon closing socket");
|
System.out.println("IO error in server thread handler upon closing socket");
|
||||||
@@ -164,6 +167,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendSetupMessages() {
|
private void sendSetupMessages() {
|
||||||
|
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
||||||
broadcastMessage(MessageFactory.getRaceXML());
|
broadcastMessage(MessageFactory.getRaceXML());
|
||||||
broadcastMessage(MessageFactory.getRegattaXML());
|
broadcastMessage(MessageFactory.getRegattaXML());
|
||||||
broadcastMessage(MessageFactory.getBoatXML());
|
broadcastMessage(MessageFactory.getBoatXML());
|
||||||
@@ -175,63 +179,6 @@ 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
|
||||||
*
|
*
|
||||||
@@ -259,22 +206,26 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
|
//serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
||||||
for (ServerYacht serverYacht : GameState.getYachts().values()) {
|
|
||||||
System.out.println("Connecterino" + serverYacht);
|
|
||||||
}
|
|
||||||
serverToClientThread.addConnectionListener(() -> {
|
|
||||||
System.out.println("LUSTENER");
|
|
||||||
sendSetupMessages();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Couldn't update advertisement");
|
logger.warn("Couldn't update advertisement");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (regattaXMLData == null && raceXMLData == null){
|
||||||
|
try {
|
||||||
|
Thread.sleep(50);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
||||||
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -295,6 +246,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
serverToClientThread.sendSetupMessages();
|
serverToClientThread.sendSetupMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -503,4 +455,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasStarted() {
|
||||||
|
return hasStarted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import seng302.gameServer.messages.*;
|
||||||
import java.util.ArrayList;
|
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;
|
||||||
@@ -11,6 +13,8 @@ import seng302.gameServer.messages.RaceStatusMessage;
|
|||||||
import seng302.gameServer.messages.RaceType;
|
import seng302.gameServer.messages.RaceType;
|
||||||
import seng302.gameServer.messages.XMLMessage;
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
@@ -18,8 +22,12 @@ import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
|||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.model.token.Token;
|
import seng302.model.token.Token;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class for interfacing between the data we have in the GameState to the messages we need to send
|
* A Class for interfacing between the data we have in the GameState to the messages we need to send
|
||||||
* through the MainServerThread.
|
* through the MainServerThread.
|
||||||
@@ -69,9 +77,9 @@ public class MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void updateBoats(List<ServerYacht> yachts) {
|
public static void updateBoats(List<ServerYacht> yachts) {
|
||||||
for (ServerYacht serverYacht : yachts) {
|
// for (ServerYacht serverYacht : yachts) {
|
||||||
System.out.println(serverYacht);
|
// System.out.println(serverYacht);
|
||||||
}
|
// }
|
||||||
xmlGenerator.getRace().setBoats(yachts);
|
xmlGenerator.getRace().setBoats(yachts);
|
||||||
String xmlStr = xmlGenerator.getBoatsAsXml();
|
String xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
@@ -152,4 +160,73 @@ public class MessageFactory {
|
|||||||
public static XMLMessage getBoatXML() {
|
public static XMLMessage getBoatXML() {
|
||||||
return boats;
|
return boats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
|
||||||
|
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) {
|
||||||
|
YachtEventType yachtEventType = null;
|
||||||
|
switch (token.getTokenType()) {
|
||||||
|
case BOOST:
|
||||||
|
yachtEventType = YachtEventType.TOKEN_VELOCITY;
|
||||||
|
break;
|
||||||
|
case HANDLING:
|
||||||
|
yachtEventType = YachtEventType.TOKEN_HANDLING;
|
||||||
|
break;
|
||||||
|
case WIND_WALKER:
|
||||||
|
yachtEventType = YachtEventType.TOKEN_WIND_WALKER;
|
||||||
|
break;
|
||||||
|
case BUMPER:
|
||||||
|
yachtEventType = YachtEventType.TOKEN_BUMPER;
|
||||||
|
break;
|
||||||
|
case RANDOM:
|
||||||
|
yachtEventType = YachtEventType.TOKEN_RANDOM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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,10 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.discoveryServer.DiscoveryServerClient;
|
||||||
|
import seng302.discoveryServer.util.ServerListing;
|
||||||
|
|
||||||
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 +37,16 @@ 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 Logger logger = LoggerFactory.getLogger(ServerAdvertiser.class);
|
||||||
|
|
||||||
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");
|
||||||
@@ -122,10 +131,13 @@ public class ServerAdvertiser {
|
|||||||
try {
|
try {
|
||||||
jmdnsInstance.registerService(serviceInfo);
|
jmdnsInstance.registerService(serviceInfo);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Failed");
|
logger.warn("Failed to register service info");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
ServerListing serverListing = new ServerListing(serverName, props.get("map"), new DiscoveryServerClient().getInetIp(), 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,17 @@ 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;
|
||||||
|
return System.currentTimeMillis() - lastRefreshed > EXPIRY_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hasBeenRefreshed(){
|
||||||
|
lastRefreshed = System.currentTimeMillis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.Checksum;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.messages.*;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.ChatterMessage;
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
@@ -31,8 +21,20 @@ import seng302.model.stream.xml.parser.RaceXMLData;
|
|||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.StreamParser;
|
import seng302.utilities.StreamParser;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.Checksum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -77,7 +79,6 @@ 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;
|
||||||
|
|
||||||
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
|
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
|
||||||
@@ -103,16 +104,15 @@ public class ServerToClientThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setUpPlayer(){
|
private void setUpPlayer(){
|
||||||
String fName = "Player" + GameState.getNumberOfPlayers().toString();
|
String shortName = "P" + sourceId;
|
||||||
String lName = "";
|
String longName = "Player " + sourceId;
|
||||||
|
|
||||||
ServerYacht yacht = new ServerYacht(
|
ServerYacht yacht = new ServerYacht(
|
||||||
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
BoatMeshType.DINGHY, sourceId, sourceId.toString(), shortName, longName, "NZ");
|
||||||
);
|
|
||||||
System.out.println(yacht);
|
|
||||||
player = new Player(socket, yacht);
|
player = new Player(socket, yacht);
|
||||||
GameState.addYacht(sourceId, yacht);
|
GameState.addYacht(sourceId, yacht);
|
||||||
GameState.addPlayer(player);
|
GameState.addPlayer(player);
|
||||||
System.out.println(GameState.getYachts().size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeRegistration(ClientType clientType) throws IOException {
|
private void completeRegistration(ClientType clientType) throws IOException {
|
||||||
@@ -136,9 +136,8 @@ public class ServerToClientThread implements Runnable {
|
|||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
isRegistered = true;
|
isRegistered = true;
|
||||||
os.write(responseMessage.getBuffer());
|
os.write(responseMessage.getBuffer());
|
||||||
System.out.println("MAKING A PLAYER");
|
|
||||||
setUpPlayer();
|
setUpPlayer();
|
||||||
System.out.println("DONE MAKING A PLAYER");
|
|
||||||
|
|
||||||
for (ConnectionListener listener : connectionListeners) {
|
for (ConnectionListener listener : connectionListeners) {
|
||||||
listener.notifyConnection();
|
listener.notifyConnection();
|
||||||
@@ -204,6 +203,7 @@ public class ServerToClientThread implements Runnable {
|
|||||||
XMLParser.parseRace(document)
|
XMLParser.parseRace(document)
|
||||||
);
|
);
|
||||||
GameState.setMaxPlayers(XMLParser.getMaxPlayers(document));
|
GameState.setMaxPlayers(XMLParser.getMaxPlayers(document));
|
||||||
|
GameState.setTokensEnabled(XMLParser.tokensEnabled(document));
|
||||||
break;
|
break;
|
||||||
case REGATTA_XML:
|
case REGATTA_XML:
|
||||||
regattaXMLProperty.set(
|
regattaXMLProperty.set(
|
||||||
@@ -300,10 +300,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class ChatterMessage extends Message {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMessage_type() {
|
public int getMessageType() {
|
||||||
return message_type;
|
return message_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,13 @@ public abstract class Message {
|
|||||||
* @return The current buffer as a byte array
|
* @return The current buffer as a byte array
|
||||||
*/
|
*/
|
||||||
public byte[] getBuffer(){
|
public byte[] getBuffer(){
|
||||||
return buffer.array();
|
byte[] bytes = buffer.array();
|
||||||
|
|
||||||
|
// buffer.reset();
|
||||||
|
// buffer.clear();
|
||||||
|
// buffer = null;
|
||||||
|
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,64 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerRegistrationMessage getEmptyRegistration() {
|
||||||
|
return new ServerRegistrationMessage("","","",0,0,0,"");
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,11 +1,18 @@
|
|||||||
package seng302.gameServer.messages;
|
package seng302.gameServer.messages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by wmu16 on 11/09/17.
|
* Enum for different event types for the yacht
|
||||||
*/
|
*/
|
||||||
public enum YachtEventType {
|
public enum YachtEventType {
|
||||||
COLLISION(33),
|
COLLISION(33),
|
||||||
TOKEN(34);
|
TOKEN_VELOCITY(34),
|
||||||
|
TOKEN_BUMPER(35),
|
||||||
|
TOKEN_HANDLING(36),
|
||||||
|
TOKEN_WIND_WALKER(37),
|
||||||
|
TOKEN_RANDOM(38),
|
||||||
|
POWER_DOWN(39),
|
||||||
|
BUMPER_CRASH(40);
|
||||||
|
|
||||||
|
|
||||||
private int code;
|
private int code;
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,15 @@ import javafx.beans.property.ReadOnlyIntegerProperty;
|
|||||||
import javafx.beans.property.ReadOnlyIntegerWrapper;
|
import javafx.beans.property.ReadOnlyIntegerWrapper;
|
||||||
import javafx.beans.property.ReadOnlyLongProperty;
|
import javafx.beans.property.ReadOnlyLongProperty;
|
||||||
import javafx.beans.property.ReadOnlyLongWrapper;
|
import javafx.beans.property.ReadOnlyLongWrapper;
|
||||||
|
import javafx.beans.value.ObservableObjectValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
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.visualiser.fxObjects.assets_3D.BoatMeshType;
|
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,6 +42,26 @@ 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
|
||||||
|
public interface PowerUpListener {
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
@@ -47,6 +72,7 @@ public class ClientYacht extends Observable {
|
|||||||
private String boatName;
|
private String boatName;
|
||||||
private String country;
|
private String country;
|
||||||
private Integer position;
|
private Integer position;
|
||||||
|
private TokenType powerUp;
|
||||||
|
|
||||||
private Long estimateTimeAtFinish;
|
private Long estimateTimeAtFinish;
|
||||||
private Boolean sailIn = true;
|
private Boolean sailIn = true;
|
||||||
@@ -65,6 +91,10 @@ public class ClientYacht extends Observable {
|
|||||||
|
|
||||||
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<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();
|
||||||
@@ -208,6 +238,32 @@ 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) {
|
||||||
|
this.powerUp = tokenType;
|
||||||
|
for (PowerUpListener listener : powerUpListeners) {
|
||||||
|
listener.notifyPowerUp(this, tokenType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenType getPowerUp() {
|
||||||
|
return powerUp;
|
||||||
|
}
|
||||||
|
|
||||||
public void toggleSail() {
|
public void toggleSail() {
|
||||||
sailIn = !sailIn;
|
sailIn = !sailIn;
|
||||||
}
|
}
|
||||||
@@ -257,6 +313,9 @@ 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) {
|
||||||
@@ -282,6 +341,18 @@ public class ClientYacht extends Observable {
|
|||||||
markRoundingListeners.add(listener);
|
markRoundingListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addPowerUpListener(PowerUpListener 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ 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
|
||||||
@@ -17,6 +19,7 @@ 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;
|
||||||
@@ -33,11 +36,13 @@ public final class PolarTable {
|
|||||||
upwindOptimal = new HashMap<>();
|
upwindOptimal = new HashMap<>();
|
||||||
downwindOptimal = new HashMap<>();
|
downwindOptimal = new HashMap<>();
|
||||||
|
|
||||||
String line;
|
String line = null;
|
||||||
|
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 ((line = br.readLine()) != null) {
|
while ((check = br.readLine()) != null) {
|
||||||
|
line = check;
|
||||||
String[] thisLine = line.split(",");
|
String[] thisLine = line.split(",");
|
||||||
|
|
||||||
//Initial line in file
|
//Initial line in file
|
||||||
@@ -66,7 +71,10 @@ 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");
|
||||||
@@ -74,6 +82,27 @@ 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
|
||||||
@@ -85,14 +114,18 @@ 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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class ServerYacht {
|
|||||||
//Boat info
|
//Boat info
|
||||||
private BoatMeshType boatType;
|
private BoatMeshType boatType;
|
||||||
private Double turnStep = 5.0;
|
private Double turnStep = 5.0;
|
||||||
private Double maxSpeedMultiplier = 1.0;
|
private Double boatTypeSpeedMultiplier = 1.0;
|
||||||
private Double turnStepMultiplier = 1.0;
|
private Double boatTypeTurnStepMultiplier = 1.0;
|
||||||
private Double accelerationMultiplier = 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,6 +55,8 @@ 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
|
//turning mode
|
||||||
private Boolean continuouslyTurning;
|
private Boolean continuouslyTurning;
|
||||||
@@ -78,11 +80,11 @@ 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;
|
this.continuouslyTurning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,13 +112,33 @@ 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() {
|
||||||
@@ -133,7 +155,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 * turnStepMultiplier);
|
Double newVal = heading + amount * powerUpHandlingMultiplier * boatTypeTurnStepMultiplier;
|
||||||
lastHeading = heading;
|
lastHeading = heading;
|
||||||
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
heading = (double) Math.floorMod(newVal.longValue(), 360L);
|
||||||
}
|
}
|
||||||
@@ -435,18 +457,18 @@ public class ServerYacht {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBoatType(BoatMeshType boatType) {
|
public void setBoatType(BoatMeshType boatType) {
|
||||||
this.accelerationMultiplier = boatType.accelerationMultiplier;
|
this.boatTypeAccelerationMultiplier = boatType.accelerationMultiplier;
|
||||||
this.maxSpeedMultiplier = boatType.maxSpeedMultiplier;
|
this.boatTypeSpeedMultiplier = boatType.maxSpeedMultiplier;
|
||||||
this.turnStepMultiplier = boatType.turnStep;
|
this.boatTypeTurnStepMultiplier = boatType.turnStep;
|
||||||
this.boatType = boatType;
|
this.boatType = boatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getMaxSpeedMultiplier() {
|
public Double getBoatTypeSpeedMultiplier() {
|
||||||
return maxSpeedMultiplier;
|
return boatTypeSpeedMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getAccelerationMultiplier(){
|
public Double getBoatTypeAccelerationMultiplier() {
|
||||||
return accelerationMultiplier;
|
return boatTypeAccelerationMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -457,4 +479,20 @@ public class ServerYacht {
|
|||||||
public void setContinuouslyTurning(Boolean continuouslyTurning) {
|
public void setContinuouslyTurning(Boolean continuouslyTurning) {
|
||||||
this.continuouslyTurning = 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ import seng302.model.stream.xml.parser.RaceXMLData;
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
|
|
||||||
|
|
||||||
public MarkOrder(RaceXMLData raceXMLData){
|
public MarkOrder(RaceXMLData raceXMLData){
|
||||||
@@ -25,6 +27,7 @@ public class MarkOrder {
|
|||||||
);
|
);
|
||||||
raceMarkOrder.add(compoundMark);
|
raceMarkOrder.add(compoundMark);
|
||||||
}
|
}
|
||||||
|
orderedUniqueCompoundMarks = new ArrayList<>(raceXMLData.getCompoundMarks().values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +42,10 @@ 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)
|
||||||
|
|||||||
@@ -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,5 +1,9 @@
|
|||||||
package seng302.model.token;
|
package seng302.model.token;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,13 +13,50 @@ import seng302.model.GeoPoint;
|
|||||||
public class Token extends GeoPoint {
|
public class Token extends GeoPoint {
|
||||||
|
|
||||||
private TokenType tokenType;
|
private TokenType tokenType;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a random type to the token (including the random type token)
|
||||||
|
*/
|
||||||
|
public void assignRandomType() {
|
||||||
|
tokenType = TokenType.values()[random.nextInt(TokenType.values().length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a random, concrete type to the token (cannot be the random type)
|
||||||
|
*/
|
||||||
|
public void realiseRandom() {
|
||||||
|
List<TokenType> tokenTypeList = new ArrayList<>(Arrays.asList(TokenType.values()));
|
||||||
|
tokenTypeList.remove(TokenType.RANDOM);
|
||||||
|
tokenType = tokenTypeList.get(random.nextInt(tokenTypeList.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exists for testing purposes only
|
||||||
|
*/
|
||||||
|
public void assignType(TokenType tokenType) {
|
||||||
|
this.tokenType = tokenType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,27 +5,32 @@ package seng302.model.token;
|
|||||||
* Created by wmu16 on 28/08/17.
|
* Created by wmu16 on 28/08/17.
|
||||||
*/
|
*/
|
||||||
public enum TokenType {
|
public enum TokenType {
|
||||||
BOOST(0),
|
|
||||||
HANDLING(1);
|
BOOST(0, "Boost", 10_000),
|
||||||
|
HANDLING(1, "Handling", 10_000),
|
||||||
|
BUMPER(2, "Bumper", 10_000),
|
||||||
|
WIND_WALKER(3, "Wind Walker", 10_000),
|
||||||
|
RANDOM(4, "Random", 10_000);
|
||||||
|
|
||||||
private int value;
|
private int value;
|
||||||
|
private String name;
|
||||||
|
private int timeout;
|
||||||
|
|
||||||
TokenType(int value) {
|
TokenType(int value, String name, int timeout) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
this.name = name;
|
||||||
|
this.timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getValue() {
|
public int getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TokenType getToken(int value) {
|
public String getName() {
|
||||||
switch (value) {
|
return name;
|
||||||
case 0:
|
}
|
||||||
return BOOST;
|
|
||||||
case 1:
|
public int getTimeout() {
|
||||||
return HANDLING;
|
return timeout;
|
||||||
default:
|
|
||||||
return BOOST;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
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 Object[] spawnCentres;
|
||||||
|
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);
|
||||||
|
spawnCentres = spawnRadii.keySet().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getRandomToken() {
|
||||||
|
GeoPoint randomSpawnCentre = (GeoPoint) spawnCentres[random.nextInt(spawnCentres.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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -101,6 +101,10 @@ public class Sounds {
|
|||||||
musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||||
musicPlayer.setVolume(0.3);
|
musicPlayer.setVolume(0.3);
|
||||||
musicPlayer.play();
|
musicPlayer.play();
|
||||||
|
musicPlayer.setMute(musicMuted);
|
||||||
|
if (soundEffect != null) {
|
||||||
|
soundEffect.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ public class StreamParser {
|
|||||||
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
||||||
String xmlMessage = new String(
|
String xmlMessage = new String(
|
||||||
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
||||||
System.out.println(xmlMessage);
|
|
||||||
//Create XML document Object
|
//Create XML document Object
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -201,11 +202,16 @@ public class XMLParser {
|
|||||||
public static Boolean tokensEnabled(Document doc) {
|
public static Boolean tokensEnabled(Document doc) {
|
||||||
Element docEle = doc.getDocumentElement();
|
Element docEle = doc.getDocumentElement();
|
||||||
try {
|
try {
|
||||||
Node tokenNode = docEle.getAttributeNode("Tokens");
|
NamedNodeMap namedNodeMap = docEle.getElementsByTagName("Tokens").item(0).getAttributes();
|
||||||
return Boolean.valueOf(XMLParser.getNodeAttributeString(tokenNode, "Enabled"));
|
Node node = namedNodeMap.getNamedItem("Enabled");
|
||||||
|
if (node != null) {
|
||||||
|
return Boolean.parseBoolean(node.getNodeValue());
|
||||||
|
}
|
||||||
} catch (NullPointerException npe) {
|
} catch (NullPointerException npe) {
|
||||||
|
npe.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getMaxPlayers(Document doc) {
|
public static Integer getMaxPlayers(Document doc) {
|
||||||
@@ -375,7 +381,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
||||||
* Look upon it and despair.
|
* Look upon it and despair.
|
||||||
* @param url the location of the race def file
|
* @param url The input file path
|
||||||
* @param serverName the name of the server
|
* @param serverName the name of the server
|
||||||
* @param repetitions the repetitions of a segment of the race def file.
|
* @param repetitions the repetitions of a segment of the race def file.
|
||||||
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
|
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
|
||||||
@@ -390,7 +396,7 @@ public class XMLParser {
|
|||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
db = dbf.newDocumentBuilder();
|
db = dbf.newDocumentBuilder();
|
||||||
doc = db.parse(url);
|
doc = db.parse(XMLParser.class.getResourceAsStream(url));
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.messages.*;
|
||||||
|
import seng302.model.stream.packets.PacketType;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -34,6 +43,7 @@ import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
|||||||
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
* A class describing a single connection to a Server for the purposes of sending and receiving on
|
||||||
@@ -41,6 +51,8 @@ import seng302.utilities.XMLParser;
|
|||||||
*/
|
*/
|
||||||
public class ClientToServerThread implements Runnable {
|
public class ClientToServerThread implements Runnable {
|
||||||
|
|
||||||
|
private boolean isStarted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional interface for receiving packets from client socket.
|
* Functional interface for receiving packets from client socket.
|
||||||
*/
|
*/
|
||||||
@@ -54,6 +66,11 @@ public class ClientToServerThread implements Runnable {
|
|||||||
void notifyDisconnection(String message);
|
void notifyDisconnection(String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ConnectionErrorListener {
|
||||||
|
void notifyConnectionError(String message);
|
||||||
|
}
|
||||||
|
|
||||||
private class ByteReadException extends Exception {
|
private class ByteReadException extends Exception {
|
||||||
private ByteReadException(String message) {
|
private ByteReadException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
@@ -63,6 +80,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
|
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
|
||||||
private List<ClientSocketListener> listeners = new ArrayList<>();
|
private List<ClientSocketListener> listeners = new ArrayList<>();
|
||||||
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
|
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
|
||||||
|
private ConnectionErrorListener connectionErrorListener = null;
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
@@ -110,6 +128,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* variable is false.
|
* variable is false.
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
|
isStarted = true;
|
||||||
|
|
||||||
int sync1;
|
int sync1;
|
||||||
int sync2;
|
int sync2;
|
||||||
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
@@ -140,10 +160,12 @@ public class ClientToServerThread implements Runnable {
|
|||||||
else {
|
else {
|
||||||
if (clientId == -1) continue; // Do not continue if not registered
|
if (clientId == -1) continue; // Do not continue if not registered
|
||||||
streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload));
|
streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload));
|
||||||
|
synchronized (this) {
|
||||||
for (ClientSocketListener csl : listeners)
|
for (ClientSocketListener csl : listeners)
|
||||||
csl.newPacket();
|
csl.newPacket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Packet has been dropped", 1);
|
logger.warn("Packet has been dropped", 1);
|
||||||
}
|
}
|
||||||
@@ -157,6 +179,11 @@ public class ClientToServerThread implements Runnable {
|
|||||||
logger.warn("Closed connection to server", 1);
|
logger.warn("Closed connection to server", 1);
|
||||||
notifyDisconnectListeners("Connection to server was terminated");
|
notifyDisconnectListeners("Connection to server was terminated");
|
||||||
closeSocket();
|
closeSocket();
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("Server rejected connection.");
|
||||||
|
ViewManager.getInstance().goToStartView();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendCustomizationRequest(CustomizeRequestType reqType, byte[] payload) {
|
public void sendCustomizationRequest(CustomizeRequestType reqType, byte[] payload) {
|
||||||
@@ -178,6 +205,12 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleConnectionError(String message){
|
||||||
|
if (connectionErrorListener != null){
|
||||||
|
connectionErrorListener.notifyConnectionError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a request to the server asking for a source ID
|
* Sends a request to the server asking for a source ID
|
||||||
*/
|
*/
|
||||||
@@ -217,8 +250,10 @@ public class ClientToServerThread implements Runnable {
|
|||||||
else{
|
else{
|
||||||
alertErrorText = "Could not connect to server";
|
alertErrorText = "Could not connect to server";
|
||||||
}
|
}
|
||||||
|
handleConnectionError("Server no longer available.");
|
||||||
notifyDisconnectListeners(alertErrorText);
|
notifyDisconnectListeners(alertErrorText);
|
||||||
closeSocket();
|
|
||||||
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -325,20 +360,32 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addStreamObserver (ClientSocketListener streamListener) {
|
public void addStreamObserver (ClientSocketListener streamListener) {
|
||||||
|
synchronized (this){
|
||||||
listeners.add(streamListener);
|
listeners.add(streamListener);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removeStreamObserver (ClientSocketListener streamListener) {
|
public void removeStreamObserver (ClientSocketListener streamListener) {
|
||||||
listeners.remove(streamListener);
|
listeners.remove(streamListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDisconnectionListener (DisconnectedFromHostListener listener) {
|
public void addDisconnectionListener (DisconnectedFromHostListener listener) {
|
||||||
|
synchronized (this){
|
||||||
disconnectionListeners.add(listener);
|
disconnectionListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removeDisconnectionListener (DisconnectedFromHostListener listener) {
|
public void removeDisconnectionListener (DisconnectedFromHostListener listener) {
|
||||||
|
synchronized (this){
|
||||||
disconnectionListeners.remove(listener);
|
disconnectionListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectionErrorListener(ConnectionErrorListener listener){
|
||||||
|
synchronized (this){
|
||||||
|
connectionErrorListener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int readByte() throws ByteReadException {
|
private int readByte() throws ByteReadException {
|
||||||
int currentByte = -1;
|
int currentByte = -1;
|
||||||
@@ -352,8 +399,9 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
if (currentByte == -1) {
|
if (currentByte == -1) {
|
||||||
notifyDisconnectListeners("Cannot read from server.");
|
notifyDisconnectListeners("Cannot read from server.");
|
||||||
closeSocket();
|
|
||||||
logger.warn("InputStream reach end of stream", 1);
|
logger.warn("InputStream reach end of stream", 1);
|
||||||
|
handleConnectionError("Could not connect to server. Server is no longer available.");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
return currentByte;
|
return currentByte;
|
||||||
}
|
}
|
||||||
@@ -396,4 +444,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
).getBuffer()
|
).getBuffer()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasStarted() {
|
||||||
|
return isStarted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +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.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;
|
||||||
@@ -37,6 +39,7 @@ import seng302.model.stream.parser.RaceStatusData;
|
|||||||
import seng302.model.stream.parser.YachtEventData;
|
import seng302.model.stream.parser.YachtEventData;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.utilities.StreamParser;
|
import seng302.utilities.StreamParser;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
@@ -92,7 +95,6 @@ public class GameClient {
|
|||||||
socketThread.addDisconnectionListener((cause) -> {
|
socketThread.addDisconnectionListener((cause) -> {
|
||||||
showConnectionError(cause);
|
showConnectionError(cause);
|
||||||
tearDownConnection();
|
tearDownConnection();
|
||||||
Platform.runLater(this::loadStartScreen);
|
|
||||||
});
|
});
|
||||||
socketThread.addStreamObserver(this::parsePackets);
|
socketThread.addStreamObserver(this::parsePackets);
|
||||||
|
|
||||||
@@ -109,13 +111,23 @@ public class GameClient {
|
|||||||
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
||||||
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
||||||
|
|
||||||
|
getServerThread().setConnectionErrorListener((eMessage) -> {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar(eMessage);
|
||||||
|
//destroyClientToServerThread();
|
||||||
|
});
|
||||||
|
|
||||||
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
showConnectionError("Unable to find server");
|
ViewManager.getInstance().showErrorSnackBar("There are no servers currently available.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void destroyClientToServerThread() {
|
||||||
|
socketThread.closeSocket();
|
||||||
|
socketThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a game as the host at the given address and starts the visualiser.
|
* Connect to a game as the host at the given address and starts the visualiser.
|
||||||
* @param ipAddress IP to connect to.
|
* @param ipAddress IP to connect to.
|
||||||
@@ -129,18 +141,45 @@ public class GameClient {
|
|||||||
|
|
||||||
server = new MainServerThread();
|
server = new MainServerThread();
|
||||||
|
|
||||||
|
while (!server.hasStarted()){
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, 4942);
|
startClientToServerThread(ipAddress, 4942);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
showConnectionError("Cannot connect to server as host");
|
showConnectionError("Cannot connect to server as host");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for C2S thread
|
||||||
|
while (!socketThread.hasStarted()){
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled);
|
socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled);
|
||||||
while (regattaData == null){
|
|
||||||
|
int triesLeft = 15;
|
||||||
|
|
||||||
|
while (regattaData == null && triesLeft > 0){
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
triesLeft--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triesLeft <= 0){
|
||||||
|
showConnectionError("Could not launch server");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lobbyController = ViewManager.getInstance().goToLobby(false);
|
this.lobbyController = ViewManager.getInstance().goToLobby(false);
|
||||||
@@ -157,16 +196,6 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadStartScreen() {
|
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
|
||||||
getClass().getResource("/views/StartScreenView.fxml"));
|
|
||||||
try {
|
|
||||||
holderPane.getChildren().clear();
|
|
||||||
holderPane.getChildren().add(fxmlLoader.load());
|
|
||||||
} catch (IOException e) {
|
|
||||||
showConnectionError("JavaFX crashed. Please restart the app");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showConnectionError (String message) {
|
private void showConnectionError (String message) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
@@ -214,7 +243,6 @@ public class GameClient {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RACE_XML:
|
case RACE_XML:
|
||||||
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
|
|
||||||
RaceXMLData raceXMLData = XMLParser.parseRace(
|
RaceXMLData raceXMLData = XMLParser.parseRace(
|
||||||
StreamParser.extractXmlMessage(packet)
|
StreamParser.extractXmlMessage(packet)
|
||||||
);
|
);
|
||||||
@@ -254,12 +282,7 @@ public class GameClient {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case YACHT_EVENT_CODE:
|
case YACHT_EVENT_CODE:
|
||||||
YachtEventData yachtEventData = StreamParser.extractYachtEventCode(packet);
|
processYachtEvent(StreamParser.extractYachtEventCode(packet));
|
||||||
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
|
|
||||||
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
|
||||||
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN.getCode()) {
|
|
||||||
showPickUp();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHATTER_TEXT:
|
case CHATTER_TEXT:
|
||||||
@@ -279,12 +302,14 @@ public class GameClient {
|
|||||||
|
|
||||||
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
|
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
|
||||||
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
||||||
|
raceView.showView();
|
||||||
raceView.getSendPressedProperty().addListener((obs, old, isPressed) -> {
|
raceView.getSendPressedProperty().addListener((obs, old, isPressed) -> {
|
||||||
if (isPressed) {
|
if (isPressed) {
|
||||||
formatAndSendChatMessage(raceView.readChatInput());
|
formatAndSendChatMessage(raceView.readChatInput());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
gameKeyBind.toggleTurningMode();
|
||||||
|
sendToggleTurningModePacket(); // notify the server about player's steering mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,21 +443,66 @@ public class GameClient {
|
|||||||
return courseData;
|
return courseData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appropriately displays the event client side given the YachtEventCode (collision / token..)
|
||||||
|
*
|
||||||
|
* @param yachtEventData The YachtEvent data packet
|
||||||
|
*/
|
||||||
|
private void processYachtEvent(YachtEventData yachtEventData) {
|
||||||
|
ClientYacht thisYacht = allBoatsMap.get(yachtEventData.getSubjectId().intValue());
|
||||||
|
|
||||||
|
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
|
||||||
|
showCollisionAlert(thisYacht);
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.POWER_DOWN.getCode()) {
|
||||||
|
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;
|
||||||
|
if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) {
|
||||||
|
tokenType = TokenType.BOOST;
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_BUMPER.getCode()) {
|
||||||
|
tokenType = TokenType.BUMPER;
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_HANDLING.getCode()) {
|
||||||
|
tokenType = TokenType.HANDLING;
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_RANDOM.getCode()) {
|
||||||
|
tokenType = TokenType.RANDOM;
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_WIND_WALKER.getCode()) {
|
||||||
|
tokenType = TokenType.WIND_WALKER;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sounds.playTokenPickupSound();
|
||||||
|
thisYacht.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(YachtEventData yachtEventData) {
|
private void showCollisionAlert(ClientYacht yacht) {
|
||||||
Sounds.playCrashSound();
|
Sounds.playCrashSound();
|
||||||
raceState.storeCollision(
|
raceState.storeCollision(yacht);
|
||||||
allBoatsMap.get(
|
|
||||||
yachtEventData.getSubjectId().intValue()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
|
|
||||||
private void showPickUp() {
|
|
||||||
Sounds.playTokenPickupSound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void formatAndSendChatMessage(String rawChat) {
|
private void formatAndSendChatMessage(String rawChat) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import seng302.model.mark.CompoundMark;
|
|||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common elements of game visualizing classes.
|
* Abstract class for keeping functionality common between race visualisation.
|
||||||
*/
|
*/
|
||||||
public abstract class GameView {
|
public abstract class GameView {
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.geometry.Point3D;
|
import javafx.geometry.Point3D;
|
||||||
import javafx.scene.Camera;
|
import javafx.scene.Camera;
|
||||||
@@ -15,11 +16,13 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.PerspectiveCamera;
|
import javafx.scene.PerspectiveCamera;
|
||||||
import javafx.scene.SceneAntialiasing;
|
import javafx.scene.SceneAntialiasing;
|
||||||
import javafx.scene.SubScene;
|
import javafx.scene.SubScene;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.transform.Rotate;
|
import javafx.scene.transform.Rotate;
|
||||||
import javafx.scene.transform.Scale;
|
import javafx.scene.transform.Scale;
|
||||||
import javafx.scene.transform.Translate;
|
import javafx.scene.transform.Translate;
|
||||||
|
import org.fxyz3d.scene.Skybox;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.GameKeyBind;
|
import seng302.model.GameKeyBind;
|
||||||
@@ -40,12 +43,14 @@ import seng302.visualiser.controllers.ViewManager;
|
|||||||
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
import seng302.visualiser.fxObjects.assets_3D.Marker3D;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.Model;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of animated3D assets that displays a race.
|
* Collection of animated3D assets that displays a race.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class GameView3D extends GameView {
|
public class GameView3D extends GameView {
|
||||||
|
|
||||||
private final double FOV = 60;
|
private final double FOV = 60;
|
||||||
@@ -54,6 +59,8 @@ public class GameView3D extends GameView{
|
|||||||
|
|
||||||
private Group root3D;
|
private Group root3D;
|
||||||
private SubScene view;
|
private SubScene view;
|
||||||
|
private Group gameObjects;
|
||||||
|
|
||||||
private Group raceBorder = new Group();
|
private Group raceBorder = new Group();
|
||||||
// Cameras
|
// Cameras
|
||||||
private PerspectiveCamera isometricCam;
|
private PerspectiveCamera isometricCam;
|
||||||
@@ -63,14 +70,16 @@ public class GameView3D extends GameView{
|
|||||||
/* Note that if either of these is null then values for it have not been added and the other
|
/* Note that if either of these is null then values for it have not been added and the other
|
||||||
should be used as the limits of the map. */
|
should be used as the limits of the map. */
|
||||||
private Map<Mark, Marker3D> markerObjects;
|
private Map<Mark, Marker3D> markerObjects;
|
||||||
|
|
||||||
|
private BoatObject playerBoat;
|
||||||
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
|
||||||
private BoatObject selectedBoat = null;
|
|
||||||
private Group wakesGroup = new Group();
|
private Group wakesGroup = new Group();
|
||||||
private Group boatObjectGroup = new Group();
|
private Group boatObjectGroup = new Group();
|
||||||
private List<Node> mapTokens;
|
private List<Node> mapTokens;
|
||||||
private AnimationTimer playerBoatAnimationTimer;
|
private AnimationTimer playerBoatAnimationTimer;
|
||||||
private Group trail = new Group();
|
private Group trail = new Group();
|
||||||
private Double windDir;
|
private Double windDir;
|
||||||
|
private Skybox skybox;
|
||||||
|
|
||||||
public GameView3D () {
|
public GameView3D () {
|
||||||
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
|
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
|
||||||
@@ -80,7 +89,7 @@ public class GameView3D extends GameView{
|
|||||||
canvasWidth = canvasHeight = 300;
|
canvasWidth = canvasHeight = 300;
|
||||||
|
|
||||||
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
|
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
|
||||||
pc.setFarClip(600);
|
pc.setFarClip(100000);
|
||||||
pc.setNearClip(0.1);
|
pc.setNearClip(0.1);
|
||||||
pc.setFieldOfView(FOV);
|
pc.setFieldOfView(FOV);
|
||||||
}
|
}
|
||||||
@@ -88,21 +97,26 @@ public class GameView3D extends GameView{
|
|||||||
gameObjects = new Group();
|
gameObjects = new Group();
|
||||||
root3D = new Group(isometricCam, gameObjects);
|
root3D = new Group(isometricCam, gameObjects);
|
||||||
view = new SubScene(
|
view = new SubScene(
|
||||||
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
|
root3D, 5000, 3000, true, SceneAntialiasing.BALANCED
|
||||||
);
|
);
|
||||||
view.setCamera(isometricCam);
|
view.setCamera(isometricCam);
|
||||||
|
|
||||||
|
skybox = new Skybox(new Image(getClass().getResourceAsStream("/images/skybox.jpg")), 100000, isometricCam);
|
||||||
|
skybox.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS));
|
||||||
|
|
||||||
|
Model land = ModelFactory.importModel(ModelType.LAND_SMOOTH);
|
||||||
|
land.getAssets().getTransforms().add(new Rotate(90, Rotate.X_AXIS));
|
||||||
|
|
||||||
gameObjects.getChildren().addAll(
|
gameObjects.getChildren().addAll(
|
||||||
ModelFactory.importModel(ModelType.OCEAN).getAssets(),
|
raceBorder, trail, markers, tokens, skybox, land.getAssets()
|
||||||
raceBorder, trail, markers, tokens
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
view.sceneProperty().addListener((obs, old, scene) -> {
|
view.sceneProperty().addListener((obs, old, scene) -> {
|
||||||
if (scene != null) {
|
if (scene != null) {
|
||||||
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -262,6 +276,7 @@ public class GameView3D extends GameView{
|
|||||||
public void cameraMovement(KeyEvent event) {
|
public void cameraMovement(KeyEvent event) {
|
||||||
GameKeyBind keyBinds = GameKeyBind.getInstance();
|
GameKeyBind keyBinds = GameKeyBind.getInstance();
|
||||||
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
|
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
|
||||||
|
if (keyPressed != null) {
|
||||||
switch (keyPressed) {
|
switch (keyPressed) {
|
||||||
case ZOOM_IN:
|
case ZOOM_IN:
|
||||||
((RaceCamera) view.getCamera()).zoomIn();
|
((RaceCamera) view.getCamera()).zoomIn();
|
||||||
@@ -286,6 +301,7 @@ public class GameView3D extends GameView{
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void toggleCamera() {
|
private void toggleCamera() {
|
||||||
Camera currCamera = view.getCamera();
|
Camera currCamera = view.getCamera();
|
||||||
@@ -314,19 +330,42 @@ public class GameView3D extends GameView{
|
|||||||
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((boat, lat, lon, heading, sailIn, velocity) -> {
|
clientYacht.addLocationListener(this::updateBoatLocation);
|
||||||
BoatObject bo = boatObjects.get(boat);
|
clientYacht.addColorChangeListener(this::updateBoatColor);
|
||||||
Point2D p2d = scaledPoint.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) chaseCam).setPlayerBoat(newBoat);
|
||||||
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
|
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
|
||||||
|
|
||||||
|
newBoat.setMarkIndicator(ModelFactory.importSTL("mark_pointer.stl"));
|
||||||
|
playerBoat = newBoat;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
|
ClientYacht playerYacht = ViewManager.getInstance().getGameClient().getAllBoatsMap()
|
||||||
|
.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId());
|
||||||
|
|
||||||
|
for (ObservableValue o : Arrays
|
||||||
|
.asList(playerBoat.layoutXProperty(), playerBoat.layoutXProperty())) {
|
||||||
|
o.addListener((obs, oldVal, newVal) -> {
|
||||||
|
|
||||||
|
List<Mark> marks = course.get(playerYacht.getLegNumber()).getMarks();
|
||||||
|
Point2D midPoint = new Point2D(0, 0);
|
||||||
|
if (marks.size() == 1) {
|
||||||
|
midPoint = scaledPoint.findScaledXY(marks.get(0));
|
||||||
|
} else if (marks.size() == 2) {
|
||||||
|
midPoint = (scaledPoint.findScaledXY(marks.get(0)))
|
||||||
|
.midpoint(scaledPoint.findScaledXY(marks.get(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (midPoint != null) {
|
||||||
|
playerBoat.updateMarkIndicator(midPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
gameObjects.getChildren().addAll(wakes);
|
gameObjects.getChildren().addAll(wakes);
|
||||||
gameObjects.getChildren().addAll(boatObjectGroup);
|
gameObjects.getChildren().addAll(boatObjectGroup);
|
||||||
});
|
});
|
||||||
@@ -336,6 +375,23 @@ public class GameView3D extends GameView{
|
|||||||
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 = scaledPoint.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.
|
||||||
@@ -413,7 +469,27 @@ public class GameView3D extends GameView{
|
|||||||
mapTokens = new ArrayList<>();
|
mapTokens = new ArrayList<>();
|
||||||
for (Token token : newTokens) {
|
for (Token token : newTokens) {
|
||||||
Point2D location = scaledPoint.findScaledXY(token.getLat(), token.getLng());
|
Point2D location = scaledPoint.findScaledXY(token.getLat(), token.getLng());
|
||||||
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
|
||||||
|
ModelType modelType = null;
|
||||||
|
switch (token.getTokenType()) {
|
||||||
|
case BOOST:
|
||||||
|
modelType = ModelType.VELOCITY_PICKUP;
|
||||||
|
break;
|
||||||
|
case HANDLING:
|
||||||
|
modelType = ModelType.HANDLING_PICKUP;
|
||||||
|
break;
|
||||||
|
case BUMPER:
|
||||||
|
modelType = ModelType.BUMPER_PICKUP;
|
||||||
|
break;
|
||||||
|
case RANDOM:
|
||||||
|
modelType = ModelType.RANDOM_PICKUP;
|
||||||
|
break;
|
||||||
|
case WIND_WALKER:
|
||||||
|
modelType = ModelType.WIND_WALKER_PICKUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node tokenObject = ModelFactory.importModel(modelType).getAssets();
|
||||||
tokenObject.setLayoutX(location.getX());
|
tokenObject.setLayoutX(location.getX());
|
||||||
tokenObject.setLayoutY(location.getY());
|
tokenObject.setLayoutY(location.getY());
|
||||||
mapTokens.add(tokenObject);
|
mapTokens.add(tokenObject);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
@@ -34,6 +35,8 @@ public class MapMaker {
|
|||||||
private int index = 0;
|
private int index = 0;
|
||||||
private XMLGenerator xmlGenerator = new XMLGenerator();
|
private XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
|
||||||
|
private List<String> maps = new ArrayList<>(Arrays.asList("default.xml", "horseshoe.xml", "loop.xml"));
|
||||||
|
|
||||||
public static MapMaker getInstance() {
|
public static MapMaker getInstance() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new MapMaker();
|
instance = new MapMaker();
|
||||||
@@ -42,15 +45,17 @@ public class MapMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MapMaker() {
|
private MapMaker() {
|
||||||
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
|
for (String mapPath : maps){
|
||||||
File[] directoryListing = dir.listFiles();
|
String path = ("/maps/" + mapPath);
|
||||||
if (directoryListing != null) {
|
|
||||||
for (File child : directoryListing) {
|
|
||||||
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
||||||
child.getAbsolutePath(), "", 1, null, false
|
path, "", 1, null, false
|
||||||
);
|
);
|
||||||
filePaths.add(child.getAbsolutePath());
|
|
||||||
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
|
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
|
||||||
|
|
||||||
|
filePaths.add(path);
|
||||||
|
|
||||||
regattas.add(new RegattaXMLData(
|
regattas.add(new RegattaXMLData(
|
||||||
regattaTemplate.getRegattaId(),
|
regattaTemplate.getRegattaId(),
|
||||||
regattaTemplate.getName(),
|
regattaTemplate.getName(),
|
||||||
@@ -79,9 +84,10 @@ public class MapMaker {
|
|||||||
new ArrayList<>(race.getCompoundMarks().values()),
|
new ArrayList<>(race.getCompoundMarks().values()),
|
||||||
race.getMarkSequence(), race.getCourseLimit()
|
race.getMarkSequence(), race.getCourseLimit()
|
||||||
));
|
));
|
||||||
|
|
||||||
races.add(race);
|
races.add(race);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import seng302.visualiser.fxObjects.assets_2D.Marker2D;
|
|||||||
public class MapPreview extends GameView {
|
public class MapPreview extends GameView {
|
||||||
|
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
private Map<Mark, Marker2D> markerObjects;
|
protected Map<Mark, Marker2D> markerObjects;
|
||||||
|
|
||||||
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
|
||||||
this.compoundMarks = marks;
|
this.compoundMarks = marks;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package seng302.visualiser;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.shape.Polygon;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.mark.Corner;
|
||||||
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class converts a map preview to a minimap by adding boats.
|
||||||
|
*/
|
||||||
|
public class MiniMap extends MapPreview {
|
||||||
|
|
||||||
|
private HashMap<ClientYacht, Polygon> boatIcons = new HashMap<>();
|
||||||
|
private Polygon playerBoat;
|
||||||
|
private double playerRotation;
|
||||||
|
private List<ClientYacht> boats;
|
||||||
|
private ClientYacht player;
|
||||||
|
|
||||||
|
public MiniMap (List<CompoundMark> marks, List<Corner> course, List<Limit> border, List<ClientYacht> boats, ClientYacht player) {
|
||||||
|
super(marks, course, border);
|
||||||
|
this.boats = boats;
|
||||||
|
this.player = player;
|
||||||
|
setBoats(boats);
|
||||||
|
player.addMarkRoundingListener(this::updateMarkArrows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoats(List<ClientYacht> yachts) {
|
||||||
|
for (ClientYacht yacht : yachts) {
|
||||||
|
Polygon boatIcon = new Polygon(0, -3.5, 3.5, 3.5, -3.5, 3.5);
|
||||||
|
boatIcon.setStroke(Color.BLACK);
|
||||||
|
boatIcon.setFill(Color.GRAY);
|
||||||
|
boatIcon.setFill(yacht.getColour());
|
||||||
|
boatIcon.setFill(yacht.getColour());
|
||||||
|
boatIcons.put(yacht, boatIcon);
|
||||||
|
boatIcon.getTransforms().add(new Rotate(0));
|
||||||
|
yacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Polygon bi = boatIcons.get(boat);
|
||||||
|
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
|
||||||
|
bi.setLayoutX(p2d.getX());
|
||||||
|
bi.setLayoutY(p2d.getY());
|
||||||
|
((Rotate) bi.getTransforms().get(0)).setAngle(heading);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
gameObjects.getChildren().addAll(boatIcons.values());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
|
||||||
|
CompoundMark compoundMark;
|
||||||
|
if (legNumber - 1 >= 0) {
|
||||||
|
Sounds.playMarkRoundingSound();
|
||||||
|
compoundMark = course.get(legNumber-1);
|
||||||
|
for (Mark mark : compoundMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).showNextExitArrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompoundMark nextMark = null;
|
||||||
|
if (legNumber < course.size() - 1) {
|
||||||
|
Sounds.playMarkRoundingSound();
|
||||||
|
nextMark = course.get(legNumber);
|
||||||
|
for (Mark mark : nextMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).showNextEnterArrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (legNumber - 2 >= 0) {
|
||||||
|
CompoundMark lastMark = course.get(Math.max(0, legNumber - 2));
|
||||||
|
if (lastMark != nextMark) {
|
||||||
|
for (Mark mark : lastMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).hideAllArrows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,31 @@ import com.jfoenix.controls.JFXDialog;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.Group;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Scale;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
import seng302.discoveryServer.DiscoveryServerClient;
|
||||||
import seng302.gameServer.GameStages;
|
import seng302.gameServer.GameStages;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
@@ -32,6 +43,10 @@ import seng302.utilities.Sounds;
|
|||||||
import seng302.visualiser.MapPreview;
|
import seng302.visualiser.MapPreview;
|
||||||
import seng302.visualiser.controllers.cells.PlayerCell;
|
import seng302.visualiser.controllers.cells.PlayerCell;
|
||||||
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
|
||||||
|
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
||||||
|
import seng302.visualiser.controllers.dialogs.TokenInfoDialogController;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||||
|
|
||||||
public class LobbyController implements Initializable {
|
public class LobbyController implements Initializable {
|
||||||
|
|
||||||
@@ -53,10 +68,15 @@ public class LobbyController implements Initializable {
|
|||||||
private Label mapName;
|
private Label mapName;
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane serverMap;
|
private AnchorPane serverMap;
|
||||||
|
@FXML
|
||||||
|
private Label roomLabel;
|
||||||
|
@FXML
|
||||||
|
private Pane speedTokenPane, handlingTokenPane, windWalkerTokenPane, bumperTokenPane, randomTokenPane;
|
||||||
//---------FXML END---------//
|
//---------FXML END---------//
|
||||||
|
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
private JFXDialog customizationDialog;
|
private JFXDialog customizationDialog;
|
||||||
|
private JFXDialog tokenInfoDialog;
|
||||||
public Color playersColor;
|
public Color playersColor;
|
||||||
private Map<Integer, ClientYacht> playerBoats;
|
private Map<Integer, ClientYacht> playerBoats;
|
||||||
private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT;
|
private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT;
|
||||||
@@ -64,7 +84,7 @@ public class LobbyController implements Initializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
roomLabel.setText("");
|
||||||
this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap();
|
this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap();
|
||||||
|
|
||||||
if (this.playersColor == null) {
|
if (this.playersColor == null) {
|
||||||
@@ -87,6 +107,21 @@ 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"));
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
while (DiscoveryServerClient.getRoomCode() == null && tries <= 10){
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
tries ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
@@ -109,6 +144,107 @@ public class LobbyController implements Initializable {
|
|||||||
beginRaceButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
beginRaceButton.setOnMouseEntered(e -> Sounds.playHoverSound());
|
||||||
|
|
||||||
initMapPreview();
|
initMapPreview();
|
||||||
|
initTokenPreviews();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the tokens in the side panel
|
||||||
|
*/
|
||||||
|
private void initTokenPreviews() {
|
||||||
|
Group speedToken = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
|
||||||
|
Group handlingToken = ModelFactory.importModel(ModelType.HANDLING_PICKUP).getAssets();
|
||||||
|
Group windWalkerToken = ModelFactory.importModel(ModelType.WIND_WALKER_PICKUP).getAssets();
|
||||||
|
Group bumperToken = ModelFactory.importModel(ModelType.BUMPER_PICKUP).getAssets();
|
||||||
|
Group randomToken = ModelFactory.importModel(ModelType.RANDOM_PICKUP).getAssets();
|
||||||
|
|
||||||
|
HashMap<Pane, Group> tokenPanes = new HashMap<>();
|
||||||
|
tokenPanes.put(speedTokenPane, speedToken);
|
||||||
|
tokenPanes.put(handlingTokenPane, handlingToken);
|
||||||
|
tokenPanes.put(windWalkerTokenPane, windWalkerToken);
|
||||||
|
tokenPanes.put(bumperTokenPane, bumperToken);
|
||||||
|
tokenPanes.put(randomTokenPane, randomToken);
|
||||||
|
|
||||||
|
Scale hoverScale = new Scale(1.2, 1.2, 1.2);
|
||||||
|
|
||||||
|
tokenPanes.entrySet().forEach((entry) -> {
|
||||||
|
Pane thisPane = entry.getKey();
|
||||||
|
Group thisToken = entry.getValue();
|
||||||
|
|
||||||
|
thisToken.getTransforms().addAll(
|
||||||
|
new Translate(40, 50, 0),
|
||||||
|
new Scale(13, 13, 13));
|
||||||
|
|
||||||
|
thisPane.setOnMouseEntered(event -> {
|
||||||
|
thisToken.getTransforms().add(hoverScale);
|
||||||
|
});
|
||||||
|
thisPane.setOnMouseExited(event -> {
|
||||||
|
thisToken.getTransforms().remove(hoverScale);
|
||||||
|
});
|
||||||
|
thisPane.setOnMouseReleased(event -> {
|
||||||
|
tokenInfoDialog = makeTokenDialog(thisPane);
|
||||||
|
tokenInfoDialog.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
thisPane.getChildren().add(thisToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Hacky rotations for wind and random to level it in the plane
|
||||||
|
windWalkerToken.getTransforms().addAll(
|
||||||
|
new Rotate(-70, new Point3D(1, 0, 0)),
|
||||||
|
new Translate(0, 2,0)
|
||||||
|
);
|
||||||
|
randomToken.getTransforms().addAll(
|
||||||
|
new Rotate(-90, new Point3D(1, 0, 0)),
|
||||||
|
new Translate(0, 0,1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JFXDialog makeTokenDialog(Pane inducingPane) {
|
||||||
|
String header = "...";
|
||||||
|
String body = "Nothing to see here";
|
||||||
|
ModelType modelType = ModelType.RANDOM_PICKUP;
|
||||||
|
|
||||||
|
if (inducingPane == speedTokenPane) {
|
||||||
|
header = "Speed Boost";
|
||||||
|
body = "Increases your max velocity";
|
||||||
|
modelType = ModelType.VELOCITY_PICKUP;
|
||||||
|
} else if (inducingPane == handlingTokenPane) {
|
||||||
|
header = "Handling Boost";
|
||||||
|
body = "Increases your turing rate";
|
||||||
|
modelType = ModelType.HANDLING_PICKUP;
|
||||||
|
} else if (inducingPane == windWalkerTokenPane) {
|
||||||
|
header = "Wind Walker";
|
||||||
|
body = "The wind now rotates with you, giving you your optimal speed in all directions";
|
||||||
|
modelType = ModelType.WIND_WALKER_PICKUP;
|
||||||
|
} else if (inducingPane == bumperTokenPane) {
|
||||||
|
header = "Bumper";
|
||||||
|
body = "While this is active, upon hitting another boat, you will power it down for a short time";
|
||||||
|
modelType = ModelType.BUMPER_PICKUP;
|
||||||
|
} else if (inducingPane == randomTokenPane) {
|
||||||
|
header = "Random";
|
||||||
|
body = "A 50% chance of becoming any other token and a 50% chance of slowing your boat for a time";
|
||||||
|
modelType = ModelType.RANDOM_PICKUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
FXMLLoader dialog = new FXMLLoader(
|
||||||
|
getClass().getResource("/views/dialogs/TokenInfoDialog.fxml"));
|
||||||
|
|
||||||
|
JFXDialog tokenInfoDialog = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
tokenInfoDialog = new JFXDialog(serverListMainStackPane, dialog.load(),
|
||||||
|
JFXDialog.DialogTransition.CENTER);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenInfoDialogController controller = dialog.getController();
|
||||||
|
controller.setParentController(this);
|
||||||
|
controller.setHeader(header);
|
||||||
|
controller.setContent(body);
|
||||||
|
controller.setToken(modelType);
|
||||||
|
return tokenInfoDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JFXDialog createCustomizeDialog() {
|
private JFXDialog createCustomizeDialog() {
|
||||||
@@ -137,6 +273,7 @@ public class LobbyController implements Initializable {
|
|||||||
return customizationDialog;
|
return customizationDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a top down preview of the race course map.
|
* Initializes a top down preview of the race course map.
|
||||||
*/
|
*/
|
||||||
@@ -231,4 +368,12 @@ public class LobbyController implements Initializable {
|
|||||||
public void closeCustomizationDialog() {
|
public void closeCustomizationDialog() {
|
||||||
customizationDialog.close();
|
customizationDialog.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeTokenInfoDialog() {
|
||||||
|
tokenInfoDialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomCode(String roomCode) {
|
||||||
|
roomLabel.setText("Room: " + roomCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,68 +4,47 @@ import com.jfoenix.controls.JFXButton;
|
|||||||
import com.jfoenix.controls.JFXDialog;
|
import com.jfoenix.controls.JFXDialog;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.TimeUnit;
|
import javafx.animation.RotateTransition;
|
||||||
import javafx.animation.Timeline;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.geometry.Point2D;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.SubScene;
|
import javafx.scene.SubScene;
|
||||||
import javafx.scene.chart.LineChart;
|
|
||||||
import javafx.scene.chart.NumberAxis;
|
|
||||||
import javafx.scene.chart.XYChart.Series;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.scene.control.ComboBox;
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Line;
|
import javafx.util.Duration;
|
||||||
import javafx.scene.shape.Polyline;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
import javafx.stage.StageStyle;
|
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
import seng302.model.mark.CompoundMark;
|
|
||||||
import seng302.model.mark.Mark;
|
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameView3D;
|
import seng302.visualiser.GameView3D;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
|
import seng302.visualiser.MiniMap;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
|
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
|
|
||||||
import seng302.visualiser.controllers.dialogs.FinishDialogController;
|
import seng302.visualiser.controllers.dialogs.FinishDialogController;
|
||||||
import seng302.visualiser.fxObjects.ChatHistory;
|
import seng302.visualiser.fxObjects.ChatHistory;
|
||||||
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
|
|
||||||
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class that manages the display of a race
|
* Controller class that manages the display of a race
|
||||||
*/
|
*/
|
||||||
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
public class RaceViewController extends Thread {
|
||||||
|
|
||||||
private final int CHAT_LIMIT = 128;
|
private final int CHAT_LIMIT = 128;
|
||||||
|
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
|
||||||
|
private static final Integer ICON_BLINK_PERIOD = 500;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Pane basePane;
|
private AnchorPane loadingScreenPane;
|
||||||
|
@FXML
|
||||||
|
private ImageView loadingScreen;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton chatSend;
|
private JFXButton chatSend;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -73,31 +52,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
@FXML
|
@FXML
|
||||||
private TextField chatInput;
|
private TextField chatInput;
|
||||||
@FXML
|
@FXML
|
||||||
private LineChart<String, Double> raceSparkLine;
|
|
||||||
@FXML
|
|
||||||
private NumberAxis sparklineYAxis;
|
|
||||||
@FXML
|
|
||||||
private VBox positionVbox;
|
|
||||||
@FXML
|
|
||||||
private CheckBox toggleFps;
|
|
||||||
@FXML
|
|
||||||
private Label timerLabel;
|
private Label timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private StackPane contentStackPane;
|
private StackPane contentStackPane;
|
||||||
|
|
||||||
private GridPane contentGridPane;
|
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane rvAnchorPane;
|
private Pane miniMapPane;
|
||||||
@FXML
|
|
||||||
private AnchorPane windArrowHolder;
|
|
||||||
@FXML
|
|
||||||
private Slider annotationSlider;
|
|
||||||
@FXML
|
|
||||||
private Button selectAnnotationBtn;
|
|
||||||
@FXML
|
|
||||||
private ComboBox<ClientYacht> yachtSelectionComboBox;
|
|
||||||
@FXML
|
|
||||||
private Text fpsDisplay;
|
|
||||||
@FXML
|
@FXML
|
||||||
private ImageView windImageView;
|
private ImageView windImageView;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -106,27 +65,44 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private Label windSpeedLabel;
|
private Label windSpeedLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
|
private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
|
||||||
|
@FXML
|
||||||
|
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
|
||||||
|
@FXML
|
||||||
|
private JFXButton miniMapButton;
|
||||||
|
|
||||||
//Race Data
|
|
||||||
private Map<Integer, ClientYacht> participants;
|
|
||||||
private Map<Integer, CompoundMark> markers;
|
|
||||||
private RaceXMLData courseData;
|
|
||||||
private GameView3D gameView;
|
private GameView3D gameView;
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
|
|
||||||
private ChatHistory chatHistory;
|
private ChatHistory chatHistory;
|
||||||
|
|
||||||
private Timeline timerTimeline;
|
|
||||||
private Timer timer = new Timer();
|
private Timer timer = new Timer();
|
||||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
|
||||||
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
|
|
||||||
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
|
|
||||||
private ClientYacht player;
|
private ClientYacht player;
|
||||||
private JFXDialog finishScreenDialog;
|
private JFXDialog finishScreenDialog;
|
||||||
private FinishDialogController finishDialogController;
|
private FinishDialogController finishDialogController;
|
||||||
|
private Timer blinkingTimer = new Timer();
|
||||||
|
private ImageView iconToDisplay;
|
||||||
|
private Double lastWindDirection;
|
||||||
|
private MiniMap miniMap;
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
miniMapPane.setVisible(false);
|
||||||
|
miniMapButton.setVisible(false);
|
||||||
|
contentStackPane.setVisible(false);
|
||||||
|
Image loadingImage = new Image("PP.png");
|
||||||
|
loadingScreen.setImage(loadingImage);
|
||||||
|
//Centers the Image within the image view
|
||||||
|
double w = 0;
|
||||||
|
double h = 0;
|
||||||
|
double ratioX = loadingScreen.getFitWidth() / loadingImage.getWidth();
|
||||||
|
double ratioY = loadingScreen.getFitHeight() / loadingImage.getHeight();
|
||||||
|
double reduceRatio = 0;
|
||||||
|
if(ratioX >= ratioY) {
|
||||||
|
reduceRatio = ratioY;
|
||||||
|
} else {
|
||||||
|
reduceRatio = ratioX;
|
||||||
|
}
|
||||||
|
w = loadingImage.getWidth() * reduceRatio;
|
||||||
|
h = loadingImage.getHeight() * reduceRatio;
|
||||||
|
loadingScreen.setX((loadingScreen.getFitWidth() - w) / 2);
|
||||||
|
loadingScreen.setY((loadingScreen.getFitHeight() - h) / 2);
|
||||||
Sounds.stopMusic();
|
Sounds.stopMusic();
|
||||||
Sounds.playRaceMusic();
|
Sounds.playRaceMusic();
|
||||||
|
|
||||||
@@ -156,6 +132,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
chatHistory.decreaseOpacity();
|
chatHistory.decreaseOpacity();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
lastWindDirection = 0d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
|
||||||
@@ -163,6 +141,19 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
createFinishDialog(finishedBoats);
|
createFinishDialog(finishedBoats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showView(){
|
||||||
|
loadingScreenPane.setVisible(false);
|
||||||
|
contentStackPane.setVisible(true);
|
||||||
|
miniMapPane.setVisible(true);
|
||||||
|
miniMapButton.setVisible(true);
|
||||||
|
Platform.runLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
contentStackPane.requestFocus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create finishScreenDialog and set up finishDialogController.
|
* Create finishScreenDialog and set up finishDialogController.
|
||||||
*/
|
*/
|
||||||
@@ -183,32 +174,41 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void loadRace (
|
public void loadRace (
|
||||||
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
|
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
|
||||||
ClientYacht player) {
|
ClientYacht player) {
|
||||||
|
|
||||||
this.participants = participants;
|
|
||||||
this.courseData = raceData;
|
|
||||||
this.markers = raceData.getCompoundMarks();
|
|
||||||
this.raceState = raceState;
|
this.raceState = raceState;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
|
player.addPowerUpListener(this::displayPowerUpIcon);
|
||||||
while (c.next()) {
|
player.addPowerDownListener(this::removeIcon);
|
||||||
if (c.wasPermutated()) {
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
gameView = new GameView3D();
|
||||||
}
|
miniMap = new MiniMap(
|
||||||
|
new ArrayList<>(raceData.getCompoundMarks().values()),
|
||||||
|
raceData.getMarkSequence(), raceData.getCourseLimit(),
|
||||||
|
new ArrayList<>(participants.values()), player
|
||||||
|
);
|
||||||
|
|
||||||
|
miniMapButton.setOnMouseClicked((event) -> {
|
||||||
|
if (miniMapPane.visibleProperty().get()) {
|
||||||
|
miniMapPane.setVisible(false);
|
||||||
|
miniMapButton.setText("✓");
|
||||||
|
} else {
|
||||||
|
miniMapPane.setVisible(true);
|
||||||
|
miniMapButton.setText("✕");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateOrder(raceState.getPlayerPositions());
|
|
||||||
gameView = new GameView3D();
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
contentStackPane.getChildren().add(0, gameView.getAssets());
|
contentStackPane.getChildren().add(0, gameView.getAssets());
|
||||||
((SubScene) gameView.getAssets()).widthProperty()
|
((SubScene) gameView.getAssets()).widthProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().widthProperty());
|
.bind(ViewManager.getInstance().getStage().widthProperty());
|
||||||
((SubScene) gameView.getAssets()).heightProperty()
|
((SubScene) gameView.getAssets()).heightProperty()
|
||||||
.bind(ViewManager.getInstance().getStage().heightProperty());
|
.bind(ViewManager.getInstance().getStage().heightProperty());
|
||||||
|
miniMapPane.getChildren().add(miniMap.getAssets());
|
||||||
});
|
});
|
||||||
gameView.setBoats(new ArrayList<>(participants.values()));
|
gameView.setBoats(new ArrayList<>(participants.values()));
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
@@ -236,40 +236,63 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The important annotations have been changed, update this view
|
* Displays the relevant icon, starts blinking it when it is close to turning off and then
|
||||||
|
* switches it off after the tokens time out
|
||||||
*
|
*
|
||||||
* @param importantAnnotationsState The current state of the selected annotations
|
* @param yacht The yacht only for which we are displaying the icon
|
||||||
|
* @param tokenType The type of token, indicating what icon needs to be displayed
|
||||||
*/
|
*/
|
||||||
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
|
private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) {
|
||||||
this.importantAnnotations = importantAnnotationsState;
|
if (yacht == player) {
|
||||||
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
|
if (iconToDisplay != null) {
|
||||||
|
iconToDisplay.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (tokenType) {
|
||||||
|
case BOOST:
|
||||||
|
iconToDisplay = velocityIcon;
|
||||||
|
break;
|
||||||
|
case HANDLING:
|
||||||
|
iconToDisplay = handlingIcon;
|
||||||
|
break;
|
||||||
|
case WIND_WALKER:
|
||||||
|
iconToDisplay = windWalkerIcon;
|
||||||
|
break;
|
||||||
|
case BUMPER:
|
||||||
|
iconToDisplay = bumperIcon;
|
||||||
|
break;
|
||||||
|
case RANDOM:
|
||||||
|
iconToDisplay = badRandomIcon;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
iconToDisplay = velocityIcon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
//Turn icon on
|
||||||
* Loads the "select annotations" view in a new window
|
iconToDisplay.setVisible(true);
|
||||||
*/
|
|
||||||
private void loadSelectAnnotationView() {
|
//Start blinking icon towards end
|
||||||
try {
|
if (blinkingTimer != null) {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader();
|
blinkingTimer.cancel();
|
||||||
Stage stage = new Stage();
|
}
|
||||||
// Set controller
|
blinkingTimer = new Timer("Blinking Timer");
|
||||||
ImportantAnnotationController controller = new ImportantAnnotationController(
|
blinkingTimer.schedule(new TimerTask() {
|
||||||
this, stage
|
Boolean isVisible = true;
|
||||||
);
|
|
||||||
fxmlLoader.setController(controller);
|
@Override
|
||||||
// Load FXML and set CSS
|
public void run() {
|
||||||
fxmlLoader.setLocation(
|
isVisible = !isVisible;
|
||||||
getClass().getResource("/views/importantAnnotationSelectView.fxml")
|
iconToDisplay.setVisible(isVisible);
|
||||||
);
|
}
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
|
}, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD);
|
||||||
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
}
|
||||||
stage.initStyle(StageStyle.UNDECORATED);
|
}
|
||||||
stage.setScene(scene);
|
|
||||||
stage.show();
|
public void removeIcon(ClientYacht yacht) {
|
||||||
controller.loadState(importantAnnotations);
|
if (yacht == player) {
|
||||||
} catch (IOException e) {
|
blinkingTimer.cancel();
|
||||||
e.printStackTrace();
|
iconToDisplay.setVisible(false);
|
||||||
|
iconToDisplay = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,42 +313,19 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
}, 0, 1000);
|
}, 0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
|
|
||||||
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
|
|
||||||
* Returns null if no next mark found.
|
|
||||||
* @param bg The BoatGroup to find the next mark of
|
|
||||||
* @return The next Mark or null if none found
|
|
||||||
*/
|
|
||||||
private Mark getNextMark(BoatObject bg) {
|
|
||||||
// TODO: 1/08/17 Move to GameView
|
|
||||||
//
|
|
||||||
// Integer legNumber = bg.getClientYacht().getLegNumber();
|
|
||||||
// List<Corner> markSequence = courseData.getMarkSequence();
|
|
||||||
//
|
|
||||||
// if (legNumber == 0) {
|
|
||||||
// return null;
|
|
||||||
// } else if (legNumber == markSequence.size() - 1) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (Corner corner : markSequence) {
|
|
||||||
// if (legNumber + 2 == corner.getSeqID()) {
|
|
||||||
// return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the wind direction arrow and text as from info from the StreamParser
|
* Updates the wind direction arrow and text as from info from the StreamParser
|
||||||
* @param direction the from north angle of the wind.
|
* @param direction the from north angle of the wind.
|
||||||
*/
|
*/
|
||||||
private void updateWindDirection(double direction) {
|
private void updateWindDirection(double direction) {
|
||||||
windDirectionLabel.setText(String.format("%.1f°", direction));
|
windDirectionLabel.setText(String.format("%.1f°", direction));
|
||||||
windImageView.setRotate(direction);
|
RotateTransition rt = new RotateTransition(Duration.millis(300), windImageView);
|
||||||
|
rt.setByAngle(direction - lastWindDirection);
|
||||||
|
rt.setCycleCount(3);
|
||||||
|
rt.setAutoReverse(true);
|
||||||
|
rt.play();
|
||||||
|
lastWindDirection = direction;
|
||||||
|
// windImageView.setRotate(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -394,226 +394,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading()));
|
boatHeadingLabel.setText(String.format("Boat Heading:\n%.1f°", player.getHeading()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the order of the yachts as from the StreamParser and sets them in the yacht order
|
|
||||||
* section
|
|
||||||
*/
|
|
||||||
private void updateOrder(ObservableList<ClientYacht> yachts) {
|
|
||||||
// List<Text> vboxEntries = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < yachts.size(); i++) {
|
|
||||||
//// System.out.println("yacht == null " + String.valueOf(yacht == null));
|
|
||||||
// if (yachts.get(i).getBoatStatus() == BoatStatus.FINISHED
|
|
||||||
// .getCode()) { // 3 is finish status
|
|
||||||
// Text textToAdd = new Text(i + 1 + ". " +
|
|
||||||
// yachts.get(i).getShortName() + " (Finished)");
|
|
||||||
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
||||||
// vboxEntries.add(textToAdd);
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// Text textToAdd = new Text(i + 1 + ". " +
|
|
||||||
// yachts.get(i).getShortName() + " ");
|
|
||||||
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
|
|
||||||
// textToAdd.setStyle("");
|
|
||||||
// vboxEntries.add(textToAdd);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Platform.runLater(() ->
|
|
||||||
// positionVbox.getChildren().setAll(vboxEntries)
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void updateLaylines(BoatObject bg) {
|
|
||||||
// TODO: 1/08/17 move to GameView
|
|
||||||
//
|
|
||||||
// Mark nextMark = getNextMark(bg);
|
|
||||||
// Boolean isUpwind = null;
|
|
||||||
// // Can only calc leg direction if there is a next mark and it is a gate mark
|
|
||||||
// if (nextMark != null) {
|
|
||||||
// if (nextMark instanceof GateMark) {
|
|
||||||
// if (bg.isUpwindLeg(gameViewController, nextMark)) {
|
|
||||||
// isUpwind = true;
|
|
||||||
// } else {
|
|
||||||
// isUpwind = false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for(MarkObject mg : gameViewController.getMarkGroups()) {
|
|
||||||
//
|
|
||||||
// mg.removeLaylines();
|
|
||||||
//
|
|
||||||
// if (mg.getMainMark().getId() == nextMark.getId()) {
|
|
||||||
//
|
|
||||||
// SingleMark singleMark1 = ((GateMark) nextMark).getSingleMark1();
|
|
||||||
// SingleMark singleMark2 = ((GateMark) nextMark).getSingleMark2();
|
|
||||||
// Point2D markPoint1 = gameViewController
|
|
||||||
// .findScaledXY(singleMark1.getLatitude(), singleMark1.getLongitude());
|
|
||||||
// Point2D markPoint2 = gameViewController
|
|
||||||
// .findScaledXY(singleMark2.getLatitude(), singleMark2.getLongitude());
|
|
||||||
// HashMap<Double, Double> angleAndSpeed;
|
|
||||||
// if (isUpwind) {
|
|
||||||
// angleAndSpeed = PolarTable.getOptimalUpwindVMG(StreamParser.getWindSpeed());
|
|
||||||
// } else {
|
|
||||||
// angleAndSpeed = PolarTable.getOptimalDownwindVMG(StreamParser.getWindSpeed());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Double resultingAngle = angleAndSpeed.keySet().iterator().next();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Point2D yachtCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
|
|
||||||
// Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
|
|
||||||
// Integer lineFuncResult = GeoUtility.lineFunction(yachtCurrentPos, gateMidPoint, markPoint2);
|
|
||||||
// Line rightLayline = new Line();
|
|
||||||
// Line leftLayline = new Line();
|
|
||||||
// if (lineFuncResult == 1) {
|
|
||||||
// rightLayline = makeRightLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// leftLayline = makeLeftLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// } else if (lineFuncResult == -1) {
|
|
||||||
// rightLayline = makeRightLayline(markPoint1, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// leftLayline = makeLeftLayline(markPoint2, 180 - resultingAngle, StreamParser.getWindDirection());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// leftLayline.setStrokeWidth(0.5);
|
|
||||||
// leftLayline.setStroke(bg.getBoat().getColour());
|
|
||||||
//
|
|
||||||
// rightLayline.setStrokeWidth(0.5);
|
|
||||||
// rightLayline.setStroke(bg.getBoat().getColour());
|
|
||||||
//
|
|
||||||
// bg.setLaylines(leftLayline, rightLayline);
|
|
||||||
// mg.addLaylines(leftLayline, rightLayline);
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) {
|
|
||||||
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle)
|
|
||||||
- (ref.getY() + distance - ref.getY()) * Math.sin(angle);
|
|
||||||
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
|
|
||||||
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
|
|
||||||
|
|
||||||
return new Point2D(newX, newY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
|
|
||||||
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
|
|
||||||
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
|
|
||||||
return line;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Line makeRightLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
|
|
||||||
|
|
||||||
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle - layLineAngle);
|
|
||||||
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
|
|
||||||
return line;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialised the combo box with any yachts currently in the race and adds the required listener
|
|
||||||
* for the combobox to take action upon selection
|
|
||||||
*/
|
|
||||||
private void initialiseBoatSelectionComboBox() {
|
|
||||||
// yachtSelectionComboBox.setItems(
|
|
||||||
// FXCollections.observableArrayList(participants.values())
|
|
||||||
// );
|
|
||||||
// //Null check is if the listener is fired but nothing selected
|
|
||||||
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
|
||||||
// if (selectedBoat != null) {
|
|
||||||
// gameView.selectBoat(selectedBoat);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
//TODO uncomment out
|
|
||||||
// selectionComboBoxList.setAll(participants.values());
|
|
||||||
// yachtSelectionComboBox.setItems(selectionComboBoxList);
|
|
||||||
// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
|
||||||
// if (selectedBoat != null) {
|
|
||||||
// gameView.selectBoat(selectedBoat);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the list of yachts in the order they finished the race
|
|
||||||
*/
|
|
||||||
private void loadRaceResultView() {
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
contentGridPane.getChildren().removeAll();
|
|
||||||
contentGridPane.getChildren().clear();
|
|
||||||
contentGridPane.getChildren().addAll((Pane) loader.load());
|
|
||||||
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
|
||||||
System.err.println(e.getCause().toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMillisToFormattedTime(long milliseconds) {
|
|
||||||
return String.format("%02d:%02d:%02d",
|
|
||||||
TimeUnit.MILLISECONDS.toHours(milliseconds),
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAnnotations(Integer annotationLevel) {
|
|
||||||
// switch (annotationLevel) {
|
|
||||||
// // No Annotations
|
|
||||||
// case 0:
|
|
||||||
// gameView.setAnnotationVisibilities(
|
|
||||||
// false, false, false, false, false, false
|
|
||||||
// );
|
|
||||||
// break;
|
|
||||||
// // Important Annotations
|
|
||||||
// case 1:
|
|
||||||
// gameView.setAnnotationVisibilities(
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.NAME),
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.SPEED),
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK),
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.LEGTIME),
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.TRACK),
|
|
||||||
// importantAnnotations.getAnnotationState(Annotation.WAKE)
|
|
||||||
// );
|
|
||||||
// break;
|
|
||||||
// // All Annotations
|
|
||||||
// case 2:
|
|
||||||
// gameView.setAnnotationVisibilities(
|
|
||||||
// true, true, true, true, true, true
|
|
||||||
// );
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets all the annotations of the selected yacht to be visible and all others to be hidden
|
|
||||||
*
|
|
||||||
* @param yacht The yacht for which we want to view all annotations
|
|
||||||
*/
|
|
||||||
private void setSelectedBoat(ClientYacht yacht) {
|
|
||||||
// for (BoatObject bg : gameViewController.getBoatGroups()) {
|
|
||||||
// //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we
|
|
||||||
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup.
|
|
||||||
// if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
|
|
||||||
//// updateLaylines(bg);
|
|
||||||
// bg.setIsSelected(true);
|
|
||||||
//// selectedBoat = yacht;
|
|
||||||
// } else {
|
|
||||||
// bg.setIsSelected(false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateTokens(RaceXMLData raceData) {
|
public void updateTokens(RaceXMLData raceData) {
|
||||||
gameView.updateTokens(raceData.getTokens());
|
gameView.updateTokens(raceData.getTokens());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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;
|
||||||
@@ -22,11 +23,22 @@ 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.DiscoveryServerClient;
|
||||||
|
import seng302.discoveryServer.util.ServerListing;
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
|
import seng302.gameServer.messages.ServerRegistrationMessage;
|
||||||
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.DirectConnectController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
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;
|
||||||
@@ -46,15 +58,29 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
private JFXButton serverListHostButton;
|
private JFXButton serverListHostButton;
|
||||||
//Direct Connect
|
//Direct Connect
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton connectButton;
|
private JFXButton directConnectButton;
|
||||||
@FXML
|
|
||||||
private JFXTextField serverHostName;
|
|
||||||
@FXML
|
@FXML
|
||||||
private JFXTextField serverPortNumber;
|
private JFXTextField serverPortNumber;
|
||||||
|
@FXML
|
||||||
|
private JFXButton roomConnectButton;
|
||||||
|
@FXML
|
||||||
|
private JFXTextField roomNumber;
|
||||||
|
@FXML
|
||||||
|
private JFXButton autoSelectGame;
|
||||||
//---------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 directConnectDialog;
|
||||||
|
|
||||||
|
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
|
||||||
@@ -62,13 +88,25 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
serverListVBox.minWidthProperty().bind(serverListScrollPane.widthProperty());
|
serverListVBox.minWidthProperty().bind(serverListScrollPane.widthProperty());
|
||||||
|
|
||||||
// Set Event Bindings
|
// Set Event Bindings
|
||||||
connectButton.setOnMouseEntered(event -> Sounds.playHoverSound());
|
directConnectButton.setOnMouseEntered(event -> Sounds.playHoverSound());
|
||||||
serverListHostButton.setOnMouseEntered(event -> Sounds.playHoverSound());
|
serverListHostButton.setOnMouseEntered(event -> Sounds.playHoverSound());
|
||||||
connectButton.setOnMouseReleased(event -> {
|
|
||||||
attemptToDirectConnect();
|
|
||||||
|
|
||||||
|
roomNumber.setOnKeyPressed(event -> {
|
||||||
|
if (event.getCode().equals(KeyCode.ENTER)) {
|
||||||
|
connectToRoomCode(roomNumber.getText());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
directConnectButton.setOnMouseReleased(event -> {
|
||||||
|
directConnectDialog.show();
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
});
|
});
|
||||||
for (JFXTextField textField : Arrays.asList(serverHostName, serverPortNumber)) {
|
|
||||||
|
directConnectDialog = createDirectConnectDialog();
|
||||||
|
|
||||||
|
for (JFXTextField textField : Arrays.asList(roomNumber)) {
|
||||||
// Event for pressing enter to submit direct connection
|
// Event for pressing enter to submit direct connection
|
||||||
textField.setOnKeyPressed(event -> {
|
textField.setOnKeyPressed(event -> {
|
||||||
if (event.getCode().equals(KeyCode.ENTER)) {
|
if (event.getCode().equals(KeyCode.ENTER)) {
|
||||||
@@ -82,15 +120,41 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
textField.getValidators().add(validator);
|
textField.getValidators().add(validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autoSelectGame.setOnMouseReleased(e -> {
|
||||||
|
ServerListing listing;
|
||||||
|
DiscoveryServerClient client = new DiscoveryServerClient();
|
||||||
|
|
||||||
|
try {
|
||||||
|
listing = client.getRandomServer();
|
||||||
|
} catch (Exception e1) {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("Unable to connect to matchmaking server. Are you connected to the internet?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.didFail()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listing == null || listing.equals(ServerRegistrationMessage.getEmptyRegistration())) {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("There are currently no servers available for you to connect to.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewManager.getInstance().getGameClient().runAsClient(listing.getAddress(), listing.getPortNumber());
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
// Validating the hostname
|
// Validating the hostname
|
||||||
HostNameFieldValidator hostNameValidator = new HostNameFieldValidator();
|
HostNameFieldValidator hostNameValidator = new HostNameFieldValidator();
|
||||||
hostNameValidator.setMessage("Host name incorrect");
|
hostNameValidator.setMessage("Host name incorrect");
|
||||||
serverHostName.getValidators().add(hostNameValidator);
|
roomCodeInput.getValidators().add(hostNameValidator);
|
||||||
|
|
||||||
// Validating the port number
|
// Validating the port number
|
||||||
NumberRangeValidator portNumberValidator = new NumberRangeValidator(1025, 65536);
|
NumberRangeValidator portNumberValidator = new NumberRangeValidator(1025, 65536);
|
||||||
portNumberValidator.setMessage("Port number incorrect");
|
portNumberValidator.setMessage("Port number incorrect");
|
||||||
serverPortNumber.getValidators().add(portNumberValidator);
|
serverPortNumber.getValidators().add(portNumberValidator);
|
||||||
|
TODO later
|
||||||
|
*/
|
||||||
|
|
||||||
// Start listening for servers on network
|
// Start listening for servers on network
|
||||||
try {
|
try {
|
||||||
@@ -111,10 +175,17 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
);
|
);
|
||||||
serverListVBox.getChildren().add(noServersFound);
|
serverListVBox.getChildren().add(noServersFound);
|
||||||
|
|
||||||
|
roomConnectButton.setOnMouseReleased(e -> {
|
||||||
|
String roomCode = roomNumber.getText();
|
||||||
|
connectToRoomCode(roomCode);
|
||||||
|
});
|
||||||
|
|
||||||
// Set up dialog for server creation
|
// Set up dialog for server creation
|
||||||
serverListHostButton.setOnAction(action -> {
|
serverListHostButton.setOnAction(action -> {
|
||||||
showServerCreationDialog();
|
showServerCreationDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addServerCreationDialogListener(this::closeServerCreationDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,9 +196,11 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
|
||||||
"/views/dialogs/ServerCreationDialog.fxml"));
|
"/views/dialogs/ServerCreationDialog.fxml"));
|
||||||
try {
|
try {
|
||||||
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
serverCreationDialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
|
||||||
DialogTransition.CENTER);
|
DialogTransition.CENTER);
|
||||||
dialog.show();
|
ServerCreationController serverCreationController = dialogContent.getController();
|
||||||
|
serverCreationController.setListener(serverCreationDialogListeners);
|
||||||
|
serverCreationDialog.show();
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -136,13 +209,35 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JFXDialog createDirectConnectDialog() {
|
||||||
|
FXMLLoader dialog = new FXMLLoader(
|
||||||
|
getClass().getResource("/views/dialogs/DirectConnect.fxml"));
|
||||||
|
|
||||||
|
JFXDialog dcDialog = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
dcDialog = new JFXDialog(serverListMainStackPane, dialog.load(),
|
||||||
|
JFXDialog.DialogTransition.CENTER);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectConnectController controller = dialog.getController();
|
||||||
|
|
||||||
|
return dcDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
private void attemptToDirectConnect() {
|
private void attemptToDirectConnect() {
|
||||||
if (validateDirectConnection(serverHostName.getText(), serverPortNumber.getText())) {
|
/*if (validateDirectConnection(serverHostName.getText(), serverPortNumber.getText())) {
|
||||||
DirectConnect();
|
DirectConnect();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,10 +247,40 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
* @return boolean value if host and port number are valid values
|
* @return boolean value if host and port number are valid values
|
||||||
*/
|
*/
|
||||||
private Boolean validateDirectConnection(String hostName, String portNumber) {
|
private Boolean validateDirectConnection(String hostName, String portNumber) {
|
||||||
Boolean hostNameValid = ValidationTools.validateTextField(serverHostName);
|
/*Boolean hostNameValid = ValidationTools.validateTextField(serverHostName);
|
||||||
|
*
|
||||||
Boolean portNumberValid = ValidationTools.validateTextField(serverPortNumber);
|
Boolean portNumberValid = ValidationTools.validateTextField(serverPortNumber);
|
||||||
|
|
||||||
return hostNameValid && portNumberValid;
|
return hostNameValid && portNumberValid;*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToRoomCode(String roomCode){
|
||||||
|
DiscoveryServerClient client = new DiscoveryServerClient();
|
||||||
|
ServerListing serverListing;
|
||||||
|
|
||||||
|
if (client.didFail()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
serverListing = client.getServerForRoomCode(roomCode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("Error connecting to matchmaking server. Please try again later.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverListing == null || serverListing.equals(new ServerListing("","","", 0, 0))){
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("No servers could be found with that room code.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ViewManager.getInstance().getGameClient().runAsClient(serverListing.getAddress(), serverListing.getPortNumber());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("Error connecting to matchmaking service.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,7 +288,7 @@ public class ServerListController implements Initializable, ServerListenerDelega
|
|||||||
*/
|
*/
|
||||||
private void DirectConnect() {
|
private void DirectConnect() {
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
ViewManager.getInstance().getGameClient().runAsClient(serverHostName.getText(), Integer.parseInt(serverPortNumber.getText()));
|
// ViewManager.getInstance().getGameClient().runAsClient(serverHostName.getText(), Integer.parseInt(serverPortNumber.getText()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,4 +329,14 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package seng302.visualiser.controllers;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Kusal on 26-Sep-17.
|
||||||
|
*/
|
||||||
|
public class SplashScreenController implements Initializable{
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private StackPane rootPane;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
new SplashScreen().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SplashScreen extends Thread {
|
||||||
|
public void run(){
|
||||||
|
try {
|
||||||
|
Thread.sleep(3000);
|
||||||
|
Platform.runLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
ViewManager.getInstance().initialStartView(stage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
rootPane.getScene().getWindow().hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,7 +59,7 @@ public class StartScreenController implements Initializable{
|
|||||||
/**
|
/**
|
||||||
* Changes the view to the Server Browser.
|
* Changes the view to the Server Browser.
|
||||||
*/
|
*/
|
||||||
private void goToServerBrowser() {
|
public void goToServerBrowser() {
|
||||||
try {
|
try {
|
||||||
ViewManager.getInstance().setScene(serverList);
|
ViewManager.getInstance().setScene(serverList);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -6,30 +6,27 @@ import com.jfoenix.controls.JFXDialog;
|
|||||||
import com.jfoenix.controls.JFXDialog.DialogTransition;
|
import com.jfoenix.controls.JFXDialog.DialogTransition;
|
||||||
import com.jfoenix.controls.JFXSnackbar;
|
import com.jfoenix.controls.JFXSnackbar;
|
||||||
import com.jfoenix.svg.SVGGlyph;
|
import com.jfoenix.svg.SVGGlyph;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.*;
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
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.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.StageStyle;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.ServerAdvertiser;
|
import seng302.gameServer.ServerAdvertiser;
|
||||||
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.KeyBindingDialogController;
|
||||||
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
import seng302.visualiser.controllers.dialogs.PopupDialogController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ViewManager {
|
public class ViewManager {
|
||||||
|
|
||||||
private static ViewManager instance;
|
private static ViewManager instance;
|
||||||
@@ -56,10 +53,20 @@ public class ViewManager {
|
|||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new ViewManager();
|
instance = new ViewManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initialiseSplashScreen(Stage stage) throws IOException {
|
||||||
|
this.stage = stage;
|
||||||
|
Parent root = FXMLLoader.load(getClass().getResource("/views/SplashScreen.fxml"));
|
||||||
|
Scene scene = new Scene(root);
|
||||||
|
stage.setTitle("Party Parrots At Sea");
|
||||||
|
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.initStyle(StageStyle.UNDECORATED);
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the start view in the given stage.
|
* Initialize the start view in the given stage.
|
||||||
*/
|
*/
|
||||||
@@ -67,7 +74,6 @@ public class ViewManager {
|
|||||||
this.stage = stage;
|
this.stage = stage;
|
||||||
Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml"));
|
Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml"));
|
||||||
stage.setTitle("Party Parrots At Sea");
|
stage.setTitle("Party Parrots At Sea");
|
||||||
|
|
||||||
JFXDecorator decorator = new JFXDecorator(stage, root, false, true, true);
|
JFXDecorator decorator = new JFXDecorator(stage, root, false, true, true);
|
||||||
decorator.setCustomMaximize(true);
|
decorator.setCustomMaximize(true);
|
||||||
decorator.applyCss();
|
decorator.applyCss();
|
||||||
@@ -102,8 +108,6 @@ public class ViewManager {
|
|||||||
gameClient.stopGame();
|
gameClient.stopGame();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
jfxSnackbar = new JFXSnackbar(decorator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,6 +192,7 @@ public class ViewManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jfxSnackbar = new JFXSnackbar(decorator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,16 +273,9 @@ public class ViewManager {
|
|||||||
jfxSnackbar.show(snackbarText, 1500);
|
jfxSnackbar.show(snackbarText, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if a PC has compatibility with the bonjour protocol for server detection.
|
|
||||||
*/
|
|
||||||
private void checkCompatibility() {
|
|
||||||
if (BonjourInstallChecker.isBonjourSupported()) {
|
|
||||||
BonjourInstallChecker.openInstallUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeAll() {
|
private void closeAll() {
|
||||||
|
if (stage!= null) stage.close();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().unregister();
|
ServerAdvertiser.getInstance().unregister();
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
@@ -304,7 +302,7 @@ public class ViewManager {
|
|||||||
Stage stage = new Stage();
|
Stage stage = new Stage();
|
||||||
initialStartView(stage);
|
initialStartView(stage);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.warn("Could not go to start view");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,8 +341,9 @@ public class ViewManager {
|
|||||||
logger.error("Could not load lobby view");
|
logger.error("Could not load lobby view");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disableReadyButton) {
|
|
||||||
LobbyController lobbyController = loader.getController();
|
LobbyController lobbyController = loader.getController();
|
||||||
|
|
||||||
|
if (disableReadyButton) {
|
||||||
lobbyController.disableReadyButton();
|
lobbyController.disableReadyButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +355,6 @@ public class ViewManager {
|
|||||||
*
|
*
|
||||||
* @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
|
||||||
@@ -401,6 +399,16 @@ public class ViewManager {
|
|||||||
return loader.getController();
|
return loader.getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showErrorSnackBar(String msg){
|
||||||
|
decorator.getStylesheets()
|
||||||
|
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
|
||||||
|
|
||||||
|
JFXSnackbar bar = new JFXSnackbar(decorator);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Stage getStage() {
|
public Stage getStage() {
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXSlider;
|
||||||
|
import com.jfoenix.controls.JFXTextField;
|
||||||
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import seng302.gameServer.ServerDescription;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.controllers.ViewManager;
|
||||||
|
import seng302.visualiser.validators.FieldLengthValidator;
|
||||||
|
import seng302.visualiser.validators.ValidationTools;
|
||||||
|
|
||||||
|
public class DirectConnectController implements Initializable {
|
||||||
|
|
||||||
|
//--------FXML BEGIN--------//
|
||||||
|
@FXML
|
||||||
|
private JFXTextField serverAddress;
|
||||||
|
@FXML
|
||||||
|
private JFXTextField portNumber;
|
||||||
|
@FXML
|
||||||
|
private JFXButton submitBtn;
|
||||||
|
//---------FXML END---------//
|
||||||
|
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
|
||||||
|
fieldLengthValidator.setMessage("Too long.");
|
||||||
|
|
||||||
|
RequiredFieldValidator fieldRequiredValidator = new RequiredFieldValidator();
|
||||||
|
fieldRequiredValidator.setMessage("Required.");
|
||||||
|
|
||||||
|
serverAddress.setValidators(fieldLengthValidator, fieldRequiredValidator);
|
||||||
|
portNumber.setValidators(fieldLengthValidator, fieldRequiredValidator);
|
||||||
|
|
||||||
|
submitBtn.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
connectToServer();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connects to the server
|
||||||
|
*/
|
||||||
|
private void connectToServer() {
|
||||||
|
//TODO fix port number validation
|
||||||
|
|
||||||
|
try{
|
||||||
|
Integer.parseInt(portNumber.getText());
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e){
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("You need to enter a valid port number");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewManager.getInstance().getGameClient()
|
||||||
|
.runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
|
Sounds.playHoverSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ public class KeyBindingDialogController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private Label closeLabel;
|
private Label closeLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton zoomInbtn;
|
private JFXButton zoomInBtn;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton zoomOutBtn;
|
private JFXButton zoomOutBtn;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -43,6 +43,8 @@ public class KeyBindingDialogController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private JFXButton resetBtn;
|
private JFXButton resetBtn;
|
||||||
@FXML
|
@FXML
|
||||||
|
private JFXButton confirmBtn;
|
||||||
|
@FXML
|
||||||
private Label upwindLabel;
|
private Label upwindLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private Label downwindLabel;
|
private Label downwindLabel;
|
||||||
@@ -70,7 +72,7 @@ public class KeyBindingDialogController implements Initializable {
|
|||||||
gameKeyBind = GameKeyBind.getInstance();
|
gameKeyBind = GameKeyBind.getInstance();
|
||||||
buttons = new ArrayList<>();
|
buttons = new ArrayList<>();
|
||||||
Collections.addAll(buttons,
|
Collections.addAll(buttons,
|
||||||
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
|
zoomInBtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
|
||||||
viewButton, rightButton, leftButton, forwardButton, backwardButton);
|
viewButton, rightButton, leftButton, forwardButton, backwardButton);
|
||||||
bindButtonWithAction();
|
bindButtonWithAction();
|
||||||
loadKeyBind();
|
loadKeyBind();
|
||||||
@@ -87,9 +89,11 @@ public class KeyBindingDialogController implements Initializable {
|
|||||||
resetBtn.setOnMouseClicked(event -> {
|
resetBtn.setOnMouseClicked(event -> {
|
||||||
gameKeyBind.setToDefault();
|
gameKeyBind.setToDefault();
|
||||||
loadKeyBind();
|
loadKeyBind();
|
||||||
|
showSnackBar("All keys reset!", false);
|
||||||
});
|
});
|
||||||
|
|
||||||
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
|
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
|
||||||
|
confirmBtn.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
@@ -14,6 +15,7 @@ import javafx.scene.layout.AnchorPane;
|
|||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
import seng302.utilities.Sounds;
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.MapMaker;
|
import seng302.visualiser.MapMaker;
|
||||||
|
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;
|
||||||
@@ -26,10 +28,12 @@ public class ServerCreationController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private JFXSlider maxPlayersSlider;
|
private JFXSlider maxPlayersSlider;
|
||||||
@FXML
|
@FXML
|
||||||
private Label maxPlayersLabel;
|
|
||||||
@FXML
|
|
||||||
private JFXButton submitBtn;
|
private JFXButton submitBtn;
|
||||||
@FXML
|
@FXML
|
||||||
|
private Label closeLabel;
|
||||||
|
@FXML
|
||||||
|
private Label maxPlayersLabel;
|
||||||
|
@FXML
|
||||||
private JFXButton nextMapButton;
|
private JFXButton nextMapButton;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXButton lastMapButton;
|
private JFXButton lastMapButton;
|
||||||
@@ -43,10 +47,11 @@ public class ServerCreationController implements Initializable {
|
|||||||
private JFXCheckBox pickupsCheckBox;
|
private JFXCheckBox pickupsCheckBox;
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane mapHolder;
|
private AnchorPane mapHolder;
|
||||||
|
//---------FXML END---------//
|
||||||
|
|
||||||
private MapMaker mapMaker = MapMaker.getInstance();
|
private MapMaker mapMaker = MapMaker.getInstance();
|
||||||
|
|
||||||
//---------FXML END---------//
|
private List<ServerCreationDialogListener> serverCreationDialogListeners;
|
||||||
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
|
||||||
@@ -89,6 +94,8 @@ public class ServerCreationController implements Initializable {
|
|||||||
|
|
||||||
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
|
||||||
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
|
||||||
|
pickupsCheckBox.setSelected(true);
|
||||||
|
closeLabel.setOnMouseClicked(event -> notifyListeners());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +118,12 @@ public class ServerCreationController implements Initializable {
|
|||||||
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
|
||||||
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
|
.getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
|
||||||
|
|
||||||
|
if (serverDescription == null){
|
||||||
|
ViewManager.getInstance().getGameClient().getServerThread().closeSocket();
|
||||||
|
ViewManager.getInstance().getGameClient().stopGame();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
|
||||||
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
|
||||||
}
|
}
|
||||||
@@ -120,7 +133,8 @@ public class ServerCreationController implements Initializable {
|
|||||||
*/
|
*/
|
||||||
private void updateMaxPlayerLabel() {
|
private void updateMaxPlayerLabel() {
|
||||||
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
|
||||||
maxPlayersLabel.setText(String.format("Max players: %.0f", maxPlayersSlider.getValue()));
|
maxPlayersLabel.setText(String
|
||||||
|
.format("Only %.0f players are allowed into the game", maxPlayersSlider.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLegSliderLabel() {
|
private void updateLegSliderLabel() {
|
||||||
@@ -151,4 +165,15 @@ public class ServerCreationController implements Initializable {
|
|||||||
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
|
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
|
||||||
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
|
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setListener(List<ServerCreationDialogListener> serverCreationDialogListeners) {
|
||||||
|
this.serverCreationDialogListeners = serverCreationDialogListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyListeners() {
|
||||||
|
for (ServerCreationDialogListener serverCreationDialogListener : serverCreationDialogListeners) {
|
||||||
|
serverCreationDialogListener.notifyClosure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package seng302.visualiser.controllers.dialogs;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import com.jfoenix.controls.JFXTextArea;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.geometry.Point3D;
|
||||||
|
import javafx.scene.Group;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Scale;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.controllers.LobbyController;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
|
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by wmu16 on 28/09/17.
|
||||||
|
*/
|
||||||
|
public class TokenInfoDialogController implements Initializable {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label headerLabel;
|
||||||
|
@FXML
|
||||||
|
private TextArea contentText;
|
||||||
|
@FXML
|
||||||
|
private Pane tokenPane;
|
||||||
|
@FXML
|
||||||
|
private Button optionButton;
|
||||||
|
|
||||||
|
private LobbyController lobbyController;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
|
optionButton.setOnMouseReleased(event -> {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
lobbyController.closeTokenInfoDialog();
|
||||||
|
});
|
||||||
|
|
||||||
|
contentText.setEditable(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
contentText.setText(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeader(String header) {
|
||||||
|
this.headerLabel.setText(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(ModelType token) {
|
||||||
|
tokenPane.getChildren().clear();
|
||||||
|
|
||||||
|
Group tokenObject = ModelFactory.importModel(token).getAssets();
|
||||||
|
|
||||||
|
tokenObject.getTransforms().addAll(
|
||||||
|
new Translate(138 / 2, 138 / 2, 0),
|
||||||
|
new Scale(20, 20, 20));
|
||||||
|
|
||||||
|
if (token == ModelType.WIND_WALKER_PICKUP) {
|
||||||
|
tokenObject.getTransforms().addAll(
|
||||||
|
new Rotate(-70, new Point3D(1, 0, 0)),
|
||||||
|
new Translate(0, 2, 0)
|
||||||
|
);
|
||||||
|
} else if (token == ModelType.RANDOM_PICKUP) {
|
||||||
|
tokenObject.getTransforms().addAll(
|
||||||
|
new Rotate(-90, new Point3D(1, 0, 0)),
|
||||||
|
new Translate(0, 0, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenPane.getChildren().add(tokenObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentController(LobbyController lobbyController) {
|
||||||
|
this.lobbyController = lobbyController;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -29,11 +29,11 @@ public class MarkArrowFactory {
|
|||||||
STARBOARD,
|
STARBOARD,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final double MARK_ARROW_SEPARATION = 15;
|
public static final double MARK_ARROW_SEPARATION = 8;
|
||||||
public static final double ARROW_LENGTH = 75;
|
public static final double ARROW_LENGTH = 20;
|
||||||
public static final double ARROW_HEAD_DEPTH = 10;
|
public static final double ARROW_HEAD_DEPTH = 5;
|
||||||
public static final double ARROW_HEAD_WIDTH = 6;
|
public static final double ARROW_HEAD_WIDTH = 3;
|
||||||
public static final double STROKE_WIDTH = 3;
|
public static final double STROKE_WIDTH = 1;
|
||||||
|
|
||||||
public static Model constructEntryArrow3D (
|
public static Model constructEntryArrow3D (
|
||||||
RoundingSide roundingSide, double angle, ModelType type) {
|
RoundingSide roundingSide, double angle, ModelType type) {
|
||||||
@@ -106,7 +106,7 @@ public class MarkArrowFactory {
|
|||||||
Arc roundSection = new Arc(
|
Arc roundSection = new Arc(
|
||||||
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
|
0, 0, MARK_ARROW_SEPARATION, MARK_ARROW_SEPARATION,
|
||||||
//Where to start drawing arc from
|
//Where to start drawing arc from
|
||||||
(roundingSide == RoundingSide.PORT ? 0 : angleOfEntry),
|
(roundingSide == RoundingSide.PORT ? 180 + angleOfEntry : angleOfEntry),
|
||||||
//Which way to go around the mark. (clockwise vs anticlockwise)
|
//Which way to go around the mark. (clockwise vs anticlockwise)
|
||||||
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
|
roundingSide == RoundingSide.PORT ? Math.abs(angleOfExit - angleOfEntry) : -Math.abs(angleOfEntry - angleOfExit)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ public class Marker2D extends Group {
|
|||||||
mark.setRadius(5);
|
mark.setRadius(5);
|
||||||
mark.setCenterX(0);
|
mark.setCenterX(0);
|
||||||
mark.setCenterY(0);
|
mark.setCenterY(0);
|
||||||
Platform.runLater(() -> this.getChildren()
|
Platform.runLater(() -> this.getChildren().add(mark));
|
||||||
.addAll(mark, new Group())); //Empty group placeholder or arrows.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,13 +81,9 @@ public class Marker2D extends Group {
|
|||||||
|
|
||||||
private void showArrow(List<Group> arrowList, int arrowListIndex) {
|
private void showArrow(List<Group> arrowList, int arrowListIndex) {
|
||||||
if (arrowListIndex < arrowList.size()) {
|
if (arrowListIndex < arrowList.size()) {
|
||||||
if (arrowListIndex == 1) {
|
Platform.runLater(() ->
|
||||||
;
|
this.getChildren().setAll(mark, arrowList.get(arrowListIndex))
|
||||||
}
|
);
|
||||||
Platform.runLater(() -> {
|
|
||||||
this.getChildren().remove(1);
|
|
||||||
this.getChildren().add(arrowList.get(arrowListIndex));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ public enum BoatMeshType {
|
|||||||
CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl",
|
CATAMARAN("catamaran_hull.stl", "catamaran_mast.stl", 0.997, "catamaran_sail.stl",
|
||||||
0.997, null, false, 1.0, 1.4, 2.0),
|
0.997, null, false, 1.0, 1.4, 2.0),
|
||||||
PIRATE_SHIP("pirateship_hull.stl", "pirateship_mast.stl", -0.5415, "pirateship_mainsail.stl",
|
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);
|
-0.5415, "pirateship_frontsail.stl", true, 1.2, 1.6, 1.2),
|
||||||
|
DUCKY("ducky_hull.stl", "ducky_mast.stl", -2.18539, "ducky_sail.stl", -2.18539, "ducky_eyes.stl", false, 1.2, 1.1, 1.4),
|
||||||
|
PARROT("parrot_hull.stl", null, 0, "parrot_sail.stl", 0, "parrot_features.stl", true, 1, 1, 1),
|
||||||
|
WAKA("waka_hull.stl", "waka_mast.stl", 0, "waka_sail.stl", 0, null, true, 1.7, 0.5, 1.5);
|
||||||
|
|
||||||
final String hullFile, mastFile, sailFile, jibFile;
|
final String hullFile, mastFile, sailFile, jibFile;
|
||||||
final double mastOffset, sailOffset;
|
final double mastOffset, sailOffset;
|
||||||
@@ -19,7 +22,7 @@ public enum BoatMeshType {
|
|||||||
public final double accelerationMultiplier;
|
public final double accelerationMultiplier;
|
||||||
public final double turnStep;
|
public final double turnStep;
|
||||||
final boolean fixedSail;
|
final boolean fixedSail;
|
||||||
final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP};
|
final static BoatMeshType[] boatTypes = new BoatMeshType[]{DINGHY, CATAMARAN, PIRATE_SHIP, DUCKY, PARROT, WAKA};
|
||||||
|
|
||||||
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile,
|
BoatMeshType(String hullFile, String mastFile, double mastOffset, String sailFile,
|
||||||
double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) {
|
double sailOffset, String jibFile, boolean fixedSail, double maxSpeedMultiplier, double accelerationMultiplier, double turnStep) {
|
||||||
|
|||||||
@@ -60,8 +60,10 @@ public class BoatModel extends Model {
|
|||||||
*/
|
*/
|
||||||
public void changeColour(Color newColour) {
|
public void changeColour(Color newColour) {
|
||||||
changeColourChild(HULL_INDEX, newColour);
|
changeColourChild(HULL_INDEX, newColour);
|
||||||
|
if (meshType != BoatMeshType.PARROT) {
|
||||||
changeColourChild(MAST_INDEX, newColour);
|
changeColourChild(MAST_INDEX, newColour);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void changeColourChild(int index, Color newColour) {
|
private void changeColourChild(int index, Color newColour) {
|
||||||
MeshView meshView = getMeshViewChild(index);
|
MeshView meshView = getMeshViewChild(index);
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ 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.beans.property.ReadOnlyDoubleWrapper;
|
||||||
|
import javafx.geometry.Point2D;
|
||||||
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;
|
||||||
|
import javafx.scene.paint.PhongMaterial;
|
||||||
|
import javafx.scene.shape.MeshView;
|
||||||
import javafx.scene.transform.Rotate;
|
import javafx.scene.transform.Rotate;
|
||||||
|
import javafx.scene.transform.Translate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@@ -31,6 +35,9 @@ public class BoatObject extends Group {
|
|||||||
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, new Point3D(0,0,1));
|
||||||
|
|
||||||
|
// This stuff only matters to the players boat object.
|
||||||
|
private MeshView markIndicator;
|
||||||
|
private MeshView playerIndicator;
|
||||||
private ReadOnlyDoubleWrapper rotationProperty;
|
private ReadOnlyDoubleWrapper rotationProperty;
|
||||||
|
|
||||||
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
|
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
|
||||||
@@ -79,6 +86,19 @@ public class BoatObject extends Group {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateMarkIndicator(Point2D markPoint) {
|
||||||
|
Point2D boatLoc = new Point2D(this.getLayoutX(), this.getLayoutY());
|
||||||
|
Double angle = Math.toDegrees(
|
||||||
|
Math.atan2(boatLoc.getY() - markPoint.getY(), boatLoc.getX() - markPoint.getX())) - 90;
|
||||||
|
|
||||||
|
Double radius = 0.5;
|
||||||
|
markIndicator.getTransforms().clear();
|
||||||
|
markIndicator.getTransforms().addAll(
|
||||||
|
new Rotate(angle, new Point3D(0, 0, 1)),
|
||||||
|
new Translate(0, -radius, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private Double normalizeHeading(double heading, double windDirection) {
|
private Double normalizeHeading(double heading, double windDirection) {
|
||||||
Double normalizedHeading = heading - windDirection;
|
Double normalizedHeading = heading - windDirection;
|
||||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
|
||||||
@@ -118,6 +138,26 @@ public class BoatObject extends Group {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMarkIndicator(MeshView indicator) {
|
||||||
|
this.markIndicator = indicator;
|
||||||
|
this.getChildren().add(markIndicator);
|
||||||
|
createPlayerIndicator();
|
||||||
|
setIndicatorColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPlayerIndicator() {
|
||||||
|
MeshView torus = ModelFactory.importSTL("player_circle.stl");
|
||||||
|
playerIndicator = torus;
|
||||||
|
this.getChildren().add(torus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndicatorColor() {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
markIndicator.setMaterial(new PhongMaterial(Color.DARKORANGE));
|
||||||
|
playerIndicator.setMaterial(new PhongMaterial(colour));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Group getWake () {
|
public Group getWake () {
|
||||||
return wake;
|
return wake;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -81,30 +80,6 @@ public class ModelFactory {
|
|||||||
return bo;
|
return bo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoatModel boatRotatingView(BoatMeshType boatType, Color primaryColour) {
|
|
||||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
|
||||||
boatAssets.getTransforms().addAll(
|
|
||||||
new Scale(40, 40, 40),
|
|
||||||
new Rotate(90, new Point3D(0,0,1)),
|
|
||||||
new Rotate(90, new Point3D(0, 1, 0))
|
|
||||||
);
|
|
||||||
|
|
||||||
final Rotate animationRotate = new Rotate(0, new Point3D(1,1,1));
|
|
||||||
boatAssets.getTransforms().add(animationRotate);
|
|
||||||
|
|
||||||
return new BoatModel(boatAssets, new AnimationTimer() {
|
|
||||||
|
|
||||||
private double rotation = 0;
|
|
||||||
private Rotate rotate = animationRotate;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(long now) {
|
|
||||||
rotation += 0.5;
|
|
||||||
rotate.setAngle(rotation);
|
|
||||||
}
|
|
||||||
}, boatType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
|
public static BoatModel boatGameView(BoatMeshType boatType, Color primaryColour) {
|
||||||
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
Group boatAssets = getUnmodifiedBoatModel(boatType, primaryColour);
|
||||||
boatAssets.getTransforms().setAll(
|
boatAssets.getTransforms().setAll(
|
||||||
@@ -116,27 +91,42 @@ 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 = importBoatSTL(boatType.hullFile);
|
||||||
hull.setMaterial(new PhongMaterial(primaryColour));
|
hull.setMaterial(new PhongMaterial(primaryColour));
|
||||||
MeshView mast = importSTL(boatType.mastFile);
|
boatAssets.getChildren().add(hull);
|
||||||
|
|
||||||
|
if (boatType.mastFile != null) {
|
||||||
|
MeshView mast = importBoatSTL(boatType.mastFile);
|
||||||
mast.setMaterial(new PhongMaterial(primaryColour));
|
mast.setMaterial(new PhongMaterial(primaryColour));
|
||||||
MeshView sail = importSTL(boatType.sailFile);
|
boatAssets.getChildren().add(mast);
|
||||||
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
} else {
|
||||||
|
boatAssets.getChildren().add(new Group());
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshView sail = importBoatSTL(boatType.sailFile);
|
||||||
|
sail.setMaterial(
|
||||||
|
new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.DARKGRAY : Color.WHITE)
|
||||||
|
);
|
||||||
|
boatAssets.getChildren().add(sail);
|
||||||
|
|
||||||
if (boatType.jibFile != null) {
|
if (boatType.jibFile != null) {
|
||||||
MeshView jib = importSTL(boatType.jibFile);
|
MeshView jib = importBoatSTL(boatType.jibFile);
|
||||||
sail.setMaterial(new PhongMaterial(Color.WHITE));
|
jib.setMaterial(
|
||||||
boatAssets.getChildren().addAll(hull, mast, sail, jib);
|
new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.BLACK : Color.WHITE)
|
||||||
} else {
|
);
|
||||||
boatAssets.getChildren().addAll(hull, mast, sail);
|
boatAssets.getChildren().add(jib);
|
||||||
}
|
}
|
||||||
|
|
||||||
return boatAssets;
|
return boatAssets;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MeshView importSTL(String fileName) {
|
private static MeshView importBoatSTL(String fileName) {
|
||||||
|
return importSTL("boatSTLs/" + fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MeshView importSTL(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);
|
||||||
@@ -155,8 +145,16 @@ public class ModelFactory {
|
|||||||
assets.setCacheHint(CacheHint.SCALE_AND_ROTATE);
|
assets.setCacheHint(CacheHint.SCALE_AND_ROTATE);
|
||||||
}
|
}
|
||||||
switch (tokenType) {
|
switch (tokenType) {
|
||||||
|
case PLAYER_IDENTIFIER_TORUS:
|
||||||
|
return makeIdentifierTorus(assets);
|
||||||
|
case NEXT_MARK_INDICATOR:
|
||||||
|
return makeNextMarkIndicator(assets);
|
||||||
case VELOCITY_PICKUP:
|
case VELOCITY_PICKUP:
|
||||||
return makeCoinPickup(assets);
|
case BUMPER_PICKUP:
|
||||||
|
case RANDOM_PICKUP:
|
||||||
|
case HANDLING_PICKUP:
|
||||||
|
case WIND_WALKER_PICKUP:
|
||||||
|
return makeTokenPickup(assets);
|
||||||
case FINISH_MARKER:
|
case FINISH_MARKER:
|
||||||
case PLAIN_MARKER:
|
case PLAIN_MARKER:
|
||||||
case START_MARKER:
|
case START_MARKER:
|
||||||
@@ -185,24 +183,32 @@ public class ModelFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Model makeCoinPickup(Group assets){
|
private static Model makeIdentifierTorus(Group assets) {
|
||||||
assets.setRotationAxis(new Point3D(1,0,0));
|
// assets.getChildren().add(new AmbientLight());
|
||||||
assets.setRotate(90);
|
return new Model(new Group(assets), null);
|
||||||
assets.setTranslateX(0.2);
|
}
|
||||||
assets.setTranslateY(1);
|
|
||||||
|
private static Model makeNextMarkIndicator(Group assets) {
|
||||||
|
// assets.getChildren().add(new AmbientLight());
|
||||||
|
return new Model(new Group(assets), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Model makeTokenPickup(Group assets) {
|
||||||
|
Rotate animationRotate = new Rotate(0, new Point3D(0, 0, 1));
|
||||||
assets.getTransforms().addAll(
|
assets.getTransforms().addAll(
|
||||||
new Translate(0,-1,0),
|
animationRotate,
|
||||||
new Rotate(0 ,new Point3D(1,1,1))
|
new Translate(0, 0, -1)
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Model(new Group(assets), new AnimationTimer() {
|
return new Model(new Group(assets), new AnimationTimer() {
|
||||||
|
|
||||||
private double rotation = 0;
|
private double rotation = 0;
|
||||||
private Group group = assets;
|
private Rotate rotate = animationRotate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(long now) {
|
public void handle(long now) {
|
||||||
rotation += 1;
|
rotation += 1;
|
||||||
((Rotate) group.getTransforms().get(1)).setAngle(rotation);
|
rotate.setAngle(rotation);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ package seng302.visualiser.fxObjects.assets_3D;
|
|||||||
public enum ModelType {
|
public enum ModelType {
|
||||||
|
|
||||||
VELOCITY_PICKUP("velocity_pickup.dae"),
|
VELOCITY_PICKUP("velocity_pickup.dae"),
|
||||||
|
HANDLING_PICKUP("turning_pickup.dae"),
|
||||||
|
WIND_WALKER_PICKUP("wind_walker_pickup.dae"),
|
||||||
|
BUMPER_PICKUP("bumper_pickup.dae"),
|
||||||
|
RANDOM_PICKUP("random_pickup.dae"),
|
||||||
FINISH_MARKER ("finish_marker.dae"),
|
FINISH_MARKER ("finish_marker.dae"),
|
||||||
START_MARKER ("start_marker.dae"),
|
START_MARKER ("start_marker.dae"),
|
||||||
PLAIN_MARKER ("plain_marker.dae"),
|
PLAIN_MARKER ("plain_marker.dae"),
|
||||||
@@ -22,7 +26,11 @@ public enum ModelType {
|
|||||||
PLAYER_IDENTIFIER ("player_identifier.dae"),
|
PLAYER_IDENTIFIER ("player_identifier.dae"),
|
||||||
PLAIN_ARROW ("arrow.dae"),
|
PLAIN_ARROW ("arrow.dae"),
|
||||||
START_ARROW ("start_arrow.dae"),
|
START_ARROW ("start_arrow.dae"),
|
||||||
FINISH_ARROW ("finish_arrow.dae");
|
FINISH_ARROW ("finish_arrow.dae"),
|
||||||
|
LAND("land.dae"),
|
||||||
|
LAND_SMOOTH("land_smooth.dae"),
|
||||||
|
NEXT_MARK_INDICATOR("indicator_arrow.dae"),
|
||||||
|
PLAYER_IDENTIFIER_TORUS("torus.dae");
|
||||||
|
|
||||||
final String filename;
|
final String filename;
|
||||||
|
|
||||||
|
|||||||
@@ -66,3 +66,11 @@
|
|||||||
/*-fx-background-size: cover;*/
|
/*-fx-background-size: cover;*/
|
||||||
-fx-background-color: dodgerblue;
|
-fx-background-color: dodgerblue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tokenView {
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tokenGridView StackPane {
|
||||||
|
-fx-background-color: white;
|
||||||
|
}
|
||||||
@@ -38,30 +38,31 @@
|
|||||||
-fx-font-size: 23px;
|
-fx-font-size: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connectButton {
|
#connectButton, #roomConnectButton, #directConnectButton, #autoSelectGame {
|
||||||
-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;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connectButton:hover {
|
#connectButton:hover, #roomConnectButton:hover, #directConnectButton:hover, #autoSelectGame:hover {
|
||||||
-fx-font-size: 23px;
|
-fx-font-size: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
.root {
|
||||||
|
-fx-effect: -fx-pp-dropshadow-dark;
|
||||||
|
-fx-background-radius: 5;
|
||||||
|
-fx-padding: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rootPane {
|
||||||
|
-fx-background-image: url("/images/waves.png");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#headText {
|
||||||
|
-fx-font-size: 52px;
|
||||||
|
-fx-text-fill: rgb(30, 30, 30);
|
||||||
|
-fx-effect: -fx-pp-dropshadow-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
#subHeadLabel {
|
||||||
|
-fx-text-fill: rgb(30, 30, 30);
|
||||||
|
-fx-effect: -fx-pp-dropshadow-dark;
|
||||||
|
-fx-font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-purple .arc {
|
||||||
|
-fx-stroke: #ab47bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-blue .arc {
|
||||||
|
-fx-stroke: #2962ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-cyan .arc {
|
||||||
|
-fx-stroke: #00b8d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-green .arc {
|
||||||
|
-fx-stroke: #00c853;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-yellow .arc {
|
||||||
|
-fx-stroke: #ffd600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-orange .arc {
|
||||||
|
-fx-stroke: #ff6d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.materialDesign-red .arc {
|
||||||
|
-fx-stroke: #d50000;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
.text-area {
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-background-color: transparent, white, transparent, white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area .content {
|
||||||
|
-fx-background-color: transparent, white, transparent, white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area:focused .content {
|
||||||
|
-fx-background-color: transparent, white, transparent, white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area:focused {
|
||||||
|
-fx-highlight-fill: #7ecfff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area .content {
|
||||||
|
-fx-padding: 10px;
|
||||||
|
-fx-text-fill: gray;
|
||||||
|
-fx-highlight-fill: #7ecfff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#maxPlayersGridPane VBox * {
|
||||||
|
-fx-font-family: monospace !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#submitBtn {
|
||||||
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-light-text-color;
|
||||||
|
-fx-font-size: 20px;
|
||||||
|
-fx-effect: -fx-pp-dropshadow-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jfx-rippler {
|
||||||
|
-jfx-rippler-fill: -fx-pp-light-theme-color; /* set rippler color for button */
|
||||||
|
}
|
||||||
|
|
||||||
|
#submitBtn:hover {
|
||||||
|
-fx-font-size: 23px;
|
||||||
|
-fx-background-color: -fx-pp-light-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hostDialogHeader {
|
||||||
|
-fx-font-size: 30px;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#serverName {
|
||||||
|
-jfx-focus-color: -fx-pp-dark-text-color;
|
||||||
|
-jfx-unfocus-color: -fx-pp-dark-text-color;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
-fx-prompt-text-fill: -fx-pp-dark-text-color;
|
||||||
|
-fx-font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#maxPlayersLabel {
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
-fx-font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#maxPlayerPromptLabel {
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
-fx-font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maxPlayers {
|
||||||
|
-fx-font-size: 13px;
|
||||||
|
}
|
||||||
@@ -35,14 +35,14 @@ JFXToggleButton {
|
|||||||
-fx-text-fill: -fx-pp-theme-color;
|
-fx-text-fill: -fx-pp-theme-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
#resetBtn {
|
#resetBtn, #confirmBtn {
|
||||||
-fx-background-color: -fx-pp-theme-color;
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
-fx-text-fill: -fx-pp-front-color;
|
-fx-text-fill: -fx-pp-front-color;
|
||||||
-fx-effect: -fx-pp-dropshadow-light;
|
-fx-effect: -fx-pp-dropshadow-light;
|
||||||
-fx-font-size: 18;
|
-fx-font-size: 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
#resetBtn:hover {
|
#resetBtn:hover, #confirmBtn:hover {
|
||||||
-fx-font-size: 20;
|
-fx-font-size: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,14 @@
|
|||||||
-fx-font-family: monospace !important;
|
-fx-font-family: monospace !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sliderLabel {
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-label * {
|
||||||
|
-fx-text-fill: red;
|
||||||
|
}
|
||||||
|
|
||||||
#submitBtn {
|
#submitBtn {
|
||||||
-fx-background-color: -fx-pp-theme-color;
|
-fx-background-color: -fx-pp-theme-color;
|
||||||
-fx-text-fill: -fx-pp-light-text-color;
|
-fx-text-fill: -fx-pp-light-text-color;
|
||||||
@@ -32,12 +40,7 @@
|
|||||||
-fx-font-size: 16px;
|
-fx-font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#maxPlayersLabel {
|
.optionLabel {
|
||||||
-fx-text-fill: -fx-pp-dark-text-color;
|
|
||||||
-fx-font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#maxPlayerPromptLabel {
|
|
||||||
-fx-text-fill: -fx-pp-dark-text-color;
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
-fx-font-size: 16px;
|
-fx-font-size: 16px;
|
||||||
}
|
}
|
||||||
@@ -45,3 +48,18 @@
|
|||||||
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXCheckBox {
|
||||||
|
-jfx-checked-color: -fx-pp-theme-color;
|
||||||
|
-fx-text-fill: -fx-pp-dark-text-color;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* a separate file to dynamically change snackbar's color */
|
/* a separate file to dynamically change snackbar's color */
|
||||||
.jfx-snackbar-toast {
|
.jfx-snackbar-toast {
|
||||||
-fx-text-fill: red !important;
|
-fx-text-fill: black !important;
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 866 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RaceDefinition>
|
||||||
|
|
||||||
|
<CourseName> Loopty Loop </CourseName>
|
||||||
|
|
||||||
|
<CentralLat> 57.6679590 </CentralLat>
|
||||||
|
<CentralLng> 11.8503233 </CentralLng>
|
||||||
|
|
||||||
|
<MaxPlayers> 5 </MaxPlayers>
|
||||||
|
|
||||||
|
<Marks>
|
||||||
|
<CompoundMark CompoundMarkID="1">
|
||||||
|
<Mark Lat="57.6675700" Lng="11.8359880"/>
|
||||||
|
<Mark Lat="57.667610" Lng="11.833473"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2">
|
||||||
|
<Mark Lat="57.670914" Lng="11.835263"/>
|
||||||
|
<Mark Lat="57.6699024" Lng="11.8353195"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3">
|
||||||
|
<Mark Lat="57.6674596" Lng="11.8417500"/>
|
||||||
|
<Mark Lat="57.667473" Lng="11.84429"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4">
|
||||||
|
<Mark Lat="57.6657945" Lng="11.8351409"/>
|
||||||
|
<Mark Lat="57.6643158" Lng="11.8352297"/>
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5">
|
||||||
|
<Mark Lat="57.667311" Lng="11.828857"/>
|
||||||
|
<Mark Lat="57.667334" Lng="11.825853"/>
|
||||||
|
</CompoundMark>
|
||||||
|
</Marks>
|
||||||
|
|
||||||
|
<Course>
|
||||||
|
<OpeningSegment>
|
||||||
|
<Corner CompoundMarkID="1" Rounding="PS"/>
|
||||||
|
<Corner CompoundMarkID="2" Rounding="P"/>
|
||||||
|
</OpeningSegment>
|
||||||
|
|
||||||
|
<RepeatingSegment>
|
||||||
|
<Corner CompoundMarkID="3" Rounding="SP"/>
|
||||||
|
<Corner CompoundMarkID="4" Rounding="PS"/>
|
||||||
|
</RepeatingSegment>
|
||||||
|
|
||||||
|
<ClosingSegment>
|
||||||
|
<Corner CompoundMarkID="5" Rounding="PS"/>
|
||||||
|
</ClosingSegment>
|
||||||
|
</Course>
|
||||||
|
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit Lat="57.672937" Lng="11.836257" />
|
||||||
|
<Limit Lat="57.671239" Lng="11.843078" />
|
||||||
|
<Limit Lat="57.667128" Lng="11.848022" />
|
||||||
|
<Limit Lat="57.664512" Lng="11.844839" />
|
||||||
|
<Limit Lat="57.662515" Lng="11.835569" />
|
||||||
|
<Limit Lat="57.663939" Lng="11.827501" />
|
||||||
|
<Limit Lat="57.667542" Lng="11.822952" />
|
||||||
|
<Limit Lat="57.671123" Lng="11.826858" />
|
||||||
|
</CourseLimit>
|
||||||
|
|
||||||
|
</RaceDefinition>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<asset>
|
||||||
|
<contributor>
|
||||||
|
<author>Blender User</author>
|
||||||
|
<authoring_tool>Blender 2.79.0 commit date:2017-09-11, commit time:10:43, hash:5bd8ac9</authoring_tool>
|
||||||
|
</contributor>
|
||||||
|
<created>2017-09-28T01:59:46</created>
|
||||||
|
<modified>2017-09-28T01:59:46</modified>
|
||||||
|
<unit name="meter" meter="1"/>
|
||||||
|
<up_axis>Z_UP</up_axis>
|
||||||
|
</asset>
|
||||||
|
<library_images/>
|
||||||
|
<library_effects>
|
||||||
|
<effect id="Material_001-effect">
|
||||||
|
<profile_COMMON>
|
||||||
|
<technique sid="common">
|
||||||
|
<phong>
|
||||||
|
<emission>
|
||||||
|
<color sid="emission">0 0 0 1</color>
|
||||||
|
</emission>
|
||||||
|
<ambient>
|
||||||
|
<color sid="ambient">0 0 0 1</color>
|
||||||
|
</ambient>
|
||||||
|
<diffuse>
|
||||||
|
<color sid="diffuse">0 0.3215737 0.002428917 1</color>
|
||||||
|
</diffuse>
|
||||||
|
<specular>
|
||||||
|
<color sid="specular">0.1614584 0.1614584 0.1614584 1</color>
|
||||||
|
</specular>
|
||||||
|
<shininess>
|
||||||
|
<float sid="shininess">50</float>
|
||||||
|
</shininess>
|
||||||
|
<index_of_refraction>
|
||||||
|
<float sid="index_of_refraction">1</float>
|
||||||
|
</index_of_refraction>
|
||||||
|
</phong>
|
||||||
|
</technique>
|
||||||
|
</profile_COMMON>
|
||||||
|
</effect>
|
||||||
|
</library_effects>
|
||||||
|
<library_materials>
|
||||||
|
<material id="Material_001-material" name="Material_001">
|
||||||
|
<instance_effect url="#Material_001-effect"/>
|
||||||
|
</material>
|
||||||
|
</library_materials>
|
||||||
|
<library_geometries>
|
||||||
|
<geometry id="Cone-mesh" name="Cone">
|
||||||
|
<mesh>
|
||||||
|
<source id="Cone-mesh-positions">
|
||||||
|
<float_array id="Cone-mesh-positions-array" count="99">0 1 -1 0 0 1 0.1950902 0.9807853 -1 0.3826835 0.9238795 -1 0.5555703 0.8314696 -1 0.7071068 0.7071068 -1 0.8314697 0.5555702 -1 0.9238795 0.3826834 -1 0.9807853 0.1950902 -1 1 0 -1 0.9807853 -0.1950902 -1 0.9238796 -0.3826833 -1 0.8314697 -0.5555702 -1 0.7071068 -0.7071068 -1 0.5555702 -0.8314697 -1 0.3826833 -0.9238796 -1 0.1950901 -0.9807853 -1 -3.25841e-7 -1 -1 -0.1950907 -0.9807852 -1 -0.3826839 -0.9238793 -1 -0.5555707 -0.8314693 -1 -0.7071073 -0.7071064 -1 -0.83147 -0.5555697 -1 -0.9238799 -0.3826827 -1 -0.9807854 -0.1950893 -1 -1 9.65599e-7 -1 -0.9807851 0.1950913 -1 -0.9238791 0.3826845 -1 -0.8314689 0.5555713 -1 -0.7071059 0.7071077 -1 -0.5555691 0.8314704 -1 -0.3826821 0.9238801 -1 -0.1950888 0.9807856 -1</float_array>
|
||||||
|
<technique_common>
|
||||||
|
<accessor source="#Cone-mesh-positions-array" count="33" stride="3">
|
||||||
|
<param name="X" type="float"/>
|
||||||
|
<param name="Y" type="float"/>
|
||||||
|
<param name="Z" type="float"/>
|
||||||
|
</accessor>
|
||||||
|
</technique_common>
|
||||||
|
</source>
|
||||||
|
<source id="Cone-mesh-normals">
|
||||||
|
<float_array id="Cone-mesh-normals-array" count="117">0.08775347 0.8909768 0.4454884 0.2598883 0.8567371 0.4454883 0.4220357 0.7895733 0.4454883 0.5679644 0.6920669 0.4454883 0.6920669 0.5679644 0.4454883 0.7895736 0.4220353 0.4454883 0.8567369 0.2598885 0.4454883 0.8909768 0.08775347 0.4454884 0.8909768 -0.08775347 0.4454884 0.8567371 -0.2598881 0.4454883 0.7895734 -0.4220355 0.4454884 0.6920669 -0.5679644 0.4454883 0.5679644 -0.6920669 0.4454883 0.4220356 -0.7895734 0.4454883 0.2598879 -0.8567371 0.4454885 0.08775335 -0.8909768 0.4454884 -0.08775389 -0.8909767 0.4454883 -0.2598887 -0.8567368 0.4454883 -0.4220361 -0.7895731 0.4454884 -0.5679646 -0.6920668 0.4454883 -0.6920675 -0.5679637 0.4454884 -0.7895734 -0.4220355 0.4454884 -0.8567374 -0.2598869 0.4454883 -0.8909769 -0.08775287 0.4454884 -0.8909766 0.08775418 0.4454883 -0.8567367 0.2598895 0.4454884 -0.7895728 0.4220367 0.4454883 -0.6920663 0.5679652 0.4454883 -0.5679636 0.6920676 0.4454884 -0.4220345 0.789574 0.4454885 -0.259887 0.8567373 0.4454883 -0.08775269 0.8909768 0.4454884 0 0 -1 -3.97508e-6 0 -1 3.97512e-6 0 -1 3.88859e-7 0 -1 -1.36853e-6 0 -1 1.36853e-6 0 -1 -3.88857e-7 0 -1</float_array>
|
||||||
|
<technique_common>
|
||||||
|
<accessor source="#Cone-mesh-normals-array" count="39" stride="3">
|
||||||
|
<param name="X" type="float"/>
|
||||||
|
<param name="Y" type="float"/>
|
||||||
|
<param name="Z" type="float"/>
|
||||||
|
</accessor>
|
||||||
|
</technique_common>
|
||||||
|
</source>
|
||||||
|
<vertices id="Cone-mesh-vertices">
|
||||||
|
<input semantic="POSITION" source="#Cone-mesh-positions"/>
|
||||||
|
</vertices>
|
||||||
|
<triangles material="Material_001-material" count="62">
|
||||||
|
<input semantic="VERTEX" source="#Cone-mesh-vertices" offset="0"/>
|
||||||
|
<input semantic="NORMAL" source="#Cone-mesh-normals" offset="1"/>
|
||||||
|
<p>0 0 1 0 2 0 2 1 1 1 3 1 3 2 1 2 4 2 4 3 1 3 5 3 5 4 1 4 6 4 6 5 1 5 7 5 7 6 1 6 8 6 8 7 1 7 9 7 9 8 1 8 10 8 10 9 1 9 11 9 11 10 1 10 12 10 12 11 1 11 13 11 13 12 1 12 14 12 14 13 1 13 15 13 15 14 1 14 16 14 16 15 1 15 17 15 17 16 1 16 18 16 18 17 1 17 19 17 19 18 1 18 20 18 20 19 1 19 21 19 21 20 1 20 22 20 22 21 1 21 23 21 23 22 1 22 24 22 24 23 1 23 25 23 25 24 1 24 26 24 26 25 1 25 27 25 27 26 1 26 28 26 28 27 1 27 29 27 29 28 1 28 30 28 30 29 1 29 31 29 31 30 1 30 32 30 32 31 1 31 0 31 16 32 24 32 8 32 32 32 0 32 2 32 2 32 3 32 4 32 4 32 5 32 6 32 6 32 7 32 4 32 8 32 9 32 10 32 10 32 11 32 8 32 12 32 13 32 16 32 14 32 15 32 16 32 16 32 17 32 18 32 18 32 19 32 20 32 20 32 21 32 22 32 22 33 23 33 24 33 24 34 25 34 26 34 26 32 27 32 28 32 28 32 29 32 32 32 30 32 31 32 32 32 32 35 2 35 8 35 4 36 7 36 8 36 8 37 11 37 12 37 13 32 14 32 16 32 16 32 18 32 24 32 20 32 22 32 24 32 24 38 26 38 32 38 29 32 30 32 32 32 2 32 4 32 8 32 8 32 12 32 16 32 18 32 20 32 24 32 26 32 28 32 32 32 32 32 8 32 24 32</p>
|
||||||
|
</triangles>
|
||||||
|
</mesh>
|
||||||
|
</geometry>
|
||||||
|
</library_geometries>
|
||||||
|
<library_controllers/>
|
||||||
|
<library_visual_scenes>
|
||||||
|
<visual_scene id="Scene" name="Scene">
|
||||||
|
<node id="Cone" name="Cone" type="NODE">
|
||||||
|
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 1.015816 0 0 0 1</matrix>
|
||||||
|
<instance_geometry url="#Cone-mesh" name="Cone">
|
||||||
|
<bind_material>
|
||||||
|
<technique_common>
|
||||||
|
<instance_material symbol="Material_001-material" target="#Material_001-material"/>
|
||||||
|
</technique_common>
|
||||||
|
</bind_material>
|
||||||
|
</instance_geometry>
|
||||||
|
</node>
|
||||||
|
</visual_scene>
|
||||||
|
</library_visual_scenes>
|
||||||
|
<scene>
|
||||||
|
<instance_visual_scene url="#Scene"/>
|
||||||
|
</scene>
|
||||||
|
</COLLADA>
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.net.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?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 java.lang.String?>
|
<?import java.lang.String?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
@@ -13,7 +21,7 @@
|
|||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
|
||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||||
<children>
|
<children>
|
||||||
@@ -51,10 +59,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="586.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="120000.0" minWidth="10.0" prefWidth="314.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="445.0" minWidth="10.0" prefWidth="314.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" />
|
||||||
@@ -63,29 +80,148 @@
|
|||||||
</GridPane>
|
</GridPane>
|
||||||
<GridPane GridPane.rowIndex="1">
|
<GridPane GridPane.rowIndex="1">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" />
|
<ColumnConstraints hgrow="NEVER" maxWidth="-Infinity" minWidth="-Infinity"
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="400.0" minWidth="400.0" prefWidth="400.0" />
|
prefWidth="115.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"
|
||||||
|
minWidth="337.0" prefWidth="430.0"/>
|
||||||
|
<ColumnConstraints hgrow="NEVER" maxWidth="350.0" minWidth="350.0"
|
||||||
|
prefWidth="350.0"/>
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints vgrow="SOMETIMES" />
|
<RowConstraints vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
<ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
<content>
|
<content>
|
||||||
<VBox fx:id="playerListVBox" prefHeight="200.0" prefWidth="100.0" />
|
<VBox fx:id="playerListVBox" alignment="TOP_RIGHT" maxWidth="328.0" minWidth="328.0" prefWidth="328.0" />
|
||||||
</content>
|
</content>
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
|
<padding>
|
||||||
|
<Insets right="5.0" />
|
||||||
|
</padding>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
<AnchorPane fx:id="serverMap" style="-fx-background-color: skyblue;">
|
<AnchorPane fx:id="serverMap" style="-fx-background-color: skyblue;" GridPane.columnIndex="1">
|
||||||
<opaqueInsets>
|
<opaqueInsets>
|
||||||
<Insets />
|
<Insets />
|
||||||
</opaqueInsets>
|
</opaqueInsets>
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
|
<Insets bottom="15.0" left="7.0" right="7.0" top="15.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
|
<GridPane prefHeight="370.0" prefWidth="189.0" styleClass="tokenGridView"
|
||||||
|
vgap="5.0">
|
||||||
|
<children>
|
||||||
|
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Tokens"
|
||||||
|
GridPane.halignment="CENTER">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="18.0"/>
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0"
|
||||||
|
GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<Label alignment="BOTTOM_CENTER" text="Speed"
|
||||||
|
StackPane.alignment="BOTTOM_CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="12.0"/>
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="5.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Pane fx:id="speedTokenPane" prefHeight="999.0"
|
||||||
|
prefWidth="200.0" styleClass="tokenView"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0"
|
||||||
|
GridPane.rowIndex="2">
|
||||||
|
<children>
|
||||||
|
<Label alignment="BOTTOM_CENTER" text="Handling"
|
||||||
|
StackPane.alignment="BOTTOM_CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="12.0"/>
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="5.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Pane fx:id="handlingTokenPane" prefHeight="999.0"
|
||||||
|
prefWidth="200.0" styleClass="tokenView"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0"
|
||||||
|
GridPane.rowIndex="3">
|
||||||
|
<children>
|
||||||
|
<Label alignment="BOTTOM_CENTER" text="Wind Walker"
|
||||||
|
StackPane.alignment="BOTTOM_CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="12.0"/>
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="5.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Pane fx:id="windWalkerTokenPane" prefHeight="999.0"
|
||||||
|
prefWidth="200.0" styleClass="tokenView"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0"
|
||||||
|
GridPane.rowIndex="4">
|
||||||
|
<children>
|
||||||
|
<Label alignment="BOTTOM_CENTER" text="Bumper"
|
||||||
|
StackPane.alignment="BOTTOM_CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="12.0"/>
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="5.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Pane fx:id="bumperTokenPane" prefHeight="999.0"
|
||||||
|
prefWidth="200.0" styleClass="tokenView"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<StackPane prefHeight="150.0" prefWidth="200.0"
|
||||||
|
GridPane.rowIndex="5">
|
||||||
|
<children>
|
||||||
|
<Label alignment="BOTTOM_CENTER" text="Random"
|
||||||
|
StackPane.alignment="BOTTOM_CENTER">
|
||||||
|
<font>
|
||||||
|
<Font size="12.0"/>
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="5.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Pane fx:id="randomTokenPane" prefHeight="999.0"
|
||||||
|
prefWidth="60.0" styleClass="tokenView"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
</children>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="80.0"
|
||||||
|
prefWidth="80.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0"/>
|
||||||
|
</padding>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="116.0" minHeight="0.0" prefHeight="40.0"
|
||||||
|
vgrow="NEVER"/>
|
||||||
|
<RowConstraints maxHeight="285.0" minHeight="-Infinity"
|
||||||
|
prefHeight="60.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="285.0" minHeight="-Infinity"
|
||||||
|
prefHeight="60.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="141.0" minHeight="-Infinity"
|
||||||
|
prefHeight="60.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="285.0" minHeight="-Infinity"
|
||||||
|
prefHeight="60.0" vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="285.0" minHeight="-Infinity"
|
||||||
|
prefHeight="60.0" vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
@@ -97,10 +233,10 @@
|
|||||||
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="400.0" prefHeight="400.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="400.0" prefHeight="400.0" vgrow="SOMETIMES" />
|
||||||
<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>
|
</rowConstraints>
|
||||||
<stylesheets>
|
|
||||||
<String fx:value="/css/Master.css" />
|
|
||||||
<String fx:value="/css/LobbyView.css" />
|
|
||||||
</stylesheets>
|
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../css/Master.css"/>
|
||||||
|
<URL value="@../css/LobbyView.css"/>
|
||||||
|
</stylesheets>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
<?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.image.*?>
|
||||||
|
<?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?>
|
||||||
@@ -14,11 +21,12 @@
|
|||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
|
<StackPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.RaceViewController">
|
||||||
|
<children>
|
||||||
<StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308"
|
<StackPane fx:id="contentStackPane" 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: skyblue;" xmlns="http://javafx.com/javafx/8.0.111"
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1">
|
||||||
fx:controller="seng302.visualiser.controllers.RaceViewController">
|
|
||||||
<children>
|
<children>
|
||||||
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
<GridPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
||||||
prefHeight="800.0" prefWidth="1200.0">
|
prefHeight="800.0" prefWidth="1200.0">
|
||||||
@@ -224,9 +232,84 @@
|
|||||||
<Insets bottom="10.0" left="10.0" top="40.0"/>
|
<Insets bottom="10.0" left="10.0" top="40.0"/>
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
<RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0"
|
||||||
|
vgrow="SOMETIMES"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0"
|
||||||
|
pickOnBounds="true" preserveRatio="true" visible="false"
|
||||||
|
GridPane.halignment="CENTER" GridPane.rowIndex="1">
|
||||||
|
<image>
|
||||||
|
<Image url="@../icons/velocity.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0"
|
||||||
|
pickOnBounds="true" preserveRatio="true" visible="false"
|
||||||
|
GridPane.columnIndex="1" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1">
|
||||||
|
<image>
|
||||||
|
<Image url="@../icons/handlingIcon.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0"
|
||||||
|
pickOnBounds="true" preserveRatio="true" visible="false"
|
||||||
|
GridPane.columnIndex="2" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1">
|
||||||
|
<image>
|
||||||
|
<Image url="@../icons/windWalkerIcon.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0"
|
||||||
|
pickOnBounds="true" preserveRatio="true" visible="false"
|
||||||
|
GridPane.columnIndex="3" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1">
|
||||||
|
<image>
|
||||||
|
<Image url="@../icons/bumperIcon.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0"
|
||||||
|
pickOnBounds="true" preserveRatio="true" visible="false"
|
||||||
|
GridPane.columnIndex="4" GridPane.halignment="CENTER"
|
||||||
|
GridPane.rowIndex="1" GridPane.valignment="CENTER">
|
||||||
|
<image>
|
||||||
|
<Image url="@../icons/slowedIcon.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<Pane fx:id="miniMapPane" maxHeight="200.0" maxWidth="200.0" minHeight="200.0" minWidth="200.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" StackPane.alignment="TOP_RIGHT">
|
||||||
|
<StackPane.margin>
|
||||||
|
<Insets right="15.0" top="15.0" />
|
||||||
|
</StackPane.margin>
|
||||||
|
</Pane>
|
||||||
|
<JFXButton fx:id="miniMapButton" style="-fx-background-color: white; -fx-opacity: 0.45; -fx-background-radius: 10;" text="✕" StackPane.alignment="TOP_RIGHT">
|
||||||
|
<font>
|
||||||
|
<Font size="15.0" />
|
||||||
|
</font>
|
||||||
|
<StackPane.margin>
|
||||||
|
<Insets right="15.0" top="15.0" />
|
||||||
|
</StackPane.margin>
|
||||||
|
</JFXButton>
|
||||||
|
<AnchorPane fx:id="loadingScreenPane">
|
||||||
|
<ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" />
|
||||||
|
<JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" />
|
||||||
|
</AnchorPane>
|
||||||
|
</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" />
|
||||||
|
|||||||
@@ -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,49 +18,60 @@
|
|||||||
<?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" prefHeight="70.0" prefWidth="888.0" GridPane.rowIndex="2">
|
||||||
<children>
|
<children>
|
||||||
<JFXButton fx:id="connectButton" buttonType="RAISED" prefHeight="45.0"
|
<JFXButton fx:id="directConnectButton" buttonType="RAISED" maxHeight="45.0" prefHeight="45.0" prefWidth="220.0" ripplerFill="#3493e3" text="Direct Connect" textFill="WHITE" GridPane.columnIndex="7" GridPane.halignment="RIGHT" 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">
|
<Label fx:id="connectLabel" text="Join Room: " GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="20.0" right="20.0" />
|
|
||||||
</GridPane.margin>
|
|
||||||
</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">
|
|
||||||
<GridPane.margin>
|
|
||||||
<Insets left="20.0" right="20.0" />
|
|
||||||
</GridPane.margin>
|
|
||||||
</JFXTextField>
|
|
||||||
<Label fx:id="connectLabel" text="Direct Connect:" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets right="45.0" />
|
<Insets right="45.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</Label>
|
</Label>
|
||||||
|
<JFXButton fx:id="roomConnectButton" maxHeight="45.0" prefHeight="45.0" prefWidth="220.0" text="Join Room" textFill="WHITE" GridPane.columnIndex="4" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets />
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXButton>
|
||||||
|
<JFXTextField fx:id="roomNumber" promptText="Room Code" GridPane.columnIndex="3">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets bottom="5.0" right="20.0" top="5.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
<font>
|
||||||
|
<Font size="11.0" />
|
||||||
|
</font>
|
||||||
|
<opaqueInsets>
|
||||||
|
<Insets />
|
||||||
|
</opaqueInsets>
|
||||||
|
</JFXTextField>
|
||||||
|
<JFXButton fx:id="autoSelectGame" maxHeight="45.0" prefHeight="45.0" prefWidth="220.0" text="Auto-Select Game" textFill="WHITE" GridPane.columnIndex="6" GridPane.halignment="RIGHT" GridPane.valignment="CENTER">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="10.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXButton>
|
||||||
</children>
|
</children>
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" />
|
<ColumnConstraints hgrow="SOMETIMES" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="280.0" minWidth="180.0" prefWidth="180.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="280.0" minWidth="21.0" prefWidth="21.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="320.0" minWidth="280.0" prefWidth="280.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="320.0" minWidth="70.0" prefWidth="112.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="180.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="260.0" minWidth="-Infinity" prefWidth="119.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="17.0" minWidth="17.0" prefWidth="17.0" />
|
<ColumnConstraints halignment="LEFT" hgrow="SOMETIMES" maxWidth="215.0" minWidth="17.0" prefWidth="148.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="273.0" minWidth="250.0" prefWidth="273.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1000.0" minWidth="17.0" prefWidth="77.0" />
|
||||||
|
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="326.0" minWidth="134.0" prefWidth="226.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="326.0" minWidth="198.0" prefWidth="198.0" />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
<ScrollPane id="serverListPane" fx:id="serverListScrollPane" hbarPolicy="NEVER" prefHeight="1000.0" prefWidth="880.0" GridPane.rowIndex="1">
|
<ScrollPane id="serverListPane" fx:id="serverListScrollPane" hbarPolicy="NEVER" prefHeight="1000.0" prefWidth="900.0" GridPane.rowIndex="1">
|
||||||
<content>
|
<content>
|
||||||
<VBox id="serverListVBox" fx:id="serverListVBox" prefHeight="200.0" prefWidth="100.0">
|
<VBox id="serverListVBox" fx:id="serverListVBox" prefHeight="200.0" prefWidth="100.0">
|
||||||
<padding>
|
<padding>
|
||||||
@@ -76,10 +93,7 @@
|
|||||||
<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>
|
||||||
@@ -99,8 +113,8 @@
|
|||||||
</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="429.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
|
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/Master.css" />
|
<String fx:value="/css/Master.css" />
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.jfoenix.controls.JFXSpinner?>
|
||||||
|
<?import java.net.URL?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.image.Image?>
|
||||||
|
<?import javafx.scene.image.ImageView?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<StackPane fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
||||||
|
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8"
|
||||||
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="seng302.visualiser.controllers.SplashScreenController">
|
||||||
|
<children>
|
||||||
|
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||||
|
<children>
|
||||||
|
<Label fx:id="subHeadLabel" layoutX="225.0" layoutY="370.0"
|
||||||
|
text="MADE BY :PARTYPARROT:"/>
|
||||||
|
<StackPane layoutX="150.0" layoutY="10.0" prefHeight="150.0" prefWidth="200.0">
|
||||||
|
<children>
|
||||||
|
<ImageView fitHeight="190.0" fitWidth="190.0" pickOnBounds="true"
|
||||||
|
preserveRatio="true">
|
||||||
|
<image>
|
||||||
|
<Image url="@../PP.png"/>
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<JFXSpinner fx:id="materialDesignRed" radius="150.0" startingAngle="0.0"
|
||||||
|
styleClass="materialDesign-red"/>
|
||||||
|
<JFXSpinner radius="140.0" startingAngle="20.0"
|
||||||
|
styleClass="materialDesign-orange"/>
|
||||||
|
<JFXSpinner radius="130.0" startingAngle="40.0"
|
||||||
|
styleClass="materialDesign-yellow"/>
|
||||||
|
<JFXSpinner radius="120.0" startingAngle="60.0"
|
||||||
|
styleClass="materialDesign-green"/>
|
||||||
|
<JFXSpinner radius="110.0" startingAngle="80.0" styleClass="materialDesign-cyan"/>
|
||||||
|
<JFXSpinner radius="100.0" startingAngle="100.0"
|
||||||
|
styleClass="materialDesign-blue"/>
|
||||||
|
<JFXSpinner radius="90.0" startingAngle="120.0"
|
||||||
|
styleClass="materialDesign-purple"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
<Label fx:id="headText" layoutX="36.0" layoutY="295.0" text="PARTY PARROT AT SEA"/>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<URL value="@../css/Master.css"/>
|
||||||
|
<URL value="@../css/SplashScreenView.css"/>
|
||||||
|
</stylesheets>
|
||||||
|
</StackPane>
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
<?import java.lang.String?>
|
<?import java.lang.String?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
@@ -8,20 +12,17 @@
|
|||||||
<?import javafx.scene.layout.Pane?>
|
<?import javafx.scene.layout.Pane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<VBox fx:id="playerCellVBox" maxHeight="-Infinity" maxWidth="1.7976931348623157E308"
|
|
||||||
minHeight="-Infinity" minWidth="-Infinity" prefHeight="80.0"
|
<VBox fx:id="playerCellVBox" maxHeight="-Infinity" maxWidth="340.0" minHeight="-Infinity" minWidth="340.0" prefHeight="80.0" prefWidth="340.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
|
|
||||||
<stylesheets>
|
<stylesheets>
|
||||||
<String fx:value="/css/Master.css" />
|
<String fx:value="/css/Master.css" />
|
||||||
<String fx:value="/css/cells/PlayerCell.css" />
|
<String fx:value="/css/cells/PlayerCell.css" />
|
||||||
</stylesheets>
|
</stylesheets>
|
||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="playerListCell" maxHeight="-Infinity" maxWidth="1.7976931348623157E308"
|
<GridPane fx:id="playerListCell" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="70.0">
|
||||||
minHeight="-Infinity" prefHeight="70.0">
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="80.0" prefWidth="80.0" />
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="80.0" prefWidth="80.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="290.0" minWidth="290.0"
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="260.0" minWidth="260.0" prefWidth="260.0" />
|
||||||
prefWidth="290.0"/>
|
|
||||||
</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" />
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.jfoenix.controls.JFXButton?>
|
||||||
|
<?import com.jfoenix.controls.JFXDialogLayout?>
|
||||||
|
<?import com.jfoenix.controls.JFXTextField?>
|
||||||
|
<?import java.lang.String?>
|
||||||
|
<?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.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.DirectConnectController">
|
||||||
|
<children>
|
||||||
|
<GridPane>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="100.0" minHeight="60.0" prefHeight="66.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="140.0" minHeight="58.0" prefHeight="62.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="176.0" minHeight="100.0" prefHeight="172.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<Label fx:id="hostDialogHeader" text="Direct Connect" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
|
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="CONNECT" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
|
||||||
|
<JFXTextField fx:id="serverAddress" promptText="SERVER NAME" GridPane.rowIndex="1">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="30.0" right="30.0" />
|
||||||
|
</GridPane.margin></JFXTextField>
|
||||||
|
<JFXTextField fx:id="portNumber" promptText="PORT NUMBER" GridPane.rowIndex="2">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="30.0" right="30.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</JFXTextField>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</children>
|
||||||
|
<stylesheets>
|
||||||
|
<String fx:value="/css/dialogs/DirectConnect.css" />
|
||||||
|
<String fx:value="/css/Master.css" />
|
||||||
|
</stylesheets>
|
||||||
|
</JFXDialogLayout>
|
||||||