mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Merge remote-tracking branch 'origin/develop' into NewUI_merge
# Conflicts: # src/main/java/seng302/gameServer/GameState.java # src/main/java/seng302/gameServer/MainServerThread.java # src/main/java/seng302/gameServer/ServerToClientThread.java # src/main/java/seng302/visualiser/GameClient.java # src/main/java/seng302/visualiser/GameView.java # src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java # src/main/java/seng302/visualiser/controllers/LobbyController.java # src/main/java/seng302/visualiser/controllers/RaceViewController.java # src/main/java/seng302/visualiser/controllers/StartScreenController.java # src/main/resources/views/LobbyView.fxml # src/main/resources/views/RaceView.fxml # src/main/resources/views/StartScreenView.fxml
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -7,6 +15,21 @@ import org.w3c.dom.Document;
|
|||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import seng302.gameServer.messages.*;
|
import seng302.gameServer.messages.*;
|
||||||
import seng302.model.*;
|
import seng302.model.*;
|
||||||
|
import seng302.gameServer.messages.BoatAction;
|
||||||
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
|
import seng302.gameServer.messages.MarkRoundingMessage;
|
||||||
|
import seng302.gameServer.messages.MarkType;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RoundingBoatStatus;
|
||||||
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
import seng302.model.Limit;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.PolarTable;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
@@ -28,11 +51,10 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface NewMessageListener {
|
interface NewMessageListener {
|
||||||
|
|
||||||
void notify(Message message);
|
void notify(Message message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(GameState.class);
|
private static Logger logger = LoggerFactory.getLogger(GameState.class);
|
||||||
|
|
||||||
|
|
||||||
static final int WARNING_TIME = 10 * -1000;
|
static final int WARNING_TIME = 10 * -1000;
|
||||||
@@ -52,13 +74,13 @@ public class GameState implements Runnable {
|
|||||||
private static Long previousUpdateTime;
|
private static Long previousUpdateTime;
|
||||||
public static Double windDirection;
|
public static Double windDirection;
|
||||||
private static Double windSpeed;
|
private static Double windSpeed;
|
||||||
|
private static Double speedMultiplier = 1d;
|
||||||
|
|
||||||
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
||||||
|
|
||||||
private static String hostIpAddress;
|
private static String hostIpAddress;
|
||||||
private static List<Player> players;
|
private static List<Player> players;
|
||||||
private static Map<Integer, ServerYacht> yachts;
|
private static Map<Integer, ServerYacht> yachts;
|
||||||
private static List<Token> tokens;
|
|
||||||
private static Boolean isRaceStarted;
|
private static Boolean isRaceStarted;
|
||||||
private static GameStages currentStage;
|
private static GameStages currentStage;
|
||||||
private static MarkOrder markOrder;
|
private static MarkOrder markOrder;
|
||||||
@@ -68,36 +90,30 @@ public class GameState implements Runnable {
|
|||||||
private static Integer maxPlayers = 8;
|
private static Integer maxPlayers = 8;
|
||||||
|
|
||||||
|
|
||||||
private static List<NewMessageListener> markListeners;
|
private static List<Token> allTokens;
|
||||||
|
private static List<Token> tokensInPlay;
|
||||||
|
|
||||||
|
private static List<NewMessageListener> newMessageListeners;
|
||||||
|
|
||||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||||
/*
|
|
||||||
Ideally I would like to make this class an object instantiated by the server and given to
|
|
||||||
it's created threads if necessary. Outside of that I think the dependencies on it
|
|
||||||
(atm only Yacht & GameClient) can be removed from most other classes. The observable list of
|
|
||||||
players could be pulled directly from the server by the GameClient since it instantiates it
|
|
||||||
and it is reasonable for it to pull data. The current setup of publicly available statics is
|
|
||||||
pretty meh IMO because anything can change it making it unreliable and like people did with
|
|
||||||
the old ServerParser class everything that needs shared just gets thrown in the static
|
|
||||||
collections and things become a real mess.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public GameState(String hostIpAddress) {
|
public GameState(String hostIpAddress) {
|
||||||
windDirection = 180d;
|
windDirection = 180d;
|
||||||
windSpeed = 10000d;
|
windSpeed = 10000d;
|
||||||
this.hostIpAddress = hostIpAddress;
|
|
||||||
yachts = new HashMap<>();
|
yachts = new HashMap<>();
|
||||||
tokens = new ArrayList<>();
|
tokensInPlay = new ArrayList<>();
|
||||||
|
|
||||||
players = new ArrayList<>();
|
players = new ArrayList<>();
|
||||||
GameState.hostIpAddress = hostIpAddress;
|
GameState.hostIpAddress = hostIpAddress;
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
|
speedMultiplier = 1.0;
|
||||||
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
|
||||||
previousUpdateTime = System.currentTimeMillis();
|
previousUpdateTime = System.currentTimeMillis();
|
||||||
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
||||||
markListeners = new ArrayList<>();
|
newMessageListeners = new ArrayList<>();
|
||||||
|
allTokens = makeTokens();
|
||||||
|
|
||||||
resetStartTime();
|
resetStartTime();
|
||||||
|
|
||||||
@@ -122,6 +138,21 @@ public class GameState implements Runnable {
|
|||||||
courseLimit = XMLParser.parseRace(document).getCourseLimit();
|
courseLimit = XMLParser.parseRace(document).getCourseLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
|
||||||
|
* race ideally
|
||||||
|
*
|
||||||
|
* @return A list of possible tokensInPlay for this race
|
||||||
|
*/
|
||||||
|
private ArrayList<Token> makeTokens() {
|
||||||
|
Token token1 = new Token(TokenType.BOOST, 57.66946, 11.83154);
|
||||||
|
Token token2 = new Token(TokenType.BOOST, 57.66877, 11.83382);
|
||||||
|
Token token3 = new Token(TokenType.BOOST, 57.66914, 11.83965);
|
||||||
|
Token token4 = new Token(TokenType.BOOST, 57.66684, 11.83214);
|
||||||
|
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
|
||||||
|
}
|
||||||
|
|
||||||
public static String getHostIpAddress() {
|
public static String getHostIpAddress() {
|
||||||
return hostIpAddress;
|
return hostIpAddress;
|
||||||
}
|
}
|
||||||
@@ -134,16 +165,8 @@ public class GameState implements Runnable {
|
|||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addToken(Token token) {
|
public static List<Token> getTokensInPlay() {
|
||||||
tokens.add(token);
|
return tokensInPlay;
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Token> getTokens() {
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearTokens() {
|
|
||||||
tokens.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addPlayer(Player player) {
|
public static void addPlayer(Player player) {
|
||||||
@@ -273,7 +296,23 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called periodically in this GameState thread to update the GameState values
|
* Randomly select a subset of tokensInPlay from a pre defined superset
|
||||||
|
* Broadasts a new race status message to show this update
|
||||||
|
*/
|
||||||
|
public static void spawnNewToken() {
|
||||||
|
Random random = new Random();
|
||||||
|
tokensInPlay.clear();
|
||||||
|
tokensInPlay.add(allTokens.get(random.nextInt(allTokens.size())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called periodically in this GameState thread to update the GameState values.
|
||||||
|
* -Updates yachts velocity
|
||||||
|
* -Updates locations
|
||||||
|
* -Checks for collisions
|
||||||
|
* -Checks for progression
|
||||||
|
*
|
||||||
|
* -Also checks things like the end of the race and race start time etc
|
||||||
*/
|
*/
|
||||||
public void update() {
|
public void update() {
|
||||||
Boolean raceFinished = true;
|
Boolean raceFinished = true;
|
||||||
@@ -288,9 +327,8 @@ public class GameState implements Runnable {
|
|||||||
checkPowerUpTimeout(yacht);
|
checkPowerUpTimeout(yacht);
|
||||||
yacht.runAutoPilot();
|
yacht.runAutoPilot();
|
||||||
yacht.updateLocation(timeInterval);
|
yacht.updateLocation(timeInterval);
|
||||||
if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
|
|
||||||
checkCollision(yacht);
|
checkCollision(yacht);
|
||||||
checkTokenPickUp(yacht);
|
if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
|
||||||
checkForLegProgression(yacht);
|
checkForLegProgression(yacht);
|
||||||
raceFinished = false;
|
raceFinished = false;
|
||||||
}
|
}
|
||||||
@@ -333,27 +371,38 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks all tokens to see if a yacht has picked one up
|
* Checks all tokensInPlay to see if a yacht has picked one up
|
||||||
*
|
* @return Token which was collided with
|
||||||
* @param serverYacht The yacht to check for
|
* @param serverYacht The yacht to check for collision with a token
|
||||||
*/
|
*/
|
||||||
private void checkTokenPickUp(ServerYacht serverYacht) {
|
private static Token checkTokenPickUp(ServerYacht serverYacht) {
|
||||||
for (Token token : tokens) {
|
for (Token token : tokensInPlay) {
|
||||||
Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
|
Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
|
||||||
if (distance < YACHT_COLLISION_DISTANCE) {
|
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||||
tokens.remove(token);
|
return token;
|
||||||
serverYacht.powerUp(token.getTokenType());
|
|
||||||
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + token
|
|
||||||
.getTokenType());
|
|
||||||
notifyMessageListeners(MessageFactory.getRaceXML());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for collision with other in game objects for the given serverYacht. To be called each
|
||||||
|
* update. If there is a collision, Notifies the server to send the appropriate messages out.
|
||||||
|
* Checks for these items in turn:
|
||||||
|
* - Other yachts
|
||||||
|
* - Marks
|
||||||
|
* - Boundary
|
||||||
|
* - Tokens
|
||||||
|
*
|
||||||
|
* @param serverYacht The server yacht to check collisions with
|
||||||
|
*/
|
||||||
public static void checkCollision(ServerYacht serverYacht) {
|
public static void checkCollision(ServerYacht serverYacht) {
|
||||||
|
//Yacht Collision
|
||||||
ServerYacht collidedYacht = checkYachtCollision(serverYacht);
|
ServerYacht collidedYacht = checkYachtCollision(serverYacht);
|
||||||
|
Mark collidedMark = checkMarkCollision(serverYacht);
|
||||||
|
|
||||||
if (collidedYacht != null) {
|
if (collidedYacht != null) {
|
||||||
GeoPoint originalLocation = serverYacht.getLocation();
|
GeoPoint originalLocation = serverYacht.getLocation();
|
||||||
serverYacht.setLocation(
|
serverYacht.setLocation(
|
||||||
@@ -369,35 +418,49 @@ public class GameState implements Runnable {
|
|||||||
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId())
|
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
Mark collidedMark = checkMarkCollision(serverYacht);
|
|
||||||
if (collidedMark != null) {
|
//Mark Collision
|
||||||
|
else if (collidedMark != null) {
|
||||||
serverYacht.setLocation(
|
serverYacht.setLocation(
|
||||||
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
|
calculateBounceBack(serverYacht, collidedMark, BOUNCE_DISTANCE_MARK)
|
||||||
);
|
);
|
||||||
|
|
||||||
serverYacht.setCurrentVelocity(
|
serverYacht.setCurrentVelocity(
|
||||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId())
|
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
if (checkBoundaryCollision(serverYacht)) {
|
//Boundary Collision
|
||||||
|
else if (checkBoundaryCollision(serverYacht)) {
|
||||||
serverYacht.setLocation(
|
serverYacht.setLocation(
|
||||||
calculateBounceBack(serverYacht, serverYacht.getLocation(),
|
calculateBounceBack(serverYacht, serverYacht.getLocation(),
|
||||||
BOUNCE_DISTANCE_YACHT)
|
BOUNCE_DISTANCE_YACHT)
|
||||||
);
|
);
|
||||||
|
|
||||||
serverYacht.setCurrentVelocity(
|
serverYacht.setCurrentVelocity(
|
||||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
notifyMessageListeners(
|
notifyMessageListeners(
|
||||||
new YachtEventCodeMessage(serverYacht.getSourceId())
|
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
//Token Collision
|
||||||
|
Token collidedToken = checkTokenPickUp(serverYacht);
|
||||||
|
if (collidedToken != null) {
|
||||||
|
tokensInPlay.remove(collidedToken);
|
||||||
|
serverYacht.powerUp(collidedToken.getTokenType());
|
||||||
|
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
|
||||||
|
.getTokenType());
|
||||||
|
notifyMessageListeners(MessageFactory.getRaceXML());
|
||||||
|
notifyMessageListeners(
|
||||||
|
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,9 +468,10 @@ public class GameState implements Runnable {
|
|||||||
private void updateVelocity(ServerYacht yacht) {
|
private void updateVelocity(ServerYacht yacht) {
|
||||||
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
|
||||||
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
|
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
|
||||||
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * 4;
|
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier;
|
||||||
if (yacht.getPowerUp() != null) {
|
if (yacht.getPowerUp() != null) {
|
||||||
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
||||||
|
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
|
||||||
maxBoatSpeed *= 2;
|
maxBoatSpeed *= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,15 +775,14 @@ public class GameState implements Runnable {
|
|||||||
// TODO: 13/8/17 figure out the rounding side, rounded mark source ID and boat status.
|
// TODO: 13/8/17 figure out the rounding side, rounded mark source ID and boat status.
|
||||||
Message markRoundingMessage = new MarkRoundingMessage(0, 0,
|
Message markRoundingMessage = new MarkRoundingMessage(0, 0,
|
||||||
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
|
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
|
||||||
currentMark.getId());
|
currentMarkSeqID + 1);
|
||||||
// currentMarkSeqID + 1);
|
|
||||||
|
|
||||||
notifyMessageListeners(markRoundingMessage);
|
notifyMessageListeners(markRoundingMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void notifyMessageListeners(Message message) {
|
private static void notifyMessageListeners(Message message) {
|
||||||
for (NewMessageListener mpl : markListeners) {
|
for (NewMessageListener ml : newMessageListeners) {
|
||||||
mpl.notify(message);
|
ml.notify(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,8 +794,37 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
|
||||||
|
String chatterText = chatterMessage.getMessage();
|
||||||
|
String[] words = chatterText.split("\\s+");
|
||||||
|
if (words.length > 2 && isHost) {
|
||||||
|
switch (words[2].trim()) {
|
||||||
|
case ">speed":
|
||||||
|
try {
|
||||||
|
setSpeedMultiplier(Double.valueOf(words[3]));
|
||||||
|
notifyMessageListeners(new ChatterMessage(
|
||||||
|
chatterMessage.getMessage_type(),
|
||||||
|
"SERVER: Speed modifier set to x" + words[3]
|
||||||
|
));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger logger = LoggerFactory.getLogger(GameState.class);
|
||||||
|
logger.error("cannot parse >speed value");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case ">finish":
|
||||||
|
notifyMessageListeners(new ChatterMessage(
|
||||||
|
chatterMessage.getMessage_type(),
|
||||||
|
"SERVER: Game will now finish"
|
||||||
|
));
|
||||||
|
endRace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyMessageListeners(chatterMessage);
|
||||||
|
}
|
||||||
|
|
||||||
public static void addMessageEventListener(NewMessageListener listener) {
|
public static void addMessageEventListener(NewMessageListener listener) {
|
||||||
markListeners.add(listener);
|
newMessageListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCustomizationFlag() {
|
public static void setCustomizationFlag() {
|
||||||
@@ -767,4 +859,16 @@ public class GameState implements Runnable {
|
|||||||
maxPlayers = newMax;
|
maxPlayers = newMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void endRace () {
|
||||||
|
yachts.forEach((id, yacht) -> yacht.setBoatStatus(BoatStatus.FINISHED));
|
||||||
|
currentStage = GameStages.FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSpeedMultiplier (double multiplier) {
|
||||||
|
speedMultiplier = multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getSpeedMultiplier () {
|
||||||
|
return speedMultiplier;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
|||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.gameServer.messages.Heartbeat;
|
import seng302.gameServer.messages.Heartbeat;
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
@@ -14,6 +16,9 @@ import seng302.gameServer.messages.Message;
|
|||||||
* cannot be sent to a player
|
* cannot be sent to a player
|
||||||
*/
|
*/
|
||||||
public class HeartbeatThread implements Runnable {
|
public class HeartbeatThread implements Runnable {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(HeartbeatThread.class);
|
||||||
|
|
||||||
private final int HEARTBEAT_PERIOD = 200;
|
private final int HEARTBEAT_PERIOD = 200;
|
||||||
private ClientConnectionDelegate delegate;
|
private ClientConnectionDelegate delegate;
|
||||||
private Integer seqNum;
|
private Integer seqNum;
|
||||||
@@ -44,12 +49,12 @@ public class HeartbeatThread implements Runnable {
|
|||||||
* The delegate is notified if a player has disconnected
|
* The delegate is notified if a player has disconnected
|
||||||
*/
|
*/
|
||||||
private void sendHeartbeatToAllPlayers(){
|
private void sendHeartbeatToAllPlayers(){
|
||||||
|
try {
|
||||||
Message heartbeat = new Heartbeat(seqNum);
|
Message heartbeat = new Heartbeat(seqNum);
|
||||||
for (Player player : GameState.getPlayers()) {
|
for (Player player : GameState.getPlayers()) {
|
||||||
if (!player.getSocket().isConnected()) {
|
if (!player.getSocket().isConnected()) {
|
||||||
playerLostConnection(player);
|
playerLostConnection(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
|
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -58,6 +63,9 @@ public class HeartbeatThread implements Runnable {
|
|||||||
}
|
}
|
||||||
updateDelegate();
|
updateDelegate();
|
||||||
seqNum++;
|
seqNum++;
|
||||||
|
} catch (NullPointerException ne) {
|
||||||
|
logger.debug("Socket closed between checking for connection and sending heartbeat");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ import java.util.*;
|
|||||||
* Created by wmu16 on 13/07/17.
|
* Created by wmu16 on 13/07/17.
|
||||||
*/
|
*/
|
||||||
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 final Integer CLIENT_UPDATES_PER_SECOND = 60;
|
private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
|
||||||
|
|
||||||
@@ -135,29 +138,32 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
|
|
||||||
//FINISHED
|
//FINISHED
|
||||||
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||||
|
broadcastMessage(MessageFactory.getRaceStatusMessage());
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000); //Hackish fix to make sure all threads have sent closing RaceStatus
|
||||||
terminate();
|
terminate();
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
logger.trace("Thread interrupted while waiting to terminate clients", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
|
|
||||||
try {
|
try {
|
||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
serverToClientThread.terminate();
|
serverToClientThread.terminate();
|
||||||
}
|
}
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("IO error in server thread handler upon closing socket");
|
System.out.println("IO error in server thread handler upon closing socket");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBoatLocations() {
|
private void sendBoatLocations() {
|
||||||
for (ServerYacht serverYacht : GameState.getYachts().values()) {
|
for (ServerYacht serverYacht : GameState.getYachts().values()) {
|
||||||
broadcastMessage(MessageFactory.getBoatLocationMessage(serverYacht));
|
broadcastMessage(MessageFactory.getBoatLocationMessage(serverYacht));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendSetupMessages() {
|
private void sendSetupMessages() {
|
||||||
broadcastMessage(MessageFactory.getRaceXML());
|
broadcastMessage(MessageFactory.getRaceXML());
|
||||||
broadcastMessage(MessageFactory.getRegattaXML());
|
broadcastMessage(MessageFactory.getRegattaXML());
|
||||||
broadcastMessage(MessageFactory.getBoatXML());
|
broadcastMessage(MessageFactory.getBoatXML());
|
||||||
@@ -220,34 +226,10 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
timer.schedule(new TimerTask() {
|
timer.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
spawnNewCoins();
|
GameState.spawnNewToken();
|
||||||
broadcastMessage(MessageFactory.getRaceXML());
|
broadcastMessage(MessageFactory.getRaceXML());
|
||||||
}
|
}
|
||||||
}, 0, 60000);
|
}, 10000, 60000);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Randomly select a subset of tokens from a pre defined superset
|
|
||||||
* Broadasts a new race status message to show this update
|
|
||||||
*/
|
|
||||||
private void spawnNewCoins() {
|
|
||||||
|
|
||||||
List<Token> allTokens = new ArrayList<>();
|
|
||||||
Token token1 = new Token(TokenType.BOOST, 57.66946, 11.83154);
|
|
||||||
Token token2 = new Token(TokenType.BOOST, 57.66877, 11.83382);
|
|
||||||
Token token3 = new Token(TokenType.BOOST, 57.66914, 11.83965);
|
|
||||||
Token token4 = new Token(TokenType.BOOST, 57.66684, 11.83214);
|
|
||||||
allTokens.add(token1);
|
|
||||||
allTokens.add(token2);
|
|
||||||
allTokens.add(token3);
|
|
||||||
allTokens.add(token4);
|
|
||||||
|
|
||||||
GameState.clearTokens();
|
|
||||||
Random random = new Random();
|
|
||||||
Collections.shuffle(allTokens);
|
|
||||||
for (int i = 0; i < random.nextInt(allTokens.size()); i++) {
|
|
||||||
GameState.addToken(allTokens.get(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,6 +240,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
@Override
|
@Override
|
||||||
public void clientConnected(ServerToClientThread serverToClientThread) {
|
public void clientConnected(ServerToClientThread serverToClientThread) {
|
||||||
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
||||||
|
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
||||||
|
serverToClientThread.setAsHost();
|
||||||
|
}
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
@@ -320,7 +305,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}, 0, 500);
|
}, 0, 500);
|
||||||
|
|
||||||
|
|
||||||
if (GameState.getCurrentStage() != GameStages.RACING) {
|
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
||||||
sendSetupMessages();
|
sendSetupMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,10 +318,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() {
|
||||||
// Getting the start line compound marks
|
|
||||||
// if (gameClient== null) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
|
CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
|
||||||
GeoPoint startMark1 = cm.getSubMark(1);
|
GeoPoint startMark1 = cm.getSubMark(1);
|
||||||
GeoPoint startMark2 = cm.getSubMark(2);
|
GeoPoint startMark2 = cm.getSubMark(2);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class MessageFactory {
|
|||||||
|
|
||||||
public static XMLMessage getRaceXML() {
|
public static XMLMessage getRaceXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
||||||
List<Token> tokens = GameState.getTokens();
|
List<Token> tokens = GameState.getTokensInPlay();
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ public class MessageFactory {
|
|||||||
|
|
||||||
public static XMLMessage getBoatXML() {
|
public static XMLMessage getBoatXML() {
|
||||||
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
||||||
List<Token> tokens = GameState.getTokens();
|
List<Token> tokens = GameState.getTokensInPlay();
|
||||||
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
||||||
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package seng302.gameServer;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.gameServer.messages.ClientType;
|
import seng302.gameServer.messages.ClientType;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
@@ -28,5 +29,18 @@ public class ServerPacketParser {
|
|||||||
long type = Message.bytesToLong(Arrays.copyOfRange(payload, 4, 5));
|
long type = Message.bytesToLong(Arrays.copyOfRange(payload, 4, 5));
|
||||||
return CustomizeRequestType.getRequestType((int) type);
|
return CustomizeRequestType.getRequestType((int) type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ChatterMessage extractChatterText(byte[] payload) {
|
||||||
|
return new ChatterMessage(
|
||||||
|
payload[1], new String(Arrays.copyOfRange(payload, 3, payload.length))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatterMessage extractChatterText(StreamPacket packet) {
|
||||||
|
byte[] payload = packet.getPayload();
|
||||||
|
return new ChatterMessage(
|
||||||
|
payload[1], new String(Arrays.copyOfRange(payload, 3, payload.length))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,27 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.messages.BoatAction;
|
||||||
|
import seng302.gameServer.messages.BoatLocationMessage;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
|
import seng302.gameServer.messages.ClientType;
|
||||||
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RegistrationResponseMessage;
|
||||||
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.stream.packets.PacketType;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
import seng302.utilities.XMLGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
||||||
@@ -58,6 +79,7 @@ public class ServerToClientThread implements Runnable {
|
|||||||
|
|
||||||
private ClientType clientType;
|
private ClientType clientType;
|
||||||
private Boolean isRegistered = false;
|
private Boolean isRegistered = false;
|
||||||
|
private Boolean isHost = false;
|
||||||
|
|
||||||
private XMLGenerator xmlGenerator;
|
private XMLGenerator xmlGenerator;
|
||||||
|
|
||||||
@@ -182,7 +204,12 @@ public class ServerToClientThread implements Runnable {
|
|||||||
|
|
||||||
completeRegistration(requestedType);
|
completeRegistration(requestedType);
|
||||||
break;
|
break;
|
||||||
|
case CHATTER_TEXT:
|
||||||
|
ChatterMessage chatterMessage = ServerPacketParser
|
||||||
|
.extractChatterText(
|
||||||
|
new StreamPacket(type, payloadLength, timeStamp, payload));
|
||||||
|
GameState.processChatter(chatterMessage, isHost);
|
||||||
|
break;
|
||||||
case RACE_CUSTOMIZATION_REQUEST:
|
case RACE_CUSTOMIZATION_REQUEST:
|
||||||
Long sourceID = Message
|
Long sourceID = Message
|
||||||
.bytesToLong(Arrays.copyOfRange(payload, 0, 3));
|
.bytesToLong(Arrays.copyOfRange(payload, 0, 3));
|
||||||
@@ -293,10 +320,6 @@ public class ServerToClientThread implements Runnable {
|
|||||||
return yacht;
|
return yacht;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendCollisionMessage(Integer yachtId) {
|
|
||||||
sendMessage(new YachtEventCodeMessage(yachtId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addConnectionListener(ConnectionListener listener) {
|
public void addConnectionListener(ConnectionListener listener) {
|
||||||
connectionListeners.add(listener);
|
connectionListeners.add(listener);
|
||||||
}
|
}
|
||||||
@@ -316,4 +339,8 @@ public class ServerToClientThread implements Runnable {
|
|||||||
public void addDisconnectListener(DisconnectListener disconnectListener) {
|
public void addDisconnectListener(DisconnectListener disconnectListener) {
|
||||||
this.disconnectListener = disconnectListener;
|
this.disconnectListener = disconnectListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAsHost() {
|
||||||
|
isHost = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ public class ChatterMessage extends Message {
|
|||||||
private int message_size = 21;
|
private int message_size = 21;
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
public ChatterMessage(int message_type, int message_size, String message) {
|
public ChatterMessage(int message_type, String message) {
|
||||||
|
byte[] byteMessage = message.getBytes();
|
||||||
|
|
||||||
this.message_type = message_type;
|
this.message_type = message_type;
|
||||||
this.message_size = message_size;
|
this.message_size = byteMessage.length;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
|
||||||
setHeader(new Header(MessageType.CHATTER_TEXT, 1, (short) getSize()));
|
setHeader(new Header(MessageType.CHATTER_TEXT, 1, (short) getSize()));
|
||||||
@@ -23,7 +25,7 @@ public class ChatterMessage extends Message {
|
|||||||
putByte((byte) MESSAGE_VERSION_NUMBER);
|
putByte((byte) MESSAGE_VERSION_NUMBER);
|
||||||
putInt(message_type, 1);
|
putInt(message_type, 1);
|
||||||
putInt(message_size, 1);
|
putInt(message_size, 1);
|
||||||
putBytes(message.getBytes());
|
putBytes(byteMessage);
|
||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
rewind();
|
rewind();
|
||||||
@@ -34,5 +36,11 @@ public class ChatterMessage extends Message {
|
|||||||
return MESSAGE_SIZE + message_size;
|
return MESSAGE_SIZE + message_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessage_type() {
|
||||||
|
return message_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ public class YachtEventCodeMessage extends Message {
|
|||||||
private int eventId;
|
private int eventId;
|
||||||
|
|
||||||
|
|
||||||
public YachtEventCodeMessage(Integer subjectId) {
|
public YachtEventCodeMessage(Integer subjectId, YachtEventType yachtEventType) {
|
||||||
timeStamp = System.currentTimeMillis() / 1000L;
|
timeStamp = System.currentTimeMillis() / 1000L;
|
||||||
ack = 0;
|
ack = 0;
|
||||||
raceId = 1;
|
raceId = 1;
|
||||||
destSourceId = subjectId; // collision boat source id
|
destSourceId = subjectId; // collision boat source id
|
||||||
incidentId = 0;
|
incidentId = 0;
|
||||||
eventId = 33;
|
eventId = yachtEventType.getCode();
|
||||||
|
|
||||||
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
setHeader(new Header(MESSAGE_TYPE, 0x01, (short) getSize()));
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package seng302.gameServer.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by wmu16 on 11/09/17.
|
||||||
|
*/
|
||||||
|
public enum YachtEventType {
|
||||||
|
COLLISION(33),
|
||||||
|
TOKEN(34);
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
YachtEventType(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@ import javafx.beans.property.ReadOnlyLongWrapper;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.model.mark.CompoundMark;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
|
||||||
@@ -32,7 +31,7 @@ public class ClientYacht extends Observable {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface MarkRoundingListener {
|
public interface MarkRoundingListener {
|
||||||
void notifyRounding(ClientYacht yacht, CompoundMark markPassed, int legNumber);
|
void notifyRounding(ClientYacht yacht, int legNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
||||||
@@ -63,7 +62,6 @@ public class ClientYacht extends Observable {
|
|||||||
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
|
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
|
||||||
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
|
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
|
||||||
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
|
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
|
||||||
private CompoundMark lastMarkRounded;
|
|
||||||
private Color colour;
|
private Color colour;
|
||||||
|
|
||||||
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
||||||
@@ -189,14 +187,6 @@ public class ClientYacht extends Observable {
|
|||||||
return markRoundTime;
|
return markRoundTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundMark getLastMarkRounded() {
|
|
||||||
return lastMarkRounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastMarkRounded(CompoundMark lastMarkRounded) {
|
|
||||||
this.lastMarkRounded = lastMarkRounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeoPoint getLocation() {
|
public GeoPoint getLocation() {
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
@@ -286,13 +276,12 @@ public class ClientYacht extends Observable {
|
|||||||
return sailIn;
|
return sailIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void roundMark(CompoundMark mark, long markRoundTime, long timeSinceLastMark) {
|
public void roundMark(long markRoundTime, long timeSinceLastMark) {
|
||||||
this.markRoundTime = markRoundTime;
|
this.markRoundTime = markRoundTime;
|
||||||
timeSinceLastMarkProperty.set(timeSinceLastMark);
|
timeSinceLastMarkProperty.set(timeSinceLastMark);
|
||||||
lastMarkRounded = mark;
|
|
||||||
legNumber++;
|
legNumber++;
|
||||||
for (MarkRoundingListener listener : markRoundingListeners) {
|
for (MarkRoundingListener listener : markRoundingListeners) {
|
||||||
listener.notifyRounding(this, lastMarkRounded, legNumber);
|
listener.notifyRounding(this, legNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import seng302.model.stream.parser.RaceStartData;
|
import seng302.model.stream.parser.RaceStartData;
|
||||||
import seng302.model.stream.parser.RaceStatusData;
|
import seng302.model.stream.parser.RaceStatusData;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for storing race data that does not relate to specific vessels or marks such as time or wind.
|
* Class for storing race data that does not relate to specific vessels or marks such as time or wind.
|
||||||
@@ -34,6 +35,7 @@ public class RaceState {
|
|||||||
private long serverSystemTime;
|
private long serverSystemTime;
|
||||||
private long expectedStartTime;
|
private long expectedStartTime;
|
||||||
private boolean isRaceStarted = false;
|
private boolean isRaceStarted = false;
|
||||||
|
private boolean gunFired = false;
|
||||||
long timeTillStart;
|
long timeTillStart;
|
||||||
private ObservableList<ClientYacht> playerPositions;
|
private ObservableList<ClientYacht> playerPositions;
|
||||||
private List<ClientYacht> collisions = new ArrayList<>();
|
private List<ClientYacht> collisions = new ArrayList<>();
|
||||||
@@ -64,6 +66,10 @@ public class RaceState {
|
|||||||
if (raceTime < 0) {
|
if (raceTime < 0) {
|
||||||
return "-" + DATE_TIME_FORMAT.format(-1 * (raceTime - 1000));
|
return "-" + DATE_TIME_FORMAT.format(-1 * (raceTime - 1000));
|
||||||
} else {
|
} else {
|
||||||
|
if (!gunFired) {
|
||||||
|
gunFired = true;
|
||||||
|
Sounds.playCapGunSound();
|
||||||
|
}
|
||||||
return DATE_TIME_FORMAT.format(serverSystemTime - expectedStartTime);
|
return DATE_TIME_FORMAT.format(serverSystemTime - expectedStartTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class RaceStatusData {
|
|||||||
* Returns the data for boats collected form race status packets.
|
* Returns the data for boats collected form race status packets.
|
||||||
*
|
*
|
||||||
* @return A list of boat data. Boat data is in the form
|
* @return A list of boat data. Boat data is in the form
|
||||||
* [boatID, estTimeToNextMark, estTimeToFinish, legNumber].
|
* [boatID, estTimeToNextMark, estTimeToFinish, legNumber, status].
|
||||||
*/
|
*/
|
||||||
public List<long[]> getBoatData () {
|
public List<long[]> getBoatData () {
|
||||||
return boatData;
|
return boatData;
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package seng302.utilities;
|
||||||
|
|
||||||
|
import javafx.scene.media.AudioClip;
|
||||||
|
import javafx.scene.media.Media;
|
||||||
|
import javafx.scene.media.MediaPlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static class for playing sounds throughout the program
|
||||||
|
*
|
||||||
|
* Created by kre39 on 28/08/17.
|
||||||
|
*/
|
||||||
|
public class Sounds {
|
||||||
|
|
||||||
|
private static MediaPlayer musicPlayer;
|
||||||
|
private static MediaPlayer soundEffect;
|
||||||
|
private static MediaPlayer soundPlayer;
|
||||||
|
private static MediaPlayer hoverSoundPlayer;
|
||||||
|
|
||||||
|
private static boolean hoverInitialized = false;
|
||||||
|
private static boolean musicMuted = false;
|
||||||
|
private static boolean soundEffectsMuted = false;
|
||||||
|
|
||||||
|
|
||||||
|
public static void stopMusic() {
|
||||||
|
if (musicPlayer != null) {
|
||||||
|
musicPlayer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setMutes() {
|
||||||
|
if (soundPlayer != null) {
|
||||||
|
soundPlayer.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
if (soundEffect != null) {
|
||||||
|
soundEffect.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
if (musicPlayer != null) {
|
||||||
|
musicPlayer.setMute(musicMuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopSoundEffects() {
|
||||||
|
if (soundEffect != null) {
|
||||||
|
soundEffect.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void toggleMuteMusic() {
|
||||||
|
musicMuted = !musicMuted;
|
||||||
|
if (musicPlayer != null) {
|
||||||
|
musicPlayer.setMute(musicMuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void toggleMuteEffects() {
|
||||||
|
soundEffectsMuted = !soundEffectsMuted;
|
||||||
|
if (soundPlayer != null) {
|
||||||
|
soundPlayer.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
if (soundEffect != null) {
|
||||||
|
soundEffect.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMusicMuted() {
|
||||||
|
return musicMuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSoundEffectsMuted() {
|
||||||
|
return soundEffectsMuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playRaceMusic() {
|
||||||
|
// Media menuMusic = new Media(Sounds.class.getClassLoader().getResource("sounds/Chill-house-music-loop-116-bpm.wav").toString());
|
||||||
|
Media raceMusic = new Media(Sounds.class.getClassLoader().getResource("sounds/Music-loop-120-bpm.mp3").toString());
|
||||||
|
musicPlayer = new MediaPlayer(raceMusic);
|
||||||
|
musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||||
|
musicPlayer.setVolume(0.3);
|
||||||
|
musicPlayer.play();
|
||||||
|
raceMusic = new Media(Sounds.class.getClassLoader().getResource("sounds/Sounds-of-the-ocean.mp3").toString());
|
||||||
|
soundEffect = new MediaPlayer(raceMusic);
|
||||||
|
soundEffect.setCycleCount(MediaPlayer.INDEFINITE);
|
||||||
|
soundEffect.setVolume(0.3);
|
||||||
|
soundEffect.play();
|
||||||
|
musicPlayer.setMute(musicMuted);
|
||||||
|
soundEffect.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playMenuMusic() {
|
||||||
|
Media menuMusic = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Elevator-music.mp3").toString());
|
||||||
|
musicPlayer = new MediaPlayer(menuMusic);
|
||||||
|
musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||||
|
musicPlayer.setVolume(0.3);
|
||||||
|
musicPlayer.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void playFinishMusic() {
|
||||||
|
Media finishMusic = new Media(Sounds.class.getClassLoader().getResource("sounds/Happy-birthday-song.mp3").toString());
|
||||||
|
musicPlayer = new MediaPlayer(finishMusic);
|
||||||
|
musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||||
|
musicPlayer.setVolume(0.3);
|
||||||
|
musicPlayer.play();
|
||||||
|
musicPlayer.setMute(musicMuted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playButtonClick() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media buttonClick = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Button-click-sound.mp3")
|
||||||
|
.toString());
|
||||||
|
soundPlayer = new MediaPlayer(buttonClick);
|
||||||
|
soundPlayer.setVolume(0.5);
|
||||||
|
soundPlayer.play();
|
||||||
|
soundPlayer.setMute(soundEffectsMuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playFinishSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media finishSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Sms-notification.mp3")
|
||||||
|
.toString());
|
||||||
|
soundPlayer = new MediaPlayer(finishSound);
|
||||||
|
soundPlayer.setVolume(0.5);
|
||||||
|
soundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void playMarkRoundingSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media markRoundingSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/sms-tone.mp3").toString());
|
||||||
|
soundPlayer = new MediaPlayer(markRoundingSound);
|
||||||
|
soundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playCapGunSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media gunSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Gunshot-sound.mp3").toString());
|
||||||
|
soundPlayer = new MediaPlayer(gunSound);
|
||||||
|
soundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playCrashSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media crashSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Large-metal-door-slam.mp3")
|
||||||
|
.toString());
|
||||||
|
soundPlayer = new MediaPlayer(crashSound);
|
||||||
|
soundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playTokenPickupSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
Media pickupSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Coin-pick-up-sound-effect.mp3")
|
||||||
|
.toString());
|
||||||
|
soundPlayer = new MediaPlayer(pickupSound);
|
||||||
|
soundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playHoverSound() {
|
||||||
|
if (!soundEffectsMuted) {
|
||||||
|
if (!hoverInitialized) {
|
||||||
|
Media crashSound = new Media(
|
||||||
|
Sounds.class.getClassLoader().getResource("sounds/Error-sound-effect.mp3")
|
||||||
|
.toString());
|
||||||
|
hoverSoundPlayer = new MediaPlayer(crashSound);
|
||||||
|
hoverInitialized = true;
|
||||||
|
}
|
||||||
|
hoverSoundPlayer.setVolume(0.5);
|
||||||
|
if (hoverSoundPlayer != null) {
|
||||||
|
hoverSoundPlayer.stop();
|
||||||
|
}
|
||||||
|
hoverSoundPlayer.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,9 +2,11 @@ package seng302.utilities;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javafx.util.Pair;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@@ -62,31 +64,10 @@ public class StreamParser {
|
|||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
||||||
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
||||||
|
|
||||||
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
|
||||||
// currentTime = format.format((new Date(currentTime)))
|
|
||||||
|
|
||||||
RaceStatusData data = new RaceStatusData(
|
RaceStatusData data = new RaceStatusData(
|
||||||
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
||||||
);
|
);
|
||||||
|
|
||||||
// long timeTillStart =
|
|
||||||
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
|
||||||
//
|
|
||||||
// if (timeTillStart > 0) {
|
|
||||||
// timeSinceStart = timeTillStart;
|
|
||||||
// } else {
|
|
||||||
// if (raceStatus == 4 || raceStatus == 8) {
|
|
||||||
// raceFinished = true;
|
|
||||||
// raceStarted = false;
|
|
||||||
// } else if (!raceStarted) {
|
|
||||||
// raceStarted = true;
|
|
||||||
// raceFinished = false;
|
|
||||||
// }
|
|
||||||
// timeSinceStart = timeTillStart;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
int noBoats = payload[22];
|
int noBoats = payload[22];
|
||||||
int raceType = payload[23];
|
int raceType = payload[23];
|
||||||
long boatID, estTimeAtNextMark, estTimeAtFinish;
|
long boatID, estTimeAtNextMark, estTimeAtFinish;
|
||||||
@@ -106,24 +87,6 @@ public class StreamParser {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){
|
|
||||||
// Integer placing = 1;
|
|
||||||
// if (leg != updatingBoat.getLegNumber() && (raceStarted || raceFinished)) {
|
|
||||||
// for (Yacht boat : boats.values()) {
|
|
||||||
// if (boat.getLegNumber() != null && leg <= boat.getLegNumber()){
|
|
||||||
// placing += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// updatingBoat.setPlacing(placing.toString());
|
|
||||||
// updatingBoat.setLegNumber(leg);
|
|
||||||
// boatsPos.putIfAbsent(placing, updatingBoat);
|
|
||||||
// boatsPos.replace(placing, updatingBoat);
|
|
||||||
// } else if(updatingBoat.getLegNumber() == null){
|
|
||||||
// updatingBoat.setPlacing("1");
|
|
||||||
// updatingBoat.setLegNumber(leg);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses and returns the text from a StreamPacket containing text data for display.
|
* Parses and returns the text from a StreamPacket containing text data for display.
|
||||||
*
|
*
|
||||||
@@ -255,15 +218,15 @@ public class StreamParser {
|
|||||||
* @return Chatter text message as a string. Returns null if the packet is not of type
|
* @return Chatter text message as a string. Returns null if the packet is not of type
|
||||||
* CHATTER_TEXT.
|
* CHATTER_TEXT.
|
||||||
*/
|
*/
|
||||||
public static String extractChatterText(StreamPacket packet) {
|
public static Pair<Integer, String> extractChatterText(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
int length = payload[2];
|
int length = (int) bytesToLong(new byte[]{payload[2]});
|
||||||
return new String(Arrays.copyOfRange(payload, 3, 3 + length));
|
return new Pair<>(messageType, new String(Arrays.copyOfRange(payload, 3, 3 + length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -392,26 +355,6 @@ public class StreamParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void extractBoatAction(StreamPacket packet) {
|
|
||||||
byte[] payload = packet.getPayload();
|
|
||||||
int messageVersionNo = payload[0];
|
|
||||||
long actionType = bytesToLong(Arrays.copyOfRange(payload, 0, 1));
|
|
||||||
if (actionType == 1) {
|
|
||||||
System.out.println("VMG");
|
|
||||||
} else if (actionType == 2) {
|
|
||||||
System.out.println("SAILS IN");
|
|
||||||
} else if (actionType == 3) {
|
|
||||||
System.out.println("SAILS OUT");
|
|
||||||
} else if (actionType == 4) {
|
|
||||||
System.out.println("TACK/GYBE");
|
|
||||||
} else if (actionType == 5) {
|
|
||||||
System.out.println("UPWIND");
|
|
||||||
} else if (actionType == 6) {
|
|
||||||
System.out.println("DOWNWIND");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.BoatActionMessage;
|
import seng302.gameServer.messages.BoatActionMessage;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.gameServer.messages.ClientType;
|
import seng302.gameServer.messages.ClientType;
|
||||||
import seng302.gameServer.messages.CustomizeRequestMessage;
|
import seng302.gameServer.messages.CustomizeRequestMessage;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
@@ -281,9 +282,17 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* @param message The given message type.
|
* @param message The given message type.
|
||||||
*/
|
*/
|
||||||
private void sendBoatActionMessage(BoatActionMessage message) {
|
private void sendBoatActionMessage(BoatActionMessage message) {
|
||||||
|
sendByteBuffer(message.getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendChatterMessage(String message) {
|
||||||
|
sendByteBuffer(new ChatterMessage(clientId, message).getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendByteBuffer(byte[] bytes) {
|
||||||
if (clientId != -1) {
|
if (clientId != -1) {
|
||||||
try {
|
try {
|
||||||
os.write(message.getBuffer());
|
os.write(bytes);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("IOException on attempting to sendBoatAction from Client");
|
logger.warn("IOException on attempting to sendBoatAction from Client");
|
||||||
notifyDisconnectListeners("Cannot communicate with server");
|
notifyDisconnectListeners("Cannot communicate with server");
|
||||||
@@ -292,7 +301,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeSocket() {
|
public void closeSocket() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
socketOpen = false;
|
socketOpen = false;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package seng302.visualiser;
|
package seng302.visualiser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@@ -14,14 +17,17 @@ import javafx.fxml.FXMLLoader;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Alert.AlertType;
|
import javafx.scene.control.Alert.AlertType;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import seng302.gameServer.GameStages;
|
import seng302.gameServer.GameStages;
|
||||||
|
import javafx.util.Pair;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.gameServer.MainServerThread;
|
import seng302.gameServer.MainServerThread;
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
@@ -32,6 +38,7 @@ import seng302.model.stream.parser.RaceStatusData;
|
|||||||
import seng302.model.stream.parser.YachtEventData;
|
import seng302.model.stream.parser.YachtEventData;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.utilities.StreamParser;
|
import seng302.utilities.StreamParser;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
@@ -56,6 +63,8 @@ public class GameClient {
|
|||||||
private RaceState raceState = new RaceState();
|
private RaceState raceState = new RaceState();
|
||||||
private LobbyController lobbyController;
|
private LobbyController lobbyController;
|
||||||
|
|
||||||
|
private ArrayList<ClientYacht> finishedBoats = new ArrayList<>();
|
||||||
|
|
||||||
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
private ObservableList<String> clientLobbyList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,12 +84,11 @@ public class GameClient {
|
|||||||
public void runAsClient(String ipAddress, Integer portNumber) {
|
public void runAsClient(String ipAddress, Integer portNumber) {
|
||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, portNumber);
|
startClientToServerThread(ipAddress, portNumber);
|
||||||
|
socketThread.addDisconnectionListener((cause) -> {
|
||||||
// socketThread.addDisconnectionListener((cause) -> {
|
showConnectionError(cause);
|
||||||
// showConnectionError(cause);
|
tearDownConnection();
|
||||||
// Platform.runLater(this::loadStartScreen);
|
Platform.runLater(this::loadStartScreen);
|
||||||
// });
|
});
|
||||||
|
|
||||||
socketThread.addStreamObserver(this::parsePackets);
|
socketThread.addStreamObserver(this::parsePackets);
|
||||||
|
|
||||||
ViewManager.getInstance().setPlayerList(clientLobbyList);
|
ViewManager.getInstance().setPlayerList(clientLobbyList);
|
||||||
@@ -203,9 +211,19 @@ public class GameClient {
|
|||||||
raceView = fxmlLoader.getController();
|
raceView = fxmlLoader.getController();
|
||||||
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
|
ClientYacht player = allBoatsMap.get(socketThread.getClientId());
|
||||||
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
raceView.loadRace(allBoatsMap, courseData, raceState, player);
|
||||||
|
raceView.getSendPressedProperty().addListener((obs, old, isPressed) -> {
|
||||||
|
if (isPressed) {
|
||||||
|
formatAndSendChatMessage(raceView.readChatInput());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void loadFinishScreenView() {
|
private void loadFinishScreenView() {
|
||||||
|
Sounds.stopMusic();
|
||||||
|
Sounds.stopSoundEffects();
|
||||||
|
Sounds.playFinishMusic();
|
||||||
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
|
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
|
||||||
FinishScreenViewController controller = fxmlLoader.getController();
|
FinishScreenViewController controller = fxmlLoader.getController();
|
||||||
controller.setFinishers(raceState.getPlayerPositions());
|
controller.setFinishers(raceState.getPlayerPositions());
|
||||||
@@ -233,6 +251,7 @@ 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) {
|
if (raceState.getTimeTillStart() <= 5000) {
|
||||||
startRaceIfAllDataReceived();
|
startRaceIfAllDataReceived();
|
||||||
}
|
}
|
||||||
@@ -288,8 +307,21 @@ public class GameClient {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case YACHT_EVENT_CODE:
|
case YACHT_EVENT_CODE:
|
||||||
|
YachtEventData yachtEventData = StreamParser.extractYachtEventCode(packet);
|
||||||
|
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
|
||||||
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
||||||
|
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN.getCode()) {
|
||||||
|
showPickUp();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CHATTER_TEXT:
|
||||||
|
Pair<Integer, String> playerIdMessagePair = StreamParser
|
||||||
|
.extractChatterText(packet);
|
||||||
|
raceView.updateChatHistory(
|
||||||
|
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
|
||||||
|
playerIdMessagePair.getValue()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,7 +365,6 @@ public class GameClient {
|
|||||||
if (allXMLReceived()) {
|
if (allXMLReceived()) {
|
||||||
ClientYacht clientYacht = allBoatsMap.get(roundingData.getBoatId());
|
ClientYacht clientYacht = allBoatsMap.get(roundingData.getBoatId());
|
||||||
clientYacht.roundMark(
|
clientYacht.roundMark(
|
||||||
courseData.getCompoundMarks().get(roundingData.getMarkId()),
|
|
||||||
roundingData.getTimeStamp(),
|
roundingData.getTimeStamp(),
|
||||||
raceState.getRaceTime() - roundingData.getTimeStamp()
|
raceState.getRaceTime() - roundingData.getTimeStamp()
|
||||||
);
|
);
|
||||||
@@ -348,6 +379,9 @@ public class GameClient {
|
|||||||
for (ClientYacht yacht : allBoatsMap.values()) {
|
for (ClientYacht yacht : allBoatsMap.values()) {
|
||||||
if (yacht.getBoatStatus() != BoatStatus.FINISHED.getCode()) {
|
if (yacht.getBoatStatus() != BoatStatus.FINISHED.getCode()) {
|
||||||
raceFinished = false;
|
raceFinished = false;
|
||||||
|
} else if (!finishedBoats.contains(yacht)) {
|
||||||
|
finishedBoats.add(yacht);
|
||||||
|
Sounds.playFinishSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +397,7 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (raceFinished) {
|
if (raceFinished) {
|
||||||
|
Sounds.playFinishSound();
|
||||||
close();
|
close();
|
||||||
loadFinishScreenView();
|
loadFinishScreenView();
|
||||||
}
|
}
|
||||||
@@ -385,7 +420,13 @@ public class GameClient {
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
public void keyPressed(KeyEvent e) {
|
private void keyPressed(KeyEvent e) {
|
||||||
|
if (raceView.isChatInputFocused()) {
|
||||||
|
if (e.getCode() == KeyCode.ENTER) {
|
||||||
|
formatAndSendChatMessage(raceView.readChatInput());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (e.getCode()) {
|
switch (e.getCode()) {
|
||||||
case SPACE: // align with vmg
|
case SPACE: // align with vmg
|
||||||
socketThread.sendBoatAction(BoatAction.VMG); break;
|
socketThread.sendBoatAction(BoatAction.VMG); break;
|
||||||
@@ -394,12 +435,16 @@ public class GameClient {
|
|||||||
case PAGE_DOWN: // downwind
|
case PAGE_DOWN: // downwind
|
||||||
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
|
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
|
||||||
case ENTER: // tack/gybe
|
case ENTER: // tack/gybe
|
||||||
|
// if chat box is active take whatever is in there and send it to server
|
||||||
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
|
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void keyReleased(KeyEvent e) {
|
private void keyReleased(KeyEvent e) {
|
||||||
|
if (raceView.isChatInputFocused()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (e.getCode()) {
|
switch (e.getCode()) {
|
||||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
||||||
case SHIFT: // sails in/sails out
|
case SHIFT: // sails in/sails out
|
||||||
@@ -420,31 +465,43 @@ public class GameClient {
|
|||||||
* Tells race view to show a collision animation.
|
* Tells race view to show a collision animation.
|
||||||
*/
|
*/
|
||||||
private void showCollisionAlert(YachtEventData yachtEventData) {
|
private void showCollisionAlert(YachtEventData yachtEventData) {
|
||||||
// 33 is the agreed code to show collision
|
Sounds.playCrashSound();
|
||||||
if (yachtEventData.getEventId() == 33) {
|
|
||||||
raceState.storeCollision(
|
raceState.storeCollision(
|
||||||
allBoatsMap.get(
|
allBoatsMap.get(
|
||||||
yachtEventData.getSubjectId().intValue()
|
yachtEventData.getSubjectId().intValue()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
|
||||||
|
private void showPickUp() {
|
||||||
|
Sounds.playTokenPickupSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startGame(){
|
private void formatAndSendChatMessage(String rawChat) {
|
||||||
server.startGame();
|
if (rawChat.length() > 0) {
|
||||||
|
socketThread.sendChatterMessage(
|
||||||
|
new SimpleDateFormat("[HH:mm:ss] ").format(new Date()) +
|
||||||
|
allBoatsMap.get(socketThread.getClientId()).getShortName() + ": " + rawChat
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientToServerThread getServerThread() {
|
// public void startGame(){
|
||||||
return socketThread;
|
// server.startGame();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public List<String> getPlayerNames(){
|
// public ClientToServerThread getServerThread() {
|
||||||
return Collections.unmodifiableList(clientLobbyList.sorted());
|
// return socketThread;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public void stopGame() {
|
// public List<String> getPlayerNames(){
|
||||||
GameState.setCurrentStage(GameStages.CANCELLED);
|
// return Collections.unmodifiableList(clientLobbyList.sorted());
|
||||||
if (server != null) server.terminate();
|
// }
|
||||||
if (socketThread != null) socketThread.setSocketToClose();
|
//
|
||||||
}
|
// public void stopGame() {
|
||||||
|
// GameState.setCurrentStage(GameStages.CANCELLED);
|
||||||
|
// if (server != null) server.terminate();
|
||||||
|
// if (socketThread != null) socketThread.setSocketToClose();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import javafx.animation.KeyFrame;
|
|||||||
import javafx.animation.KeyValue;
|
import javafx.animation.KeyValue;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import javafx.scene.*;
|
import javafx.scene.*;
|
||||||
@@ -24,6 +26,7 @@ import javafx.scene.paint.Paint;
|
|||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.scene.shape.Polygon;
|
import javafx.scene.shape.Polygon;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.transform.Scale;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
@@ -42,6 +45,13 @@ import seng302.visualiser.fxObjects.assets_2D.MarkArrowFactory;
|
|||||||
import seng302.visualiser.fxObjects.assets_2D.Marker;
|
import seng302.visualiser.fxObjects.assets_2D.Marker;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
|
||||||
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
import seng302.visualiser.fxObjects.assets_3D.ModelType;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.fxObjects.AnnotationBox;
|
||||||
|
import seng302.visualiser.fxObjects.BoatObject;
|
||||||
|
import seng302.visualiser.fxObjects.CourseBoundary;
|
||||||
|
import seng302.visualiser.fxObjects.Gate;
|
||||||
|
import seng302.visualiser.fxObjects.MarkArrowFactory;
|
||||||
|
import seng302.visualiser.fxObjects.Marker;
|
||||||
import seng302.visualiser.map.Boundary;
|
import seng302.visualiser.map.Boundary;
|
||||||
import seng302.visualiser.map.CanvasMap;
|
import seng302.visualiser.map.CanvasMap;
|
||||||
|
|
||||||
@@ -51,7 +61,7 @@ import seng302.visualiser.map.CanvasMap;
|
|||||||
public class GameView extends Pane {
|
public class GameView extends Pane {
|
||||||
|
|
||||||
private double bufferSize = 50;
|
private double bufferSize = 50;
|
||||||
private double panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
|
private double panelWidth = 1280;
|
||||||
private double panelHeight = 960;
|
private double panelHeight = 960;
|
||||||
private double canvasWidth = 1100;
|
private double canvasWidth = 1100;
|
||||||
private double canvasHeight = 920;
|
private double canvasHeight = 920;
|
||||||
@@ -63,7 +73,7 @@ public class GameView extends Pane {
|
|||||||
private double referencePointX, referencePointY;
|
private double referencePointX, referencePointY;
|
||||||
private double metersPerPixelX, metersPerPixelY;
|
private double metersPerPixelX, metersPerPixelY;
|
||||||
|
|
||||||
final double SCALE_DELTA = 1.1;
|
private boolean isZoom = false;
|
||||||
|
|
||||||
private Text fpsDisplay = new Text();
|
private Text fpsDisplay = new Text();
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
@@ -165,6 +175,48 @@ public class GameView extends Pane {
|
|||||||
});
|
});
|
||||||
initializeTimer();
|
initializeTimer();
|
||||||
gameObjects.addAll(mapImage, raceBorder, markers, tokens, pl);
|
gameObjects.addAll(mapImage, raceBorder, markers, tokens, pl);
|
||||||
|
// TODO: 11/09/17 ajm412: do you even zoom bro?
|
||||||
|
// this.sceneProperty().addListener(((observable, oldValue, scene) -> {
|
||||||
|
// if (scene != null) {
|
||||||
|
// setupZoom();
|
||||||
|
// } else {
|
||||||
|
// disableZoom();
|
||||||
|
// }
|
||||||
|
// }));
|
||||||
|
//
|
||||||
|
// this.widthProperty().addListener(new ChangeListener<Number>() {
|
||||||
|
// @Override
|
||||||
|
// public void changed(ObservableValue<? extends Number> observable, Number oldValue,
|
||||||
|
// Number newValue) {
|
||||||
|
// scaleFactor = getWidth() / panelWidth;
|
||||||
|
//
|
||||||
|
// if (panelHeight * scaleFactor < getHeight()) {
|
||||||
|
// Scale scale = new Scale(scaleFactor, scaleFactor, 0, 0);
|
||||||
|
// getTransforms().remove(0, getTransforms().size());
|
||||||
|
// getTransforms().add(scale);
|
||||||
|
//
|
||||||
|
// setPrefWidth(getWidth() / scaleFactor);
|
||||||
|
// setPrefHeight(getHeight() / scaleFactor);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// this.heightProperty().addListener(new ChangeListener<Number>() {
|
||||||
|
// @Override
|
||||||
|
// public void changed(ObservableValue<? extends Number> observable, Number oldValue,
|
||||||
|
// Number newValue) {
|
||||||
|
// scaleFactor = getHeight() / panelHeight;
|
||||||
|
//
|
||||||
|
// if (panelWidth * scaleFactor < getWidth()) {
|
||||||
|
// Scale scale = new Scale(scaleFactor, scaleFactor, 0, 0);
|
||||||
|
// getTransforms().remove(0, getTransforms().size());
|
||||||
|
// getTransforms().add(scale);
|
||||||
|
//
|
||||||
|
// setPrefWidth(getWidth() / scaleFactor);
|
||||||
|
// setPrefHeight(getHeight() / scaleFactor);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer() {
|
private void initializeTimer() {
|
||||||
@@ -456,18 +508,18 @@ public class GameView extends Pane {
|
|||||||
raceBorder.getPoints().setAll(boundaryPoints);
|
raceBorder.getPoints().setAll(boundaryPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Rescales the race to the size of the window.
|
// * Rescales the race to the size of the window.
|
||||||
*
|
// *
|
||||||
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
// * @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
||||||
*/
|
// */
|
||||||
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
// private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
||||||
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
// //Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||||
findMinMaxPoint(limitingCoordinates);
|
// findMinMaxPoint(limitingCoordinates);
|
||||||
double minLonToMaxLon = scaleRaceExtremities();
|
// double minLonToMaxLon = scaleRaceExtremities();
|
||||||
calculateReferencePointLocation(minLonToMaxLon);
|
// calculateReferencePointLocation(minLonToMaxLon);
|
||||||
// drawGoogleMap();
|
//// drawGoogleMap();
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces all tokens in the course with those passed in
|
* Replaces all tokens in the course with those passed in
|
||||||
@@ -483,27 +535,46 @@ public class GameView extends Pane {
|
|||||||
tokenObject.setLayoutY(location.getY());
|
tokenObject.setLayoutY(location.getY());
|
||||||
mapTokens.add(tokenObject);
|
mapTokens.add(tokenObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
tokens.getChildren().clear();
|
tokens.getChildren().clear();
|
||||||
tokens.getChildren().addAll(mapTokens);
|
tokens.getChildren().addAll(mapTokens);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 16/08/17 initialize zooming internal to GameView only
|
// // TODO: 16/08/17 initialize zooming internal to GameView only
|
||||||
|
// /**
|
||||||
|
// * Enables zoom. Has to be called after this is added to a scene.
|
||||||
|
// */
|
||||||
|
// private void setupZoom() {
|
||||||
|
// this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
|
||||||
|
// if (event.getCode() == KeyCode.Z) {
|
||||||
|
// zoomIn();
|
||||||
|
// } else if (event.getCode() == KeyCode.X) {
|
||||||
|
// zoomOut();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// enableZoom();
|
||||||
|
// }
|
||||||
|
////
|
||||||
|
// public void enableZoom() {
|
||||||
|
// isZoom = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void disableZoom() {
|
||||||
|
// isZoom = false;
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables zoom. Has to be called after this is added to a scene.
|
* Rescales the race to the size of the window.
|
||||||
|
*
|
||||||
|
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
|
||||||
*/
|
*/
|
||||||
public void enableZoom () {
|
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
|
||||||
if (this.getScene() != null) {
|
//Check is called once to avoid unnecessarily change the course limits once the race is running
|
||||||
this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
|
findMinMaxPoint(limitingCoordinates);
|
||||||
if (event.getCode() == KeyCode.Z) {
|
double minLonToMaxLon = scaleRaceExtremities();
|
||||||
zoomIn();
|
calculateReferencePointLocation(minLonToMaxLon);
|
||||||
} else if (event.getCode() == KeyCode.X) {
|
// drawGoogleMap();
|
||||||
zoomOut();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSelectedBoat(BoatObject bo, Boolean isSelected) {
|
private void setSelectedBoat(BoatObject bo, Boolean isSelected) {
|
||||||
@@ -825,17 +896,11 @@ public class GameView extends Pane {
|
|||||||
playerYacht.addMarkRoundingListener(this::updateMarkArrows);
|
playerYacht.addMarkRoundingListener(this::updateMarkArrows);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMarkArrows (ClientYacht yacht, CompoundMark compoundMark, int legNumber) {
|
private void updateMarkArrows (ClientYacht yacht, int legNumber) {
|
||||||
//Only show arrows for this and next leg.
|
//Only show arrows for this and next leg.
|
||||||
// System.out.println(markerObjects);
|
|
||||||
if (compoundMark != null) {
|
|
||||||
for (Mark mark : compoundMark.getMarks()) {
|
|
||||||
// System.out.println("markerObjects.get(mark) = " + markerObjects.get(mark));
|
|
||||||
markerObjects.get(mark).showNextExitArrow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CompoundMark nextMark = null;
|
CompoundMark nextMark = null;
|
||||||
if (legNumber < course.size() - 1) {
|
if (legNumber < course.size() - 1) {
|
||||||
|
Sounds.playMarkRoundingSound();
|
||||||
nextMark = course.get(legNumber);
|
nextMark = course.get(legNumber);
|
||||||
for (Mark mark : nextMark.getMarks()) {
|
for (Mark mark : nextMark.getMarks()) {
|
||||||
markerObjects.get(mark).showNextEnterArrow();
|
markerObjects.get(mark).showNextEnterArrow();
|
||||||
@@ -849,6 +914,14 @@ public class GameView extends Pane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (legNumber - 1 >= 0) {
|
||||||
|
CompoundMark thisMark = course.get(Math.max(0, legNumber - 1));
|
||||||
|
if (thisMark != nextMark) {
|
||||||
|
for (Mark mark : thisMark.getMarks()) {
|
||||||
|
markerObjects.get(mark).showNextExitArrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import javafx.scene.control.TextField;
|
|||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
public class CustomizationController_old {
|
public class CustomizationController_old {
|
||||||
@@ -34,7 +35,8 @@ public class CustomizationController_old {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void submitCustomization() {
|
public void submitCustomization() {
|
||||||
System.out.println("Attempting to send");
|
Sounds.playButtonClick();
|
||||||
|
// System.out.println("Attempting to send");
|
||||||
socketThread.sendCustomizationRequest(CustomizeRequestType.NAME, nameField.getText().getBytes());
|
socketThread.sendCustomizationRequest(CustomizeRequestType.NAME, nameField.getText().getBytes());
|
||||||
// TODO: 16/08/17 ajm412: Turn colors into byte array.
|
// TODO: 16/08/17 ajm412: Turn colors into byte array.
|
||||||
Color color = boatColorPicker.getValue();
|
Color color = boatColorPicker.getValue();
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ import javafx.fxml.Initializable;
|
|||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import seng302.model.ClientYacht;
|
import seng302.model.ClientYacht;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
|
||||||
public class FinishScreenViewController implements Initializable {
|
public class FinishScreenViewController implements Initializable {
|
||||||
|
|
||||||
@@ -85,6 +87,12 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void switchToStartScreenView() {
|
public void switchToStartScreenView() {
|
||||||
setContentPane("/views/StartScreenView_old.fxml");
|
Sounds.playButtonClick();
|
||||||
|
//TODO merge fix
|
||||||
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
|
Sounds.playHoverSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package seng302.visualiser.controllers;
|
|||||||
|
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@@ -17,7 +19,8 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Slider;
|
import javafx.scene.control.Slider;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.control.TextField;
|
||||||
|
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;
|
||||||
@@ -32,10 +35,15 @@ import seng302.model.RaceState;
|
|||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
|
import seng302.visualiser.GameView;
|
||||||
|
import seng302.visualiser.controllers.annotations.Annotation;
|
||||||
import seng302.visualiser.GameView3D;
|
import seng302.visualiser.GameView3D;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
|
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
|
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
|
||||||
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
|
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
|
||||||
|
import seng302.visualiser.fxObjects.BoatObject;
|
||||||
|
import seng302.visualiser.fxObjects.ChatHistory;
|
||||||
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
|
import seng302.visualiser.fxObjects.assets_2D.BoatObject;
|
||||||
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
|
import seng302.visualiser.fxObjects.assets_2D.WindArrow;
|
||||||
|
|
||||||
@@ -48,6 +56,16 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*/
|
*/
|
||||||
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
||||||
|
|
||||||
|
private final int CHAT_LIMIT = 128;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Pane basePane;
|
||||||
|
@FXML
|
||||||
|
private Button chatSend;
|
||||||
|
@FXML
|
||||||
|
private Pane chatHistoryHolder;
|
||||||
|
@FXML
|
||||||
|
private TextField chatInput;
|
||||||
@FXML
|
@FXML
|
||||||
private LineChart<String, Double> raceSparkLine;
|
private LineChart<String, Double> raceSparkLine;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -60,6 +78,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private Text timerLabel;
|
private Text timerLabel;
|
||||||
@FXML
|
@FXML
|
||||||
private StackPane contentAnchorPane;
|
private StackPane contentAnchorPane;
|
||||||
|
private GridPane contentGridPane;
|
||||||
@FXML
|
@FXML
|
||||||
private AnchorPane rvAnchorPane;
|
private AnchorPane rvAnchorPane;
|
||||||
@FXML
|
@FXML
|
||||||
@@ -84,13 +103,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private GameView3D gameView;
|
private GameView3D gameView;
|
||||||
private RaceState raceState;
|
private RaceState raceState;
|
||||||
|
|
||||||
|
private ChatHistory chatHistory;
|
||||||
|
|
||||||
private Timeline timerTimeline;
|
private Timeline timerTimeline;
|
||||||
private Timer timer = new Timer();
|
private Timer timer = new Timer();
|
||||||
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
private List<Series<String, Double>> sparkLineData = new ArrayList<>();
|
||||||
private ImportantAnnotationsState importantAnnotations;
|
private ImportantAnnotationsState importantAnnotations;
|
||||||
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
|
private Polyline windArrow = new WindArrow(Color.LIGHTGRAY);
|
||||||
|
private ObservableList<ClientYacht> selectionComboBoxList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
Sounds.stopMusic();
|
||||||
|
Sounds.playRaceMusic();
|
||||||
// Load a default important annotation state
|
// Load a default important annotation state
|
||||||
//importantAnnotations = new ImportantAnnotationsState();
|
//importantAnnotations = new ImportantAnnotationsState();
|
||||||
|
|
||||||
@@ -103,6 +127,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
//sparklineYAxis.setTickMarkVisible(false);
|
//sparklineYAxis.setTickMarkVisible(false);
|
||||||
|
|
||||||
//positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
//positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
raceSparkLine.visibleProperty().setValue(false);
|
||||||
|
raceSparkLine.getYAxis().setAutoRanging(false);
|
||||||
|
sparklineYAxis.setTickMarkVisible(false);
|
||||||
|
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
|
||||||
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||||
// rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
|
// rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
|
||||||
@@ -112,6 +140,28 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
|
// windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
|
||||||
// windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
|
// windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
|
||||||
|
|
||||||
|
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
||||||
|
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
|
||||||
|
if (newLen.intValue() > CHAT_LIMIT) {
|
||||||
|
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chatHistory = new ChatHistory();
|
||||||
|
chatHistoryHolder.getChildren().addAll(chatHistory);
|
||||||
|
chatHistory.prefWidthProperty().bind(
|
||||||
|
chatHistoryHolder.widthProperty()
|
||||||
|
);
|
||||||
|
chatHistory.prefHeightProperty().bind(
|
||||||
|
chatHistoryHolder.heightProperty()
|
||||||
|
);
|
||||||
|
// chatHistory.setFitToWidth(true);
|
||||||
|
// chatHistory.setFitToHeight(true);
|
||||||
|
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
|
||||||
|
// chatHistory.setScrollTop(Double.MAX_VALUE);
|
||||||
|
// });
|
||||||
|
contentGridPane.setOnMouseClicked((event) ->
|
||||||
|
contentGridPane.requestFocus()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRace (
|
public void loadRace (
|
||||||
@@ -123,12 +173,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
this.markers = raceData.getCompoundMarks();
|
this.markers = raceData.getCompoundMarks();
|
||||||
this.raceState = raceState;
|
this.raceState = raceState;
|
||||||
|
|
||||||
initializeUpdateTimer();
|
|
||||||
initialiseFPSCheckBox();
|
|
||||||
initialiseAnnotationSlider();
|
|
||||||
initialiseBoatSelectionComboBox();
|
|
||||||
initialiseSparkLine();
|
|
||||||
|
|
||||||
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
|
raceState.getPlayerPositions().addListener((ListChangeListener<ClientYacht>) c -> {
|
||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
if (c.wasPermutated()) {
|
if (c.wasPermutated()) {
|
||||||
@@ -165,6 +209,33 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// updateWindSpeed(raceState.getWindSpeed());
|
// updateWindSpeed(raceState.getWindSpeed());
|
||||||
// });
|
// });
|
||||||
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||||
|
|
||||||
|
//TODO extract chat stuff
|
||||||
|
// raceState.addCollisionListener(gameView::drawCollision);
|
||||||
|
// raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
|
||||||
|
// gameView.setWindDir(newDirection.doubleValue());
|
||||||
|
// updateWindDirection(newDirection.doubleValue());
|
||||||
|
// });
|
||||||
|
// raceState.windSpeedProperty().addListener((obs, oldSpeed, newSpeed) -> {
|
||||||
|
// updateWindSpeed(newSpeed.doubleValue());
|
||||||
|
// });
|
||||||
|
// updateWindDirection(raceState.windDirectionProperty().doubleValue());
|
||||||
|
// updateWindSpeed(raceState.getWindSpeed());
|
||||||
|
// gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
||||||
|
// chatInput.focusedProperty().addListener((obs, oldValue, newValue) -> {
|
||||||
|
// if (newValue) {
|
||||||
|
// gameView.disableZoom();
|
||||||
|
// } else {
|
||||||
|
// gameView.enableZoom();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// Platform.runLater(() -> {
|
||||||
|
// initializeUpdateTimer();
|
||||||
|
// initialiseFPSCheckBox();
|
||||||
|
// initialiseAnnotationSlider();
|
||||||
|
// initialiseBoatSelectionComboBox();
|
||||||
|
// initialiseSparkLine();
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -315,13 +386,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// XYChart.Series<String, Double> positionData = sparkLineData.get(yacht.getSourceID());
|
|
||||||
// positionData.getData().add(
|
|
||||||
// new XYChart.Data<>(
|
|
||||||
// Integer.toString(legNumber),
|
|
||||||
// 1.0 + participants.size() - yacht.getPlacing()
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -551,6 +615,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
// if (selectedBoat != null) {
|
// if (selectedBoat != null) {
|
||||||
// gameView.selectBoat(selectedBoat);
|
// 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);
|
||||||
|
// }
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,9 +634,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contentAnchorPane.getChildren().removeAll();
|
contentGridPane.getChildren().removeAll();
|
||||||
contentAnchorPane.getChildren().clear();
|
contentGridPane.getChildren().clear();
|
||||||
contentAnchorPane.getChildren().addAll((Pane) loader.load());
|
contentGridPane.getChildren().addAll((Pane) loader.load());
|
||||||
|
|
||||||
} catch (javafx.fxml.LoadException e) {
|
} catch (javafx.fxml.LoadException e) {
|
||||||
System.err.println(e.getCause().toString());
|
System.err.println(e.getCause().toString());
|
||||||
@@ -632,4 +705,24 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
gameView.updateTokens(raceData.getTokens());
|
gameView.updateTokens(raceData.getTokens());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlyBooleanProperty getSendPressedProperty() {
|
||||||
|
return chatSend.pressedProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChatInputFocused() {
|
||||||
|
return chatInput.focusedProperty().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readChatInput() {
|
||||||
|
String chat = chatInput.getText();
|
||||||
|
chatInput.clear();
|
||||||
|
basePane.requestFocus();
|
||||||
|
return chat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateChatHistory(Paint playerColour, String newMessage) {
|
||||||
|
Platform.runLater(() -> chatHistory.addMessage(playerColour, newMessage));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ 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.application.Platform;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
@@ -19,10 +20,14 @@ import javafx.scene.control.Alert;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import seng302.gameServer.ServerAdvertiser;
|
import seng302.gameServer.ServerAdvertiser;
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
|
import seng302.gameServer.GameState;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameClient;
|
import seng302.visualiser.GameClient;
|
||||||
import seng302.visualiser.ServerListener;
|
import seng302.visualiser.ServerListener;
|
||||||
import seng302.visualiser.ServerListenerDelegate;
|
import seng302.visualiser.ServerListenerDelegate;
|
||||||
@@ -49,6 +54,23 @@ public class StartScreenController implements Initializable{
|
|||||||
private Logger logger = LoggerFactory.getLogger(StartScreenController.class);
|
private Logger logger = LoggerFactory.getLogger(StartScreenController.class);
|
||||||
|
|
||||||
private List<ServerDescription> servers;
|
private List<ServerDescription> servers;
|
||||||
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
|
Sounds.stopMusic();
|
||||||
|
Sounds.stopSoundEffects();
|
||||||
|
Sounds.playMenuMusic();
|
||||||
|
if (Sounds.isMusicMuted()) {
|
||||||
|
muteMusicButton.setText("UnMute Music");
|
||||||
|
} else {
|
||||||
|
muteMusicButton.setText("Mute Music");
|
||||||
|
}
|
||||||
|
if (Sounds.isSoundEffectsMuted()) {
|
||||||
|
muteSoundsButton.setText("UnMute Sounds");
|
||||||
|
} else {
|
||||||
|
muteSoundsButton.setText("Mute Sounds");
|
||||||
|
}
|
||||||
|
Sounds.setMutes();
|
||||||
|
// gameClient = new GameClient(holder);
|
||||||
|
}
|
||||||
|
|
||||||
private void setInitialDropShadow(){
|
private void setInitialDropShadow(){
|
||||||
DropShadow dropShadow = new DropShadow();
|
DropShadow dropShadow = new DropShadow();
|
||||||
@@ -57,7 +79,25 @@ public class StartScreenController implements Initializable{
|
|||||||
dropShadow.setOffsetY(4.0);
|
dropShadow.setOffsetY(4.0);
|
||||||
dropShadow.setColor(Color.color(0, 0, 0, 0.5));
|
dropShadow.setColor(Color.color(0, 0, 0, 0.5));
|
||||||
headText.setEffect(dropShadow);
|
headText.setEffect(dropShadow);
|
||||||
|
/**
|
||||||
|
* Creates an instance of GameClient and runs it as a host.
|
||||||
|
*/
|
||||||
|
@FXML
|
||||||
|
public void hostButtonPressed() {
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
gameClient = new GameClient(holder);
|
||||||
|
gameClient.runAsHost(getLocalHostIp(), 4942);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of GameClient and runs it has a client.
|
||||||
|
*/
|
||||||
|
@FXML
|
||||||
|
public void connectButtonPressed() {
|
||||||
|
// TODO: 10/07/17 wmu16 - Finish function
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
gameClient = new GameClient(holder);
|
||||||
|
gameClient.runAsClient(ipTextField.getText().trim().toLowerCase(), 4942);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void preloadServerListView(){
|
private void preloadServerListView(){
|
||||||
@@ -88,4 +128,27 @@ public class StartScreenController implements Initializable{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toggleMusic(ActionEvent actionEvent) {
|
||||||
|
Sounds.toggleMuteMusic();
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
if (Sounds.isMusicMuted()) {
|
||||||
|
muteMusicButton.setText("UnMute Music");
|
||||||
|
} else {
|
||||||
|
muteMusicButton.setText("Mute Music");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleSounds(ActionEvent actionEvent) {
|
||||||
|
Sounds.toggleMuteEffects();
|
||||||
|
Sounds.playButtonClick();
|
||||||
|
if (Sounds.isSoundEffectsMuted()) {
|
||||||
|
muteSoundsButton.setText("UnMute Sounds");
|
||||||
|
} else {
|
||||||
|
muteSoundsButton.setText("Mute Sounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
|
Sounds.playHoverSound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package seng302.visualiser.fxObjects;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.layout.Background;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.text.TextFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension of a ScrollPane that contains a TextFlow. Has an addMessage() function to parse and
|
||||||
|
* display chatter text.
|
||||||
|
*/
|
||||||
|
public class ChatHistory extends ScrollPane {
|
||||||
|
|
||||||
|
private TextFlow textFlow = new TextFlow();
|
||||||
|
|
||||||
|
public ChatHistory() {
|
||||||
|
this.setContent(textFlow);
|
||||||
|
this.setFitToWidth(true);
|
||||||
|
this.setFitToHeight(true);
|
||||||
|
this.setMaxHeight(Double.MAX_VALUE);
|
||||||
|
this.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
this.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||||
|
this.setHbarPolicy(ScrollBarPolicy.NEVER);
|
||||||
|
this.lookup(".scroll-pane").setStyle("-fx-background: rgba(255, 255, 255, 0.1); -fx-background-color: rgba(255, 255, 255, 0.1);");
|
||||||
|
|
||||||
|
this.textFlow.setStyle(
|
||||||
|
"-fx-background: rgba(255, 255, 255, 0.1); -fx-background-color: rgba(255, 255, 255, 0.1);"
|
||||||
|
);
|
||||||
|
//This makes the window auto scroll.
|
||||||
|
textFlow.getChildren().addListener((ListChangeListener<Node>) c ->
|
||||||
|
this.setVvalue(1.0)
|
||||||
|
);
|
||||||
|
//This just makes it so that the ChatHistory is on focus it passes it off to the parent.
|
||||||
|
this.parentProperty().addListener((obs, old, parent) ->
|
||||||
|
this.focusedProperty().addListener((obsVal, oldVal, onFocus) -> {
|
||||||
|
if (onFocus) {
|
||||||
|
parent.requestFocus();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message to chat history. Messages should be either of the form:
|
||||||
|
* "[HH:MM:ss] player_name: message_text" or
|
||||||
|
* "SERVER: message_text"
|
||||||
|
* @param colour The colour of the user sending the message
|
||||||
|
* @param Text The chatter text message to be displayed
|
||||||
|
*/
|
||||||
|
public void addMessage (Paint colour, String Text) {
|
||||||
|
String[] words = Text.split(":");
|
||||||
|
if (words[0].trim().equals("SERVER")) {
|
||||||
|
Text text = new Text(Text + "\n\n");
|
||||||
|
text.setStyle("-fx-font-weight: bolder");
|
||||||
|
textFlow.getChildren().add(text);
|
||||||
|
} else {
|
||||||
|
Text timePlayer = new Text(
|
||||||
|
String.join(":", Arrays.copyOfRange(words, 0, 3)) + ":"
|
||||||
|
);
|
||||||
|
timePlayer.setStyle("-fx-font-weight: bold");
|
||||||
|
timePlayer.setFill(colour);
|
||||||
|
Text message = new Text(
|
||||||
|
String.join(":", Arrays.copyOfRange(words, 3, words.length)) + "\n\n"
|
||||||
|
);
|
||||||
|
message.wrappingWidthProperty().bind(this.widthProperty());
|
||||||
|
textFlow.getChildren().addAll(timePlayer, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import javafx.geometry.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
@@ -10,6 +15,7 @@
|
|||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?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">
|
<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>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
@@ -42,6 +48,6 @@
|
|||||||
<Insets bottom="50.0" />
|
<Insets bottom="50.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</TableView>
|
</TableView>
|
||||||
<Button mnemonicParsing="false" onAction="#switchToStartScreenView" styleClass="blue-ui-btn" text="Return to Start Screen" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="TOP" />
|
<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>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Feature: SendChat
|
||||||
|
Scenario: User send chat to another client
|
||||||
|
Given There are two games running
|
||||||
|
When the first client has sent the message "Hello world"
|
||||||
|
Then the other client should receive the message "Hello world"
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
package seng302.gameServer.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import seng302.gameServer.GameState;
|
||||||
|
import seng302.gameServer.MainServerThread;
|
||||||
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.model.stream.parser.RaceStatusData;
|
||||||
|
import seng302.utilities.StreamParser;
|
||||||
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by cir27 on 3/09/17.
|
||||||
|
*/
|
||||||
|
public class ChatCommandsTest {
|
||||||
|
|
||||||
|
|
||||||
|
private boolean dcSent = false;
|
||||||
|
private ClientToServerThread client;
|
||||||
|
private ClientToServerThread host;
|
||||||
|
private MainServerThread mst;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendFinishAsHost () {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dcSent = false;
|
||||||
|
new GameState("localhost");
|
||||||
|
mst = new MainServerThread();
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
host.addStreamObserver(() -> {
|
||||||
|
while (host.getPacketQueue().peek() != null) {
|
||||||
|
StreamPacket packet = host.getPacketQueue().poll();
|
||||||
|
switch (packet.getType()) {
|
||||||
|
case RACE_STATUS:
|
||||||
|
RaceStatusData rsd = StreamParser.extractRaceStatus(packet);
|
||||||
|
if (rsd.getBoatData().get(0)[4] == BoatStatus.FINISHED.getCode()) {
|
||||||
|
mst.terminate();
|
||||||
|
Assert.assertTrue(dcSent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.startGame();
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
host.sendChatterMessage("[time_prefix] <name_prefix> >finish");
|
||||||
|
dcSent = true;
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
host = null;
|
||||||
|
client = null;
|
||||||
|
mst = null;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendSpeedAsHostValid () {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
new GameState("localhost");
|
||||||
|
mst = new MainServerThread();
|
||||||
|
host = null;
|
||||||
|
try {
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.startGame();
|
||||||
|
host.sendChatterMessage("[time_prefix] <name_prefix> >speed 5.0");
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
Assert.assertEquals(5.0, GameState.getSpeedMultiplier(), 0.00001);
|
||||||
|
mst.terminate();
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
host = null;
|
||||||
|
client = null;
|
||||||
|
mst = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendSpeedAsHostInvalid () {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
new GameState("localhost");
|
||||||
|
mst = new MainServerThread();
|
||||||
|
host = null;
|
||||||
|
try {
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.startGame();
|
||||||
|
host.sendChatterMessage("[time_prefix] <name_prefix> >speed fdgdgdfg");
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.terminate();
|
||||||
|
Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendCommandAsClient () {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst = new MainServerThread();
|
||||||
|
try {
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
client = new ClientToServerThread("localhost", 4942);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.startGame();
|
||||||
|
try {
|
||||||
|
Thread.sleep(200);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
client.sendChatterMessage("[time_prefix] <name_prefix> >speed 5.0");
|
||||||
|
try {
|
||||||
|
Thread.sleep(200);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
|
||||||
|
mst.terminate();
|
||||||
|
host.setSocketToClose();
|
||||||
|
client.setSocketToClose();
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void receiveFinishedAsClient () {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
new GameState("localhost");
|
||||||
|
dcSent = false;
|
||||||
|
mst = new MainServerThread();
|
||||||
|
host = null;
|
||||||
|
try {
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
client = new ClientToServerThread("localhost", 4942);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
client.addStreamObserver(() -> {
|
||||||
|
while (client.getPacketQueue().peek() != null) {
|
||||||
|
StreamPacket packet = client.getPacketQueue().poll();
|
||||||
|
switch (packet.getType()) {
|
||||||
|
case RACE_STATUS:
|
||||||
|
RaceStatusData rsd = StreamParser.extractRaceStatus(packet);
|
||||||
|
if (rsd.getBoatData().get(0)[4] == BoatStatus.FINISHED.getCode()) {
|
||||||
|
mst.terminate();
|
||||||
|
Assert.assertTrue(dcSent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
host.sendChatterMessage("[time_prefix] <name_prefix> >finish");
|
||||||
|
dcSent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,10 @@ package seng302.models;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import javafx.util.Pair;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -21,6 +24,7 @@ public class YachtTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() {
|
||||||
|
new GameState("localhost");
|
||||||
y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1");
|
y1 = new ServerYacht("Yacht", 1, "Y1", "Y1", "Yacht 1", "C1");
|
||||||
gs = new GameState("localhost");
|
gs = new GameState("localhost");
|
||||||
}
|
}
|
||||||
@@ -52,7 +56,7 @@ public class YachtTest {
|
|||||||
Double upwind = PolarTable.getOptimalUpwindVMG(windSpeed).keySet().iterator().next();
|
Double upwind = PolarTable.getOptimalUpwindVMG(windSpeed).keySet().iterator().next();
|
||||||
Double downwind = PolarTable.getOptimalDownwindVMG(windSpeed).keySet().iterator().next();
|
Double downwind = PolarTable.getOptimalDownwindVMG(windSpeed).keySet().iterator().next();
|
||||||
|
|
||||||
HashMap<Double, Double> values = new HashMap<>();
|
List<Pair<Double, Double>> values = new ArrayList<>();
|
||||||
|
|
||||||
upwind = (double) Math.floorMod(upwind.longValue() + windDirection.longValue(), 360L);
|
upwind = (double) Math.floorMod(upwind.longValue() + windDirection.longValue(), 360L);
|
||||||
Double upwindRight = upwind;
|
Double upwindRight = upwind;
|
||||||
@@ -61,19 +65,19 @@ public class YachtTest {
|
|||||||
Double downwindRight = downwind;
|
Double downwindRight = downwind;
|
||||||
Double downwindLeft = 360 - downwindRight;
|
Double downwindLeft = 360 - downwindRight;
|
||||||
|
|
||||||
values.put(190d, upwindRight);
|
values.add(new Pair<>(190d, upwindRight));
|
||||||
values.put(170d, upwindLeft);
|
values.add(new Pair<>(170d, upwindLeft));
|
||||||
values.put(10d, downwindLeft);
|
values.add(new Pair<>(10d, downwindLeft));
|
||||||
values.put(350d, downwindRight);
|
values.add(new Pair<>(350d, downwindRight));
|
||||||
|
|
||||||
for (Double begin : values.keySet()) {
|
for (Pair<Double, Double> beginEndPair : values) {
|
||||||
y1.setHeading(begin);
|
y1.setHeading(beginEndPair.getKey());
|
||||||
y1.turnToVMG();
|
y1.turnToVMG();
|
||||||
for (int i = 0; i < 200; i++) {
|
for (int i = 0; i < 200; i++) {
|
||||||
y1.runAutoPilot();
|
y1.runAutoPilot();
|
||||||
}
|
}
|
||||||
y1.disableAutoPilot();
|
y1.disableAutoPilot();
|
||||||
assertEquals(values.get(begin), y1.getHeading(), 5.0);
|
assertEquals(beginEndPair.getValue(), y1.getHeading(), 5.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package steps;
|
||||||
|
|
||||||
|
import cucumber.api.java.en.Given;
|
||||||
|
import cucumber.api.java.en.Then;
|
||||||
|
import cucumber.api.java.en.When;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import seng302.gameServer.MainServerThread;
|
||||||
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
|
import seng302.utilities.StreamParser;
|
||||||
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cucumber test for sending chat messages
|
||||||
|
* Created by kre39 on 7/08/17.
|
||||||
|
*/
|
||||||
|
public class SendChatSteps {
|
||||||
|
|
||||||
|
private ClientToServerThread client;
|
||||||
|
private ClientToServerThread host;
|
||||||
|
private MainServerThread mst;
|
||||||
|
|
||||||
|
|
||||||
|
@Given("^There are two games running$")
|
||||||
|
public void the_are_two_games_running() throws Throwable {
|
||||||
|
mst = new MainServerThread();
|
||||||
|
host = new ClientToServerThread("localhost", 4942);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
client = new ClientToServerThread("localhost", 4942);
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
mst.startGame();
|
||||||
|
Thread.sleep(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@When("^the first client has sent the message \"([^\"]*)\"$")
|
||||||
|
public void the_user_has_pressed_sends_the_message_in_a_text_box(String arg1) throws Throwable {
|
||||||
|
client.sendChatterMessage("[time_prefix] <name_prefix> " + arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Then("^the other client should receive the message \"([^\"]*)\"$")
|
||||||
|
public void the_other_client_should_receive_the_message(String arg1) throws Throwable {
|
||||||
|
Object[] packets = host.getPacketQueue().toArray();
|
||||||
|
Pair<Integer, String> message = StreamParser.extractChatterText((StreamPacket) packets[packets.length - 1]);
|
||||||
|
Assert.assertEquals("[time_prefix] <name_prefix> " + arg1, message.getValue());
|
||||||
|
mst.terminate();
|
||||||
|
host.setSocketToClose();
|
||||||
|
client.setSocketToClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import seng302.model.ServerYacht;
|
|||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Cucumber test for toggling sail
|
||||||
* Created by kre39 on 7/08/17.
|
* Created by kre39 on 7/08/17.
|
||||||
*/
|
*/
|
||||||
public class ToggleSailSteps {
|
public class ToggleSailSteps {
|
||||||
@@ -49,5 +50,7 @@ public class ToggleSailSteps {
|
|||||||
} else {
|
} else {
|
||||||
Assert.assertFalse(yacht.getSailIn());
|
Assert.assertFalse(yacht.getSailIn());
|
||||||
}
|
}
|
||||||
|
mst.terminate();
|
||||||
|
client.closeSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user