Merge branch 'develop' into Story40_Zooming

This commit is contained in:
Kusal Ekanayake
2017-08-16 17:27:09 +12:00
11 changed files with 227 additions and 70 deletions
+81 -17
View File
@@ -6,8 +6,12 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.server.messages.BoatAction;
import seng302.gameServer.server.messages.BoatStatus; import seng302.gameServer.server.messages.BoatStatus;
import seng302.gameServer.server.messages.MarkRoundingMessage; import seng302.gameServer.server.messages.MarkRoundingMessage;
@@ -16,6 +20,7 @@ import seng302.gameServer.server.messages.Message;
import seng302.gameServer.server.messages.RoundingBoatStatus; import seng302.gameServer.server.messages.RoundingBoatStatus;
import seng302.gameServer.server.messages.YachtEventCodeMessage; import seng302.gameServer.server.messages.YachtEventCodeMessage;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Limit;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.PolarTable; import seng302.model.PolarTable;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
@@ -23,6 +28,7 @@ import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.mark.MarkOrder; import seng302.model.mark.MarkOrder;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.XMLParser;
/** /**
* A Static class to hold information about the current state of the game (model) * A Static class to hold information about the current state of the game (model)
@@ -33,6 +39,7 @@ public class GameState implements Runnable {
@FunctionalInterface @FunctionalInterface
interface NewMessageListener { interface NewMessageListener {
void notify(Message message); void notify(Message message);
} }
@@ -59,6 +66,7 @@ public class GameState implements Runnable {
private static MarkOrder markOrder; private static MarkOrder markOrder;
private static long startTime; private static long startTime;
private static Set<Mark> marks; private static Set<Mark> marks;
private static List<Limit> courseLimit;
private static List<NewMessageListener> markListeners; private static List<NewMessageListener> markListeners;
@@ -81,7 +89,7 @@ public class GameState implements Runnable {
yachts = new HashMap<>(); yachts = new HashMap<>();
players = new ArrayList<>(); players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress; GameState.hostIpAddress = hostIpAddress;
;
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
//set this when game stage changes to prerace //set this when game stage changes to prerace
@@ -89,9 +97,28 @@ public class GameState implements Runnable {
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map? markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
markListeners = new ArrayList<>(); markListeners = new ArrayList<>();
resetStartTime();
new Thread(this).start(); //Run the auto updates on the game state
new Thread(this, "GameState").start(); //Run the auto updates on the game state new Thread(this, "GameState").start(); //Run the auto updates on the game state
marks = new MarkOrder().getAllMarks(); marks = new MarkOrder().getAllMarks();
setCourseLimit("/server_config/race.xml");
}
private void setCourseLimit(String url) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder;
Document document = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder.parse(new InputSource(getClass().getResourceAsStream(url)));
} catch (Exception e) {
// sorry, we have to catch general one, otherwise we have to catch five different exceptions.
logger.trace("Failed to load course limit for boundary collision detection.", e);
}
courseLimit = XMLParser.parseRace(document).getCourseLimit();
} }
public static String getHostIpAddress() { public static String getHostIpAddress() {
@@ -135,10 +162,6 @@ public class GameState implements Runnable {
} }
public static void setCurrentStage(GameStages currentStage) { public static void setCurrentStage(GameStages currentStage) {
if (currentStage == GameStages.RACING) {
startTime = System.currentTimeMillis();
}
GameState.currentStage = currentStage; GameState.currentStage = currentStage;
} }
@@ -150,6 +173,10 @@ public class GameState implements Runnable {
return startTime; return startTime;
} }
public static void resetStartTime(){
startTime = System.currentTimeMillis() + MainServerThread.TIME_TILL_START;
}
public static Double getWindDirection() { public static Double getWindDirection() {
return windDirection; return windDirection;
} }
@@ -190,7 +217,7 @@ public class GameState implements Runnable {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("[GameState] interrupted exception"); System.out.println("[GameState] interrupted exception");
} }
if (currentStage == GameStages.PRE_RACE) { if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
update(); update();
} }
@@ -233,12 +260,15 @@ public class GameState implements Runnable {
Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0; Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0;
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
if (System.currentTimeMillis() > startTime) {
GameState.setCurrentStage(GameStages.RACING);
}
for (ServerYacht yacht : yachts.values()) { for (ServerYacht yacht : yachts.values()) {
updateVelocity(yacht); updateVelocity(yacht);
yacht.runAutoPilot(); yacht.runAutoPilot();
yacht.updateLocation(timeInterval); yacht.updateLocation(timeInterval);
if (yacht.getBoatStatus() != BoatStatus.FINISHED) { if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
checkForCollision(yacht); checkCollision(yacht);
checkForLegProgression(yacht); checkForLegProgression(yacht);
raceFinished = false; raceFinished = false;
} }
@@ -249,9 +279,28 @@ public class GameState implements Runnable {
} }
} }
/**
* Check if the yacht has crossed the course limit
*
* @param yacht the yacht to be tested
* @return a boolean value of if there is a boundary collision
*/
private static Boolean checkBoundaryCollision(ServerYacht yacht) {
for (int i = 0; i < courseLimit.size() - 1; i++) {
if (GeoUtility.checkCrossedLine(courseLimit.get(i), courseLimit.get(i + 1),
yacht.getLastLocation(), yacht.getLocation()) != 0) {
return true;
}
}
if (GeoUtility.checkCrossedLine(courseLimit.get(courseLimit.size() - 1), courseLimit.get(0),
yacht.getLastLocation(), yacht.getLocation()) != 0) {
return true;
}
return false;
}
public static void checkForCollision(ServerYacht serverYacht) { public static void checkCollision(ServerYacht serverYacht) {
ServerYacht collidedYacht = checkCollision(serverYacht); ServerYacht collidedYacht = checkYachtCollision(serverYacht);
if (collidedYacht != null) { if (collidedYacht != null) {
GeoPoint originalLocation = serverYacht.getLocation(); GeoPoint originalLocation = serverYacht.getLocation();
serverYacht.setLocation( serverYacht.setLocation(
@@ -270,7 +319,7 @@ public class GameState implements Runnable {
new YachtEventCodeMessage(serverYacht.getSourceId()) new YachtEventCodeMessage(serverYacht.getSourceId())
); );
} else { } else {
Mark collidedMark = markCollidedWith(serverYacht); Mark collidedMark = checkMarkCollision(serverYacht);
if (collidedMark != null) { if (collidedMark != null) {
serverYacht.setLocation( serverYacht.setLocation(
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK) calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
@@ -281,6 +330,17 @@ public class GameState implements Runnable {
notifyMessageListeners( notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId()) new YachtEventCodeMessage(serverYacht.getSourceId())
); );
} else if (checkBoundaryCollision(serverYacht)) {
serverYacht.setLocation(
calculateBounceBack(serverYacht, serverYacht.getLocation(),
BOUNCE_DISTANCE_YACHT)
);
serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
);
notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId())
);
} }
} }
} }
@@ -296,7 +356,7 @@ public class GameState implements Runnable {
if (velocity < maxBoatSpeed - 500) { if (velocity < maxBoatSpeed - 500) {
yacht.changeVelocity(maxBoatSpeed / 100); yacht.changeVelocity(maxBoatSpeed / 100);
} else if (velocity > maxBoatSpeed + 500) { } else if (velocity > maxBoatSpeed + 500) {
yacht.changeVelocity(-maxBoatSpeed / 100); yacht.changeVelocity(-velocity / 200);
} else { } else {
yacht.setCurrentVelocity(maxBoatSpeed); yacht.setCurrentVelocity(maxBoatSpeed);
} }
@@ -347,6 +407,7 @@ public class GameState implements Runnable {
/** /**
* 4 Different cases of progression in the race 1 - Passing the start line 2 - Passing any * 4 Different cases of progression in the race 1 - Passing the start line 2 - Passing any
* in-race Gate 3 - Passing any in-race Mark 4 - Passing the finish line * in-race Gate 3 - Passing any in-race Mark 4 - Passing the finish line
*
* @param yacht the current yacht to check for progression * @param yacht the current yacht to check for progression
*/ */
private void checkForLegProgression(ServerYacht yacht) { private void checkForLegProgression(ServerYacht yacht) {
@@ -510,7 +571,7 @@ public class GameState implements Runnable {
} }
private static Mark markCollidedWith(ServerYacht yacht) { private static Mark checkMarkCollision(ServerYacht yacht) {
Set<Mark> marksInRace = GameState.getMarks(); Set<Mark> marksInRace = GameState.getMarks();
for (Mark mark : marksInRace) { for (Mark mark : marksInRace) {
if (GeoUtility.getDistance(yacht.getLocation(), mark) if (GeoUtility.getDistance(yacht.getLocation(), mark)
@@ -526,12 +587,14 @@ public class GameState implements Runnable {
* *
* @return The boats new position * @return The boats new position
*/ */
private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith, Double bounceDistance) { private static GeoPoint calculateBounceBack(ServerYacht yacht, GeoPoint collidedWith,
Double heading = GeoUtility.getBearing(yacht.getLocation(), collidedWith); Double bounceDistance) {
Double heading = GeoUtility.getBearing(yacht.getLastLocation(), collidedWith);
// Invert heading // Invert heading
heading -= 180; heading -= 180;
Integer newHeading = Math.floorMod(heading.intValue(), 360); Integer newHeading = Math.floorMod(heading.intValue(), 360);
return GeoUtility.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance); return GeoUtility
.getGeoCoordinate(yacht.getLocation(), newHeading.doubleValue(), bounceDistance);
} }
/** /**
@@ -540,11 +603,12 @@ public class GameState implements Runnable {
* *
* @return yacht to compare to all other yachts. * @return yacht to compare to all other yachts.
*/ */
private static ServerYacht checkCollision(ServerYacht yacht) { private static ServerYacht checkYachtCollision(ServerYacht yacht) {
for (ServerYacht otherYacht : GameState.getYachts().values()) { for (ServerYacht otherYacht : GameState.getYachts().values()) {
if (otherYacht != yacht) { if (otherYacht != yacht) {
Double distance = GeoUtility.getDistance(otherYacht.getLocation(), yacht.getLocation()); Double distance = GeoUtility
.getDistance(otherYacht.getLocation(), yacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) { if (distance < YACHT_COLLISION_DISTANCE) {
return otherYacht; return otherYacht;
} }
@@ -8,11 +8,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import seng302.gameServer.server.messages.BoatSubMessage;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.server.messages.*;
import seng302.gameServer.server.messages.RaceStatus;
import seng302.gameServer.server.messages.RaceStatusMessage;
import seng302.gameServer.server.messages.RaceType;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.PolarTable; import seng302.model.PolarTable;
@@ -30,6 +27,10 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer CLIENT_UPDATES_PER_SECOND = 10; private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
private static final int LOG_LEVEL = 1; private static final int LOG_LEVEL = 1;
private static final int WARNING_TIME = 10 * -1000;
private static final int PREPATORY_TIME = 5 * -1000;
public static final int TIME_TILL_START = 10 * 1000;
private boolean terminated; private boolean terminated;
private Thread thread; private Thread thread;
@@ -166,10 +167,21 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
@Override @Override
public void run() { public void run() {
broadcastMessage(makeRaceStatusMessage()); broadcastMessage(makeRaceStatusMessage());
if (GameState.getCurrentStage() == GameStages.PRE_RACE || GameState.getCurrentStage() == GameStages.LOBBYING) {
broadcastMessage(makeRaceStartMessage());
}
} }
}, 0, 500); }, 0, 500);
} }
private RaceStartStatusMessage makeRaceStartMessage() {
Long raceStartTime = GameState.getStartTime();
return new RaceStartStatusMessage(1, raceStartTime ,
1, RaceStartNotificationType.SET_RACE_START_TIME);
}
private RaceStatusMessage makeRaceStatusMessage() { private RaceStatusMessage makeRaceStatusMessage() {
// variables taken from GameServerThread // variables taken from GameServerThread
@@ -184,12 +196,24 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
boatSubMessages.add(m); boatSubMessages.add(m);
} }
if (GameState.getCurrentStage() == GameStages.RACING) { long timeTillStart = System.currentTimeMillis() - GameState.getStartTime();
raceStatus = RaceStatus.STARTED;
} else { if (GameState.getCurrentStage() == GameStages.LOBBYING) {
raceStatus = RaceStatus.PRESTART;
} else if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
raceStatus = RaceStatus.PRESTART;
if (timeTillStart > WARNING_TIME) {
raceStatus = RaceStatus.WARNING; raceStatus = RaceStatus.WARNING;
} }
if (timeTillStart > PREPATORY_TIME) {
raceStatus = RaceStatus.PREPARATORY;
}
} else {
raceStatus = RaceStatus.STARTED;
}
return new RaceStatusMessage(1, raceStatus, GameState.getStartTime(), return new RaceStatusMessage(1, raceStatus, GameState.getStartTime(),
GameState.getWindDirection(), GameState.getWindDirection(),
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(), GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
@@ -209,8 +209,6 @@ public class ServerToClientThread implements Runnable, Observer {
} }
} }
} catch (Exception e) { } catch (Exception e) {
// TODO: 24/07/17 zyt10 - fix a logic here when a client disconnected
// serverLog("ERROR OCCURRED, CLOSING SERVER CONNECTION: " + socket.getRemoteSocketAddress().toString(), 1);
closeSocket(); closeSocket();
return; return;
} }
@@ -226,7 +224,7 @@ public class ServerToClientThread implements Runnable, Observer {
} }
//@TODO calculate lat/lng values //@TODO calculate lat/lng values
xml.setRegatta(new Regatta("RaceVision Test Game", 57.6679590, 11.8503233)); xml.setRegatta(new Regatta("Party Parrot Test Server", "Bermuda Test Course", 57.6679590, 11.8503233));
xml.setRace(race); xml.setRace(race);
XMLMessage xmlMessage; XMLMessage xmlMessage;
+12 -12
View File
@@ -17,10 +17,10 @@ public class RaceState {
private double windSpeed; private double windSpeed;
private double windDirection; private double windDirection;
private long raceTime; private long serverSystemTime;
private long expectedStartTime; private long expectedStartTime;
private boolean isRaceStarted = false; private boolean isRaceStarted = false;
// long timeTillStart; long timeTillStart;
public RaceState() { public RaceState() {
} }
@@ -28,7 +28,7 @@ public class RaceState {
public void updateState (RaceStatusData data) { public void updateState (RaceStatusData data) {
this.windSpeed = data.getWindSpeed(); this.windSpeed = data.getWindSpeed();
this.windDirection = data.getWindDirection(); this.windDirection = data.getWindDirection();
this.raceTime = data.getCurrentTime(); this.serverSystemTime = data.getCurrentTime();
this.expectedStartTime = data.getExpectedStartTime(); this.expectedStartTime = data.getExpectedStartTime();
this.isRaceStarted = data.isRaceStarted(); this.isRaceStarted = data.isRaceStarted();
} }
@@ -38,16 +38,20 @@ public class RaceState {
} }
public void updateState (RaceStartData data) { public void updateState (RaceStartData data) {
// this.timeTillStart = data.getRaceStartTime(); this.timeTillStart = data.getRaceStartTime();
System.out.println(data.getRaceStartTime());
} }
public String getRaceTimeStr () { public String getRaceTimeStr () {
return DATE_TIME_FORMAT.format(raceTime); long raceTime = serverSystemTime - expectedStartTime;
if (raceTime < 0) {
return "-" + DATE_TIME_FORMAT.format(-1 * (raceTime - 1000));
} else {
return DATE_TIME_FORMAT.format(serverSystemTime - expectedStartTime);
}
} }
public long getTimeTillStart () { public long getTimeTillStart () {
return (expectedStartTime - raceTime) / 1000; return (expectedStartTime - serverSystemTime);
} }
public double getWindSpeed() { public double getWindSpeed() {
@@ -59,11 +63,7 @@ public class RaceState {
} }
public long getRaceTime() { public long getRaceTime() {
return raceTime; return serverSystemTime;
}
public long getExpectedStartTime() {
return expectedStartTime;
} }
public boolean isRaceStarted () { public boolean isRaceStarted () {
+1 -1
View File
@@ -60,7 +60,7 @@ public class ServerYacht extends Observable {
this.country = country; this.country = country;
this.sailIn = false; this.sailIn = false;
this.isAuto = false; this.isAuto = false;
this.location = new GeoPoint(57.670341, 11.826856); this.location = new GeoPoint(57.67046, 11.83751);
this.lastLocation = location; this.lastLocation = location;
this.heading = 120.0; //In degrees this.heading = 120.0; //In degrees
this.currentVelocity = 0d; //in mms-1 this.currentVelocity = 0d; //in mms-1
@@ -18,10 +18,10 @@ public class Regatta {
private Integer utcOffset; private Integer utcOffset;
private Double magneticVariation; private Double magneticVariation;
public Regatta(String name, Double latitude, Double longitude) { public Regatta(String name, String courseName, Double latitude, Double longitude) {
this.name = name; this.name = name;
this.id = DEFAULT_REGATTA_ID; this.id = DEFAULT_REGATTA_ID;
this.courseName = name; this.courseName = courseName;
this.latitude = latitude; this.latitude = latitude;
this.longitude = longitude; this.longitude = longitude;
@@ -12,6 +12,7 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.server.messages.BoatAction;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
@@ -46,6 +47,7 @@ public class GameClient {
private RegattaXMLData regattaData; private RegattaXMLData regattaData;
private RaceXMLData courseData; private RaceXMLData courseData;
private RaceState raceState = new RaceState(); private RaceState raceState = new RaceState();
private LobbyController lobbyController;
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList(); private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
@@ -75,8 +77,18 @@ public class GameClient {
LobbyController lobbyController = loadLobby(); LobbyController lobbyController = loadLobby();
lobbyController.setPlayerListSource(clientLobbyList); lobbyController.setPlayerListSource(clientLobbyList);
lobbyController.disableReadyButton(); lobbyController.disableReadyButton();
lobbyController.setTitle("Connected to host - IP : " + ipAddress + " Port : " + portNumber);
if (regattaData != null){
lobbyController.setTitle(regattaData.getRegattaName());
lobbyController.setCourseName(regattaData.getCourseName());
}
else{
lobbyController.setTitle(ipAddress);
lobbyController.setCourseName("");
}
lobbyController.addCloseListener((exitCause) -> this.loadStartScreen()); lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
this.lobbyController = lobbyController;
} }
/** /**
@@ -95,15 +107,27 @@ public class GameClient {
socketThread.addStreamObserver(this::parsePackets); socketThread.addStreamObserver(this::parsePackets);
LobbyController lobbyController = loadLobby(); LobbyController lobbyController = loadLobby();
lobbyController.setPlayerListSource(clientLobbyList); lobbyController.setPlayerListSource(clientLobbyList);
lobbyController.setTitle("Hosting Lobby - IP : " + ipAddress + " Port : " + portNumber);
if (regattaData != null){
lobbyController.setTitle("Hosting: " + regattaData.getRegattaName());
lobbyController.setCourseName(regattaData.getCourseName());
}
else{
lobbyController.setTitle("Hosting: " + ipAddress);
lobbyController.setCourseName("");
}
lobbyController.addCloseListener(exitCause -> { lobbyController.addCloseListener(exitCause -> {
if (exitCause == CloseStatus.READY) { if (exitCause == CloseStatus.READY) {
GameState.resetStartTime();
lobbyController.disableReadyButton();
server.startGame(); server.startGame();
} else if (exitCause == CloseStatus.LEAVE) { } else if (exitCause == CloseStatus.LEAVE) {
loadStartScreen(); loadStartScreen();
} }
}); });
this.lobbyController = lobbyController;
server.setGameClient(this); server.setGameClient(this);
} }
@@ -179,13 +203,18 @@ public class GameClient {
switch (packet.getType()) { switch (packet.getType()) {
case RACE_STATUS: case RACE_STATUS:
processRaceStatusUpdate(StreamParser.extractRaceStatus(packet)); processRaceStatusUpdate(StreamParser.extractRaceStatus(packet));
if (raceState.getTimeTillStart() <= 5000) {
startRaceIfAllDataReceived(); startRaceIfAllDataReceived();
}
break; break;
case REGATTA_XML: case REGATTA_XML:
regattaData = XMLParser.parseRegatta( regattaData = XMLParser.parseRegatta(
StreamParser.extractXmlMessage(packet) StreamParser.extractXmlMessage(packet)
); );
raceState.setTimeZone( raceState.setTimeZone(
TimeZone.getTimeZone( TimeZone.getTimeZone(
ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset())) ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset()))
@@ -214,6 +243,7 @@ public class GameClient {
case RACE_START_STATUS: case RACE_START_STATUS:
raceState.updateState(StreamParser.extractRaceStartStatus(packet)); raceState.updateState(StreamParser.extractRaceStartStatus(packet));
if (lobbyController != null) lobbyController.updateRaceState(raceState);
break; break;
case BOAT_LOCATION: case BOAT_LOCATION:
@@ -1,8 +1,7 @@
package seng302.visualiser.controllers; package seng302.visualiser.controllers;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -14,6 +13,8 @@ import javafx.scene.image.ImageView;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.model.RaceState;
import seng302.visualiser.GameClient;
/** /**
* A class describing the actions of the lobby screen * A class describing the actions of the lobby screen
@@ -67,9 +68,14 @@ public class LobbyController {
private ImageView seventhImageView; private ImageView seventhImageView;
@FXML @FXML
private ImageView eighthImageView; private ImageView eighthImageView;
@FXML
private Text timeUntilStart;
@FXML
private Text courseNameText;
private List<ImageView> imageViews = new ArrayList<>(); private List<ImageView> imageViews = new ArrayList<>();
private List<TextArea> listViews = new ArrayList<>(); private List<TextArea> listViews = new ArrayList<>();
private RaceState raceState;
private int MAX_NUM_PLAYERS = 8; private int MAX_NUM_PLAYERS = 8;
@@ -89,6 +95,8 @@ public class LobbyController {
fifthImageView, sixthImageView, seventhImageView, eighthImageView fifthImageView, sixthImageView, seventhImageView, eighthImageView
); );
initialiseImageView(); initialiseImageView();
timeUntilStart.setText("Waiting For Host...");
} }
/** /**
@@ -133,7 +141,9 @@ public class LobbyController {
@FXML @FXML
public void readyButtonPressed() { public void readyButtonPressed() {
GameState.setCurrentStage(GameStages.RACING); GameState.setCurrentStage(GameStages.PRE_RACE);
// Do countdown logic here
for (LobbyCloseListener readyListener : lobbyListeners) for (LobbyCloseListener readyListener : lobbyListeners)
readyListener.notify(CloseStatus.READY); readyListener.notify(CloseStatus.READY);
} }
@@ -142,6 +152,10 @@ public class LobbyController {
lobbyIpText.setText(title); lobbyIpText.setText(title);
} }
public void setCourseName(String courseName){
courseNameText.setText(courseName);
}
public void addCloseListener(LobbyCloseListener listener) { public void addCloseListener(LobbyCloseListener listener) {
lobbyListeners.add(listener); lobbyListeners.add(listener);
} }
@@ -154,6 +168,11 @@ public class LobbyController {
Platform.runLater(this::updatePlayers); Platform.runLater(this::updatePlayers);
} }
public void updateRaceState(RaceState raceState){
this.raceState = raceState;
timeUntilStart.setText("Starting in: " + raceState.getRaceTimeStr());
}
public void disableReadyButton () { public void disableReadyButton () {
readyButton.setDisable(true); readyButton.setDisable(true);
readyButton.setVisible(false); readyButton.setVisible(false);
@@ -365,12 +365,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* Updates the clock for the race * Updates the clock for the race
*/ */
private void updateRaceTime() { private void updateRaceTime() {
if (!raceState.isRaceStarted()) { // if (!raceState.isRaceStarted()) {
timerLabel.setFill(Color.RED); // timerLabel.setFill(Color.RED);
timerLabel.setText("Race Finished!"); // timerLabel.setText("Race Finished!");
} else { // } else {
timerLabel.setText(raceState.getRaceTimeStr()); timerLabel.setText(raceState.getRaceTimeStr());
} // }
} }
/** /**
+25 -5
View File
@@ -27,11 +27,6 @@
<RowConstraints maxHeight="100.0" minHeight="0.0" prefHeight="0.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="100.0" minHeight="0.0" prefHeight="0.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<Text fx:id="lobbyIpText" fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="Lobby: IP" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER">
<font>
<Font size="29.0" />
</font>
</Text>
<GridPane prefHeight="166.0" prefWidth="1530.0" GridPane.rowIndex="2"> <GridPane prefHeight="166.0" prefWidth="1530.0" GridPane.rowIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
@@ -109,5 +104,30 @@
</ImageView> </ImageView>
</children> </children>
</GridPane> </GridPane>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="134.0" minHeight="10.0" prefHeight="32.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="134.0" minHeight="10.0" prefHeight="35.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="134.0" minHeight="10.0" prefHeight="32.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="79.0" minHeight="10.0" prefHeight="52.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="79.0" minHeight="10.0" prefHeight="35.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Text fx:id="lobbyIpText" fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="Server Name" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<font>
<Font size="29.0" />
</font>
</Text>
<Text fx:id="timeUntilStart" fill="#f8f8f8" strokeType="OUTSIDE" strokeWidth="0.0" text="00:00" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="3">
<font>
<Font size="20.0" />
</font>
</Text>
<Text fx:id="courseNameText" fill="#e1e1e1" strokeType="OUTSIDE" strokeWidth="0.0" text="Course Name" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
@@ -6,6 +6,8 @@ import org.junit.Test;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import static seng302.gameServer.GameState.checkCollision;
/** /**
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0 * Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
* meters. * meters.
@@ -37,7 +39,7 @@ public class UpdateYachtTest {
if (!yacht1.getSailIn()) { if (!yacht1.getSailIn()) {
yacht1.toggleSailIn(); yacht1.toggleSailIn();
} }
GameState.checkForCollision(yacht1); checkCollision(yacht1);
double moved = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1); double moved = GeoUtility.getDistance(yacht1.getLocation(), geoPoint1);
Assert.assertEquals(GameState.BOUNCE_DISTANCE_YACHT, moved, 0.1); Assert.assertEquals(GameState.BOUNCE_DISTANCE_YACHT, moved, 0.1);
} }
@@ -54,14 +56,14 @@ public class UpdateYachtTest {
if (!yacht1.getSailIn()) { if (!yacht1.getSailIn()) {
yacht1.toggleSailIn(); yacht1.toggleSailIn();
} }
GameState.checkForCollision(yacht1); checkCollision(yacht1);
Assert.assertTrue( Assert.assertTrue(
GameState.YACHT_COLLISION_DISTANCE < GeoUtility.getDistance(geoPoint1, geoPoint2 GameState.YACHT_COLLISION_DISTANCE < GeoUtility.getDistance(geoPoint1, geoPoint2
) )
); //Check that yachts are actually far enough apart for no collision. ); //Check that yachts are actually far enough apart for no collision.
Assert.assertEquals(geoPoint1.getLat(), yacht1.getLocation().getLat(), 0.001); Assert.assertEquals(geoPoint1.getLat(), yacht1.getLocation().getLat(), 1.001);
Assert.assertEquals(geoPoint1.getLng(), yacht1.getLocation().getLng(), 0.001); Assert.assertEquals(geoPoint1.getLng(), yacht1.getLocation().getLng(), 1.001);
Assert.assertEquals(geoPoint2.getLat(), yacht1.getLocation().getLat(), 0.001); Assert.assertEquals(geoPoint2.getLat(), yacht1.getLocation().getLat(), 1.001);
Assert.assertEquals(geoPoint2.getLng(), yacht1.getLocation().getLng(), 0.001); Assert.assertEquals(geoPoint2.getLng(), yacht1.getLocation().getLng(), 1.001);
} }
} }