Compare commits

..

86 Commits

Author SHA1 Message Date
William Muir 057af2799a Added toggle button css settings
#story[1274]
2017-09-28 16:47:55 +13:00
Zhi You Tan 45669c333a Merge remote-tracking branch 'origin/develop' into wind_arrow
# Conflicts:
#	src/main/resources/css/RaceView.css
#	src/main/resources/views/RaceView.fxml
2017-09-28 16:43:38 +13:00
Zhi You Tan f7fd5494ef merged Dev in
Fixed concurrency exception

#story[1276] #pair[zyt10, ajm412]
2017-09-28 16:40:50 +13:00
William Muir a1d468c689 Added toggle button for the chat history
#story[1274]
2017-09-28 16:39:59 +13:00
Zhi You Tan 6fafb02a8f Merge branch 'develop' into wind_arrow
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/resources/views/RaceView.fxml
2017-09-28 16:36:34 +13:00
Haoming Yin 4f80640718 Polished raceview UI elements
- changed javaFx css style into Css file

tags: #story[1273]
2017-09-28 16:33:16 +13:00
Zhi You Tan d436d2a6e4 Wind arrow now follows on every camera
Follows correctly

#story[1276] #pair[zyt10, ajm412]
2017-09-28 16:31:10 +13:00
Kusal Ekanayake 27379ae96d Fixed fatal bug to do with mark arrow on boat. 2017-09-28 16:27:57 +13:00
Kusal Ekanayake ce3e08abfc Changed minimise and maximise icons for minimap 2017-09-28 16:18:44 +13:00
Calum 923c381797 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:17:27 +13:00
Calum ece45ff967 Fixed map, parrot and camera. 2017-09-28 16:17:19 +13:00
William Muir 02dc1dbd3d Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:29 +13:00
Michael Rausch d9b9c2f808 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:07 +13:00
William Muir 4e3de02a93 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:04:04 +13:00
Michael Rausch 261f68f143 Added port number randomization
- Servers all run on different ports, so multiple servers can run on one host
- Port is displayed in lobby

Tags: #story[1281]
2017-09-28 16:03:59 +13:00
William Muir ed9b7acc62 New Map! Waiheke
#story[1274]
2017-09-28 16:03:56 +13:00
Michael Rausch 74c1219e0d Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/visualiser/GameClient.java
#	src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java
2017-09-28 16:02:04 +13:00
Calum 83218ae0a0 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 16:01:32 +13:00
Calum 0231c43a2c Arrows work. mark arrow thinner. refactored marker class.
#fix
2017-09-28 16:01:24 +13:00
Michael Rausch a05a41d5ec Added port number randomization
- Servers all run on different ports, so multiple servers can run on one host
- Port is displayed in lobby

Tags: #story[1281]
2017-09-28 15:57:59 +13:00
Haoming Yin 06bc3644bc Removed dead code in MeesageFactory and redundant classes
tags: #story[1273]
2017-09-28 15:54:09 +13:00
Haoming Yin 7620f0023e Removed dead code in MainServerThread
tags: #story[1273]
2017-09-28 15:43:35 +13:00
Kusal Ekanayake 77ee1ebbc0 Fixed faulty tests. 2017-09-28 15:35:58 +13:00
William Muir 6d0835b0cf Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
2017-09-28 15:29:00 +13:00
William Muir 54410efa12 Changed garbage collection to once every second, Changed wind walker icon to white
#story[1273]
2017-09-28 15:24:45 +13:00
William Muir 74241ee819 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:23:50 +13:00
Kusal Ekanayake a9ce8901f5 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:17:06 +13:00
Michael Rausch 8810554ce9 Fixed bug where server wasn't being unregistered from discovery server
- Added missing unregister() method call

Tags: #story[1281]
2017-09-28 15:16:37 +13:00
Kusal Ekanayake 7e3ed872ed Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	src/main/java/seng302/visualiser/ClientToServerThread.java
2017-09-28 15:08:53 +13:00
Kusal Ekanayake 21ce34dda2 Fixed finish screen and cleaned up dead code 2017-09-28 15:08:34 +13:00
William Muir 2bf318a122 Merge branch 'story1273_minimap' into develop 2017-09-28 15:08:32 +13:00
Michael Rausch e56d284792 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 15:00:24 +13:00
Michael Rausch 80c26a9e4a Fixed bug where server could connect to an expired server
- Increased update interval

Tags: #story[1281]
2017-09-28 15:00:00 +13:00
Calum e1ebbc71c1 Added drawing to fx thread
#fix
2017-09-28 14:57:52 +13:00
Calum c4a3df32c8 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:47:00 +13:00
Calum 1e19dd5ab6 Fixed parrot again. 2017-09-28 14:46:55 +13:00
William Muir c98297ea79 Merged dev changes back on to mini map
#story[1273]
2017-09-28 14:44:16 +13:00
Alistair McIntyre 1aedcaddf5 removed an added print statement
tags : #story[1275]
2017-09-28 14:42:34 +13:00
Alistair McIntyre d7fc339ad5 - Added Madagascar Map
tags : #story[1275]
2017-09-28 14:41:35 +13:00
William Muir a5eea10c87 Merge branch 'develop' into story1273_minimap
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
#	src/main/resources/meshes/boatSTLs/parrot_features.stl
2017-09-28 14:41:08 +13:00
Zhi You Tan 51078c82a0 Merge remote-tracking branch 'origin/develop' into wind_arrow
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
2017-09-28 14:38:31 +13:00
Zhi You Tan 22fbb529ef Wind arrow follows wind data
#story[1276]
2017-09-28 14:37:46 +13:00
Kusal Ekanayake 02aabc3162 Removing dead code in race view controller and fixed mark rounding bug 2017-09-28 14:35:40 +13:00
Alistair McIntyre d2a05de25a Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:34:39 +13:00
Calum 597fbe935f Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 14:28:16 +13:00
Calum 7cfad28d6b Fixed parrot 2017-09-28 14:28:07 +13:00
Michael Rausch 3345734efd Fixed memory leak by forcing garbage collection 2017-09-28 14:22:33 +13:00
Haoming Yin 9795083d4d Added confirm button in keybinding dialog.
-  clicking confirm button will exit the dialog
- [WIP] exit without clicking confirm button will still save changes, which should be fixed in the future

tags: #story[1273]
2017-09-28 13:58:25 +13:00
Kusal Ekanayake f02208ba3a Loopty loop map added 2017-09-28 13:33:09 +13:00
Zhi You Tan d3e8a21d2f Made the windView observer the gameView camera
#story[1276] #pair[ajm412, zyt10]
2017-09-28 13:18:19 +13:00
William Muir b9a2d60115 Merged dev changes back on to mini map
#story[1273]
2017-09-28 12:58:19 +13:00
William Muir 076c4c9a40 Merge branch 'develop' into story1273_minimap
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
#	src/main/resources/views/RaceView.fxml
2017-09-28 12:54:12 +13:00
Calum 8d74c3b756 Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 12:44:33 +13:00
Calum 3f666fa092 Made waka larger. 2017-09-28 12:44:24 +13:00
Haoming Yin 55d82298b6 Beautified the loading splash screen
- added 7-color rainbow spinners
- added background image
- added subtitle
- changed font size and color

tags: #story[1273]
2017-09-28 12:42:46 +13:00
William Muir 909407fe63 Merge branch '1293_PowerUps_TokenInfo' into develop 2017-09-28 12:31:14 +13:00
William Muir 499acb9733 Merge branch '1293_PowerUps_TokenInfo' into develop 2017-09-28 12:21:12 +13:00
Alistair McIntyre c72c4929ff Merge remote-tracking branch 'origin/develop' into develop 2017-09-28 12:15:44 +13:00
Alistair McIntyre 265b20ad61 - Created Madagascar Map Initial
tags : #story[1275]
2017-09-28 12:12:22 +13:00
Calum ddf5a96e0f Merge branch '1276_Next_Mark_Indicator' into develop 2017-09-28 12:03:30 +13:00
Calum 81b2d285e9 Changed arrow colour.
#fix
2017-09-28 12:02:24 +13:00
Calum 5d7f307260 Changed arrow colour.
#fix
2017-09-28 12:02:09 +13:00
Zhi You Tan 852575c9e7 Merge remote-tracking branch 'origin/develop' into wind_arrow
# Conflicts:
#	src/main/java/seng302/visualiser/controllers/RaceViewController.java
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
#	src/main/resources/views/RaceView.fxml
2017-09-28 11:57:12 +13:00
Kusal Ekanayake 4ec23a1785 Fixed race fxml not showing other elements 2017-09-28 11:30:09 +13:00
Haoming Yin 37e4fe4ce7 Issue #83: Server creation dialog need to be polished
- rearranged the layout of all the nodes
- set CSS files for the dialog
- added close button

tags: #story[1273]
2017-09-28 11:13:02 +13:00
Zhi You Tan 567e351c7f Updated wind arrow 3D model
#story[1276]
2017-09-28 11:02:47 +13:00
Calum e87931a8fc Merge branch 'develop' into story1273_minimap 2017-09-28 10:21:23 +13:00
Calum d1edbc4b8a Put the arrows into the minimap. Fixed the issue with curved section of port marks.
#fix #implement
2017-09-28 10:19:32 +13:00
Calum 275a2cbab7 Made continous turning the default. Added triangles to minimap. Made mark areas bigger
#fix #implement
2017-09-28 10:12:18 +13:00
Zhi You Tan 72fe8c4881 - Removed 2D wind and replaced with 3D wind arrow.
#story[1276]
2017-09-28 04:13:44 +13:00
Calum 0b8e2499a7 Fixed some internal stl faces on parrot
#fix
2017-09-28 03:35:28 +13:00
Calum 9075d2a909 Added a minimap to the race view.
#implement #story[1273]
2017-09-28 03:17:33 +13:00
alistairjmcintyre 00e2af9c14 - Fixed Merge Errors and some broken lighting AGAIN
#tags [1276]
2017-09-28 02:20:34 +13:00
alistairjmcintyre 73861b2ef3 Merge branch 'develop' into 1276_Next_Mark_Indicator 2017-09-28 02:06:18 +13:00
alistairjmcintyre 4018dd783e - Fixed Merge Errors and some broken lighting
#tags [1276]
2017-09-28 02:05:47 +13:00
Michael Rausch 8b7407bf89 Various bug fixes
- Closed socket when discovery server crashes, so it can be restarted
- Flattened water on terrain mesh
- Added checks to ensure server is started before connecting
- Added a check to ensure client has started  before connecting to the server
- Fixed concurrency issue in server-> client thread list

Tags: #story[1281]
2017-09-28 01:58:49 +13:00
alistairjmcintyre a08a38c985 - Fixed Merge Errors
#tags [1276]
2017-09-27 22:25:32 +13:00
alistairjmcintyre 810dde6a21 Merge branch 'develop' into 1276_Next_Mark_Indicator
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelType.java
2017-09-27 22:15:02 +13:00
alistairjmcintyre 7a76efa2ce - Added ability to color the indicators.
#tags [1276]
2017-09-27 22:07:24 +13:00
alistairjmcintyre c5e6302f86 - Added circle to boat to indicate which boat is the players and to show where the arrow is pointing.
#tags [1276]
2017-09-27 21:31:02 +13:00
Alistair McIntyre be72062c8e Merge branch 'develop' into 1276_Next_Mark_Indicator
# Conflicts:
#	src/main/java/seng302/visualiser/fxObjects/assets_3D/ModelFactory.java
2017-09-27 19:25:08 +13:00
Alistair McIntyre 0d212a4a1d - Indicator works correctly, sits in the right place, rotates around the boat correctly and sits on top of the water now.
tags : #story[1276]
2017-09-27 19:20:33 +13:00
Alistair McIntyre 0e9b818071 - Indicator points towards the next mark. Seems to do some funny stuff when entering a compound mark(gate).
tags : #story[1276]
2017-09-27 18:50:38 +13:00
Alistair McIntyre 452e83c1c3 - Marker seems to be detecting the correct mark but somethings wrong with the maths.
tags : #story[1276]
2017-09-27 17:52:54 +13:00
Alistair McIntyre aded794a67 - Added new indicator for direction to next mark.
- Marker rotates towards a given heading.

tags : #story[1276]
2017-09-27 17:17:50 +13:00
Zhi You Tan 270326ea77 Created prototype compass arrow mesh
#story[1276]
2017-09-27 16:03:59 +13:00
93 changed files with 2953 additions and 2199 deletions
+21 -6
View File
@@ -13,6 +13,9 @@ import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServer; 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);
@@ -80,16 +83,28 @@ public class App extends Application {
ViewManager.getInstance().initialiseSplashScreen(primaryStage); ViewManager.getInstance().initialiseSplashScreen(primaryStage);
} }
private static void runDiscoveryServer(){ private static void runDiscoveryServer() throws Exception {
try{ while (true){
new DiscoveryServer(); try {
} new DiscoveryServer();
catch (Exception e){ }
runDiscoveryServer(); catch (Exception ignored){
;
}
} }
} }
public static void main(String[] args) throws Exception { 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, 1_000);
try { try {
parseArgs(args); parseArgs(args);
} catch (ParseException e) { } catch (ParseException e) {
@@ -11,11 +11,13 @@ import seng302.discoveryServer.util.ServerRepoStreamParser;
import seng302.discoveryServer.util.ServerTable; import seng302.discoveryServer.util.ServerTable;
import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListener;
import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.Timer;
public class DiscoveryServer { public class DiscoveryServer {
public static final String ANSI_GREEN = "\u001B[32m"; public static final String ANSI_GREEN = "\u001B[32m";
@@ -27,6 +29,7 @@ public class DiscoveryServer {
private ServerTable serverTable; private ServerTable serverTable;
public static final Integer PORT_NUMBER = 9969; public static final Integer PORT_NUMBER = 9969;
private ServerSocket serverSocket;
private final Logger logger = LoggerFactory.getLogger(DiscoveryServer.class); private final Logger logger = LoggerFactory.getLogger(DiscoveryServer.class);
@@ -45,7 +48,7 @@ public class DiscoveryServer {
" .:;...'cxxxxxxxxxxxxoc;,::,..cdl;;l' \n" + " .:;...'cxxxxxxxxxxxxoc;,::,..cdl;;l' \n" +
" .cl;':,'';oxxxxxxdxxxxxx:....,cooc,cO; \n" + " .cl;':,'';oxxxxxxdxxxxxx:....,cooc,cO; \n" +
" .,,,::;,lxoc:,,:lxxxxxxxxxxxo:,,;lxxl;'oNc \n" + " .,,,::;,lxoc:,,:lxxxxxxxxxxxo:,,;lxxl;'oNc \n" +
" .cdxo;':lxxxxxxc'';cccccoxxxxxxxxxxxxo,.;lc. " + ANSI_YELLOW + "Party-Parrots-At-Sea Discovery Server v0.1 " + selectedColor +"\n" + " .cdxo;':lxxxxxxc'';cccccoxxxxxxxxxxxxo,.;lc. " + ANSI_YELLOW + "Party-Parrots-At-Sea Discovery Server v1.0.0 (Release) " + selectedColor +"\n" +
" .loc'.'lxxxxxxxxocc;''''';ccoxxxxxxxxx:..oc \n" + " .loc'.'lxxxxxxxxocc;''''';ccoxxxxxxxxx:..oc \n" +
"olc,..',:cccccccccccc:;;;;;;;;:ccccccccc,.'c, \n" + "olc,..',:cccccccccccc:;;;;;;;;:ccccccccc,.'c, \n" +
"Ol;......................................;l' "); "Ol;......................................;l' ");
@@ -56,8 +59,6 @@ public class DiscoveryServer {
displayHeader(); displayHeader();
serverTable = new ServerTable(); serverTable = new ServerTable();
ServerSocket serverSocket;
try{ try{
serverSocket = new ServerSocket(PORT_NUMBER); serverSocket = new ServerSocket(PORT_NUMBER);
} }
@@ -69,12 +70,17 @@ public class DiscoveryServer {
logger.info("Started successfully - Now accepting connections"); logger.info("Started successfully - Now accepting connections");
while (true){ try{
Socket clientSocket = serverSocket.accept(); while (true){
Socket clientSocket = serverSocket.accept();
parseRequest(clientSocket); parseRequest(clientSocket);
clientSocket.close(); clientSocket.close();
}
}
catch (Exception e){
close();
} }
} }
@@ -147,6 +153,18 @@ public class DiscoveryServer {
tries++; tries++;
} }
if (serverToJoin != null && serverToJoin.isMaxPlayersReached()){
return null;
}
return serverToJoin; return serverToJoin;
} }
public void close(){
try {
serverSocket.close();
} catch (IOException ignored) {
;
}
}
} }
@@ -19,7 +19,7 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
public class DiscoveryServerClient { public class DiscoveryServerClient {
private final Integer UPDATE_INTERVAL_MS = 5000; private final Integer UPDATE_INTERVAL_MS = 1000;
private static String roomCode = null; private static String roomCode = null;
private Timer serverListingUpdateTimer; private Timer serverListingUpdateTimer;
@@ -1,7 +1,7 @@
package seng302.discoveryServer.util; package seng302.discoveryServer.util;
public class ServerListing { public class ServerListing {
public final static int SERVER_TTL_DEFAULT = 10; public final static int SERVER_TTL_DEFAULT = 5;
private String serverName = ""; private String serverName = "";
private String mapName = ""; private String mapName = "";
@@ -11,6 +11,7 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import javafx.beans.property.ReadOnlyDoubleWrapper;
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;
@@ -68,7 +69,7 @@ public class GameState implements Runnable {
//Collision constants //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 = 15.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;
@@ -82,6 +83,7 @@ public class GameState implements Runnable {
private static Long previousUpdateTime; private static Long previousUpdateTime;
public static Double windDirection; public static Double windDirection;
public static ReadOnlyDoubleWrapper windDirectionProperty = new ReadOnlyDoubleWrapper();
private static Double windSpeed; private static Double windSpeed;
private static Double serverSpeedMultiplier; private static Double serverSpeedMultiplier;
@@ -108,6 +110,7 @@ public class GameState implements Runnable {
public GameState() { public GameState() {
windDirection = 180d; windDirection = 180d;
windDirectionProperty.set(windDirection);
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>(); yachts = new HashMap<>();
tokensInPlay = new ArrayList<>(); tokensInPlay = new ArrayList<>();
@@ -191,6 +194,7 @@ public class GameState implements Runnable {
public static void setWindDirection(Double newWindDirection) { public static void setWindDirection(Double newWindDirection) {
windDirection = newWindDirection; windDirection = newWindDirection;
windDirectionProperty.set(newWindDirection);
} }
public static void setWindSpeed(Double newWindSpeed) { public static void setWindSpeed(Double newWindSpeed) {
@@ -238,7 +242,7 @@ public class GameState implements Runnable {
if (System.currentTimeMillis() > startTime) { if (System.currentTimeMillis() > startTime) {
startSpawningTokens(); startSpawningTokens();
startUpdatingWind(); startUpdatingWind();
GameState.setCurrentStage(GameStages.RACING); GameState.currentStage = GameStages.RACING;
} }
} }
if (currentStage == GameStages.RACING) { if (currentStage == GameStages.RACING) {
@@ -299,8 +303,8 @@ public class GameState implements Runnable {
windSpeed += random.nextInt(500); windSpeed += random.nextInt(500);
} }
GameState.setWindSpeed(Double.valueOf(windSpeed)); GameState.windSpeed = Double.valueOf(windSpeed);
GameState.setWindDirection(direction.doubleValue()); GameState.windDirection = direction.doubleValue();
} }
@@ -509,6 +513,7 @@ public class GameState implements Runnable {
Double optimalAngle = PolarTable.getOptimalAngle(); Double optimalAngle = PolarTable.getOptimalAngle();
Double heading = yacht.getHeading(); Double heading = yacht.getHeading();
windDirection = (double) Math.floorMod(Math.round(heading + optimalAngle), 360L); windDirection = (double) Math.floorMod(Math.round(heading + optimalAngle), 360L);
windDirectionProperty.set(windDirection);
} }
@@ -1058,4 +1063,8 @@ public class GameState implements Runnable {
public static void setTokensEnabled (boolean tokensEnabled) { public static void setTokensEnabled (boolean tokensEnabled) {
GameState.tokensEnabled = tokensEnabled; GameState.tokensEnabled = tokensEnabled;
} }
public static ReadOnlyDoubleWrapper getWindDirectionProperty() {
return windDirectionProperty;
}
} }
@@ -5,7 +5,6 @@ import java.net.ServerSocket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -19,12 +18,6 @@ import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.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
@@ -32,21 +25,32 @@ import java.util.TimerTask;
*/ */
public class MainServerThread implements Runnable, ClientConnectionDelegate { public class MainServerThread implements Runnable, ClientConnectionDelegate {
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
private static final int PORT = 4942; private static final int PORT = 4942;
private static int selectedPort = PORT;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60; private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
private boolean terminated; private boolean terminated;
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<>();
private static Integer capacity;
private RaceXMLData raceXMLData; private RaceXMLData raceXMLData;
private RegattaXMLData regattaXMLData; private RegattaXMLData regattaXMLData;
private boolean serverStarted = false;
public MainServerThread() {
new GameState();
try {
serverSocket = new ServerSocket(0);
selectedPort = serverSocket.getLocalPort();
} catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket",
0);
}
terminated = false;
Thread thread = new Thread(this, "MainServer");
thread.start();
}
private void startAdvertisingServer() { private void startAdvertisingServer() {
Integer capacity = GameState.getCapacity(); Integer capacity = GameState.getCapacity();
@@ -64,25 +68,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
.setMapName(regattaXMLData.getCourseName()) .setMapName(regattaXMLData.getCourseName())
.setCapacity(capacity) .setCapacity(capacity)
.setNumberOfPlayers(numPlayers - 1) .setNumberOfPlayers(numPlayers - 1)
.registerGame(PORT, regattaXMLData.getRegattaName()); .registerGame(selectedPort, regattaXMLData.getRegattaName());
} catch (IOException e) { } catch (IOException e) {
logger.warn("Could not register server"); logger.warn("Could not register server");
} }
} }
public MainServerThread() {
new GameState();
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket",
0);
}
terminated = false;
thread = new Thread(this, "MainServer");
thread.start();
}
private void startServer() { private void startServer() {
PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv")); PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData); MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
@@ -98,6 +89,8 @@ 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()) {
@@ -119,7 +112,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1); logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
} }
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) { if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
.getCustomizationFlag()) {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
sendSetupMessages(); sendSetupMessages();
GameState.resetCustomizationFlag(); GameState.resetCustomizationFlag();
@@ -138,7 +132,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
else if (GameState.getCurrentStage() == GameStages.FINISHED) { else if (GameState.getCurrentStage() == GameStages.FINISHED) {
broadcastMessage(MessageFactory.getRaceStatusMessage()); broadcastMessage(MessageFactory.getRaceStatusMessage());
try { try {
Thread.sleep(1000); //Hackish fix to make sure all threads have sent closing RaceStatus Thread.sleep(
1000); //Hackish fix to make sure all threads have sent closing RaceStatus
terminate(); terminate();
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
logger.trace("Thread interrupted while waiting to terminate clients", 1); logger.trace("Thread interrupted while waiting to terminate clients", 1);
@@ -146,8 +141,10 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
try { try {
for (ServerToClientThread serverToClientThread : serverToClientThreads) { synchronized (this) {
serverToClientThread.terminate(); for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.terminate();
}
} }
serverSocket.close(); serverSocket.close();
} catch (IOException e) { } catch (IOException e) {
@@ -200,9 +197,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
startServer(); startServer();
} }
}); });
} else {
//serverToClientThread.addConnectionListener(this::sendSetupMessages);
} }
serverToClientThreads.add(serverToClientThread); serverToClientThreads.add(serverToClientThread);
try { try {
@@ -211,7 +207,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
logger.warn("Couldn't update advertisement"); logger.warn("Couldn't update advertisement");
} }
while (regattaXMLData == null && raceXMLData == null){ while (regattaXMLData == null && raceXMLData == null) {
try { try {
Thread.sleep(50); Thread.sleep(50);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -237,7 +233,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
for (ServerToClientThread serverToClientThread : serverToClientThreads) { for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) { if (serverToClientThread.getSocket() == player.getSocket()) {
closedConnection = serverToClientThread; closedConnection = serverToClientThread;
} else if (GameState.getCurrentStage() != GameStages.RACING){ } else if (GameState.getCurrentStage() != GameStages.RACING) {
serverToClientThread.sendSetupMessages(); serverToClientThread.sendSetupMessages();
} }
} }
@@ -250,7 +246,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
logger.warn("Couldn't update advertisement"); logger.warn("Couldn't update advertisement");
} }
closedConnection.terminate(); if (closedConnection != null) {
closedConnection.terminate();
}
} }
public void startGame() { public void startGame() {
@@ -268,16 +266,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
public void run() { public void run() {
broadcastMessage(MessageFactory.getRaceStatusMessage()); broadcastMessage(MessageFactory.getRaceStatusMessage());
if (GameState.getCurrentStage() == GameStages.PRE_RACE if (GameState.getCurrentStage() == GameStages.PRE_RACE
|| GameState.getCurrentStage() == GameStages.LOBBYING) { || GameState.getCurrentStage() == GameStages.LOBBYING) {
broadcastMessage(MessageFactory.getRaceStartStatusMessage()); broadcastMessage(MessageFactory.getRaceStartStatusMessage());
} }
} }
}, 0, 500); }, 0, 500);
// if (GameState.getCurrentStage() == GameStages.LOBBYING) {
// sendSetupMessages();
// }
} }
public void terminate() { public void terminate() {
@@ -288,108 +282,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
* Initialise boats to specific spaced out geopoints behind starting line. * Initialise boats to specific spaced out geopoints behind starting line.
*/ */
private void initialiseBoatPositions() { private void initialiseBoatPositions() {
// CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
// GeoPoint startMark1 = cm.getSubMark(1);
// GeoPoint startMark2 = cm.getSubMark(2);
//
// // Calculating midpoint
// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
// Double length = GeoUtility.getDistance(startMark1, startMark2);
// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
//
// // Setting each boats position side by side
// final double SEPARATION = 50.0; // distance apart in meters
//
// int boatIndex = 0;
// for (ServerYacht yacht : GameState.getYachts().values()) {
// int distanceApart = boatIndex / 2;
//
// if (boatIndex % 2 == 1 && boatIndex != 0) {
// distanceApart++;
// distanceApart *= -1;
// }
//
// GeoPoint spawnMark = GeoUtility
// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION);
//
// if (yacht.getHeading() < perpendicularAngle) {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION);
// } else {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION);
// }
//
// yacht.setLocation(spawnMark);
// boatIndex++;
// }
// final double SEPARATION = 50.0; // distance apart in meters
//
// //Reverse of the angle from start to first mark
// double angleToFirstMark = 360 - GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// );
//
// //Length of start line
// double startLineLength = GeoUtility.getDistance(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //Angle of start line
// double startMarkToMarkAngle = GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //How many yachts can fit along the start line
// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION);
// //The free space left by the boats.
// double buffer = (startLineLength % SEPARATION) / 2;
//
// //Randomize starting order.
// List<ServerYacht> serverYachtList = new ArrayList<>(GameState.getYachts().values());
// Collections.shuffle(serverYachtList);
//
// //set the starting point away from start line.
// GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// angleToFirstMark, SEPARATION
// );
//
// //Move it along the start line
// startingPoint = GeoUtility.getGeoCoordinate(
// startingPoint, startMarkToMarkAngle, buffer
// );
//
// int yachtCount = 0;
// int repeats = 0;
//
// GeoPoint yachtLocation;
//
// for (ServerYacht serverYacht : serverYachtList) {
//
// //Move away from start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// startingPoint, angleToFirstMark,repeats * SEPARATION
// );
// //Move along start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION
// );
// serverYacht.setLocation(yachtLocation);
// serverYacht.setHeading(GeoUtility.getBearing(
// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// ));
// //Set location for next yacht
// yachtCount++;
// if (yachtCount > spacesAlongLine) {
// yachtCount = 0;
// repeats++;
// }
// }
final double DISTANCE_TO_START = 75d; final double DISTANCE_TO_START = 75d;
final double YACHT_SEPARATION = 20d; final double YACHT_SEPARATION = 20d;
@@ -429,14 +321,16 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
Collections.shuffle(randomisedYachts); Collections.shuffle(randomisedYachts);
while (randomisedYachts.size() > 0) { while (randomisedYachts.size() > 0) {
int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine; int numYachtsInLine =
spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size()
: spacesAlongLine;
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2; double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate( GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
startingPoint, startMarkToMarkAngle + 180, yachtSpace startingPoint, startMarkToMarkAngle + 180, yachtSpace
); );
for (int i=0; i<numYachtsInLine; i++){ for (int i = 0; i < numYachtsInLine; i++) {
randomisedYachts.get(0).setHeading(angleFromStart); randomisedYachts.get(0).setHeading(angleFromStart);
randomisedYachts.get(0).setLocation(firstYachtPoint); randomisedYachts.get(0).setLocation(firstYachtPoint);
firstYachtPoint = GeoUtility.getGeoCoordinate( firstYachtPoint = GeoUtility.getGeoCoordinate(
@@ -450,4 +344,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
); );
} }
} }
public boolean hasStarted() {
return hasStarted;
}
public int getPortNumber() {
return selectedPort;
}
} }
@@ -1,6 +1,5 @@
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;
@@ -25,9 +24,6 @@ import seng302.model.token.Token;
import seng302.model.token.TokenType; 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.
@@ -77,9 +73,6 @@ public class MessageFactory {
} }
public static void updateBoats(List<ServerYacht> yachts) { public static void updateBoats(List<ServerYacht> yachts) {
// for (ServerYacht serverYacht : yachts) {
// 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());
@@ -146,6 +146,8 @@ public class ServerAdvertiser {
public void unregister(){ public void unregister(){
if (serviceInfo != null) if (serviceInfo != null)
jmdnsInstance.unregisterService(serviceInfo); jmdnsInstance.unregisterService(serviceInfo);
repositoryClient.unregister();
} }
/** /**
@@ -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;
} }
/** /**
+1 -4
View File
@@ -13,15 +13,11 @@ 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.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;
/** /**
@@ -286,6 +282,7 @@ public class ClientYacht extends Observable {
public void setHeading(Double heading) { public void setHeading(Double heading) {
this.heading = heading; this.heading = heading;
System.out.println(heading);
setHeadingProperty(); setHeadingProperty();
} }
@@ -134,4 +134,8 @@ public class RaceState {
public Boolean getRaceFinished() { public Boolean getRaceFinished() {
return raceFinished; return raceFinished;
} }
public ReadOnlyDoubleWrapper getWindDirection() {
return windDirection;
}
} }
@@ -72,7 +72,6 @@ public class CompoundMark {
getSubMark(1).setRoundingSide(RoundingSide.STARBOARD); getSubMark(1).setRoundingSide(RoundingSide.STARBOARD);
break; break;
} }
} }
@@ -34,7 +34,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
@@ -42,6 +42,8 @@ import seng302.visualiser.controllers.ViewManager;
*/ */
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.
*/ */
@@ -117,6 +119,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
@@ -167,8 +171,12 @@ public class ClientToServerThread implements Runnable {
notifyDisconnectListeners("Connection to server was terminated"); notifyDisconnectListeners("Connection to server was terminated");
closeSocket(); closeSocket();
ViewManager.getInstance().goToStartView(); //thread.interrupt();
ViewManager.getInstance().showErrorSnackBar("Server rejected connection.");
// 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) {
@@ -194,12 +202,6 @@ public class ClientToServerThread implements Runnable {
if (connectionErrorListener != null){ if (connectionErrorListener != null){
connectionErrorListener.notifyConnectionError(message); connectionErrorListener.notifyConnectionError(message);
} }
try {
this.socket.close();
} catch (IOException e) {
logger.error("Couldn't close socket");
}
} }
/** /**
@@ -390,9 +392,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."); handleConnectionError("Could not connect to server. Server is no longer available.");
closeSocket();
} }
return currentByte; return currentByte;
} }
@@ -435,4 +437,8 @@ public class ClientToServerThread implements Runnable {
).getBuffer() ).getBuffer()
); );
} }
public boolean hasStarted() {
return isStarted;
}
} }
@@ -5,9 +5,7 @@ import java.text.SimpleDateFormat;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
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.Timer;
@@ -17,7 +15,6 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
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.paint.Color; import javafx.scene.paint.Color;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
@@ -49,19 +46,12 @@ import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.controllers.dialogs.PopupDialogController; import seng302.visualiser.controllers.dialogs.PopupDialogController;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
* with a JavaFX Pane to insert itself into. * with a JavaFX Pane to insert itself into.
*/ */
public class GameClient { public class GameClient {
private Pane holderPane;
private ClientToServerThread socketThread; private ClientToServerThread socketThread;
private MainServerThread server; private MainServerThread server;
@@ -83,10 +73,8 @@ public class GameClient {
/** /**
* Create an instance of the game client. Does not do anything until run with runAsClient() * Create an instance of the game client. Does not do anything until run with runAsClient()
* runAsHost(). * runAsHost().
* @param holder The JavaFX Pane that the visual elements for the race will be inserted into.
*/ */
public GameClient(Pane holder) { public GameClient() {
this.holderPane = holder;
this.gameKeyBind = GameKeyBind.getInstance(); this.gameKeyBind = GameKeyBind.getInstance();
} }
@@ -95,7 +83,7 @@ public class GameClient {
* @param ipAddress IP to connect to. * @param ipAddress IP to connect to.
* @param portNumber Port to connect to. * @param portNumber Port to connect to.
*/ */
public void runAsClient(String ipAddress, Integer portNumber) { public boolean runAsClient(String ipAddress, Integer portNumber) {
try { try {
startClientToServerThread(ipAddress, portNumber); startClientToServerThread(ipAddress, portNumber);
socketThread.addDisconnectionListener((cause) -> { socketThread.addDisconnectionListener((cause) -> {
@@ -106,65 +94,94 @@ public class GameClient {
ViewManager.getInstance().setPlayerList(clientLobbyList); ViewManager.getInstance().setPlayerList(clientLobbyList);
while (regattaData == null){ int triesLeft = 10;
while (regattaData == null && triesLeft >= 0){
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException ignored) {
e.printStackTrace(); ;
} }
triesLeft--;
}
if (triesLeft < 1){
return false;
} }
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) -> { getServerThread().setConnectionErrorListener((eMessage) -> ViewManager.getInstance().showErrorSnackBar(eMessage));
ViewManager.getInstance().showErrorSnackBar(eMessage);
destroyClientToServerThread();
});
this.lobbyController = ViewManager.getInstance().goToLobby(true); this.lobbyController = ViewManager.getInstance().goToLobby(true);
} catch (IOException ioe) { } catch (IOException ioe) {
ViewManager.getInstance().showErrorSnackBar("There are no servers currently available."); ViewManager.getInstance().showErrorSnackBar("There are no servers currently available.");
} }
}
private void destroyClientToServerThread() { return true;
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 portNumber Port to connect to.
*/ */
public ServerDescription runAsHost( public ServerDescription runAsHost(
String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race, String serverName, Integer maxPlayers, String race,
Integer numLegs, Boolean tokensEnabled Integer numLegs, Boolean tokensEnabled
) { ) {
XMLGenerator.setDefaultRaceName(serverName); XMLGenerator.setDefaultRaceName(serverName);
server = new MainServerThread(); server = new MainServerThread();
try { while (!server.hasStarted()){
startClientToServerThread(ipAddress, 4942);
} catch (IOException e) {
showConnectionError("Cannot connect to server as host");
}
socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled);
while (regattaData == null){
try { try {
Thread.sleep(100); Thread.sleep(10);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
try {
startClientToServerThread("localhost", server.getPortNumber());
} catch (IOException e) {
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);
int triesLeft = 15;
while (regattaData == null && triesLeft > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
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);
lobbyController.setPortNumber(""+server.getPortNumber());
ViewManager.getInstance().setPlayerList(clientLobbyList); ViewManager.getInstance().setPlayerList(clientLobbyList);
return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(), ipAddress, 4942); return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(),
"localhost", server.getPortNumber());
} }
private void tearDownConnection() { private void tearDownConnection() {
@@ -267,10 +284,12 @@ public class GameClient {
case CHATTER_TEXT: case CHATTER_TEXT:
Pair<Integer, String> playerIdMessagePair = StreamParser Pair<Integer, String> playerIdMessagePair = StreamParser
.extractChatterText(packet); .extractChatterText(packet);
raceView.updateChatHistory( if (playerIdMessagePair != null) {
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(), raceView.updateChatHistory(
playerIdMessagePair.getValue() allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
); playerIdMessagePair.getValue()
);
}
} }
} }
} }
@@ -287,6 +306,7 @@ public class GameClient {
formatAndSendChatMessage(raceView.readChatInput()); formatAndSendChatMessage(raceView.readChatInput());
} }
}); });
gameKeyBind.toggleTurningMode();
sendToggleTurningModePacket(); // notify the server about player's steering mode sendToggleTurningModePacket(); // notify the server about player's steering mode
} }
} }
@@ -306,8 +326,6 @@ public class GameClient {
positionData.getLon(), positionData.getHeading(), positionData.getLon(), positionData.getHeading(),
positionData.getGroundSpeed()); positionData.getGroundSpeed());
} }
} else if (positionData.getType() == DeviceType.MARK_TYPE) {
//CompoundMark mark = courseData.getCompoundMarks().get(positionData.getDeviceId());
} }
} }
@@ -345,21 +363,17 @@ public class GameClient {
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]); ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]);
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]); clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
clientYacht.setEstimateTimeAtFinish(boatData[2]); clientYacht.setEstimateTimeAtFinish(boatData[2]);
// int legNumber = (int) boatData[3];
clientYacht.setBoatStatus((int) boatData[4]); clientYacht.setBoatStatus((int) boatData[4]);
// if (legNumber != clientYacht.getLegNumber()) {
// clientYacht.setLegNumber(legNumber);
// }
} }
if (raceFinished) { if (raceFinished && !raceState.getRaceFinished()) {
raceViewController.showFinishDialog(finishedBoats); raceState.setRaceFinished();
Sounds.playFinishSound(); Sounds.playFinishSound();
close(); raceViewController.showFinishDialog(finishedBoats);
ViewManager.getInstance().getGameClient().stopGame(); // close();
// ViewManager.getInstance().getGameClient().stopGame();
//loadFinishScreenView(); //loadFinishScreenView();
} }
raceState.setRaceFinished();
} }
} }
@@ -370,10 +384,6 @@ public class GameClient {
} }
} }
private void close() {
socketThread.setSocketToClose();
}
/** /**
* Handle the key-pressed event from the text field. * Handle the key-pressed event from the text field.
* @param e The key event triggering this call * @param e The key event triggering this call
@@ -500,10 +510,6 @@ public class GameClient {
return socketThread; return socketThread;
} }
public List<String> getPlayerNames(){
return Collections.unmodifiableList(clientLobbyList.sorted());
}
public void stopGame() { public void stopGame() {
GameState.setCurrentStage(GameStages.CANCELLED); GameState.setCurrentStage(GameStages.CANCELLED);
if (server != null) server.terminate(); if (server != null) server.terminate();
@@ -1,13 +1,18 @@
package seng302.visualiser; package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node; import javafx.scene.Node;
import seng302.model.ClientYacht;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.ScaledPoint; import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.utilities.Sounds;
import seng302.visualiser.fxObjects.Marker;
/** /**
* Abstract class for keeping functionality common between race visualisation. * Abstract class for keeping functionality common between race visualisation.
@@ -24,8 +29,36 @@ public abstract class GameView {
List<CompoundMark> course = new ArrayList<>(); List<CompoundMark> course = new ArrayList<>();
List<CompoundMark> compoundMarks = new ArrayList<>(); List<CompoundMark> compoundMarks = new ArrayList<>();
List<Corner> courseOrder = new ArrayList<>(); List<Corner> courseOrder = new ArrayList<>();
HashMap<Mark, Marker> markerObjects = new HashMap<>();
public abstract Node getAssets(); public abstract Node getAssets();
public abstract void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence); public abstract void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence);
public abstract void updateBorder(List<Limit> border); public abstract void updateBorder(List<Limit> border);
void updateMarkArrows (ClientYacht yacht, int legNumber) {
CompoundMark compoundMark;
if (legNumber - 1 >= 0 && legNumber-1 < course.size()) {
Sounds.playMarkRoundingSound();
compoundMark = course.get(legNumber-1);
for (Mark mark : compoundMark.getMarks()) {
markerObjects.get(mark).showNextExitArrow();
}
}
CompoundMark nextMark = null;
if (legNumber < course.size()) {
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();
}
}
}
}
} }
@@ -2,12 +2,12 @@ package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
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;
@@ -24,13 +24,16 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import org.fxyz3d.scene.Skybox; import org.fxyz3d.scene.Skybox;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.*; import seng302.model.ClientYacht;
import seng302.model.GameKeyBind;
import seng302.model.KeyAction;
import seng302.model.Limit;
import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds;
import seng302.visualiser.cameras.ChaseCamera; import seng302.visualiser.cameras.ChaseCamera;
import seng302.visualiser.cameras.IsometricCamera; import seng302.visualiser.cameras.IsometricCamera;
import seng302.visualiser.cameras.RaceCamera; import seng302.visualiser.cameras.RaceCamera;
@@ -47,11 +50,11 @@ 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;
private final double DEFAULT_CAMERA_X = 0; private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 100; private final double DEFAULT_CAMERA_Y = 160;
private Group root3D; private Group root3D;
private SubScene view; private SubScene view;
@@ -62,10 +65,7 @@ public class GameView3D extends GameView{
private PerspectiveCamera isometricCam; private PerspectiveCamera isometricCam;
private PerspectiveCamera topDownCam; private PerspectiveCamera topDownCam;
private PerspectiveCamera chaseCam; private PerspectiveCamera chaseCam;
private BoatObject playerBoat;
/* Note that if either of these is null then values for it have not been added and the other
should be used as the limits of the map. */
private Map<Mark, Marker3D> markerObjects;
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>(); private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
private Group wakesGroup = new Group(); private Group wakesGroup = new Group();
private Group boatObjectGroup = new Group(); private Group boatObjectGroup = new Group();
@@ -75,6 +75,7 @@ public class GameView3D extends GameView{
private Double windDir; private Double windDir;
private Skybox skybox; 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);
topDownCam = new TopDownCamera(); topDownCam = new TopDownCamera();
@@ -89,11 +90,11 @@ public class GameView3D extends GameView{
} }
gameObjects = new Group(); gameObjects = new Group();
root3D = new Group(isometricCam, gameObjects); root3D = new Group(chaseCam, gameObjects);
view = new SubScene( view = new SubScene(
root3D, 5000, 3000, true, SceneAntialiasing.BALANCED root3D, 5000, 3000, true, SceneAntialiasing.BALANCED
); );
view.setCamera(isometricCam); view.setCamera(chaseCam);
skybox = new Skybox(new Image(getClass().getResourceAsStream("/images/skybox.jpg")), 100000, isometricCam); skybox = new Skybox(new Image(getClass().getResourceAsStream("/images/skybox.jpg")), 100000, isometricCam);
skybox.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS)); skybox.getTransforms().addAll(new Rotate(90, Rotate.X_AXIS));
@@ -331,9 +332,36 @@ public class GameView3D extends GameView{
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) -> {
if (playerYacht.getLegNumber() < course.size()) {
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);
}); });
@@ -343,6 +371,10 @@ public class GameView3D extends GameView{
return view; return view;
} }
public SubScene getView() {
return view;
}
/** /**
* Updates the boatObjects color with that of the clientYachts object. Used in notification from * 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 * a listener on this attribute in clientYacht to re paint the boat mesh
@@ -469,6 +501,7 @@ public class GameView3D extends GameView{
} }
public void setBoatAsPlayer (ClientYacht playerYacht) { public void setBoatAsPlayer (ClientYacht playerYacht) {
playerBoat.updateMarkIndicator(scaledPoint.findScaledXY(course.get(0).getMidPoint()));
playerYacht.toggleSail(); playerYacht.toggleSail();
playerBoatAnimationTimer = new AnimationTimer() { playerBoatAnimationTimer = new AnimationTimer() {
@@ -502,31 +535,4 @@ public class GameView3D extends GameView{
public void setWindDir(double windDir) { public void setWindDir(double windDir) {
this.windDir = windDir; this.windDir = windDir;
} }
}
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();
}
}
}
}
}
@@ -1,6 +1,5 @@
package seng302.visualiser; package seng302.visualiser;
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;
@@ -35,7 +34,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")); private List<String> maps = new ArrayList<>(
Arrays.asList("default.xml", "horseshoe.xml", "loop.xml", "madagascar.xml", "waiheke.xml"));
public static MapMaker getInstance() { public static MapMaker getInstance() {
if (instance == null) { if (instance == null) {
@@ -108,10 +108,6 @@ public class MapMaker {
return mapPreviews.get(index).getAssets(); return mapPreviews.get(index).getAssets();
} }
public RaceXMLData getCurrentRace() {
return races.get(index);
}
public RegattaXMLData getCurrentRegatta() { public RegattaXMLData getCurrentRegatta() {
return regattas.get(index); return regattas.get(index);
} }
@@ -3,7 +3,6 @@ package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Node; import javafx.scene.Node;
@@ -19,6 +18,7 @@ import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.MarkArrowFactory; import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.Marker;
import seng302.visualiser.fxObjects.assets_2D.CourseBoundary; import seng302.visualiser.fxObjects.assets_2D.CourseBoundary;
import seng302.visualiser.fxObjects.assets_2D.Gate; import seng302.visualiser.fxObjects.assets_2D.Gate;
import seng302.visualiser.fxObjects.assets_2D.Marker2D; import seng302.visualiser.fxObjects.assets_2D.Marker2D;
@@ -29,7 +29,6 @@ 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;
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;
@@ -240,7 +239,7 @@ public class MapPreview extends GameView {
* @param colour The desired colour of the gate. * @param colour The desired colour of the gate.
* @return the new gate. * @return the new gate.
*/ */
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) { private Gate makeAndBindGate(Marker m1, Marker m2, Paint colour) {
Gate gate = new Gate(colour); Gate gate = new Gate(colour);
gate.startXProperty().bind( gate.startXProperty().bind(
m1.layoutXProperty() m1.layoutXProperty()
@@ -0,0 +1,51 @@
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;
/**
* Class converts a map preview to a minimap by adding boats.
*/
public class MiniMap extends MapPreview {
private HashMap<ClientYacht, Polygon> boatIcons = new HashMap<>();
public MiniMap (List<CompoundMark> marks, List<Corner> course, List<Limit> border, List<ClientYacht> boats, ClientYacht player) {
super(marks, course, border);
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());
});
}
}
@@ -1,17 +1,17 @@
package seng302.visualiser; package seng302.visualiser;
import seng302.gameServer.ServerAdvertiser; import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
import seng302.gameServer.ServerDescription;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
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 seng302.gameServer.ServerAdvertiser;
import java.io.IOException; import seng302.gameServer.ServerDescription;
import java.net.InetAddress;
import java.util.*;
import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
/** /**
* Listens for servers on the local network * Listens for servers on the local network
@@ -58,7 +58,7 @@ public class ServerListener{
servers.remove(toRemove); servers.remove(toRemove);
} }
delegate.serverRemoved(new ArrayList<ServerDescription>(servers)); delegate.serverRemoved(new ArrayList<>(servers));
// Get all other servers with the same name to respond if they are up // Get all other servers with the same name to respond if they are up
jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName); jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName);
@@ -94,13 +94,6 @@ public class ServerListener{
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 {
@@ -134,7 +127,7 @@ public class ServerListener{
for (ServerDescription server : servers){ for (ServerDescription server : servers){
if (server.serverShouldBeRemoved()){ if (server.serverShouldBeRemoved()){
listener.servers.remove(server); listener.servers.remove(server);
delegate.serverRemoved(new ArrayList<ServerDescription>(listener.servers)); delegate.serverRemoved(new ArrayList<>(listener.servers));
} }
} }
@@ -16,8 +16,8 @@ public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
private final Double MAX_Y = 170.0; private final Double MAX_Y = 170.0;
private final Double PAN_LIMIT = 160.0; private final Double PAN_LIMIT = 160.0;
private final Double NEAR_ZOOM_LIMIT = -50.0; private final Double NEAR_ZOOM_LIMIT = -30.0;
private final Double FAR_ZOOM_LIMIT = -160.0; private final Double FAR_ZOOM_LIMIT = -180.0;
private Double horizontalPan; private Double horizontalPan;
private Double verticalPan; private Double verticalPan;
@@ -29,7 +29,7 @@ public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
super(true); super(true);
transforms = this.getTransforms(); transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0; zoomFactor = FAR_ZOOM_LIMIT;
horizontalPan = cameraStartX; horizontalPan = cameraStartX;
verticalPan = cameraStartY; verticalPan = cameraStartY;
@@ -11,9 +11,9 @@ import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class TopDownCamera extends PerspectiveCamera implements RaceCamera { public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
private final Double PAN_LIMIT = 30.0; private final Double PAN_LIMIT = 40d;
private final Double NEAR_ZOOM_LIMIT = -30.0; private final Double NEAR_ZOOM_LIMIT = -20.0;
private final Double FAR_ZOOM_LIMIT = -130.0; private final Double FAR_ZOOM_LIMIT = -200d;
private final Double ZOOM_STEP = 2.5; private final Double ZOOM_STEP = 2.5;
private ObservableList<Transform> transforms; private ObservableList<Transform> transforms;
@@ -27,7 +27,7 @@ public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
super(true); super(true);
transforms = this.getTransforms(); transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0; zoomFactor = FAR_ZOOM_LIMIT;
horizontalPan = 0.0; horizontalPan = 0.0;
verticalPan = 0.0; verticalPan = 0.0;
} }
@@ -1,97 +0,0 @@
package seng302.visualiser.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import seng302.model.ClientYacht;
import seng302.utilities.Sounds;
public class FinishScreenViewController implements Initializable {
@FXML
private GridPane finishScreenGridPane;
@FXML
private TableView<ClientYacht> finishOrderTable;
@FXML
private TableColumn<ClientYacht, String> posCol;
@FXML
private TableColumn<ClientYacht, String> boatNameCol;
@FXML
private TableColumn<ClientYacht, String> shortNameCol;
@FXML
private TableColumn<ClientYacht, String> countryCol;
ObservableList<ClientYacht> data = FXCollections.observableArrayList();
@Override
public void initialize(URL location, ResourceBundle resources) {
finishScreenGridPane.getStylesheets()
.add(getClass().getResource("/css/Master.css").toString());
finishOrderTable.getStylesheets().add(getClass().getResource("/css/Master.css").toString());
// set up data for table
finishOrderTable.setItems(data);
// setting table col data
posCol.setCellValueFactory(
new PropertyValueFactory<>("position")
);
boatNameCol.setCellValueFactory(
new PropertyValueFactory<>("boatName")
);
shortNameCol.setCellValueFactory(
new PropertyValueFactory<>("shortName")
);
countryCol.setCellValueFactory(
new PropertyValueFactory<>("country")
);
finishOrderTable.refresh();
}
public void setFinishers(Collection<ClientYacht> participants) {
List<ClientYacht> sorted = new ArrayList<>(participants);
sorted.sort(Comparator.comparingInt(ClientYacht::getPlacing));
finishOrderTable.getItems().setAll(sorted);
}
private void setContentPane(String jfxUrl) {
try {
// get the main controller anchor pane (FinishView -> MainView)
AnchorPane contentPane = (AnchorPane) finishScreenGridPane.getParent();
contentPane.getChildren().removeAll();
contentPane.getChildren().clear();
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren()
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} catch (javafx.fxml.LoadException e) {
System.out.println("[Controller] FXML load exception");
} catch (IOException e) {
System.out.println("[Controller] IO exception");
}
}
public void switchToStartScreenView() {
Sounds.playButtonClick();
setContentPane("/views/StartScreenView.fxml");
}
public void playButtonHoverSound(MouseEvent mouseEvent) {
Sounds.playHoverSound();
}
}
@@ -71,6 +71,8 @@ public class LobbyController implements Initializable {
@FXML @FXML
private Label roomLabel; private Label roomLabel;
@FXML @FXML
private Label portNumber;
@FXML
private Pane speedTokenPane, handlingTokenPane, windWalkerTokenPane, bumperTokenPane, randomTokenPane; private Pane speedTokenPane, handlingTokenPane, windWalkerTokenPane, bumperTokenPane, randomTokenPane;
//---------FXML END---------// //---------FXML END---------//
@@ -85,6 +87,8 @@ public class LobbyController implements Initializable {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
roomLabel.setText(""); roomLabel.setText("");
portNumber.setText("");
this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap(); this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap();
if (this.playersColor == null) { if (this.playersColor == null) {
@@ -376,4 +380,8 @@ public class LobbyController implements Initializable {
public void setRoomCode(String roomCode) { public void setRoomCode(String roomCode) {
roomLabel.setText("Room: " + roomCode); roomLabel.setText("Room: " + roomCode);
} }
public void setPortNumber(String p){
portNumber.setText("Port: " + p);
}
} }
@@ -4,28 +4,15 @@ 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.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Slider; import javafx.scene.control.Slider;
@@ -33,38 +20,27 @@ import javafx.scene.control.TextField;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.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.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polyline;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
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.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.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.cells.WindCell;
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 Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
@@ -75,27 +51,21 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML @FXML
private ImageView loadingScreen; private ImageView loadingScreen;
@FXML @FXML
private Pane basePane;
@FXML
private JFXButton chatSend; private JFXButton chatSend;
@FXML @FXML
private Pane chatHistoryHolder; private Pane chatHistoryHolder;
@FXML @FXML
private JFXButton chatToggleButton;
@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;
@FXML
private GridPane contentGridPane; private Pane miniMapPane;
@FXML
private ImageView windImageView;
@FXML @FXML
private AnchorPane rvAnchorPane; private AnchorPane rvAnchorPane;
@FXML @FXML
@@ -108,8 +78,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private ComboBox<ClientYacht> yachtSelectionComboBox; private ComboBox<ClientYacht> yachtSelectionComboBox;
@FXML @FXML
private Text fpsDisplay; private Text fpsDisplay;
@FXML // @FXML
private ImageView windImageView; // private ImageView windImageView;
@FXML @FXML
private Label windDirectionLabel; private Label windDirectionLabel;
@FXML @FXML
@@ -118,33 +88,34 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Label positionLabel, boatSpeedLabel, boatHeadingLabel; private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML @FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon; private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
@FXML
private VBox windArrowVBox;
@FXML
private JFXButton miniMapButton;
private WindCell windCell;
//Race Data //Race Data
private Map<Integer, ClientYacht> participants; private Map<Integer, ClientYacht> participants;
private Map<Integer, CompoundMark> markers; private Map<Integer, CompoundMark> markers;
private RaceXMLData courseData; 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;
//Icon stuff
private Timer blinkingTimer = new Timer(); private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay; private ImageView iconToDisplay;
private Double lastWindDirection; private Double lastWindDirection;
private MiniMap miniMap;
public void initialize() { public void initialize() {
miniMapPane.setVisible(false);
miniMapButton.setVisible(false);
chatHistoryHolder.setVisible(false);
chatToggleButton.setVisible(false);
contentStackPane.setVisible(false); contentStackPane.setVisible(false);
Image loadingImage = new Image("PP.png"); Image loadingImage = new Image("PP.png");
loadingScreen.setImage(loadingImage); loadingScreen.setImage(loadingImage);
@@ -180,6 +151,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
chatHistoryHolder.heightProperty() chatHistoryHolder.heightProperty()
); );
contentStackPane.getChildren().remove(chatToggleButton);
contentStackPane.getChildren().add(chatToggleButton);
contentStackPane.setOnMouseClicked(event -> { contentStackPane.setOnMouseClicked(event -> {
contentStackPane.requestFocus(); contentStackPane.requestFocus();
}); });
@@ -194,6 +168,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
lastWindDirection = 0d; lastWindDirection = 0d;
}
/**
* Initialise wind arrow cell.
*/
private void initialiseWindArrow() {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/views/cells/WindCell.fxml"));
windCell = new WindCell();
loader.setController(windCell);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
windCell.init(player, raceState.getWindDirection());
windCell.setCamera(gameView.getView().getCamera());
gameView.getView().cameraProperty()
.addListener((obs, oldVal, newVal) -> windCell.setCamera(newVal));
windArrowVBox.getChildren().add(windCell.getAssets());
} }
public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) { public void showFinishDialog(ArrayList<ClientYacht> finishedBoats) {
@@ -204,13 +202,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
public void showView(){ public void showView(){
loadingScreenPane.setVisible(false); loadingScreenPane.setVisible(false);
contentStackPane.setVisible(true); contentStackPane.setVisible(true);
miniMapPane.setVisible(true);
miniMapButton.setVisible(true);
chatHistoryHolder.setVisible(true);
chatToggleButton.setVisible(true);
Platform.runLater(new Runnable() { Platform.runLater(() -> contentStackPane.requestFocus());
@Override
public void run() {
contentStackPane.requestFocus();
}
});
} }
/** /**
@@ -238,31 +235,46 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
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 -> {
while (c.next()) {
if (c.wasPermutated()) {
updateOrder(raceState.getPlayerPositions());
}
}
});
player.addPowerUpListener(this::displayPowerUpIcon); player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon); player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D(); 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("");
}
});
chatToggleButton.setOnMouseClicked((event) -> {
if (chatHistoryHolder.visibleProperty().get()) {
chatHistoryHolder.setVisible(false);
chatToggleButton.setText("+");
} else {
chatHistoryHolder.setVisible(true);
chatToggleButton.setText("");
}
});
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());
@@ -287,6 +299,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
gameView.setWindDir(raceState.windDirectionProperty().doubleValue()); gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
Platform.runLater(this::initializeUpdateTimer); Platform.runLater(this::initializeUpdateTimer);
Platform.runLater(() -> {
//windCell.setCamera(gameView.getView().getCamera());
initialiseWindArrow();
});
} }
/** /**
@@ -342,7 +360,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
public void removeIcon(ClientYacht yacht) { private void removeIcon(ClientYacht yacht) {
if (yacht == player) { if (yacht == player) {
blinkingTimer.cancel(); blinkingTimer.cancel();
iconToDisplay.setVisible(false); iconToDisplay.setVisible(false);
@@ -350,45 +368,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
/**
* The important annotations have been changed, update this view
*
* @param importantAnnotationsState The current state of the selected annotations
*/
public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) {
this.importantAnnotations = importantAnnotationsState;
setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations
}
/**
* Loads the "select annotations" view in a new window
*/
private void loadSelectAnnotationView() {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Stage stage = new Stage();
// Set controller
ImportantAnnotationController controller = new ImportantAnnotationController(
this, stage
);
fxmlLoader.setController(controller);
// Load FXML and set CSS
fxmlLoader.setLocation(
getClass().getResource("/views/importantAnnotationSelectView.fxml")
);
Scene scene = new Scene(fxmlLoader.load(), 469, 298);
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
controller.loadState(importantAnnotations);
} catch (IOException e) {
e.printStackTrace();
}
}
/** /**
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht * Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly. * orderings etc.. which are dependent on the info from the stream parser constantly.
@@ -406,47 +385,18 @@ 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));
RotateTransition rt = new RotateTransition(Duration.millis(300), windImageView); // RotateTransition rt = new RotateTransition(Duration.millis(300), windImageView);
rt.setByAngle(direction - lastWindDirection); // rt.setByAngle(direction - lastWindDirection);
rt.setCycleCount(3); // rt.setCycleCount(3);
rt.setAutoReverse(true); // rt.setAutoReverse(true);
rt.play(); // rt.play();
lastWindDirection = direction; // lastWindDirection = direction;
// windImageView.setRotate(direction); // windImageView.setRotate(direction);
} }
@@ -516,226 +466,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());
@@ -140,7 +140,9 @@ public class ServerListController implements Initializable, ServerListenerDelega
return; return;
} }
ViewManager.getInstance().getGameClient().runAsClient(listing.getAddress(), listing.getPortNumber()); if (!ViewManager.getInstance().getGameClient().runAsClient(listing.getAddress(), listing.getPortNumber())){
ViewManager.getInstance().showErrorSnackBar("Could not connect to server");
}
}); });
/* /*
@@ -1,26 +1,15 @@
package seng302.visualiser.controllers; package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXDecorator;
import com.jfoenix.controls.JFXSnackbar;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import seng302.gameServer.ServerAdvertiser;
import seng302.utilities.Sounds;
import seng302.visualiser.GameClient;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/** /**
* The pre loading screen before launch the start view
* Created by Kusal on 26-Sep-17. * Created by Kusal on 26-Sep-17.
*/ */
public class SplashScreenController implements Initializable{ public class SplashScreenController implements Initializable{
@@ -37,18 +26,15 @@ public class SplashScreenController implements Initializable{
class SplashScreen extends Thread { class SplashScreen extends Thread {
public void run(){ public void run(){
try { try {
Thread.sleep(2000); Thread.sleep(3000);
Platform.runLater(new Runnable() { Platform.runLater(() -> {
@Override try {
public void run() { Stage stage = new Stage();
try { ViewManager.getInstance().initialStartView(stage);
Stage stage = new Stage(); } catch (Exception e) {
ViewManager.getInstance().initialStartView(stage); e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
rootPane.getScene().getWindow().hide();
} }
rootPane.getScene().getWindow().hide();
}); });
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
@@ -6,10 +6,16 @@ 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.*; import javafx.scene.Cursor;
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;
@@ -24,9 +30,6 @@ 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;
@@ -79,7 +82,7 @@ public class ViewManager {
decorator.applyCss(); decorator.applyCss();
decorator.getStylesheets() decorator.getStylesheets()
.add(getClass().getResource("/css/Master.css").toExternalForm()); .add(getClass().getResource("/css/Master.css").toExternalForm());
gameClient = new GameClient(decorator); gameClient = new GameClient();
setDecorator(decorator); setDecorator(decorator);
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png"))); stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
@@ -376,8 +379,8 @@ public class ViewManager {
scene.setOnKeyPressed(gameClient::keyPressed); scene.setOnKeyPressed(gameClient::keyPressed);
scene.setOnKeyReleased(gameClient::keyReleased); scene.setOnKeyReleased(gameClient::keyReleased);
stage.setMinHeight(500); stage.setMinHeight(800);
stage.setMinWidth(800); stage.setMinWidth(1200);
stage.setTitle("Party Parrots At Sea"); stage.setTitle("Party Parrots At Sea");
stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png"))); stage.getIcons().add(new Image(getClass().getResourceAsStream("/PP.png")));
stage.setOnCloseRequest(e -> closeAll()); stage.setOnCloseRequest(e -> closeAll());
@@ -404,7 +407,9 @@ public class ViewManager {
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm()); .add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
JFXSnackbar bar = new JFXSnackbar(decorator); JFXSnackbar bar = new JFXSnackbar(decorator);
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg)); Platform.runLater(() -> {
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
});
} }
public Stage getStage() { public Stage getStage() {
@@ -0,0 +1,131 @@
package seng302.visualiser.controllers.cells;
import java.util.Arrays;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.fxml.FXML;
import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import seng302.model.ClientYacht;
import seng302.visualiser.cameras.ChaseCamera;
import seng302.visualiser.fxObjects.assets_3D.Model;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
public class WindCell {
//--------FXML BEGIN--------//
@FXML
private Pane windPane;
//---------FXML END---------//
private final double FOV = 60;
private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 50;
private Group root3D;
private SubScene view;
private Group gameObjects;
private ChaseCamera chaseCam;
private ClientYacht playerYacht;
// Cameras
private PerspectiveCamera camera = null;
private Model windArrowModel;
private Boolean isChaseCam;
/**
* Initialise WindCell fxml and load 3D wind arrow into a group.
*/
public void init(ClientYacht playerYacht, ReadOnlyDoubleWrapper windDirection) {
this.playerYacht = playerYacht;
camera = new PerspectiveCamera();
camera.setFarClip(1000);
camera.setNearClip(0.1);
camera.setFieldOfView(60);
initialiseWindView();
for (DoubleProperty o : Arrays.asList(playerYacht.getHeadingProperty(), windDirection)) {
o.addListener((obs, oldValue, newValue) -> {
Platform.runLater(() -> {
if (isChaseCam) {
camera.getTransforms().clear();
for (Transform t : chaseCam.getTransforms()) {
if (t instanceof Rotate) {
camera.getTransforms().add(t);
}
}
this.camera.getTransforms().addAll(
new Translate(-55, -60, 0)
);
}
windArrowModel.getAssets().getTransforms().clear();
windArrowModel.getAssets().getTransforms().addAll(
new Rotate(windDirection.getValue(),
new Point3D(0, 0, 1))
);
});
});
}
}
private void initialiseWindView() {
gameObjects = new Group();
windPane.getChildren().add(gameObjects);
root3D = new Group(camera, gameObjects);
view = new SubScene(
root3D, 110, 120, true, SceneAntialiasing.BALANCED
);
view.setCamera(camera);
windArrowModel = ModelFactory.makeWindArrow();
gameObjects.getChildren().addAll(
windArrowModel.getAssets()
);
}
public Node getAssets() {
return view;
}
public void updateCameraTransforms(Camera camera) {
this.camera.getTransforms().clear();
for (Transform transform : camera.getTransforms()) {
if (!(transform instanceof Translate)) {
this.camera.getTransforms().add(transform);
}
}
this.camera.getTransforms().addAll(
new Translate(-55, -60, 0)
);
windArrowModel.getAssets().getTransforms().clear();
}
public void setCamera(Camera camera) {
isChaseCam = camera instanceof ChaseCamera;
if (isChaseCam) {
this.chaseCam = (ChaseCamera) camera;
} else {
this.chaseCam = null;
}
updateCameraTransforms(camera);
}
}
@@ -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();
@@ -91,6 +93,7 @@ public class KeyBindingDialogController implements Initializable {
}); });
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
confirmBtn.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
} }
/** /**
@@ -28,12 +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; private Label closeLabel;
@FXML @FXML
private Label maxPlayersLabel;
@FXML
private JFXButton nextMapButton; private JFXButton nextMapButton;
@FXML @FXML
private JFXButton lastMapButton; private JFXButton lastMapButton;
@@ -47,11 +47,10 @@ 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; private List<ServerCreationDialogListener> serverCreationDialogListeners;
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
@@ -96,7 +95,7 @@ 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); pickupsCheckBox.setSelected(true);
//closeLabel.setOnMouseClicked(event -> notifyListeners()); closeLabel.setOnMouseClicked(event -> notifyListeners());
} }
/** /**
@@ -116,9 +115,15 @@ public class ServerCreationController implements Initializable {
*/ */
private void createServer() { private void createServer() {
ServerDescription serverDescription = ViewManager.getInstance().getGameClient() ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider .runAsHost(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());
} }
@@ -128,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() {
@@ -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)
); );
@@ -0,0 +1,38 @@
package seng302.visualiser.fxObjects;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.Group;
import seng302.visualiser.fxObjects.MarkArrowFactory.RoundingSide;
/**
* Created by cir27 on 28/09/17.
*/
public abstract class Marker extends Group{
protected List<Group> enterArrows = new ArrayList<>();
protected List<Group> exitArrows = new ArrayList<>();
protected int enterArrowIndex = 0;
protected int exitArrowIndex = 0;
public abstract void addArrows(RoundingSide roundingSide, double entryAngle, double exitAngle);
/**
* Shows the next EnterArrow. Does nothing if there are no more enter arrows. Other arrows become hidden.
*/
public void showNextEnterArrow() {
showArrow(enterArrows, enterArrowIndex);
enterArrowIndex++;
}
/**
* Shows the next ExitArrow. Does nothing if there are no more enter arrows. Other arrows become hidden.
*/
public void showNextExitArrow() {
showArrow(exitArrows, exitArrowIndex);
exitArrowIndex++;
}
protected abstract void showArrow(List<Group> arrowList, int arrowListIndex);
public abstract void hideAllArrows();
}
@@ -1,230 +0,0 @@
package seng302.visualiser.fxObjects.assets_2D;
import java.util.HashMap;
import java.util.Map;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
/**
* Grouping of string objects over a semi transparent background.
*/
public class AnnotationBox extends Group {
@FunctionalInterface
public interface AnnotationFormatter<T> {
String transformString (T input);
}
/**
* Class stores a text object and relationship for updating the text object if needed
*
* @param <T> The type of observable value passed to the annotation, if there is one.
*/
public class Annotation<T> {
private Text text;
private ObservableValue<T> source;
private AnnotationFormatter<T> format;
/**
* Constructor for observing annotation
* @param textObject the javaFX text object the annotation is displayed in
* @param source observable value that the annotation is taken from
* @param formatter interface describing how to format the source data if needed
*/
public Annotation (Text textObject, ObservableValue<T> source, AnnotationFormatter<T> formatter) {
this.text = textObject;
this.source = source;
this.format = formatter;
source.addListener((obs, oldVal, newVal) ->
Platform.runLater(() -> text.setText(format.transformString(newVal)))
);
}
/**
* Constructor for a static annotation
* @param textObject the javaFX text object the annotation is displayed in
* @param annotationText the static value of the test object
*/
public Annotation (Text textObject, String annotationText) {
textObject.setText(annotationText);
text = textObject;
}
private Text getText () {
return text;
}
}
//Text offset constants
private static final double X_OFFSET_TEXT = 20d;
private static final double Y_OFFSET_TEXT_INIT = -35d;
private static final double Y_OFFSET_PER_TEXT = 12d;
//Background constants
private static final double TEXT_BUFFER = 3;
private static final double BACKGROUND_X = X_OFFSET_TEXT - TEXT_BUFFER;
private static final double BACKGROUND_Y = Y_OFFSET_TEXT_INIT - TEXT_BUFFER;
private static final double BACKGROUND_H_PER_TEXT = 9.5d;
private static final double BACKGROUND_ARC_SIZE = 10;
private int visibleAnnotations = 0;
private double backgroundWidth = 145d;
private Rectangle background = new Rectangle();
private Paint theme = Color.BLACK;
private Map<String, Annotation> annotationsByName = new HashMap<>();
/**
* Creates an empty annotation box. The box is offset from (0,0) by (17, -38).
*/
public AnnotationBox() {
this.setCache(true);
background.setX(BACKGROUND_X);
background.setY(BACKGROUND_Y);
background.setWidth(backgroundWidth);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * 4);
background.setArcHeight(BACKGROUND_ARC_SIZE);
background.setArcWidth(BACKGROUND_ARC_SIZE);
background.setFill(new Color(1, 1, 1, 0.75));
background.setStroke(theme);
background.setStrokeWidth(2);
background.setCache(true);
background.setCacheHint(CacheHint.SCALE);
this.getChildren().add(background);
}
/**
* Adds an annotation to the box. Use the name to reference the annotation for removal or\
* changing visibility.
* @param annotationName the name of the annotation.
* @param annotation the annotation.
*/
public void addAnnotation (String annotationName, Annotation annotation) {
annotationsByName.put(annotationName, annotation);
Platform.runLater(() -> {
this.getChildren().add(annotation.getText());
visibleAnnotations++;
update();
});
}
/**
* Adds an annotation with a constant text.
* @param annotationName The name of the annotation. Will be used to reference it later.
* @param annotationText The desired text.
*/
public void addAnnotation (String annotationName, String annotationText) {
Text text = getTextObject();
addAnnotation(annotationName, new Annotation(text, annotationText));
}
/**
* Adds an annotation with the given name. The annotation will contain the value of the given
* ObservableValue. The formatter should return a String and takes an object of the same type as
* the ObservableValue as a parameter. The String is how you want the annotation to look.
* @param annotationName The annotation name.
* @param observable The observable value the annotation will display.
* @param formatter A formatting function for the observable value.
* @param <E> The type of ObservableValue.
*/
public <E> void addAnnotation (String annotationName, ObservableValue<E> observable,
AnnotationFormatter<E> formatter) {
Text newText = getTextObject();
addAnnotation(annotationName, new Annotation<>(newText, observable, formatter));
}
/**
* Sets the visibility of the annotation with the given name if it exists.
* @param annotationName The name of the annotation
* @param visibility the desired visibility
*/
public void setAnnotationVisibility (String annotationName, boolean visibility) {
if (annotationsByName.containsKey(annotationName)) {
Text textField = annotationsByName.get(annotationName).text;
boolean currentState = textField.visibleProperty().get();
if (visibility != currentState) {
if (visibility)
visibleAnnotations++;
else
visibleAnnotations--;
}
textField.setVisible(visibility);
update();
}
}
/**
* Removes the annotation with the given name if it exits.
* @param annotationName The name given when the annotation was created.
*/
public void removeAnnotation (String annotationName) {
if (annotationName.contains(annotationName)) {
Platform.runLater(() -> {
this.getChildren().remove(annotationsByName.remove(annotationName).getText());
visibleAnnotations--;
update();
});
annotationsByName.remove(annotationName);
}
}
/**
* Moves the annotation.
* @param x x location
* @param y y location
*/
public void setLocation (double x, double y) {
Platform.runLater(()-> this.relocate(x + BACKGROUND_X, y + BACKGROUND_Y));
}
/**
* Changes the width of the annotation box. Default is 145.
* @param width new width.
*/
public void setWidth (double width) {
backgroundWidth = width;
Platform.runLater(() -> background.setWidth(backgroundWidth));
}
private void update () {
background.setVisible(visibleAnnotations != 0);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * visibleAnnotations);
for (int i = 1; i <= visibleAnnotations; i++) {
Text text = (Text) this.getChildren().get(i);
if (text.visibleProperty().get()) {
text.setX(X_OFFSET_TEXT);
text.setY(Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * i);
// });
}
}
}
/**
* Returns a text object for an annotation.
* @return The text object
*/
private Text getTextObject() {
Text text = new Text();
text.setFill(theme);
text.setStrokeWidth(2);
// text.setCacheHint(CacheHint.QUALITY);
text.setCache(true);
return text;
}
/**
* Set the colour of the annotation box's border and text colour.
* @param value desired colour.
*/
public void setFill (Paint value) {
theme = value;
background.setStroke(theme);
annotationsByName.forEach((name, annotation) -> annotation.getText().setFill(theme));
}
}
@@ -1,6 +1,5 @@
package seng302.visualiser.fxObjects.assets_2D; package seng302.visualiser.fxObjects.assets_2D;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.Group; import javafx.scene.Group;
@@ -8,18 +7,15 @@ import javafx.scene.paint.Color;
import javafx.scene.paint.Paint; import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
import seng302.visualiser.fxObjects.MarkArrowFactory; import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.Marker;
/** /**
* Visual object for a mark. Contains a coloured circle and any specified arrows. * Visual object for a mark. Contains a coloured circle and any specified arrows.
*/ */
public class Marker2D extends Group { public class Marker2D extends Marker {
private Circle mark = new Circle(); private Circle mark = new Circle();
private Paint colour = Color.BLACK; private Paint colour = Color.BLACK;
private List<Group> enterArrows = new ArrayList<>();
private List<Group> exitArrows = new ArrayList<>();
private int enterArrowIndex = 0;
private int exitArrowIndex = 0;
/** /**
* Creates a new Marker containing only a circle. The default colour is black. * Creates a new Marker containing only a circle. The default colour is black.
@@ -28,8 +24,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.
} }
/** /**
@@ -80,15 +75,12 @@ public class Marker2D extends Group {
exitArrowIndex++; exitArrowIndex++;
} }
private void showArrow(List<Group> arrowList, int arrowListIndex) { @Override
protected 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));
});
} }
} }
@@ -16,10 +16,6 @@ public class Wake extends Group {
//The number of wakes //The number of wakes
private int numWakes = 8; private int numWakes = 8;
//The total possible difference between the first wake and the last. Increasing/Decreasing this will make wakes fan out more/less.
private final double MAX_DIFF = 75;
//Increasing/decreasing this will alter the speed that wakes converge when the heading stop changing. Anything over about 1500 may cause oscillation.
private final int UNIFICATION_SPEED = 45;
private Arc[] arcs = new Arc[numWakes]; private Arc[] arcs = new Arc[numWakes];
@@ -69,34 +65,6 @@ public class Wake extends Group {
rad += (14 / numWakes) + (velocity / 2.5); rad += (14 / numWakes) + (velocity / 2.5);
} }
}); });
// } else {
// rotations[0] = rotation;
// ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
// for (int i = 1; i < numWakes; i++) {
// double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
// double shortestDistance = Math.atan2(
// Math.sin(wakeSeparationRad),
// Math.cos(wakeSeparationRad)
// );
// double distDeg = Math.toDegrees(shortestDistance);
// if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) {
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * 2 * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
//
// } else {
// if (distDeg < (MAX_DIFF / numWakes)) {
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
// } else
// rotationalVelocities[i] = rotationalVelocities[i - 1];
// }
// }
// }
// double rad = (14 / numWakes) + velocity;
// for (Arc arc : arcs) {
// arc.setRadiusX(rad);
// arc.setRadiusY(rad);
// rad += (14 / numWakes) + (velocity / 2.5);
// }
} }
/** /**
@@ -1,25 +0,0 @@
package seng302.visualiser.fxObjects.assets_2D;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
/**
* Created by cir27 on 5/09/17.
*/
public class WindArrow extends Polyline {
public WindArrow(Paint fill) {
this.getPoints().addAll(
-10d, 15d,
0d, 25d,
0d, -25d,
0d, 25d,
10d, 15d
);
this.setStrokeLineCap(StrokeLineCap.ROUND);
this.setStroke(fill);
this.setStrokeWidth(5);
this.setStrokeLineJoin(StrokeLineJoin.ROUND);
}
}
@@ -13,7 +13,7 @@ public enum BoatMeshType {
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), 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), PARROT("parrot_hull.stl", null, 0, "parrot_features.stl", 0, "parrot_sail.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); 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;
@@ -60,7 +60,9 @@ public class BoatModel extends Model {
*/ */
public void changeColour(Color newColour) { public void changeColour(Color newColour) {
changeColourChild(HULL_INDEX, newColour); changeColourChild(HULL_INDEX, newColour);
changeColourChild(MAST_INDEX, newColour); if (meshType != BoatMeshType.PARROT) {
changeColourChild(MAST_INDEX, newColour);
}
} }
private void changeColourChild(int index, Color newColour) { private void changeColourChild(int index, Color newColour) {
@@ -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
@@ -30,9 +34,10 @@ public class BoatObject extends Group {
private Color colour = Color.BLACK; private Color colour = Color.BLACK;
private Boolean isSelected = false; private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
// private Rotate tilt = new Rotate(0, new Point3D(0, 1, 0));
private double previousRotation = 0;
// 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<>();
@@ -81,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);
@@ -91,14 +109,6 @@ public class BoatObject extends Group {
private void rotateTo(double heading, boolean sailsIn, double windDir) { private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotationProperty.set(heading); rotationProperty.set(heading);
rotation.setAngle(heading); rotation.setAngle(heading);
// if (heading == previousRotation) {
// tilt.setAngle(0);
// } else if (heading < previousRotation) {
// tilt.setAngle(-10);
// } else {
// tilt.setAngle(10);
// }
// previousRotation = heading;
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1))); wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) { if (sailsIn) {
boatAssets.showSail(); boatAssets.showSail();
@@ -128,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;
} }
@@ -1,22 +1,17 @@
package seng302.visualiser.fxObjects.assets_3D; package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.Group; import javafx.scene.Group;
import seng302.visualiser.fxObjects.MarkArrowFactory; import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.MarkArrowFactory.RoundingSide; import seng302.visualiser.fxObjects.MarkArrowFactory.RoundingSide;
import seng302.visualiser.fxObjects.Marker;
/** /**
* Visual object for a mark. Contains a coloured circle and any specified arrows. * Visual object for a mark. Contains a coloured circle and any specified arrows.
*/ */
public class Marker3D extends Group { public class Marker3D extends Marker {
private Model mark; private Model mark;
private List<Group> enterArrows = new ArrayList<>();
private List<Group> exitArrows = new ArrayList<>();
private int enterArrowIndex = 0;
private int exitArrowIndex = 0;
private ModelType markType; private ModelType markType;
private ModelType arrowType; private ModelType arrowType;
@@ -60,23 +55,8 @@ public class Marker3D extends Group {
); );
} }
/** @Override
* Shows the next EnterArrow. Does nothing if there are no more enter arrows. Other arrows become hidden. protected void showArrow(List<Group> arrowList, int arrowListIndex) {
*/
public void showNextEnterArrow() {
showArrow(enterArrows, enterArrowIndex);
enterArrowIndex++;
}
/**
* Shows the next ExitArrow. Does nothing if there are no more enter arrows. Other arrows become hidden.
*/
public void showNextExitArrow() {
showArrow(exitArrows, exitArrowIndex);
exitArrowIndex++;
}
private void showArrow(List<Group> arrowList, int arrowListIndex) {
if (arrowListIndex < arrowList.size()) { if (arrowListIndex < arrowList.size()) {
Platform.runLater(() -> Platform.runLater(() ->
this.getChildren().setAll(mark.getAssets(), arrowList.get(arrowListIndex)) this.getChildren().setAll(mark.getAssets(), arrowList.get(arrowListIndex))
@@ -16,7 +16,6 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
/** /**
* Factory class for creating 3D models of boatTypes. * Factory class for creating 3D models of boatTypes.
*/ */
@@ -91,24 +90,27 @@ 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 sail = importSTL(boatType.sailFile); boatAssets.getChildren().add(hull);
if (boatType.mastFile != null) {
MeshView mast = importBoatSTL(boatType.mastFile);
mast.setMaterial(new PhongMaterial(primaryColour));
boatAssets.getChildren().add(mast);
} else {
boatAssets.getChildren().add(new MeshView());
}
MeshView sail = importBoatSTL(boatType.sailFile);
sail.setMaterial( sail.setMaterial(
new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.BLACK : Color.WHITE) new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.BLACK : Color.WHITE)
); );
boatAssets.getChildren().add(sail);
boatAssets.getChildren().addAll(hull, sail);
if (boatType.mastFile != null) {
MeshView mast = importSTL(boatType.mastFile);
mast.setMaterial(new PhongMaterial(primaryColour));
boatAssets.getChildren().add(mast);
}
if (boatType.jibFile != null) { if (boatType.jibFile != null) {
MeshView jib = importSTL(boatType.jibFile); MeshView jib = importBoatSTL(boatType.jibFile);
sail.setMaterial( jib.setMaterial(
new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.DARKGRAY : Color.WHITE) new PhongMaterial(boatType == BoatMeshType.PARROT ? Color.DARKGRAY : Color.WHITE)
); );
boatAssets.getChildren().add(jib); boatAssets.getChildren().add(jib);
@@ -117,9 +119,13 @@ public class ModelFactory {
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);
@@ -138,6 +144,10 @@ 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:
case BUMPER_PICKUP: case BUMPER_PICKUP:
case RANDOM_PICKUP: case RANDOM_PICKUP:
@@ -172,6 +182,16 @@ public class ModelFactory {
} }
} }
private static Model makeIdentifierTorus(Group assets) {
// assets.getChildren().add(new AmbientLight());
return new Model(new Group(assets), null);
}
private static Model makeNextMarkIndicator(Group assets) {
// assets.getChildren().add(new AmbientLight());
return new Model(new Group(assets), null);
}
private static Model makeTokenPickup(Group assets) { private static Model makeTokenPickup(Group assets) {
Rotate animationRotate = new Rotate(0, new Point3D(0, 0, 1)); Rotate animationRotate = new Rotate(0, new Point3D(0, 0, 1));
assets.getTransforms().addAll( assets.getTransforms().addAll(
@@ -255,4 +275,31 @@ public class ModelFactory {
); );
return new Model(new Group(assets), null); return new Model(new Group(assets), null);
} }
/**
* Create a 3D wind arrow.
*
* @return 3D wind arrow object
*/
public static Model makeWindArrow() {
ColModelImporter importer = new ColModelImporter();
importer.read(ModelFactory.class.getResource("/meshes/" + ModelType.WIND_ARROW.filename));
Group assets = new Group(importer.getImport());
assets.setCache(true);
assets.setCacheHint(CacheHint.SCALE_AND_ROTATE);
Rotate animationRotate = new Rotate(0, new Point3D(0, 1, 0));
assets.getTransforms().addAll(
new Translate(0, 0, 0),
new Scale(5, 5, 5),
new Rotate(270, new Point3D(1, 0, 0)),
animationRotate
);
assets.getChildren().addAll(
new AmbientLight()
);
return new Model(new Group(assets), null);
}
} }
@@ -28,7 +28,10 @@ public enum ModelType {
START_ARROW ("start_arrow.dae"), START_ARROW ("start_arrow.dae"),
FINISH_ARROW ("finish_arrow.dae"), FINISH_ARROW ("finish_arrow.dae"),
LAND("land.dae"), LAND("land.dae"),
LAND_SMOOTH("land_smooth.dae"); LAND_SMOOTH("land_smooth.dae"),
NEXT_MARK_INDICATOR("indicator_arrow.dae"),
PLAYER_IDENTIFIER_TORUS("torus.dae"),
WIND_ARROW("windFiles/arrow56.dae"); // change filename
final String filename; final String filename;
@@ -1,44 +0,0 @@
package seng302.visualiser.map;
/**
* The Boundary class represents a rectangle territorial boundary on a map. It
* contains four extremity double values(N, E, S, W). N and S are represented as
* latitudes in radians. E and W are represented as longitudes in radians.
*
* Created by Haoming on 10/5/17
*/
public class Boundary {
private double northLat, eastLng, southLat, westLng;
public Boundary(double northLat, double eastLng, double southLat, double westLng) {
this.northLat = northLat;
this.eastLng = eastLng;
this.southLat = southLat;
this.westLng = westLng;
}
double getCentreLat() {
return (northLat + southLat) / 2;
}
double getCentreLng() {
return (eastLng + westLng) / 2;
}
double getNorthLat() {
return northLat;
}
double getEastLng() {
return eastLng;
}
double getSouthLat() {
return southLat;
}
double getWestLng() {
return westLng;
}
}
@@ -1,103 +0,0 @@
package seng302.visualiser.map;
import java.net.URL;
import javafx.geometry.Point2D;
import javafx.scene.image.Image;
import javax.net.ssl.HttpsURLConnection;
import seng302.model.GeoPoint;
/**
* CanvasMap retrieves a map image with given geo boundary from Google Map server.
* By passing a rectangle like geo boundary, it returns a map image with the
* highest resolution. However, due to free quote account usage limit, the maximum
* resolution is only 1280 * 1280.
*
* Created by Haoming on 15/5/2017
*/
public class CanvasMap {
private Boundary boundary;
private long width, height; // desired image size
private int zoom;
private String KEY = "AIzaSyC-5oOShMCY5Oy_9L7guYMPUPFHDMr37wE";
public CanvasMap(Boundary boundary) {
this.boundary = boundary;
calculateOptimalMapSize();
}
public Image getMapImage() {
try {
URL url = new URL(getRequest());
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
return new Image(connection.getInputStream());
} catch (Exception e) {
System.out.println("[CanvasMap] Exception");
return null;
}
}
private String getRequest() {
StringBuilder sb = new StringBuilder();
sb.append("https://maps.googleapis.com/maps/api/staticmap?");
sb.append(String.format("center=%f,%f", boundary.getCentreLat(), boundary.getCentreLng()));
sb.append(String.format("&zoom=%d", zoom));
sb.append(String.format("&size=%dx%d&scale=2", width, height));
sb.append("&style=feature:all|element:labels|visibility:off"); // hide all labels on map
// sb.append(String.format("&markers=%f,%f", boundary.getSouthLat(), boundary.getWestLng()));
// sb.append(String.format("&key=%s", KEY));
return sb.toString();
}
private void calculateOptimalMapSize() {
for (int z = 20; z > 0; z--) {
MapSize mapSize = getMapSize(z, boundary);
zoom = z;
width = mapSize.width;
height = mapSize.height;
// if map size is valid, exit the loop as we have the highest resolution
if (mapSize.isValid()) break;
}
}
private MapSize getMapSize(int zoom, Boundary boundary) {
double scale = Math.pow(2, zoom);
GeoPoint geoSW = new GeoPoint(boundary.getSouthLat(), boundary.getWestLng());
GeoPoint geoNE = new GeoPoint(boundary.getNorthLat(), boundary.getEastLng());
Point2D pointSW = MercatorProjection.toMapPoint(geoSW);
Point2D pointNE = MercatorProjection.toMapPoint(geoNE);
return new MapSize(Math.abs(pointNE.getX() - pointSW.getX()) * scale,
Math.abs(pointNE.getY() - pointSW.getY()) * scale);
}
class MapSize {
long width, height;
MapSize(double width, double height) {
this.width = Math.round(width);
this.height = Math.round(height);
}
/**
* Map size is valid when width and height are both less than 640 pixels
* @return true if both dimensions are less than 640px
*/
boolean isValid() {
return Math.max(width, height) <= 640;
}
}
public long getWidth() {
return width;
}
public long getHeight() {
return height;
}
public int getZoom() {
return zoom;
}
}
@@ -1,55 +0,0 @@
package seng302.visualiser.map;
import javafx.geometry.Point2D;
import seng302.model.GeoPoint;
/**
* An utility class useful to convert between Geo locations and Mercator projection
* planar coordinates.
* Created by Haoming on 15/5/2017
*/
public class MercatorProjection {
private static final double MERCATOR_RANGE = 256;
private static final double pixelsPerLngDegree = MERCATOR_RANGE / 360.0;
private static final double pixelsPerLngRadian = MERCATOR_RANGE / (2 * Math.PI);
/**
* A help function keeps the value in bound between -0.9999 and 0.9999.
* @param value in bound value
* @return the value in bound
*/
private static double bound(double value) {
return Math.min(Math.max(value, -0.9999), 0.9999);
}
/**
* Projects a Geo Location (lat, lng) on a planar
* @param geo GeoPoint (lat, lng) location to be projected
* @return the projection Point2D (x, y) on planar
*/
public static Point2D toMapPoint(GeoPoint geo) {
double x, y;
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
x = (origin.getX() + geo.getLng() * pixelsPerLngDegree);
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
// 89.189. This is about a third of a tile past the edge of the world tile.
double sinY = bound(Math.sin(Math.toRadians(geo.getLat())));
y = origin.getY() + 0.5 * Math.log((1 + sinY) / (1 - sinY)) * (-pixelsPerLngRadian);
return new Point2D(x, y);
}
/**
* Converts the planar projection (x, y) back to Geo Location (lat, lng)
* @param point Point2D (x, y) to be converted back
* @return the original Geo location converted from the given projection point
*/
public static GeoPoint toMapGeo(Point2D point) {
Point2D origin = new Point2D(MERCATOR_RANGE / 2.0, MERCATOR_RANGE / 2.0);
double lng = (point.getX() - origin.getX()) / pixelsPerLngDegree;
double latRadians = (point.getY() - origin.getY()) / (-pixelsPerLngRadian);
double lat = Math.toDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2.0);
return new GeoPoint(lat, lng);
}
}
@@ -1,22 +0,0 @@
package seng302.visualiser.map;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
public class TestMapController implements Initializable{
@FXML
private Canvas mapCanvas;
@Override
public void initialize(URL location, ResourceBundle resources) {
GraphicsContext gc = mapCanvas.getGraphicsContext2D();
Boundary bound = new Boundary(57.662943, 11.848501, 57.673945, 11.824966);
CanvasMap canvasMap = new CanvasMap(bound);
gc.drawImage(canvasMap.getMapImage(), 0, 0, canvasMap.getWidth(), canvasMap.getHeight());
}
}
+24
View File
@@ -5,6 +5,7 @@
#timerGrid{ #timerGrid{
-fx-background-color: rgba(255, 255, 255, 0.6); -fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light; -fx-effect: -fx-pp-dropshadow-light;
-fx-background-radius: 5;
} }
GridPane .timer * { GridPane .timer * {
@@ -27,20 +28,24 @@ GridPane .timer * {
#chatHistoryHolder { #chatHistoryHolder {
-fx-background-color: rgba(255, 255, 255, 0.6); -fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light; -fx-effect: -fx-pp-dropshadow-light;
-fx-background-radius: 5;
} }
#chatInputHolder { #chatInputHolder {
-fx-background-color: rgba(255, 255, 255, 0.6); -fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light; -fx-effect: -fx-pp-dropshadow-light;
-fx-background-radius: 5;
} }
#windGridPane { #windGridPane {
-fx-background-color: rgba(255, 255, 255, 0.6); -fx-background-color: rgba(255, 255, 255, 0.6);
-fx-effect: -fx-pp-dropshadow-light; -fx-effect: -fx-pp-dropshadow-light;
-fx-background-radius: 5;
} }
#windHolder { #windHolder {
-fx-background-color: rgba(255, 255, 255, 0.5); -fx-background-color: rgba(255, 255, 255, 0.5);
-fx-background-radius: 5;
} }
#chatSend { #chatSend {
@@ -61,6 +66,25 @@ GridPane .timer * {
-fx-background-color: transparent; -fx-background-color: transparent;
} }
#chatToggleButton {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-background-radius: 5;
-fx-min-width: 30;
-fx-min-height: 30;
}
#windImageView { #windImageView {
-fx-image: url("/images/wind-180.png"); -fx-image: url("/images/wind-180.png");
}
#miniMapPane {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-background-radius: 5;
}
#miniMapButton {
-fx-background-color: rgba(255, 255, 255, 0.6);
-fx-background-radius: 5;
-fx-min-width: 30;
-fx-min-height: 30;
} }
+45 -5
View File
@@ -1,10 +1,50 @@
#background { .root {
-fx-background-color: #E7F1F8; -fx-effect: -fx-pp-dropshadow-dark;
-fx-background-radius: 5;
-fx-padding: 10;
}
#rootPane {
-fx-background-image: url("/images/waves.png");
} }
#headText { #headText {
-fx-background-color: transparent;
-fx-font-size: 52px; -fx-font-size: 52px;
-fx-text-fill: -fx-pp-light-text-color; -fx-text-fill: rgb(30, 30, 30);
-fx-effect: -fx-pp-dropshadow-headers; -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,3 @@
#windPane {
-fx-background-color: rgba(255, 255, 255, 0);
}
@@ -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;
} }
@@ -55,3 +58,8 @@
-fx-text-fill: red; -fx-text-fill: red;
-fx-font-size: 33px; -fx-font-size: 33px;
} }
JFXCheckBox {
-jfx-checked-color: -fx-pp-theme-color;
-fx-text-fill: -fx-pp-dark-text-color;
}
+3 -3
View File
@@ -10,8 +10,8 @@
<Marks> <Marks>
<CompoundMark CompoundMarkID="1"> <CompoundMark CompoundMarkID="1">
<Mark Lat="-14.071412" Lng="47.05756"/> <Mark Lat="-14.070412" Lng="47.05746"/>
<Mark Lat="-14.069914" Lng="47.058541"/> <Mark Lat="-14.068014" Lng="47.057541"/>
</CompoundMark> </CompoundMark>
<CompoundMark CompoundMarkID="2"> <CompoundMark CompoundMarkID="2">
<Mark Lat="-14.067194" Lng="47.053818" /> <Mark Lat="-14.067194" Lng="47.053818" />
@@ -64,7 +64,7 @@
<CourseLimit> <CourseLimit>
<Limit Lat="-14.073371" Lng="47.058213" /> <Limit Lat="-14.073371" Lng="47.058213" />
<Limit Lat="-14.06453" Lng="47.050003" /> <Limit Lat="-14.06453" Lng="47.050003" />
<Limit Lat="-14.059022" Lng="47.057286" /> <Limit Lat="-14.057022" Lng="47.057286" />
<Limit Lat="-14.058723" Lng="47.064358" /> <Limit Lat="-14.058723" Lng="47.064358" />
<Limit Lat="-14.06261" Lng="47.071293" /> <Limit Lat="-14.06261" Lng="47.071293" />
<Limit Lat="-14.070814" Lng="47.06762" /> <Limit Lat="-14.070814" Lng="47.06762" />
+66
View File
@@ -0,0 +1,66 @@
<?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"/>
</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>
<CompoundMark CompoundMarkID="6">
<Mark Lat="57.6675700" Lng="11.8359880"/>
<Mark Lat="57.667610" Lng="11.833473"/>
</CompoundMark>
</Marks>
<Course>
<OpeningSegment>
<Corner CompoundMarkID="1" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="S"/>
</OpeningSegment>
<RepeatingSegment>
<Corner CompoundMarkID="3" Rounding="SP"/>
<Corner CompoundMarkID="4" Rounding="PS"/>
<Corner CompoundMarkID="5" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="S"/>
</RepeatingSegment>
<ClosingSegment>
<Corner CompoundMarkID="6" 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>
+65
View File
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RaceDefinition>
<CourseName>Madagascar</CourseName>
<CentralLat>-15.67707</CentralLat>
<CentralLng>49.79338</CentralLng>
<MaxPlayers>10</MaxPlayers>
<Marks>
<CompoundMark CompoundMarkID="1">
<Mark Lat="-15.67466" Lng="49.79104"/>
<Mark Lat="-15.67408" Lng="49.79224"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2">
<Mark Lat="-15.67548" Lng="49.79271"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3">
<Mark Lat="-15.67744" Lng="49.79235"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4">
<Mark Lat="-15.67691" Lng="49.79501"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5">
<Mark Lat="-15.67775" Lng="49.79619"/>
<Mark Lat="-15.67827" Lng="49.79713"/>
</CompoundMark>
<CompoundMark CompoundMarkID="6">
<Mark Lat="-15.67922" Lng="49.79318"/>
<Mark Lat="-15.67972" Lng="49.79393"/>
</CompoundMark>
</Marks>
<Course>
<OpeningSegment>
<Corner CompoundMarkID="1" Rounding="PS"/>
</OpeningSegment>
<RepeatingSegment>
<Corner CompoundMarkID="2" Rounding="P"/>
<Corner CompoundMarkID="3" Rounding="S"/>
<Corner CompoundMarkID="4" Rounding="S"/>
<Corner CompoundMarkID="3" Rounding="P"/>
</RepeatingSegment>
<ClosingSegment>
<Corner CompoundMarkID="5" Rounding="PS"/>
<Corner CompoundMarkID="6" Rounding="PS"/>
</ClosingSegment>
</Course>
<CourseLimit>
<Limit Lat="-15.67571" Lng="49.78984"/>
<Limit Lat="-15.6787" Lng="49.79024"/>
<Limit Lat="-15.68046" Lng="49.79247"/>
<Limit Lat="-15.68073" Lng="49.79599"/>
<Limit Lat="-15.67939" Lng="49.79855"/>
<Limit Lat="-15.67662" Lng="49.79855"/>
<Limit Lat="-15.67474" Lng="49.79694"/>
<Limit Lat="-15.67271" Lng="49.79355"/>
<Limit Lat="-15.67333" Lng="49.79071"/>
</CourseLimit>
</RaceDefinition>
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<RaceDefinition>
<CourseName>Waiheke</CourseName>
<CentralLat>-36.80008</CentralLat>
<CentralLng>175.012225</CentralLng>
<MaxPlayers>10</MaxPlayers>
<Marks>
<CompoundMark CompoundMarkID="1">
<Mark Lat="-36.79512" Lng="175.0116"/>
<Mark Lat="-36.79468" Lng="175.01312"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2">
<Mark Lat="-36.80069" Lng="175.01495"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3">
<Mark Lat="-36.79892" Lng="175.01832"/>
<Mark Lat="-36.79988" Lng="175.01913"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4">
<Mark Lat="-36.80064" Lng="175.01171"/>
<Mark Lat="-36.80186" Lng="175.0124"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5">
<Mark Lat="-36.79579" Lng="175.01194"/>
<Mark Lat="-36.79545" Lng="175.01349"/>
</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="-36.7938" Lng="175.01194"/>
<Limit Lat="-36.79411" Lng="175.01555"/>
<Limit Lat="-36.79765" Lng="175.01898"/>
<Limit Lat="-36.79909" Lng="175.02149"/>
<Limit Lat="-36.80163" Lng="175.02014"/>
<Limit Lat="-36.80292" Lng="175.0175"/>
<Limit Lat="-36.80325" Lng="175.01008"/>
<Limit Lat="-36.80107" Lng="175.0089"/>
<Limit Lat="-36.79567" Lng="175.00961"/>
</CourseLimit>
</RaceDefinition>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,518 @@
<?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-28T02:22:29</created>
<modified>2017-09-28T02:22:29</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_cameras>
<camera id="Camera-camera" name="Camera">
<optics>
<technique_common>
<perspective>
<xfov sid="xfov">49.13434</xfov>
<aspect_ratio>1.777778</aspect_ratio>
<znear sid="znear">0.1</znear>
<zfar sid="zfar">100</zfar>
</perspective>
</technique_common>
</optics>
<extra>
<technique profile="blender">
<shiftx sid="shiftx" type="float">0</shiftx>
<shifty sid="shifty" type="float">0</shifty>
<YF_dofdist sid="YF_dofdist" type="float">0</YF_dofdist>
</technique>
</extra>
</camera>
<camera id="Camera_001-camera" name="Camera.001">
<optics>
<technique_common>
<perspective>
<xfov sid="xfov">49.13434</xfov>
<aspect_ratio>1.777778</aspect_ratio>
<znear sid="znear">0.1</znear>
<zfar sid="zfar">100</zfar>
</perspective>
</technique_common>
</optics>
<extra>
<technique profile="blender">
<shiftx sid="shiftx" type="float">0</shiftx>
<shifty sid="shifty" type="float">0</shifty>
<YF_dofdist sid="YF_dofdist" type="float">0</YF_dofdist>
</technique>
</extra>
</camera>
<camera id="Camera_001-camera" name="Camera.003">
<optics>
<technique_common>
<perspective>
<xfov sid="xfov">49.13434</xfov>
<aspect_ratio>1.777778</aspect_ratio>
<znear sid="znear">0.1</znear>
<zfar sid="zfar">100</zfar>
</perspective>
</technique_common>
</optics>
<extra>
<technique profile="blender">
<shiftx sid="shiftx" type="float">0</shiftx>
<shifty sid="shifty" type="float">0</shifty>
<YF_dofdist sid="YF_dofdist" type="float">0</YF_dofdist>
</technique>
</extra>
</camera>
<camera id="Camera_001_001-camera" name="Camera.003">
<optics>
<technique_common>
<perspective>
<xfov sid="xfov">49.13434</xfov>
<aspect_ratio>1.777778</aspect_ratio>
<znear sid="znear">0.1</znear>
<zfar sid="zfar">100</zfar>
</perspective>
</technique_common>
</optics>
<extra>
<technique profile="blender">
<shiftx sid="shiftx" type="float">0</shiftx>
<shifty sid="shifty" type="float">0</shifty>
<YF_dofdist sid="YF_dofdist" type="float">0</YF_dofdist>
</technique>
</extra>
</camera>
</library_cameras>
<library_lights>
<light id="Lamp-light" name="Lamp">
<technique_common>
<point>
<color sid="color">1 1 1</color>
<constant_attenuation>1</constant_attenuation>
<linear_attenuation>0</linear_attenuation>
<quadratic_attenuation>0.00111109</quadratic_attenuation>
</point>
</technique_common>
<extra>
<technique profile="blender">
<type sid="type" type="int">0</type>
<flag sid="flag" type="int">0</flag>
<mode sid="mode" type="int">8192</mode>
<gamma sid="blender_gamma" type="float">1</gamma>
<red sid="red" type="float">1</red>
<green sid="green" type="float">1</green>
<blue sid="blue" type="float">1</blue>
<shadow_r sid="blender_shadow_r" type="float">0</shadow_r>
<shadow_g sid="blender_shadow_g" type="float">0</shadow_g>
<shadow_b sid="blender_shadow_b" type="float">0</shadow_b>
<energy sid="blender_energy" type="float">1</energy>
<dist sid="blender_dist" type="float">29.99998</dist>
<spotsize sid="spotsize" type="float">75</spotsize>
<spotblend sid="spotblend" type="float">0.15</spotblend>
<halo_intensity sid="blnder_halo_intensity" type="float">1</halo_intensity>
<att1 sid="att1" type="float">0</att1>
<att2 sid="att2" type="float">1</att2>
<falloff_type sid="falloff_type" type="int">2</falloff_type>
<clipsta sid="clipsta" type="float">1.000799</clipsta>
<clipend sid="clipend" type="float">30.002</clipend>
<bias sid="bias" type="float">1</bias>
<soft sid="soft" type="float">3</soft>
<compressthresh sid="compressthresh" type="float">0.04999995</compressthresh>
<bufsize sid="bufsize" type="int">2880</bufsize>
<samp sid="samp" type="int">3</samp>
<buffers sid="buffers" type="int">1</buffers>
<filtertype sid="filtertype" type="int">0</filtertype>
<bufflag sid="bufflag" type="int">0</bufflag>
<buftype sid="buftype" type="int">2</buftype>
<ray_samp sid="ray_samp" type="int">1</ray_samp>
<ray_sampy sid="ray_sampy" type="int">1</ray_sampy>
<ray_sampz sid="ray_sampz" type="int">1</ray_sampz>
<ray_samp_type sid="ray_samp_type" type="int">0</ray_samp_type>
<area_shape sid="area_shape" type="int">1</area_shape>
<area_size sid="area_size" type="float">0.1</area_size>
<area_sizey sid="area_sizey" type="float">0.1</area_sizey>
<area_sizez sid="area_sizez" type="float">1</area_sizez>
<adapt_thresh sid="adapt_thresh" type="float">0.000999987</adapt_thresh>
<ray_samp_method sid="ray_samp_method" type="int">1</ray_samp_method>
<shadhalostep sid="shadhalostep" type="int">0</shadhalostep>
<sun_effect_type sid="sun_effect_type" type="int">0</sun_effect_type>
<skyblendtype sid="skyblendtype" type="int">1</skyblendtype>
<horizon_brightness sid="horizon_brightness" type="float">1</horizon_brightness>
<spread sid="spread" type="float">1</spread>
<sun_brightness sid="sun_brightness" type="float">1</sun_brightness>
<sun_size sid="sun_size" type="float">1</sun_size>
<backscattered_light sid="backscattered_light" type="float">1</backscattered_light>
<sun_intensity sid="sun_intensity" type="float">1</sun_intensity>
<atm_turbidity sid="atm_turbidity" type="float">2</atm_turbidity>
<atm_extinction_factor sid="atm_extinction_factor" type="float">1</atm_extinction_factor>
<atm_distance_factor sid="atm_distance_factor" type="float">1</atm_distance_factor>
<skyblendfac sid="skyblendfac" type="float">1</skyblendfac>
<sky_exposure sid="sky_exposure" type="float">1</sky_exposure>
<sky_colorspace sid="sky_colorspace" type="int">0</sky_colorspace>
</technique>
</extra>
</light>
<light id="Lamp_001-light" name="Lamp.001">
<technique_common>
<point>
<color sid="color">1 1 1</color>
<constant_attenuation>1</constant_attenuation>
<linear_attenuation>0</linear_attenuation>
<quadratic_attenuation>0.00111109</quadratic_attenuation>
</point>
</technique_common>
<extra>
<technique profile="blender">
<type sid="type" type="int">0</type>
<flag sid="flag" type="int">0</flag>
<mode sid="mode" type="int">8192</mode>
<gamma sid="blender_gamma" type="float">1</gamma>
<red sid="red" type="float">1</red>
<green sid="green" type="float">1</green>
<blue sid="blue" type="float">1</blue>
<shadow_r sid="blender_shadow_r" type="float">0</shadow_r>
<shadow_g sid="blender_shadow_g" type="float">0</shadow_g>
<shadow_b sid="blender_shadow_b" type="float">0</shadow_b>
<energy sid="blender_energy" type="float">1</energy>
<dist sid="blender_dist" type="float">29.99998</dist>
<spotsize sid="spotsize" type="float">75</spotsize>
<spotblend sid="spotblend" type="float">0.15</spotblend>
<halo_intensity sid="blnder_halo_intensity" type="float">1</halo_intensity>
<att1 sid="att1" type="float">0</att1>
<att2 sid="att2" type="float">1</att2>
<falloff_type sid="falloff_type" type="int">2</falloff_type>
<clipsta sid="clipsta" type="float">1.000799</clipsta>
<clipend sid="clipend" type="float">30.002</clipend>
<bias sid="bias" type="float">1</bias>
<soft sid="soft" type="float">3</soft>
<compressthresh sid="compressthresh" type="float">0.04999995</compressthresh>
<bufsize sid="bufsize" type="int">2880</bufsize>
<samp sid="samp" type="int">3</samp>
<buffers sid="buffers" type="int">1</buffers>
<filtertype sid="filtertype" type="int">0</filtertype>
<bufflag sid="bufflag" type="int">0</bufflag>
<buftype sid="buftype" type="int">2</buftype>
<ray_samp sid="ray_samp" type="int">1</ray_samp>
<ray_sampy sid="ray_sampy" type="int">1</ray_sampy>
<ray_sampz sid="ray_sampz" type="int">1</ray_sampz>
<ray_samp_type sid="ray_samp_type" type="int">0</ray_samp_type>
<area_shape sid="area_shape" type="int">1</area_shape>
<area_size sid="area_size" type="float">0.1</area_size>
<area_sizey sid="area_sizey" type="float">0.1</area_sizey>
<area_sizez sid="area_sizez" type="float">1</area_sizez>
<adapt_thresh sid="adapt_thresh" type="float">9.99987e-4</adapt_thresh>
<ray_samp_method sid="ray_samp_method" type="int">1</ray_samp_method>
<shadhalostep sid="shadhalostep" type="int">0</shadhalostep>
<sun_effect_type sid="sun_effect_type" type="int">0</sun_effect_type>
<skyblendtype sid="skyblendtype" type="int">1</skyblendtype>
<horizon_brightness sid="horizon_brightness" type="float">1</horizon_brightness>
<spread sid="spread" type="float">1</spread>
<sun_brightness sid="sun_brightness" type="float">1</sun_brightness>
<sun_size sid="sun_size" type="float">1</sun_size>
<backscattered_light sid="backscattered_light" type="float">1</backscattered_light>
<sun_intensity sid="sun_intensity" type="float">1</sun_intensity>
<atm_turbidity sid="atm_turbidity" type="float">2</atm_turbidity>
<atm_extinction_factor sid="atm_extinction_factor" type="float">1</atm_extinction_factor>
<atm_distance_factor sid="atm_distance_factor" type="float">1</atm_distance_factor>
<skyblendfac sid="skyblendfac" type="float">1</skyblendfac>
<sky_exposure sid="sky_exposure" type="float">1</sky_exposure>
<sky_colorspace sid="sky_colorspace" type="int">0</sky_colorspace>
</technique>
</extra>
</light>
<light id="Lamp_001-light" name="Lamp.003">
<technique_common>
<point>
<color sid="color">1 1 1</color>
<constant_attenuation>1</constant_attenuation>
<linear_attenuation>0</linear_attenuation>
<quadratic_attenuation>0.00111109</quadratic_attenuation>
</point>
</technique_common>
<extra>
<technique profile="blender">
<type sid="type" type="int">0</type>
<flag sid="flag" type="int">0</flag>
<mode sid="mode" type="int">8192</mode>
<gamma sid="blender_gamma" type="float">1</gamma>
<red sid="red" type="float">1</red>
<green sid="green" type="float">1</green>
<blue sid="blue" type="float">1</blue>
<shadow_r sid="blender_shadow_r" type="float">0</shadow_r>
<shadow_g sid="blender_shadow_g" type="float">0</shadow_g>
<shadow_b sid="blender_shadow_b" type="float">0</shadow_b>
<energy sid="blender_energy" type="float">1</energy>
<dist sid="blender_dist" type="float">29.99998</dist>
<spotsize sid="spotsize" type="float">75</spotsize>
<spotblend sid="spotblend" type="float">0.15</spotblend>
<halo_intensity sid="blnder_halo_intensity" type="float">1</halo_intensity>
<att1 sid="att1" type="float">0</att1>
<att2 sid="att2" type="float">1</att2>
<falloff_type sid="falloff_type" type="int">2</falloff_type>
<clipsta sid="clipsta" type="float">1.000799</clipsta>
<clipend sid="clipend" type="float">30.002</clipend>
<bias sid="bias" type="float">1</bias>
<soft sid="soft" type="float">3</soft>
<compressthresh sid="compressthresh" type="float">0.04999995</compressthresh>
<bufsize sid="bufsize" type="int">2880</bufsize>
<samp sid="samp" type="int">3</samp>
<buffers sid="buffers" type="int">1</buffers>
<filtertype sid="filtertype" type="int">0</filtertype>
<bufflag sid="bufflag" type="int">0</bufflag>
<buftype sid="buftype" type="int">2</buftype>
<ray_samp sid="ray_samp" type="int">1</ray_samp>
<ray_sampy sid="ray_sampy" type="int">1</ray_sampy>
<ray_sampz sid="ray_sampz" type="int">1</ray_sampz>
<ray_samp_type sid="ray_samp_type" type="int">0</ray_samp_type>
<area_shape sid="area_shape" type="int">1</area_shape>
<area_size sid="area_size" type="float">0.1</area_size>
<area_sizey sid="area_sizey" type="float">0.1</area_sizey>
<area_sizez sid="area_sizez" type="float">1</area_sizez>
<adapt_thresh sid="adapt_thresh" type="float">9.99987e-4</adapt_thresh>
<ray_samp_method sid="ray_samp_method" type="int">1</ray_samp_method>
<shadhalostep sid="shadhalostep" type="int">0</shadhalostep>
<sun_effect_type sid="sun_effect_type" type="int">0</sun_effect_type>
<skyblendtype sid="skyblendtype" type="int">1</skyblendtype>
<horizon_brightness sid="horizon_brightness" type="float">1</horizon_brightness>
<spread sid="spread" type="float">1</spread>
<sun_brightness sid="sun_brightness" type="float">1</sun_brightness>
<sun_size sid="sun_size" type="float">1</sun_size>
<backscattered_light sid="backscattered_light" type="float">1</backscattered_light>
<sun_intensity sid="sun_intensity" type="float">1</sun_intensity>
<atm_turbidity sid="atm_turbidity" type="float">2</atm_turbidity>
<atm_extinction_factor sid="atm_extinction_factor" type="float">1</atm_extinction_factor>
<atm_distance_factor sid="atm_distance_factor" type="float">1</atm_distance_factor>
<skyblendfac sid="skyblendfac" type="float">1</skyblendfac>
<sky_exposure sid="sky_exposure" type="float">1</sky_exposure>
<sky_colorspace sid="sky_colorspace" type="int">0</sky_colorspace>
</technique>
</extra>
</light>
<light id="Lamp_001_001-light" name="Lamp.003">
<technique_common>
<point>
<color sid="color">1 1 1</color>
<constant_attenuation>1</constant_attenuation>
<linear_attenuation>0</linear_attenuation>
<quadratic_attenuation>0.00111109</quadratic_attenuation>
</point>
</technique_common>
<extra>
<technique profile="blender">
<type sid="type" type="int">0</type>
<flag sid="flag" type="int">0</flag>
<mode sid="mode" type="int">8192</mode>
<gamma sid="blender_gamma" type="float">1</gamma>
<red sid="red" type="float">1</red>
<green sid="green" type="float">1</green>
<blue sid="blue" type="float">1</blue>
<shadow_r sid="blender_shadow_r" type="float">0</shadow_r>
<shadow_g sid="blender_shadow_g" type="float">0</shadow_g>
<shadow_b sid="blender_shadow_b" type="float">0</shadow_b>
<energy sid="blender_energy" type="float">1</energy>
<dist sid="blender_dist" type="float">29.99998</dist>
<spotsize sid="spotsize" type="float">75</spotsize>
<spotblend sid="spotblend" type="float">0.15</spotblend>
<halo_intensity sid="blnder_halo_intensity" type="float">1</halo_intensity>
<att1 sid="att1" type="float">0</att1>
<att2 sid="att2" type="float">1</att2>
<falloff_type sid="falloff_type" type="int">2</falloff_type>
<clipsta sid="clipsta" type="float">1.000799</clipsta>
<clipend sid="clipend" type="float">30.002</clipend>
<bias sid="bias" type="float">1</bias>
<soft sid="soft" type="float">3</soft>
<compressthresh sid="compressthresh" type="float">0.04999995</compressthresh>
<bufsize sid="bufsize" type="int">2880</bufsize>
<samp sid="samp" type="int">3</samp>
<buffers sid="buffers" type="int">1</buffers>
<filtertype sid="filtertype" type="int">0</filtertype>
<bufflag sid="bufflag" type="int">0</bufflag>
<buftype sid="buftype" type="int">2</buftype>
<ray_samp sid="ray_samp" type="int">1</ray_samp>
<ray_sampy sid="ray_sampy" type="int">1</ray_sampy>
<ray_sampz sid="ray_sampz" type="int">1</ray_sampz>
<ray_samp_type sid="ray_samp_type" type="int">0</ray_samp_type>
<area_shape sid="area_shape" type="int">1</area_shape>
<area_size sid="area_size" type="float">0.1</area_size>
<area_sizey sid="area_sizey" type="float">0.1</area_sizey>
<area_sizez sid="area_sizez" type="float">1</area_sizez>
<adapt_thresh sid="adapt_thresh" type="float">9.99987e-4</adapt_thresh>
<ray_samp_method sid="ray_samp_method" type="int">1</ray_samp_method>
<shadhalostep sid="shadhalostep" type="int">0</shadhalostep>
<sun_effect_type sid="sun_effect_type" type="int">0</sun_effect_type>
<skyblendtype sid="skyblendtype" type="int">1</skyblendtype>
<horizon_brightness sid="horizon_brightness" type="float">1</horizon_brightness>
<spread sid="spread" type="float">1</spread>
<sun_brightness sid="sun_brightness" type="float">1</sun_brightness>
<sun_size sid="sun_size" type="float">1</sun_size>
<backscattered_light sid="backscattered_light" type="float">1</backscattered_light>
<sun_intensity sid="sun_intensity" type="float">1</sun_intensity>
<atm_turbidity sid="atm_turbidity" type="float">2</atm_turbidity>
<atm_extinction_factor sid="atm_extinction_factor" type="float">1</atm_extinction_factor>
<atm_distance_factor sid="atm_distance_factor" type="float">1</atm_distance_factor>
<skyblendfac sid="skyblendfac" type="float">1</skyblendfac>
<sky_exposure sid="sky_exposure" type="float">1</sky_exposure>
<sky_colorspace sid="sky_colorspace" type="int">0</sky_colorspace>
</technique>
</extra>
</light>
</library_lights>
<library_images/>
<library_effects>
<effect id="Material_004-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.8 0 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 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>
<effect id="Material_002-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 0.8 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 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_004-material" name="Material_004">
<instance_effect url="#Material_004-effect"/>
</material>
<material id="Material_002-material" name="Material_002">
<instance_effect url="#Material_002-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Cone_003-mesh" name="Cone.003">
<mesh>
<source id="Cone_003-mesh-positions">
<float_array id="Cone_003-mesh-positions-array" count="198">0 -0.6151299 -0.05701982 -1.77995e-7 -1.7983e-7 -2.05702 0.1200059 -0.6033104 -0.05701982 0.2354 -0.5683059 -0.05701982 0.3417478 -0.5114619 -0.05701982 0.4349624 -0.4349625 -0.05701982 0.5114617 -0.3417478 -0.05701982 0.5683057 -0.2354 -0.05701982 0.6033101 -0.120006 -0.05701988 0.6151297 -1.61108e-7 -0.05701988 0.6033102 0.1200057 -0.05701988 0.5683057 0.2353997 -0.05701988 0.5114617 0.3417476 -0.05701988 0.4349624 0.4349623 -0.05701988 0.3417478 0.5114615 -0.05701988 0.2353999 0.5683056 -0.05701988 0.1200057 0.60331 -0.05701988 -1.59668e-7 0.6151295 -0.05701988 -0.120006 0.6033099 -0.05701988 -0.2354001 0.5683054 -0.05701982 -0.341748 0.5114613 -0.05701982 -0.4349626 0.434962 -0.05701982 -0.5114619 0.3417473 -0.05701982 -0.568306 0.2353994 -0.05701982 -0.6033103 0.1200052 -0.05701982 -0.6151297 -7.08636e-7 -0.05701982 -0.6033101 -0.1200066 -0.05701977 -0.5683055 -0.2354007 -0.05701977 -0.5114613 -0.3417485 -0.05701977 -0.4349618 -0.4349631 -0.05701977 -0.341747 -0.5114623 -0.05701977 -0.235399 -0.5683063 -0.05701977 -0.1200048 -0.6033105 -0.05701977 0 0.6151295 -0.06060606 0 -2.89444e-7 1.939394 0.1200058 0.60331 -0.06060606 0.2353999 0.5683056 -0.06060606 0.3417478 0.5114615 -0.06060606 0.4349623 0.4349622 -0.06060606 0.5114616 0.3417475 -0.06060606 0.5683057 0.2353997 -0.06060606 0.6033101 0.1200057 -0.06060606 0.6151297 -1.40432e-7 -0.06060606 0.6033102 -0.1200059 -0.06060606 0.5683057 -0.2354 -0.06060606 0.5114616 -0.3417478 -0.06060606 0.4349623 -0.4349626 -0.06060606 0.3417477 -0.5114619 -0.06060606 0.2353998 -0.568306 -0.06060606 0.1200056 -0.6033104 -0.06060606 -2.4745e-7 -0.6151298 -0.06060606 -0.1200062 -0.6033103 -0.06060606 -0.2354003 -0.5683058 -0.06060606 -0.3417481 -0.5114617 -0.06060606 -0.4349627 -0.4349622 -0.06060606 -0.511462 -0.3417476 -0.06060606 -0.568306 -0.2353997 -0.06060606 -0.6033104 -0.1200055 -0.06060606 -0.6151298 4.10911e-7 -0.06060606 -0.6033101 0.1200063 -0.06060606 -0.5683056 0.2354003 -0.06060606 -0.5114613 0.3417482 -0.06060606 -0.4349619 0.4349627 -0.06060606 -0.3417471 0.511462 -0.06060606 -0.2353991 0.5683059 -0.06060606 -0.120005 0.6033102 -0.06060606</float_array>
<technique_common>
<accessor source="#Cone_003-mesh-positions-array" count="66" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Cone_003-mesh-normals">
<float_array id="Cone_003-mesh-normals-array" count="198">0 0.8207646 -0.5712665 0 0 1 0.1601035 0.8050041 -0.5712578 0.3140783 0.7582927 -0.5712679 0.4559909 0.6824451 -0.5712627 0.5803661 0.5803661 -0.5712711 0.6824451 0.4559909 -0.5712627 0.7582927 0.3140783 -0.5712679 0.8050041 0.1601035 -0.5712578 0.8207646 0 -0.5712665 0.8050041 -0.1601035 -0.5712578 0.7582927 -0.3140783 -0.5712679 0.6824451 -0.4559909 -0.5712627 0.5803661 -0.5803661 -0.5712711 0.4559909 -0.6824451 -0.5712627 0.3140783 -0.7582927 -0.5712679 0.1601035 -0.8050041 -0.5712578 0 -0.8207646 -0.5712665 -0.1601035 -0.8050041 -0.5712578 -0.3140783 -0.7582927 -0.5712679 -0.4559909 -0.6824451 -0.5712627 -0.5803661 -0.5803661 -0.5712711 -0.6824451 -0.4559909 -0.5712627 -0.7582927 -0.3140783 -0.5712679 -0.8050041 -0.1601035 -0.5712578 -0.8207646 0 -0.5712665 -0.8050041 0.1601035 -0.5712578 -0.7582927 0.3140783 -0.5712679 -0.6824451 0.4559909 -0.5712627 -0.5803661 0.5803661 -0.5712711 -0.4559909 0.6824451 -0.5712627 -0.3140783 0.7582927 -0.5712679 -0.1601035 0.8050041 -0.5712578 0 -0.8207646 0.5712665 0 0 -1 0.1601035 -0.8050041 0.5712578 0.3140783 -0.7582927 0.5712679 0.4559909 -0.6824451 0.5712627 0.5803661 -0.5803661 0.5712711 0.6824451 -0.4559909 0.5712627 0.7582927 -0.3140783 0.5712679 0.8050041 -0.1601035 0.5712578 0.8207646 0 0.5712665 0.8050041 0.1601035 0.5712578 0.7582927 0.3140783 0.5712679 0.6824451 0.4559909 0.5712627 0.5803661 0.5803661 0.5712711 0.4559909 0.6824451 0.5712627 0.3140783 0.7582927 0.5712679 0.1601035 0.8050041 0.5712578 0 0.8207646 0.5712665 -0.1601035 0.8050041 0.5712578 -0.3140783 0.7582927 0.5712679 -0.4559909 0.6824451 0.5712627 -0.5803661 0.5803661 0.5712711 -0.6824451 0.4559909 0.5712627 -0.7582927 0.3140783 0.5712679 -0.8050041 0.1601035 0.5712578 -0.8207646 0 0.5712665 -0.8050041 -0.1601035 0.5712578 -0.7582927 -0.3140783 0.5712679 -0.6824451 -0.4559909 0.5712627 -0.5803661 -0.5803661 0.5712711 -0.4559909 -0.6824451 0.5712627 -0.3140783 -0.7582927 0.5712679 -0.1601035 -0.8050041 0.5712578</float_array>
<technique_common>
<accessor source="#Cone_003-mesh-normals-array" count="66" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Cone_003-mesh-vertices">
<input semantic="POSITION" source="#Cone_003-mesh-positions"/>
</vertices>
<triangles material="Material_004-material" count="62">
<input semantic="VERTEX" source="#Cone_003-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Cone_003-mesh-normals" offset="1"/>
<p>33 0 34 1 35 2 35 2 34 1 36 3 36 3 34 1 37 4 37 4 34 1 38 5 38 5 34 1 39 6 39 6 34 1 40 7 40 7 34 1 41 8 41 8 34 1 42 9 42 9 34 1 43 10 43 10 34 1 44 11 44 11 34 1 45 12 45 12 34 1 46 13 46 13 34 1 47 14 47 14 34 1 48 15 48 15 34 1 49 16 49 16 34 1 50 17 50 17 34 1 51 18 51 18 34 1 52 19 52 19 34 1 53 20 53 20 34 1 54 21 54 21 34 1 55 22 55 22 34 1 56 23 56 23 34 1 57 24 57 24 34 1 58 25 58 25 34 1 59 26 59 26 34 1 60 27 60 27 34 1 61 28 61 28 34 1 62 29 62 29 34 1 63 30 63 30 34 1 64 31 64 31 34 1 65 32 65 32 34 1 33 0 49 16 57 24 65 32 65 32 33 0 35 2 35 2 36 3 65 32 37 4 38 5 39 6 39 6 40 7 41 8 41 8 42 9 43 10 43 10 44 11 41 8 45 12 46 13 47 14 47 14 48 15 45 12 49 16 50 17 53 20 51 18 52 19 53 20 53 20 54 21 57 24 55 22 56 23 57 24 57 24 58 25 59 26 59 26 60 27 61 28 61 28 62 29 65 32 63 30 64 31 65 32 65 32 36 3 37 4 37 4 39 6 41 8 41 8 44 11 45 12 45 12 48 15 49 16 50 17 51 18 53 20 54 21 55 22 57 24 57 24 59 26 65 32 62 29 63 30 65 32 65 32 37 4 41 8 41 8 45 12 65 32 49 16 53 20 57 24 59 26 61 28 65 32 65 32 45 12 49 16</p>
</triangles>
<triangles material="Material_002-material" count="62">
<input semantic="VERTEX" source="#Cone_003-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Cone_003-mesh-normals" offset="1"/>
<p>0 33 1 34 2 35 2 35 1 34 3 36 3 36 1 34 4 37 4 37 1 34 5 38 5 38 1 34 6 39 6 39 1 34 7 40 7 40 1 34 8 41 8 41 1 34 9 42 9 42 1 34 10 43 10 43 1 34 11 44 11 44 1 34 12 45 12 45 1 34 13 46 13 46 1 34 14 47 14 47 1 34 15 48 15 48 1 34 16 49 16 49 1 34 17 50 17 50 1 34 18 51 18 51 1 34 19 52 19 52 1 34 20 53 20 53 1 34 21 54 21 54 1 34 22 55 22 55 1 34 23 56 23 56 1 34 24 57 24 57 1 34 25 58 25 58 1 34 26 59 26 59 1 34 27 60 27 60 1 34 28 61 28 61 1 34 29 62 29 62 1 34 30 63 30 63 1 34 31 64 31 64 1 34 32 65 32 65 1 34 0 33 16 49 24 57 8 41 32 65 0 33 2 35 2 35 3 36 4 37 4 37 5 38 8 41 6 39 7 40 8 41 8 41 9 42 10 43 10 43 11 44 8 41 12 45 13 46 14 47 14 47 15 48 16 49 16 49 17 50 20 53 18 51 19 52 20 53 20 53 21 54 22 55 22 55 23 56 24 57 24 57 25 58 26 59 26 59 27 60 24 57 28 61 29 62 32 65 30 63 31 64 32 65 32 65 2 35 8 41 5 38 6 39 8 41 8 41 11 44 12 45 12 45 14 47 16 49 17 50 18 51 20 53 20 53 22 55 24 57 24 57 27 60 28 61 29 62 30 63 32 65 2 35 4 37 8 41 8 41 12 45 16 49 16 49 20 53 24 57 24 57 28 61 32 65 32 65 8 41 24 57</p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Camera" name="Camera" type="NODE">
<matrix sid="transform">0.6859207 -0.3240135 0.6515582 7.481132 0.7276763 0.3054208 -0.6141704 -6.50764 0 0.8953956 0.4452714 5.343665 0 0 0 1</matrix>
<instance_camera url="#Camera-camera"/>
</node>
<node id="Lamp" name="Lamp" type="NODE">
<matrix sid="transform">-0.2908646 -0.7711008 0.5663932 4.076245 0.9551712 -0.1998834 0.2183912 1.005454 -0.05518906 0.6045247 0.7946723 5.903862 0 0 0 1</matrix>
<instance_light url="#Lamp-light"/>
</node>
<node id="Camera_001" name="Camera_001" type="NODE">
<matrix sid="transform">1.371841 -0.648027 1.303116 10.0091 1.455353 0.6108412 -1.228341 -10.6572 3.76898e-7 1.790791 0.8905425 5.77815 0 0 0 1</matrix>
<instance_camera url="#Camera_001-camera"/>
</node>
<node id="Lamp_001" name="Lamp_001" type="NODE">
<matrix sid="transform">-0.5817292 -1.542202 1.132786 3.199329 1.910342 -0.3997671 0.4367821 4.368987 -0.1103777 1.209049 1.589345 6.898543 0 0 0 1</matrix>
<instance_light url="#Lamp_001-light"/>
</node>
<node id="Cone_000" name="Cone_000" type="NODE">
<matrix sid="transform">0.1515022 -3.01129e-7 -1.994254 0.004837528 -3.54228e-13 -2 3.01996e-7 -0.04310748 -1.994254 -2.28762e-8 -0.1515022 -0.001579307 0 0 0 1</matrix>
<instance_geometry url="#Cone_003-mesh" name="Cone_000">
<bind_material>
<technique_common>
<instance_material symbol="Material_004-material" target="#Material_004-material"/>
<instance_material symbol="Material_002-material" target="#Material_002-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
<node id="Lamp_001" name="Lamp_001" type="NODE">
<matrix sid="transform">-0.5817294 -1.542202 1.132787 3.199328 1.910342 -0.3997668 0.4367828 4.368987 -0.1103783 1.209049 1.589345 6.898543 0 0 0 1</matrix>
<instance_light url="#Lamp_001-light"/>
</node>
<node id="Camera_001" name="Camera_001" type="NODE">
<matrix sid="transform">1.371841 -0.648027 1.303116 10.0091 1.455353 0.6108412 -1.228341 -10.6572 3.76898e-7 1.790791 0.8905425 5.77815 0 0 0 1</matrix>
<instance_camera url="#Camera_001-camera"/>
</node>
<node id="Camera_001_001" name="Camera_001_001" type="NODE">
<matrix sid="transform">1.371841 -0.648027 1.303116 10.0091 1.455353 0.6108412 -1.228341 -10.6572 3.76898e-7 1.790791 0.8905425 5.77815 0 0 0 1</matrix>
<instance_camera url="#Camera_001_001-camera"/>
</node>
<node id="Lamp_001_001" name="Lamp_001_001" type="NODE">
<matrix sid="transform">-0.5817294 -1.542202 1.132787 3.199328 1.910342 -0.3997668 0.4367828 4.368987 -0.1103783 1.209049 1.589345 6.898543 0 0 0 1</matrix>
<instance_light url="#Lamp_001_001-light"/>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long
@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane fx:id="finishScreenGridPane" maxHeight="837.0" maxWidth="837.0" minHeight="837.0" minWidth="837.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="837.0" prefWidth="837.0" style="-fx-background-color: #2C2c36;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.FinishScreenViewController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="259.0" minHeight="259.0" prefHeight="259.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="64.0" minHeight="64.0" prefHeight="64.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="257.0" minHeight="257.0" prefHeight="257.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER" text="Race Finished!" textFill="WHITE" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font>
<Font size="40.0" />
</font>
</Label>
<Label alignment="CENTER" text="Race Result:" textFill="WHITE" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<font>
<Font size="28.0" />
</font>
</Label>
<TableView fx:id="finishOrderTable" maxWidth="661.0" prefHeight="324.0" prefWidth="629.0" styleClass="ui-table" GridPane.halignment="CENTER" GridPane.rowIndex="2">
<columns>
<TableColumn fx:id="posCol" editable="false" maxWidth="74.0" minWidth="74.0" prefWidth="74.0" resizable="false" sortable="false" text="Position" />
<TableColumn fx:id="boatNameCol" editable="false" maxWidth="171.0" minWidth="171.0" prefWidth="171.0" resizable="false" sortable="false" text="Boat Name" />
<TableColumn fx:id="shortNameCol" editable="false" maxWidth="155.18472290039062" minWidth="107.0" prefWidth="155.18472290039062" resizable="false" sortable="false" text="Short Name" />
<TableColumn fx:id="countryCol" editable="false" maxWidth="258.9999694824219" minWidth="147.0" prefWidth="258.9999694824219" resizable="false" sortable="false" text="Country" />
</columns>
<GridPane.margin>
<Insets bottom="50.0" />
</GridPane.margin>
</TableView>
<Button mnemonicParsing="false" onAction="#switchToStartScreenView" onMouseEntered="#playButtonHoverSound" styleClass="blue-ui-btn" text="Return to Start Screen" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP" />
</children>
</GridPane>
+46 -68
View File
@@ -66,6 +66,11 @@
<GridPane.margin> <GridPane.margin>
<Insets right="20.0" top="10.0" /> <Insets right="20.0" top="10.0" />
</GridPane.margin> </GridPane.margin>
</Label>
<Label fx:id="portNumber" text="Port: 4191" GridPane.columnIndex="2" GridPane.halignment="RIGHT" GridPane.rowIndex="1">
<GridPane.margin>
<Insets right="20.0" top="-15.0" />
</GridPane.margin>
</Label> </Label>
</children> </children>
<columnConstraints> <columnConstraints>
@@ -80,12 +85,9 @@
</GridPane> </GridPane>
<GridPane GridPane.rowIndex="1"> <GridPane GridPane.rowIndex="1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="NEVER" maxWidth="-Infinity" minWidth="-Infinity" <ColumnConstraints hgrow="NEVER" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="115.0" />
prefWidth="115.0"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="337.0" prefWidth="430.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" <ColumnConstraints hgrow="NEVER" maxWidth="350.0" minWidth="350.0" prefWidth="350.0" />
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" />
@@ -110,116 +112,92 @@
<Insets bottom="15.0" left="7.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" <GridPane prefHeight="370.0" prefWidth="189.0" styleClass="tokenGridView" vgap="5.0">
vgap="5.0">
<children> <children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Tokens" <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Tokens" GridPane.halignment="CENTER">
GridPane.halignment="CENTER">
<font> <font>
<Font name="System Bold" size="18.0"/> <Font name="System Bold" size="18.0" />
</font> </font>
</Text> </Text>
<StackPane prefHeight="150.0" prefWidth="200.0" <StackPane prefHeight="150.0" prefWidth="200.0" GridPane.rowIndex="1">
GridPane.rowIndex="1">
<children> <children>
<Label alignment="BOTTOM_CENTER" text="Speed" <Label alignment="BOTTOM_CENTER" text="Speed" StackPane.alignment="BOTTOM_CENTER">
StackPane.alignment="BOTTOM_CENTER">
<font> <font>
<Font size="12.0"/> <Font size="12.0" />
</font> </font>
<padding> <padding>
<Insets bottom="5.0"/> <Insets bottom="5.0" />
</padding> </padding>
</Label> </Label>
<Pane fx:id="speedTokenPane" prefHeight="999.0" <Pane fx:id="speedTokenPane" prefHeight="999.0" prefWidth="200.0" styleClass="tokenView" />
prefWidth="200.0" styleClass="tokenView"/>
</children> </children>
</StackPane> </StackPane>
<StackPane prefHeight="150.0" prefWidth="200.0" <StackPane prefHeight="150.0" prefWidth="200.0" GridPane.rowIndex="2">
GridPane.rowIndex="2">
<children> <children>
<Label alignment="BOTTOM_CENTER" text="Handling" <Label alignment="BOTTOM_CENTER" text="Handling" StackPane.alignment="BOTTOM_CENTER">
StackPane.alignment="BOTTOM_CENTER">
<font> <font>
<Font size="12.0"/> <Font size="12.0" />
</font> </font>
<padding> <padding>
<Insets bottom="5.0"/> <Insets bottom="5.0" />
</padding> </padding>
</Label> </Label>
<Pane fx:id="handlingTokenPane" prefHeight="999.0" <Pane fx:id="handlingTokenPane" prefHeight="999.0" prefWidth="200.0" styleClass="tokenView" />
prefWidth="200.0" styleClass="tokenView"/>
</children> </children>
</StackPane> </StackPane>
<StackPane prefHeight="150.0" prefWidth="200.0" <StackPane prefHeight="150.0" prefWidth="200.0" GridPane.rowIndex="3">
GridPane.rowIndex="3">
<children> <children>
<Label alignment="BOTTOM_CENTER" text="Wind Walker" <Label alignment="BOTTOM_CENTER" text="Wind Walker" StackPane.alignment="BOTTOM_CENTER">
StackPane.alignment="BOTTOM_CENTER">
<font> <font>
<Font size="12.0"/> <Font size="12.0" />
</font> </font>
<padding> <padding>
<Insets bottom="5.0"/> <Insets bottom="5.0" />
</padding> </padding>
</Label> </Label>
<Pane fx:id="windWalkerTokenPane" prefHeight="999.0" <Pane fx:id="windWalkerTokenPane" prefHeight="999.0" prefWidth="200.0" styleClass="tokenView" />
prefWidth="200.0" styleClass="tokenView"/>
</children> </children>
</StackPane> </StackPane>
<StackPane prefHeight="150.0" prefWidth="200.0" <StackPane prefHeight="150.0" prefWidth="200.0" GridPane.rowIndex="4">
GridPane.rowIndex="4">
<children> <children>
<Label alignment="BOTTOM_CENTER" text="Bumper" <Label alignment="BOTTOM_CENTER" text="Bumper" StackPane.alignment="BOTTOM_CENTER">
StackPane.alignment="BOTTOM_CENTER">
<font> <font>
<Font size="12.0"/> <Font size="12.0" />
</font> </font>
<padding> <padding>
<Insets bottom="5.0"/> <Insets bottom="5.0" />
</padding> </padding>
</Label> </Label>
<Pane fx:id="bumperTokenPane" prefHeight="999.0" <Pane fx:id="bumperTokenPane" prefHeight="999.0" prefWidth="200.0" styleClass="tokenView" />
prefWidth="200.0" styleClass="tokenView"/>
</children> </children>
</StackPane> </StackPane>
<StackPane prefHeight="150.0" prefWidth="200.0" <StackPane prefHeight="150.0" prefWidth="200.0" GridPane.rowIndex="5">
GridPane.rowIndex="5">
<children> <children>
<Label alignment="BOTTOM_CENTER" text="Random" <Label alignment="BOTTOM_CENTER" text="Random" StackPane.alignment="BOTTOM_CENTER">
StackPane.alignment="BOTTOM_CENTER">
<font> <font>
<Font size="12.0"/> <Font size="12.0" />
</font> </font>
<padding> <padding>
<Insets bottom="5.0"/> <Insets bottom="5.0" />
</padding> </padding>
</Label> </Label>
<Pane fx:id="randomTokenPane" prefHeight="999.0" <Pane fx:id="randomTokenPane" prefHeight="999.0" prefWidth="60.0" styleClass="tokenView" />
prefWidth="60.0" styleClass="tokenView"/>
</children> </children>
</StackPane> </StackPane>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="80.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="80.0" prefWidth="80.0" />
prefWidth="80.0"/>
</columnConstraints> </columnConstraints>
<padding> <padding>
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0"/> <Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
</padding> </padding>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="116.0" minHeight="0.0" prefHeight="40.0" <RowConstraints maxHeight="116.0" minHeight="0.0" prefHeight="40.0" vgrow="NEVER" />
vgrow="NEVER"/> <RowConstraints maxHeight="285.0" minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="285.0" minHeight="-Infinity" <RowConstraints maxHeight="285.0" minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
prefHeight="60.0" vgrow="SOMETIMES"/> <RowConstraints maxHeight="141.0" minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="285.0" minHeight="-Infinity" <RowConstraints maxHeight="285.0" minHeight="-Infinity" prefHeight="60.0" vgrow="SOMETIMES" />
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> </rowConstraints>
</GridPane> </GridPane>
</children> </children>
@@ -236,7 +214,7 @@
</GridPane> </GridPane>
</children> </children>
<stylesheets> <stylesheets>
<URL value="@../css/Master.css"/> <URL value="@../css/Master.css" />
<URL value="@../css/LobbyView.css"/> <URL value="@../css/LobbyView.css" />
</stylesheets> </stylesheets>
</StackPane> </StackPane>
+296 -278
View File
@@ -1,308 +1,326 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?> <?import com.jfoenix.controls.*?>
<?import java.lang.*?> <?import java.lang.*?>
<?import java.net.*?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.image.*?> <?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?> <?import javafx.scene.text.*?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXSpinner?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.lang.String?> <?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?> <?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.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"> <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> <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">
<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">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="250.0" minWidth="250.0"
prefWidth="250.0"/> prefWidth="250.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/> <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="400.0"
prefWidth="400.0"/> prefWidth="400.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0" <RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/> <RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0" <RowConstraints maxHeight="250.0" minHeight="250.0" prefHeight="250.0"
valignment="BOTTOM" vgrow="SOMETIMES"/> valignment="BOTTOM" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer"> <GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
prefWidth="50.0"/> prefWidth="50.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0"
prefWidth="135.0"/> prefWidth="135.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>
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
</opaqueInsets> </opaqueInsets>
<GridPane.margin> <GridPane.margin>
<Insets left="10.0" right="200.0" top="10.0"/> <Insets left="10.0" right="200.0" top="10.0"/>
</GridPane.margin> </GridPane.margin>
<children> <children>
<ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true" <ImageView fitHeight="40.0" fitWidth="40.0" pickOnBounds="true"
preserveRatio="true" GridPane.halignment="CENTER" preserveRatio="true" GridPane.halignment="CENTER"
GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<image> <image>
<Image url="@../images/timer.png"/> <Image url="@../images/timer.png"/>
</image> </image>
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
</ImageView> </ImageView>
<Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1" <Label fx:id="timerLabel" text="00:03:34" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.valignment="CENTER"> GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font> <font>
<Font size="21.0"/> <Font size="21.0"/>
</font> </font>
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
</Label> </Label>
</children> </children>
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="2"> <GridPane GridPane.columnIndex="2">
<columnConstraints> <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> </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>
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2"> <GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0"
prefWidth="390.0"/> prefWidth="390.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/> <RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0" <Pane fx:id="chatHistoryHolder" prefHeight="200.0" prefWidth="200.0"
GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM" GridPane.hgrow="ALWAYS" GridPane.valignment="BOTTOM"
GridPane.vgrow="ALWAYS"> GridPane.vgrow="ALWAYS">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
<padding> <padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding> </padding>
</Pane> </Pane>
<GridPane fx:id="chatInputHolder" GridPane.rowIndex="1"> <GridPane fx:id="chatInputHolder" GridPane.rowIndex="1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/> prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" <ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="90.0" prefWidth="90.0"/> minWidth="90.0" prefWidth="90.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" <RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0"
valignment="CENTER" vgrow="SOMETIMES"/> valignment="CENTER" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED" <JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED"
focusTraversable="false" maxHeight="-Infinity" focusTraversable="false" maxHeight="-Infinity"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="35.0" text="SEND" minWidth="-Infinity" prefHeight="35.0" text="SEND"
GridPane.columnIndex="1"> GridPane.columnIndex="1">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</GridPane.margin> </GridPane.margin>
</JFXButton> </JFXButton>
<JFXTextField fx:id="chatInput" focusTraversable="false" <JFXTextField fx:id="chatInput" focusTraversable="false"
maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0"> maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="20.0" right="10.0"/> <Insets bottom="10.0" left="20.0" right="10.0"/>
</GridPane.margin> </GridPane.margin>
<padding> <padding>
<Insets right="15.0"/> <Insets right="15.0"/>
</padding> </padding>
</JFXTextField> </JFXTextField>
</children> </children>
<GridPane.margin> <GridPane.margin>
<Insets top="10.0"/> <Insets top="10.0"/>
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
</children> </children>
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" right="10.0"/> <Insets bottom="10.0" right="10.0"/>
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
<GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity" <GridPane fx:id="windGridPane" maxHeight="-Infinity" maxWidth="-Infinity"
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER" prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="BOTTOM"> GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0"
prefWidth="110.0"/> prefWidth="110.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
prefWidth="132.0"/> prefWidth="132.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1" <Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1"
GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP"> GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
</Label> </Label>
<Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1" <Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1"
GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
</opaqueInsets> </opaqueInsets>
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
</Label> </Label>
<Label fx:id="boatHeadingLabel" text="Boat Heading:" <Label fx:id="boatHeadingLabel" text="Boat Heading:"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.valignment="BOTTOM"> GridPane.valignment="BOTTOM">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
</Label> </Label>
<GridPane fx:id="windHolder" GridPane.rowSpan="2"> <GridPane fx:id="windHolder" GridPane.rowSpan="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/> prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/> prefHeight="120.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0" <Label fx:id="windSpeedLabel" text="0.0 Knots"
pickOnBounds="true" preserveRatio="true" GridPane.halignment="RIGHT" GridPane.rowIndex="1"
GridPane.halignment="CENTER" GridPane.rowSpan="2" GridPane.valignment="CENTER">
GridPane.valignment="CENTER"/> <GridPane.margin>
<Label fx:id="windSpeedLabel" text="0.0 Knots" <Insets right="5.0"/>
GridPane.halignment="RIGHT" GridPane.rowIndex="1" </GridPane.margin>
GridPane.valignment="CENTER"> </Label>
<GridPane.margin> <Label fx:id="windDirectionLabel" text="180.0°"
<Insets right="5.0"/> GridPane.halignment="LEFT" GridPane.rowIndex="1"
</GridPane.margin> GridPane.valignment="CENTER">
</Label> <GridPane.margin>
<Label fx:id="windDirectionLabel" text="180.0°" <Insets left="5.0"/>
GridPane.halignment="LEFT" GridPane.rowIndex="1" </GridPane.margin>
GridPane.valignment="CENTER"> </Label>
<GridPane.margin> <VBox fx:id="windArrowVBox" prefHeight="200.0" prefWidth="100.0"/>
<Insets left="5.0"/> </children>
</GridPane.margin> </GridPane>
</Label> </children>
</children> <opaqueInsets>
</GridPane> <Insets/>
</children> </opaqueInsets>
<opaqueInsets> <GridPane.margin>
<Insets/> <Insets bottom="10.0" left="10.0" top="40.0"/>
</opaqueInsets> </GridPane.margin>
<GridPane.margin> </GridPane>
<Insets bottom="10.0" left="10.0" top="40.0"/> <GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
</GridPane.margin> <columnConstraints>
</GridPane> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2"> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<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 hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> </columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> <rowConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> <RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0"
</columnConstraints> vgrow="SOMETIMES"/>
<rowConstraints> <RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0"
<RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/> </rowConstraints>
<RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0" <children>
vgrow="SOMETIMES"/> <ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0"
</rowConstraints> pickOnBounds="true" preserveRatio="true" visible="false"
<children> GridPane.halignment="CENTER" GridPane.rowIndex="1">
<ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0" <image>
pickOnBounds="true" preserveRatio="true" visible="false" <Image url="@../icons/velocity.png"/>
GridPane.halignment="CENTER" GridPane.rowIndex="1"> </image>
<image> </ImageView>
<Image url="@../icons/velocity.png"/> <ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0"
</image> pickOnBounds="true" preserveRatio="true" visible="false"
</ImageView> GridPane.columnIndex="1" GridPane.halignment="CENTER"
<ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0" GridPane.rowIndex="1">
pickOnBounds="true" preserveRatio="true" visible="false" <image>
GridPane.columnIndex="1" GridPane.halignment="CENTER" <Image url="@../icons/handlingIcon.png"/>
GridPane.rowIndex="1"> </image>
<image> </ImageView>
<Image url="@../icons/handlingIcon.png"/> <ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0"
</image> pickOnBounds="true" preserveRatio="true" visible="false"
</ImageView> GridPane.columnIndex="2" GridPane.halignment="CENTER"
<ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0" GridPane.rowIndex="1">
pickOnBounds="true" preserveRatio="true" visible="false" <image>
GridPane.columnIndex="2" GridPane.halignment="CENTER" <Image url="@../icons/windWalkerIcon.png"/>
GridPane.rowIndex="1"> </image>
<image> </ImageView>
<Image url="@../icons/windWalkerIcon.png"/> <ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0"
</image> pickOnBounds="true" preserveRatio="true" visible="false"
</ImageView> GridPane.columnIndex="3" GridPane.halignment="CENTER"
<ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0" GridPane.rowIndex="1">
pickOnBounds="true" preserveRatio="true" visible="false" <image>
GridPane.columnIndex="3" GridPane.halignment="CENTER" <Image url="@../icons/bumperIcon.png"/>
GridPane.rowIndex="1"> </image>
<image> </ImageView>
<Image url="@../icons/bumperIcon.png"/> <ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0"
</image> pickOnBounds="true" preserveRatio="true" visible="false"
</ImageView> GridPane.columnIndex="4" GridPane.halignment="CENTER"
<ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0" GridPane.rowIndex="1" GridPane.valignment="CENTER">
pickOnBounds="true" preserveRatio="true" visible="false" <image>
GridPane.columnIndex="4" GridPane.halignment="CENTER" <Image url="@../icons/slowedIcon.png"/>
GridPane.rowIndex="1" GridPane.valignment="CENTER"> </image>
<image> </ImageView>
<Image url="@../icons/slowedIcon.png"/> </children>
</image> </GridPane>
</ImageView> </children>
</children> </GridPane>
</GridPane>
</children>
</GridPane>
</children>
</StackPane>
</children> </children>
<AnchorPane fx:id="loadingScreenPane"> </StackPane>
<children> <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" 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" /> <ImageView fx:id="loadingScreen" fitHeight="672.0" fitWidth="1200.0" pickOnBounds="true" preserveRatio="true" />
<JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" /> <JFXSpinner layoutX="566.0" layoutY="692.0" radius="30.0" />
</children> </AnchorPane>
</AnchorPane> <JFXButton fx:id="chatToggleButton" text="—" StackPane.alignment="BOTTOM_RIGHT">
<font>
<Font size="15.0"/>
</font>
<StackPane.margin>
<Insets bottom="70.0" right="10.0"/>
</StackPane.margin>
</JFXButton>
</children>
<stylesheets> <stylesheets>
<String fx:value="/css/Master.css"/> <URL value="@../css/Master.css"/>
<String fx:value="/css/RaceView.css"/> <URL value="@../css/RaceView.css"/>
</stylesheets> </stylesheets>
</StackPane> </StackPane>
+2 -2
View File
@@ -113,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="459.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="1.7976931348623157E308" minHeight="400.0" prefHeight="429.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.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" />
+39 -22
View File
@@ -1,33 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXSpinner?>
<?import java.net.URL?> <?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?> <StackPane fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
<?import javafx.scene.text.Text?> minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8"
<StackPane id="background" 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"> xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.SplashScreenController">
<children> <children>
<ImageView fitHeight="296.0" fitWidth="295.0" pickOnBounds="true" preserveRatio="true" StackPane.alignment="TOP_CENTER"> <AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<image> <children>
<Image url="@../PP.png" /> <Label fx:id="subHeadLabel" layoutX="225.0" layoutY="370.0"
</image> text="MADE BY :PARTYPARROT:"/>
<StackPane.margin> <StackPane layoutX="150.0" layoutY="10.0" prefHeight="150.0" prefWidth="200.0">
<Insets top="20.0" /> <children>
</StackPane.margin> <ImageView fitHeight="190.0" fitWidth="190.0" pickOnBounds="true"
</ImageView> preserveRatio="true">
<Text fx:id="headText" strokeType="OUTSIDE" strokeWidth="0.0" text="Party Parrots at Sea" StackPane.alignment="BOTTOM_CENTER"> <image>
<font> <Image url="@../PP.png"/>
<Font name="System Bold" size="42.0" /> </image>
</font> </ImageView>
<StackPane.margin> <JFXSpinner fx:id="materialDesignRed" radius="150.0" startingAngle="0.0"
<Insets bottom="20.0" /> styleClass="materialDesign-red"/>
</StackPane.margin> <JFXSpinner radius="140.0" startingAngle="20.0"
</Text> 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> </children>
<stylesheets> <stylesheets>
<URL value="@../css/Master.css"/> <URL value="@../css/Master.css"/>
<URL value="@../css/SplashScreenView.css"/> <URL value="@../css/SplashScreenView.css"/>
</stylesheets> </stylesheets>
</StackPane> </StackPane>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<Pane fx:id="windPane" prefHeight="120.0" prefWidth="110.0"
stylesheets="@../../css/cells/WindCell.css" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"/>
@@ -23,6 +23,7 @@
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0" <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
@@ -112,7 +113,7 @@
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED" <JFXButton id="ZOOM IN" fx:id="zoomInBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="Z" minWidth="-Infinity" prefWidth="120.0" text="Z"
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER"
@@ -223,8 +224,19 @@
GridPane.valignment="TOP"/> GridPane.valignment="TOP"/>
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity" <JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" prefWidth="140.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="LEFT"
GridPane.rowIndex="2" GridPane.valignment="CENTER"/> GridPane.rowIndex="2" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="60.0"/>
</GridPane.margin>
</JFXButton>
<JFXButton fx:id="confirmBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="45.0" minWidth="140.0" prefHeight="45.0"
prefWidth="140.0" text="CONFIRM" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
<GridPane.margin>
<Insets right="60.0"/>
</GridPane.margin>
</JFXButton>
</children> </children>
</GridPane> </GridPane>
</children> </children>
@@ -5,16 +5,18 @@
<?import com.jfoenix.controls.JFXDialogLayout?> <?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXSlider?> <?import com.jfoenix.controls.JFXSlider?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController"> minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
<children> <children>
<GridPane> <GridPane>
<children> <children>
@@ -36,9 +38,14 @@
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="-Infinity" minHeight="90.0" prefHeight="90.0"
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="-Infinity" minHeight="90.0" prefHeight="90.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="90.0" prefHeight="90.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="90.0" prefHeight="90.0"
vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<JFXTextField fx:id="serverName" promptText="SERVER NAME"> <JFXTextField fx:id="serverName" promptText="SERVER NAME">
@@ -46,29 +53,33 @@
<Insets left="15.0" right="15.0" /> <Insets left="15.0" right="15.0" />
</padding> </padding>
<GridPane.margin> <GridPane.margin>
<Insets left="35.0" right="35.0" /> <Insets left="20.0" right="35.0"/>
</GridPane.margin> </GridPane.margin>
</JFXTextField> </JFXTextField>
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="1"> <GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="1">
<children> <children>
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP"> <Label styleClass="optionLabel" text="MAX PLAYERS" translateY="5.0"
GridPane.halignment="CENTER" GridPane.valignment="BOTTOM">
<GridPane.margin> <GridPane.margin>
<Insets right="30.0" /> <Insets/>
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM"> <JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0"
majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1"
snapToTicks="true" styleClass="maxPlayers" value="11.0"
GridPane.columnIndex="1" GridPane.valignment="BOTTOM">
<GridPane.margin> <GridPane.margin>
<Insets left="30.0" top="20.0" /> <Insets right="30.0"/>
</GridPane.margin> </GridPane.margin>
</Label> </JFXSlider>
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <Label fx:id="maxPlayersLabel" alignment="CENTER"
<children> styleClass="sliderLabel" text="10" GridPane.columnIndex="1"
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" /> GridPane.halignment="CENTER" GridPane.rowIndex="1"
</children> GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" right="30.0" /> <Insets right="15.0"/>
</GridPane.margin> </GridPane.margin>
</VBox> </Label>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
@@ -81,48 +92,68 @@
</GridPane> </GridPane>
<GridPane fx:id="maxPlayersGridPane1" GridPane.rowIndex="2"> <GridPane fx:id="maxPlayersGridPane1" GridPane.rowIndex="2">
<children> <children>
<Label fx:id="legsSliderLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
<GridPane.margin>
<Insets right="30.0" />
</GridPane.margin>
</Label>
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<children>
<JFXSlider fx:id="legsSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
</children>
<GridPane.margin>
<Insets bottom="10.0" right="30.0" />
</GridPane.margin>
</VBox>
<GridPane> <GridPane>
<children> <children>
<Label alignment="CENTER" text="NUMBER OF" GridPane.halignment="CENTER" /> <Label alignment="CENTER" styleClass="optionLabel"
<Label alignment="CENTER" text="REPEATING LEGS" GridPane.halignment="CENTER" GridPane.rowIndex="1" /> text="NUMBER OF" GridPane.halignment="CENTER"
GridPane.valignment="BOTTOM"/>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
</GridPane> </GridPane>
<JFXCheckBox fx:id="pickupsCheckBox" text="Enable Pickups" GridPane.rowIndex="1"> <JFXSlider fx:id="legsSlider" blockIncrement="1.0"
majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1"
snapToTicks="true" styleClass="maxPlayers" value="11.0"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.valignment="BOTTOM">
<GridPane.margin> <GridPane.margin>
<Insets left="5.0" /> <Insets right="30.0"/>
</GridPane.margin> </GridPane.margin>
</JFXCheckBox> </JFXSlider>
<Label alignment="CENTER" styleClass="optionLabel"
text="REPEATING LEGS" GridPane.halignment="CENTER"
GridPane.rowIndex="1"/>
<Label fx:id="legsSliderLabel" styleClass="sliderLabel" text="10"
GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets right="15.0"/>
</GridPane.margin>
</Label>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" /> <ColumnConstraints halignment="CENTER" hgrow="SOMETIMES"
minWidth="100.0" prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="-Infinity" minHeight="10.0"
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" /> percentHeight="60.0" prefHeight="100.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="10.0"
percentHeight="40.0" prefHeight="100.0" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
</GridPane> </GridPane>
<GridPane GridPane.rowIndex="3">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
percentWidth="30.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXCheckBox fx:id="pickupsCheckBox" text=" "
GridPane.columnIndex="1"/>
<Label styleClass="optionLabel" text="ENABLE TOKENS"
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="1"> <GridPane GridPane.columnIndex="1">
@@ -152,7 +183,8 @@
<RowConstraints maxHeight="342.0" minHeight="10.0" prefHeight="336.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="342.0" minHeight="10.0" prefHeight="336.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="mapNameLabel" text="MAP NAME" GridPane.halignment="CENTER" /> <Label fx:id="mapNameLabel" styleClass="optionLabel" text="MAP NAME"
GridPane.halignment="CENTER"/>
<AnchorPane fx:id="mapHolder" prefHeight="333.0" prefWidth="404.0" GridPane.rowIndex="1" /> <AnchorPane fx:id="mapHolder" prefHeight="333.0" prefWidth="404.0" GridPane.rowIndex="1" />
</children> </children>
</GridPane> </GridPane>
@@ -164,6 +196,8 @@
<font> <font>
<Font size="20.0" /> <Font size="20.0" />
</font></Label> </font></Label>
<Label fx:id="closeLabel" text="✖" translateY="-10.0" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
</children> </children>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
@@ -175,4 +209,8 @@
</rowConstraints> </rowConstraints>
</GridPane> </GridPane>
</children> </children>
<stylesheets>
<URL value="@../../css/Master.css"/>
<URL value="@../../css/dialogs/ServerCreation.css"/>
</stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="273.0" prefWidth="436.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.TokenInfoDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="40.0" minHeight="30.0" prefHeight="40.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
prefHeight="115.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="141.0" minHeight="34.0" prefHeight="73.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
prefWidth="150.0" text="Ok" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</JFXButton>
<Label fx:id="headerLabel" text="Popup header" GridPane.halignment="CENTER">
<font>
<Font size="15.0"/>
</font>
</Label>
<GridPane GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="270.0" minWidth="10.0"
prefWidth="270.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="225.0" minWidth="-Infinity"
prefWidth="138.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="100.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Pane fx:id="tokenPane" prefHeight="200.0" prefWidth="200.0"
GridPane.columnIndex="1"/>
<TextArea fx:id="contentText" nodeOrientation="RIGHT_TO_LEFT"
prefHeight="200.0" prefWidth="200.0" promptText="This is some text"
stylesheets="@../../css/TokenInfoDialog.css" wrapText="true">
<font>
<Font size="16.0"/>
</font>
</TextArea>
</children>
</GridPane>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/Popup.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
</JFXDialogLayout>
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<AnchorPane fx:id="annotationSelectWindow" maxHeight="270.0" maxWidth="469.0" minHeight="270.0" minWidth="469.0" prefHeight="270.0" prefWidth="469.0" styleClass="background-blue" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fill="WHITE" layoutX="26.0" layoutY="52.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Select important annotations">
<font>
<Font size="24.0" />
</font>
</Text>
<CheckBox fx:id="boatWakeSelect" layoutX="26.0" layoutY="80.0" mnemonicParsing="false" style="-fx-border-width: 0; -fx-background-insets: 0;" text="Boat Wakes" textFill="#e7e7e7" />
<CheckBox fx:id="boatSpeedSelect" layoutX="26.0" layoutY="111.0" mnemonicParsing="false" text="Boat Speed" textFill="#e7e7e7" />
<CheckBox fx:id="boatTrackSelect" layoutX="26.0" layoutY="142.0" mnemonicParsing="false" text="Boat Tracks" textFill="#e7e7e7" />
<CheckBox fx:id="boatNameSelect" layoutX="26.0" layoutY="173.0" mnemonicParsing="false" text="Boat Name" textFill="#e7e7e7" />
<CheckBox fx:id="boatEstTimeToNextMarkSelect" layoutX="26.0" layoutY="204.0" mnemonicParsing="false" text="Boat Estimated Time To Next Mark" textFill="#e7e7e7" />
<Button fx:id="closeButton" layoutX="424.0" layoutY="-1.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="49.0" style=": 0;" text="X" textFill="#ffffff4e">
<font>
<Font size="24.0" />
</font>
<styleClass>
<String fx:value="background-blue" />
<String fx:value="clearExitButton" />
</styleClass>
</Button>
<CheckBox fx:id="boatElapsedTimeSelect" layoutX="26.0" layoutY="235.0" mnemonicParsing="false" text="Boat Elapsed Time Since Last Mark" textFill="#e7e7e7" />
</children>
</AnchorPane>
@@ -48,9 +48,10 @@ public class ServerTableTest {
serverTable.addServer(listing); serverTable.addServer(listing);
listing.decrementTtl();
listing.decrementTtl(); listing.decrementTtl();
Thread.sleep(1000); Thread.sleep(1500);
assertTrue(!serverTable.getAllServers().contains(listing)); assertTrue(!serverTable.getAllServers().contains(listing));
} }
@@ -0,0 +1,9 @@
package seng302.utilities;
/**
* Created by cir27 on 28/09/17.
*/
public class MapMakerTest {
// @Test
}
@@ -12,7 +12,7 @@ public class DisconnectionTest {
@Test @Test
public void testServerDisconnection () throws Exception { public void testServerDisconnection () throws Exception {
MainServerThread serverThread = new MainServerThread(); MainServerThread serverThread = new MainServerThread();
ClientToServerThread clientThread = new ClientToServerThread("localhost", 4942); ClientToServerThread clientThread = new ClientToServerThread("localhost", serverThread.getPortNumber());
Thread.sleep(1000); Thread.sleep(1000);
clientThread.addDisconnectionListener(message -> Assert.assertTrue(message != null)); clientThread.addDisconnectionListener(message -> Assert.assertTrue(message != null));
serverThread.terminate(); serverThread.terminate();
@@ -20,7 +20,7 @@ public class RegularPacketsTest {
public void setup() throws Exception { public void setup() throws Exception {
new GameState(); new GameState();
serverThread = new MainServerThread(); serverThread = new MainServerThread();
clientThread = new ClientToServerThread("localhost", 4942); clientThread = new ClientToServerThread("localhost", serverThread.getPortNumber());
GameState.setCurrentStage(GameStages.RACING); GameState.setCurrentStage(GameStages.RACING);
} }
@@ -1,43 +0,0 @@
package seng302.visualiser.map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import seng302.model.GeoPoint;
/**
* Unit test for Mercator Project class.
* Created by hyi25 on 15/05/17.
*/
public class MercatorProjectionTest {
@Test
public void toMapPoint() throws Exception {
GeoPoint geo1 = new GeoPoint(12.485394, 19.38947);
javafx.geometry.Point2D actualPoint1 = MercatorProjection.toMapPoint(geo1);
javafx.geometry.Point2D expectedPoint1 = new javafx.geometry.Point2D(141.78806755555556, 119.0503853635612);
assertEquals(expectedPoint1.getX(), actualPoint1.getX(), 0.0001);
assertEquals(expectedPoint1.getY(), actualPoint1.getY(), 0.0001);
GeoPoint geo2 = new GeoPoint(77.456432, -23.456462);
javafx.geometry.Point2D actualPoint2 = MercatorProjection.toMapPoint(geo2);
javafx.geometry.Point2D expectedPoint2 = new javafx.geometry.Point2D(111.31984924444444, 38.03143323746788);
assertEquals(expectedPoint2.getX(), actualPoint2.getX(), 0.0001);
assertEquals(expectedPoint2.getY(), actualPoint2.getY(), 0.0001);
}
@Test
public void toMapGeo() throws Exception {
javafx.geometry.Point2D point1 = new javafx.geometry.Point2D(123.1234, 25.4565);
GeoPoint actualGeo1 = MercatorProjection.toMapGeo(point1);
GeoPoint expectedGeo1 = new GeoPoint(80.77043127275441, -6.857718749999995);
assertEquals(expectedGeo1.getLat(), actualGeo1.getLat(), 0.0001);
assertEquals(expectedGeo1.getLng(), actualGeo1.getLng(), 0.0001);
javafx.geometry.Point2D point2 = new javafx.geometry.Point2D(1.235, 255.4565);
GeoPoint actualGeo2 = MercatorProjection.toMapGeo(point2);
GeoPoint expectedGeo2 = new GeoPoint(-84.98475532898011, -178.26328125);
assertEquals(expectedGeo2.getLat(), actualGeo2.getLat(), 0.0001);
assertEquals(expectedGeo2.getLng(), actualGeo2.getLng(), 0.0001);
}
}
+19 -16
View File
@@ -3,6 +3,9 @@ package steps;
import cucumber.api.java.en.Given; import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then; import cucumber.api.java.en.Then;
import java.io.File; import java.io.File;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
import org.junit.Assert; import org.junit.Assert;
import seng302.visualiser.MapMaker; import seng302.visualiser.MapMaker;
@@ -16,26 +19,26 @@ public class CustomMapsSteps {
@Given("^that the game has multiple race xml files$") @Given("^that the game has multiple race xml files$")
public void that_the_game_has_multiple_race_xml_files() throws Throwable { public void that_the_game_has_multiple_race_xml_files() throws Throwable {
// mapMaker = MapMaker.getInstance(); mapMaker = MapMaker.getInstance();
// String firstMap = mapMaker.getCurrentRacePath(); String firstMap = mapMaker.getCurrentRacePath();
// int numMaps = 0; int numMaps = 0;
// do { do {
// mapMaker.next(); mapMaker.next();
// numMaps++; numMaps++;
// } while (!mapMaker.getCurrentRacePath().equals(firstMap)); } while (!mapMaker.getCurrentRacePath().equals(firstMap));
// Assert.assertTrue(numMaps >= 2); Assert.assertTrue(numMaps >= 2);
} }
@Then("^all of them can be seen$") @Then("^all of them can be seen$")
public void all_of_them_can_be_seen() throws Throwable { public void all_of_them_can_be_seen() throws Throwable {
// File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles(); File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles();
// for (File file : files) { Arrays.sort(files);
// if (file.isFile()) { for (File file : files) {
// Assert.assertTrue(file.getAbsolutePath().equals(mapMaker.getCurrentRacePath())); if (file.isFile()) {
// mapMaker.next(); Assert.assertTrue(file.getAbsolutePath().endsWith(mapMaker.getCurrentRacePath()));
// System.out.println(file.getAbsolutePath()); mapMaker.next();
// } }
// } }
} }
@Given("^that I choose a race$") @Given("^that I choose a race$")
+2 -2
View File
@@ -45,7 +45,7 @@ public class SendChatSteps {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
host = new ClientToServerThread("localhost", 4942); host = new ClientToServerThread("localhost", mst.getPortNumber());
host.addStreamObserver(() -> { host.addStreamObserver(() -> {
while (host.getPacketQueue().peek() != null) { while (host.getPacketQueue().peek() != null) {
StreamPacket packet = host.getPacketQueue().poll(); StreamPacket packet = host.getPacketQueue().poll();
@@ -68,7 +68,7 @@ public class SendChatSteps {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
client = new ClientToServerThread("localhost", 4942); client = new ClientToServerThread("localhost", mst.getPortNumber());
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
+1 -1
View File
@@ -44,7 +44,7 @@ public class ToggleSailSteps {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
client = new ClientToServerThread("localhost", 4942); client = new ClientToServerThread("localhost", mst.getPortNumber());
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {