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 Story1248_Game_App_Scaling
# Conflicts: # src/main/java/seng302/visualiser/GameView.java # src/main/java/seng302/visualiser/controllers/RaceViewController.java # src/main/resources/views/RaceView.fxml
This commit is contained in:
@@ -68,7 +68,7 @@ public class App extends Application {
|
|||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml"));
|
Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml"));
|
||||||
primaryStage.setTitle("RaceVision");
|
primaryStage.setTitle("Party Parrots at Sea");
|
||||||
Scene scene = new Scene(root, 1530, 960);
|
Scene scene = new Scene(root, 1530, 960);
|
||||||
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
scene.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
primaryStage.setScene(scene);
|
primaryStage.setScene(scene);
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
@@ -15,12 +17,14 @@ import org.w3c.dom.Document;
|
|||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
import seng302.gameServer.messages.MarkRoundingMessage;
|
import seng302.gameServer.messages.MarkRoundingMessage;
|
||||||
import seng302.gameServer.messages.MarkType;
|
import seng302.gameServer.messages.MarkType;
|
||||||
import seng302.gameServer.messages.Message;
|
import seng302.gameServer.messages.Message;
|
||||||
import seng302.gameServer.messages.RoundingBoatStatus;
|
import seng302.gameServer.messages.RoundingBoatStatus;
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
|
import seng302.gameServer.messages.YachtEventType;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
@@ -29,6 +33,8 @@ import seng302.model.ServerYacht;
|
|||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
@@ -41,24 +47,31 @@ 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 PREPATORY_TIME = 5 * -1000;
|
||||||
|
private static final int TIME_TILL_START = 10 * 1000;
|
||||||
|
static Integer MAX_PLAYERS = 8;
|
||||||
|
|
||||||
|
private static final Long POWERUP_TIMEOUT_MS = 10_000L;
|
||||||
|
|
||||||
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
private static final Integer STATE_UPDATES_PER_SECOND = 60;
|
||||||
public static Integer MAX_PLAYERS = 8;
|
private static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
||||||
public static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
|
private static final Double MARK_COLLISION_DISTANCE = 15d;
|
||||||
public static final Double MARK_COLLISION_DISTANCE = 15d;
|
|
||||||
public static final Double YACHT_COLLISION_DISTANCE = 25.0;
|
public static final Double YACHT_COLLISION_DISTANCE = 25.0;
|
||||||
public static final Double BOUNCE_DISTANCE_MARK = 20.0;
|
private static final Double BOUNCE_DISTANCE_MARK = 20.0;
|
||||||
public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
|
public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
|
||||||
public static final Double COLLISION_VELOCITY_PENALTY = 0.3;
|
private static final Double COLLISION_VELOCITY_PENALTY = 0.3;
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -72,35 +85,30 @@ public class GameState implements Runnable {
|
|||||||
private static Set<Mark> marks;
|
private static Set<Mark> marks;
|
||||||
private static List<Limit> courseLimit;
|
private static List<Limit> courseLimit;
|
||||||
|
|
||||||
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<>();
|
||||||
|
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();
|
||||||
|
|
||||||
@@ -125,6 +133,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;
|
||||||
}
|
}
|
||||||
@@ -137,6 +160,10 @@ public class GameState implements Runnable {
|
|||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Token> getTokensInPlay() {
|
||||||
|
return tokensInPlay;
|
||||||
|
}
|
||||||
|
|
||||||
public static void addPlayer(Player player) {
|
public static void addPlayer(Player player) {
|
||||||
players.add(player);
|
players.add(player);
|
||||||
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
|
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
|
||||||
@@ -178,7 +205,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void resetStartTime(){
|
public static void resetStartTime(){
|
||||||
startTime = System.currentTimeMillis() + MainServerThread.TIME_TILL_START;
|
startTime = System.currentTimeMillis() + TIME_TILL_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Double getWindDirection() {
|
public static Double getWindDirection() {
|
||||||
@@ -264,7 +291,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;
|
||||||
@@ -276,6 +319,7 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
for (ServerYacht yacht : yachts.values()) {
|
for (ServerYacht yacht : yachts.values()) {
|
||||||
updateVelocity(yacht);
|
updateVelocity(yacht);
|
||||||
|
checkPowerUpTimeout(yacht);
|
||||||
yacht.runAutoPilot();
|
yacht.runAutoPilot();
|
||||||
yacht.updateLocation(timeInterval);
|
yacht.updateLocation(timeInterval);
|
||||||
if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
|
if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
|
||||||
@@ -283,8 +327,6 @@ public class GameState implements Runnable {
|
|||||||
checkForLegProgression(yacht);
|
checkForLegProgression(yacht);
|
||||||
raceFinished = false;
|
raceFinished = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raceFinished) {
|
if (raceFinished) {
|
||||||
@@ -292,6 +334,17 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void checkPowerUpTimeout(ServerYacht yacht) {
|
||||||
|
if (yacht.getPowerUp() != null) {
|
||||||
|
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
|
||||||
|
yacht.powerDown();
|
||||||
|
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the yacht has crossed the course limit
|
* Check if the yacht has crossed the course limit
|
||||||
*
|
*
|
||||||
@@ -312,13 +365,45 @@ public class GameState implements Runnable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 collision with a token
|
||||||
|
*/
|
||||||
|
private static Token checkTokenPickUp(ServerYacht serverYacht) {
|
||||||
|
for (Token token : tokensInPlay) {
|
||||||
|
Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
|
||||||
|
if (distance < YACHT_COLLISION_DISTANCE) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
calculateBounceBack(serverYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
calculateBounceBack(serverYacht, originalLocation, BOUNCE_DISTANCE_YACHT)
|
||||||
);
|
);
|
||||||
|
System.out.println("DID BOUNCE BACK");
|
||||||
serverYacht.setCurrentVelocity(
|
serverYacht.setCurrentVelocity(
|
||||||
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
|
||||||
);
|
);
|
||||||
@@ -329,59 +414,83 @@ 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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
System.out.println("DID BOUNCE BACK2");
|
||||||
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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
System.out.println("DID BOUNCE BACK3");
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void updateVelocity(ServerYacht yacht) {
|
private void updateVelocity(ServerYacht yacht) {
|
||||||
Double velocity = yacht.getCurrentVelocity();
|
|
||||||
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);
|
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier;
|
||||||
|
if (yacht.getPowerUp() != null) {
|
||||||
|
if (yacht.getPowerUp().equals(TokenType.BOOST)) {
|
||||||
|
maxBoatSpeed *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Double currentVelocity = yacht.getCurrentVelocity();
|
||||||
// TODO: 15/08/17 remove magic numbers from these equations.
|
// TODO: 15/08/17 remove magic numbers from these equations.
|
||||||
if (yacht.getSailIn()) {
|
if (yacht.getSailIn()) {
|
||||||
if (velocity < maxBoatSpeed - 500) {
|
if (currentVelocity < maxBoatSpeed - 500) {
|
||||||
yacht.changeVelocity(maxBoatSpeed / 100);
|
yacht.changeVelocity(maxBoatSpeed / 100);
|
||||||
} else if (velocity > maxBoatSpeed + 500) {
|
} else if (currentVelocity > maxBoatSpeed + 500) {
|
||||||
yacht.changeVelocity(-velocity / 200);
|
yacht.changeVelocity(-currentVelocity / 200);
|
||||||
} else {
|
} else {
|
||||||
yacht.setCurrentVelocity(maxBoatSpeed);
|
yacht.setCurrentVelocity(maxBoatSpeed);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (velocity > 3000) {
|
if (currentVelocity > 3000) {
|
||||||
yacht.changeVelocity(-velocity / 200);
|
yacht.changeVelocity(-currentVelocity / 200);
|
||||||
} else if (velocity > 100) {
|
} else if (currentVelocity > 100) {
|
||||||
yacht.changeVelocity(-velocity / 50);
|
yacht.changeVelocity(-currentVelocity / 50);
|
||||||
} else if (velocity <= 100) {
|
} else if (currentVelocity <= 100) {
|
||||||
yacht.setCurrentVelocity(0d);
|
yacht.setCurrentVelocity(0d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -671,8 +780,8 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,8 +793,37 @@ public class GameState implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void addMarkPassListener(NewMessageListener listener) {
|
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
|
||||||
markListeners.add(listener);
|
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) {
|
||||||
|
newMessageListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCustomizationFlag() {
|
public static void setCustomizationFlag() {
|
||||||
@@ -699,4 +837,17 @@ public class GameState implements Runnable {
|
|||||||
public static void resetCustomizationFlag() {
|
public static void resetCustomizationFlag() {
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.*;
|
import seng302.gameServer.messages.*;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,18 +22,14 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
private static final int LOG_LEVEL = 1;
|
|
||||||
private static final int WARNING_TIME = 10 * -1000;
|
|
||||||
private static final int PREPATORY_TIME = 5 * -1000;
|
|
||||||
public static final int TIME_TILL_START = 10 * 1000;
|
|
||||||
|
|
||||||
private static final int MAX_WIND_SPEED = 12000;
|
private static final int MAX_WIND_SPEED = 12000;
|
||||||
private static final int MIN_WIND_SPEED = 8000;
|
private static final int MIN_WIND_SPEED = 8000;
|
||||||
|
|
||||||
public static int windSpeed = 1000;
|
|
||||||
|
|
||||||
private boolean terminated;
|
private boolean terminated;
|
||||||
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
@@ -43,13 +42,15 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
try {
|
try {
|
||||||
serverSocket = new ServerSocket(PORT);
|
serverSocket = new ServerSocket(PORT);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
|
logger.trace("IO error in server thread handler upon trying to make new server socket",
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
||||||
GameState.addMarkPassListener(this::broadcastMessage);
|
GameState.addMessageEventListener(this::broadcastMessage);
|
||||||
terminated = false;
|
terminated = false;
|
||||||
thread = new Thread(this, "MainServer");
|
thread = new Thread(this, "MainServer");
|
||||||
startUpdatingWind();
|
startUpdatingWind();
|
||||||
|
startSpawningTokens();
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,50 +65,57 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
try {
|
try {
|
||||||
Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
|
Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
serverLog("Interrupted exception in Main Server Thread thread sleep", 1);
|
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
|
||||||
}
|
}
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
|
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState
|
||||||
.getCustomizationFlag()) {
|
.getCustomizationFlag()) {
|
||||||
// TODO: 16/08/17 ajm412: This can probably be done in a nicer way via those fancy functional interfaces.
|
// TODO: 16/08/17 ajm412: This can probably be done in a nicer way via those fancy functional interfaces.
|
||||||
for (ServerToClientThread thread : serverToClientThreads) {
|
sendSetupMessages();
|
||||||
thread.sendSetupMessages();
|
|
||||||
}
|
|
||||||
GameState.resetCustomizationFlag();
|
GameState.resetCustomizationFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
||||||
updateClients();
|
sendBoatLocations();
|
||||||
}
|
}
|
||||||
|
|
||||||
//RACING
|
//RACING
|
||||||
if (GameState.getCurrentStage() == GameStages.RACING) {
|
if (GameState.getCurrentStage() == GameStages.RACING) {
|
||||||
updateClients();
|
sendBoatLocations();
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 updateClients() {
|
private void sendBoatLocations() {
|
||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerYacht serverYacht : GameState.getYachts().values()) {
|
||||||
serverToClientThread.sendBoatLocationPackets();
|
broadcastMessage(MessageFactory.getBoatLocationMessage(serverYacht));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendSetupMessages() {
|
||||||
|
broadcastMessage(MessageFactory.getRaceXML());
|
||||||
|
broadcastMessage(MessageFactory.getRegattaXML());
|
||||||
|
broadcastMessage(MessageFactory.getBoatXML());
|
||||||
|
}
|
||||||
|
|
||||||
private void broadcastMessage(Message message) {
|
private void broadcastMessage(Message message) {
|
||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
serverToClientThread.sendMessage(message);
|
serverToClientThread.sendMessage(message);
|
||||||
@@ -143,6 +151,25 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
GameState.setWindDirection(direction.doubleValue());
|
GameState.setWindDirection(direction.doubleValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 29/08/17 wmu16 - This should not be in one function (init and a scheduling update)
|
||||||
|
public void startGame() {
|
||||||
|
initialiseBoatPositions();
|
||||||
|
Timer t = new Timer();
|
||||||
|
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
broadcastMessage(MessageFactory.getRaceStatusMessage());
|
||||||
|
if (GameState.getCurrentStage() == GameStages.PRE_RACE
|
||||||
|
|| GameState.getCurrentStage() == GameStages.LOBBYING) {
|
||||||
|
broadcastMessage(MessageFactory.getRaceStartStatusMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
|
||||||
private static void startUpdatingWind(){
|
private static void startUpdatingWind(){
|
||||||
Timer timer = new Timer();
|
Timer timer = new Timer();
|
||||||
timer.schedule(new TimerTask() {
|
timer.schedule(new TimerTask() {
|
||||||
@@ -153,12 +180,18 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}, 0, 500);
|
}, 0, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
static void serverLog(String message, int logLevel) {
|
* Start spawning coins every 60s after the first minute
|
||||||
if (logLevel <= LOG_LEVEL) {
|
*/
|
||||||
System.out.println(
|
private void startSpawningTokens() {
|
||||||
"[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
|
Timer timer = new Timer();
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GameState.spawnNewToken();
|
||||||
|
broadcastMessage(MessageFactory.getRaceXML());
|
||||||
}
|
}
|
||||||
|
}, 0, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,13 +201,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clientConnected(ServerToClientThread serverToClientThread) {
|
public void clientConnected(ServerToClientThread serverToClientThread) {
|
||||||
serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
||||||
serverToClientThreads.add(serverToClientThread);
|
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
||||||
serverToClientThread.addConnectionListener(() -> {
|
serverToClientThread.setAsHost();
|
||||||
for (ServerToClientThread thread : serverToClientThreads) {
|
|
||||||
thread.sendSetupMessages();
|
|
||||||
}
|
}
|
||||||
});
|
serverToClientThreads.add(serverToClientThread);
|
||||||
|
serverToClientThread.addConnectionListener(this::sendSetupMessages);
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,86 +217,22 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clientDisconnected(Player player) {
|
public void clientDisconnected(Player player) {
|
||||||
// try {
|
logger.debug("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
|
||||||
// player.getSocket().close();
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// serverLog("Cannot disconnect the socket for the disconnected player.", 0);
|
|
||||||
// }
|
|
||||||
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
|
|
||||||
GameState.removeYacht(player.getYacht().getSourceId());
|
GameState.removeYacht(player.getYacht().getSourceId());
|
||||||
GameState.removePlayer(player);
|
GameState.removePlayer(player);
|
||||||
ServerToClientThread closedConnection = null;
|
ServerToClientThread closedConnection = null;
|
||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
if (serverToClientThread.getSocket() == player.getSocket()) {
|
if (serverToClientThread.getSocket() == player.getSocket()) {
|
||||||
closedConnection = serverToClientThread;
|
closedConnection = serverToClientThread;
|
||||||
} else if (GameState.getCurrentStage() != GameStages.RACING){
|
|
||||||
serverToClientThread.sendSetupMessages();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
closedConnection.terminate();
|
closedConnection.terminate();
|
||||||
}
|
|
||||||
|
|
||||||
public void startGame() {
|
|
||||||
initialiseBoatPositions();
|
|
||||||
Timer t = new Timer();
|
|
||||||
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
broadcastMessage(makeRaceStatusMessage());
|
|
||||||
if (GameState.getCurrentStage() == GameStages.PRE_RACE || GameState.getCurrentStage() == GameStages.LOBBYING) {
|
|
||||||
broadcastMessage(makeRaceStartMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private RaceStartStatusMessage makeRaceStartMessage() {
|
|
||||||
Long raceStartTime = GameState.getStartTime();
|
|
||||||
|
|
||||||
return new RaceStartStatusMessage(1, raceStartTime ,
|
|
||||||
1, RaceStartNotificationType.SET_RACE_START_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RaceStatusMessage makeRaceStatusMessage() {
|
|
||||||
// variables taken from GameServerThread
|
|
||||||
|
|
||||||
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
|
|
||||||
RaceStatus raceStatus;
|
|
||||||
|
|
||||||
for (Player player : GameState.getPlayers()) {
|
|
||||||
ServerYacht y = player.getYacht();
|
|
||||||
BoatSubMessage m = new BoatSubMessage(y.getSourceId(), y.getBoatStatus(),
|
|
||||||
y.getLegNumber(),
|
|
||||||
0, 0, 1234L,
|
|
||||||
1234L);
|
|
||||||
boatSubMessages.add(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
long timeTillStart = System.currentTimeMillis() - GameState.getStartTime();
|
|
||||||
|
|
||||||
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
||||||
raceStatus = RaceStatus.PRESTART;
|
sendSetupMessages();
|
||||||
} else if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
|
||||||
raceStatus = RaceStatus.PRESTART;
|
|
||||||
|
|
||||||
if (timeTillStart > WARNING_TIME) {
|
|
||||||
raceStatus = RaceStatus.WARNING;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeTillStart > PREPATORY_TIME) {
|
|
||||||
raceStatus = RaceStatus.PREPARATORY;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
raceStatus = RaceStatus.STARTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RaceStatusMessage(1, raceStatus, GameState.getStartTime(),
|
|
||||||
GameState.getWindDirection(),
|
|
||||||
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
|
|
||||||
RaceType.MATCH_RACE, 1, boatSubMessages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void terminate() {
|
public void terminate() {
|
||||||
@@ -275,10 +243,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);
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import seng302.gameServer.messages.BoatLocationMessage;
|
||||||
|
import seng302.gameServer.messages.BoatSubMessage;
|
||||||
|
import seng302.gameServer.messages.RaceStartNotificationType;
|
||||||
|
import seng302.gameServer.messages.RaceStartStatusMessage;
|
||||||
|
import seng302.gameServer.messages.RaceStatus;
|
||||||
|
import seng302.gameServer.messages.RaceStatusMessage;
|
||||||
|
import seng302.gameServer.messages.RaceType;
|
||||||
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
|
import seng302.model.Player;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
|
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 for interfacing between the data we have in the GameState to the messages we need to send
|
||||||
|
* through the MainServerThread.
|
||||||
|
*
|
||||||
|
* WARNING DO NOT USE THIS CLASS IF GAMESTATE HAS NOT BEEN INSTANTIATED. (Main Server has not started)
|
||||||
|
* // TODO: 29/08/17 wmu16 - Make GameState non static to fix this ¯\_(ツ)_/¯
|
||||||
|
* Created by wmu16 on 29/08/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ideally this class would be created with an instance of the GameState (I tried implementing this for
|
||||||
|
a bit) but it was too difficult to properly make GameState non static without doing some proper
|
||||||
|
re working. To do later.
|
||||||
|
*/
|
||||||
|
public class MessageFactory {
|
||||||
|
|
||||||
|
private static XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
|
||||||
|
|
||||||
|
public static RaceStartStatusMessage getRaceStartStatusMessage() {
|
||||||
|
return new RaceStartStatusMessage(
|
||||||
|
1,
|
||||||
|
GameState.getStartTime(),
|
||||||
|
1,
|
||||||
|
RaceStartNotificationType.SET_RACE_START_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RaceStatusMessage getRaceStatusMessage() {
|
||||||
|
// variables taken from GameServerThread
|
||||||
|
|
||||||
|
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
|
||||||
|
RaceStatus raceStatus;
|
||||||
|
|
||||||
|
for (Player player : GameState.getPlayers()) {
|
||||||
|
ServerYacht y = player.getYacht();
|
||||||
|
BoatSubMessage m = new BoatSubMessage(y.getSourceId(), y.getBoatStatus(),
|
||||||
|
y.getLegNumber(),
|
||||||
|
0, 0, 1234L,
|
||||||
|
1234L);
|
||||||
|
boatSubMessages.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
long timeTillStart = System.currentTimeMillis() - GameState.getStartTime();
|
||||||
|
|
||||||
|
if (GameState.getCurrentStage() == GameStages.LOBBYING) {
|
||||||
|
raceStatus = RaceStatus.PRESTART;
|
||||||
|
} else if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
||||||
|
raceStatus = RaceStatus.PRESTART;
|
||||||
|
|
||||||
|
if (timeTillStart > GameState.WARNING_TIME) {
|
||||||
|
raceStatus = RaceStatus.WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeTillStart > GameState.PREPATORY_TIME) {
|
||||||
|
raceStatus = RaceStatus.PREPARATORY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
raceStatus = RaceStatus.STARTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RaceStatusMessage(1, raceStatus, GameState.getStartTime(),
|
||||||
|
GameState.getWindDirection(),
|
||||||
|
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
|
||||||
|
RaceType.MATCH_RACE, 1, boatSubMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoatLocationMessage getBoatLocationMessage(ServerYacht yacht) {
|
||||||
|
return new BoatLocationMessage(
|
||||||
|
yacht.getSourceId(),
|
||||||
|
0, // TODO: 29/08/17 wmu16 - Work out what to do with seqNo. Currently not used
|
||||||
|
yacht.getLocation().getLat(),
|
||||||
|
yacht.getLocation().getLng(),
|
||||||
|
yacht.getHeading(),
|
||||||
|
yacht.getCurrentVelocity().longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XMLMessage getRaceXML() {
|
||||||
|
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
||||||
|
List<Token> tokens = GameState.getTokensInPlay();
|
||||||
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
||||||
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
|
||||||
|
XMLMessage raceXMLMessage = new XMLMessage(
|
||||||
|
xmlGenerator.getRaceAsXml(),
|
||||||
|
XMLMessageSubType.RACE,
|
||||||
|
xmlGenerator.getRaceAsXml().length());
|
||||||
|
|
||||||
|
return raceXMLMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XMLMessage getRegattaXML() {
|
||||||
|
//@TODO calculate lat/lng values
|
||||||
|
xmlGenerator.setRegattaTemplate(
|
||||||
|
new RegattaXMLTemplate(
|
||||||
|
"Party Parrot Test Server", "Bermuda Test Course",
|
||||||
|
57.6679590, 11.8503233)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new XMLMessage(
|
||||||
|
xmlGenerator.getRegattaAsXml(),
|
||||||
|
XMLMessageSubType.REGATTA,
|
||||||
|
xmlGenerator.getRegattaAsXml().length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XMLMessage getBoatXML() {
|
||||||
|
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
||||||
|
List<Token> tokens = GameState.getTokensInPlay();
|
||||||
|
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
|
||||||
|
xmlGenerator.setRaceTemplate(raceXMLTemplate);
|
||||||
|
|
||||||
|
return new XMLMessage(
|
||||||
|
xmlGenerator.getBoatsAsXml(),
|
||||||
|
XMLMessageSubType.BOAT,
|
||||||
|
xmlGenerator.getBoatsAsXml().length());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,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.BoatLocationMessage;
|
import seng302.gameServer.messages.BoatLocationMessage;
|
||||||
|
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;
|
||||||
@@ -30,29 +31,13 @@ import seng302.gameServer.messages.RegistrationResponseStatus;
|
|||||||
import seng302.gameServer.messages.XMLMessage;
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.packets.PacketType;
|
import seng302.model.stream.packets.PacketType;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.xml.generator.Race;
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.model.token.Token;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
|
||||||
import seng302.gameServer.messages.BoatLocationMessage;
|
|
||||||
import seng302.gameServer.messages.ClientType;
|
|
||||||
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.Race;
|
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +45,7 @@ import seng302.utilities.XMLGenerator;
|
|||||||
* its own thread. All server threads created and owned by the server thread handler which can
|
* its own thread. All server threads created and owned by the server thread handler which can
|
||||||
* trigger client updates on its threads Created by wmu16 on 13/07/17.
|
* trigger client updates on its threads Created by wmu16 on 13/07/17.
|
||||||
*/
|
*/
|
||||||
public class ServerToClientThread implements Runnable, Observer {
|
public class ServerToClientThread implements Runnable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to notify listeners when this thread receives a connection correctly.
|
* Called to notify listeners when this thread receives a connection correctly.
|
||||||
@@ -91,8 +76,9 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
|
|
||||||
private ClientType clientType;
|
private ClientType clientType;
|
||||||
private Boolean isRegistered = false;
|
private Boolean isRegistered = false;
|
||||||
|
private Boolean isHost = false;
|
||||||
|
|
||||||
private XMLGenerator xml;
|
private XMLGenerator xmlGenerator;
|
||||||
|
|
||||||
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||||
private DisconnectListener disconnectListener;
|
private DisconnectListener disconnectListener;
|
||||||
@@ -144,21 +130,11 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
||||||
);
|
);
|
||||||
|
|
||||||
yacht.addObserver(this); // TODO: yacht can notify mark rounding message hyi25 13/8/17
|
|
||||||
player = new Player(socket, yacht);
|
player = new Player(socket, yacht);
|
||||||
GameState.addYacht(sourceId, yacht);
|
GameState.addYacht(sourceId, yacht);
|
||||||
GameState.addPlayer(player);
|
GameState.addPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(Observable o, Object arg) {
|
|
||||||
if (arg != null) {
|
|
||||||
sendMessage((Message) arg);
|
|
||||||
} else {
|
|
||||||
sendSetupMessages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void completeRegistration(ClientType clientType) throws IOException {
|
private void completeRegistration(ClientType clientType) throws IOException {
|
||||||
// Fail if not a player
|
// Fail if not a player
|
||||||
if (!clientType.equals(ClientType.PLAYER)){
|
if (!clientType.equals(ClientType.PLAYER)){
|
||||||
@@ -225,7 +201,12 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
|
|
||||||
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));
|
||||||
@@ -250,36 +231,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
logger.warn("Closed serverToClientThread" + thread, 1);
|
logger.warn("Closed serverToClientThread" + thread, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendSetupMessages() {
|
|
||||||
xml = new XMLGenerator();
|
|
||||||
Race race = new Race();
|
|
||||||
|
|
||||||
for (ServerYacht yacht : GameState.getYachts().values()) {
|
|
||||||
race.addBoat(yacht);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@TODO calculate lat/lng values
|
|
||||||
xml.setRegatta(
|
|
||||||
new Regatta(
|
|
||||||
"Party Parrot Test Server", "Bermuda Test Course",
|
|
||||||
57.6679590, 11.8503233)
|
|
||||||
);
|
|
||||||
xml.setRace(race);
|
|
||||||
|
|
||||||
XMLMessage xmlMessage;
|
|
||||||
xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA,
|
|
||||||
xml.getRegattaAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xml.getBoatsAsXml(), XMLMessageSubType.BOAT,
|
|
||||||
xml.getBoatsAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
|
|
||||||
xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE,
|
|
||||||
xml.getRaceAsXml().length());
|
|
||||||
sendMessage(xmlMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeSocket() {
|
private void closeSocket() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
@@ -334,23 +285,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
return seqNo;
|
return seqNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void sendBoatLocationPackets() {
|
|
||||||
ArrayList<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values());
|
|
||||||
for (ServerYacht yacht : yachts) {
|
|
||||||
BoatLocationMessage boatLocationMessage =
|
|
||||||
new BoatLocationMessage(
|
|
||||||
yacht.getSourceId(),
|
|
||||||
getSeqNo(),
|
|
||||||
yacht.getLocation().getLat(),
|
|
||||||
yacht.getLocation().getLng(),
|
|
||||||
yacht.getHeading(),
|
|
||||||
yacht.getCurrentVelocity().longValue());
|
|
||||||
|
|
||||||
sendMessage(boatLocationMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Thread getThread() {
|
public Thread getThread() {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
@@ -363,10 +297,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
@@ -386,4 +316,8 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.gameServer.messages.BoatStatus;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +17,7 @@ import seng302.utilities.GeoUtility;
|
|||||||
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
|
||||||
* not used anymore.
|
* not used anymore.
|
||||||
*/
|
*/
|
||||||
public class ServerYacht extends Observable {
|
public class ServerYacht {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
|
||||||
|
|
||||||
@@ -30,10 +31,8 @@ public class ServerYacht extends Observable {
|
|||||||
private String boatName;
|
private String boatName;
|
||||||
private String country;
|
private String country;
|
||||||
private BoatStatus boatStatus;
|
private BoatStatus boatStatus;
|
||||||
|
|
||||||
private Color boatColor;
|
private Color boatColor;
|
||||||
|
|
||||||
|
|
||||||
//Location
|
//Location
|
||||||
private Double lastHeading;
|
private Double lastHeading;
|
||||||
private Boolean sailIn;
|
private Boolean sailIn;
|
||||||
@@ -52,6 +51,10 @@ public class ServerYacht extends Observable {
|
|||||||
private Boolean hasPassedLine;
|
private Boolean hasPassedLine;
|
||||||
private Boolean hasPassedThroughGate;
|
private Boolean hasPassedThroughGate;
|
||||||
|
|
||||||
|
//PowerUp
|
||||||
|
private TokenType powerUp;
|
||||||
|
private Long powerUpStartTime;
|
||||||
|
|
||||||
|
|
||||||
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
|
||||||
String boatName, String country) {
|
String boatName, String country) {
|
||||||
@@ -71,6 +74,7 @@ public class ServerYacht extends Observable {
|
|||||||
this.currentMarkSeqID = 0;
|
this.currentMarkSeqID = 0;
|
||||||
this.legNumber = 0;
|
this.legNumber = 0;
|
||||||
this.boatColor = Colors.getColor(sourceId - 1);
|
this.boatColor = Colors.getColor(sourceId - 1);
|
||||||
|
this.powerUp = null;
|
||||||
|
|
||||||
this.hasEnteredRoundingZone = false;
|
this.hasEnteredRoundingZone = false;
|
||||||
this.hasPassedLine = false;
|
this.hasPassedLine = false;
|
||||||
@@ -101,13 +105,21 @@ public class ServerYacht extends Observable {
|
|||||||
location = geoPoint;
|
location = geoPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void powerUp(TokenType powerUp) {
|
||||||
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
|
this.powerUp = powerUp;
|
||||||
* rounding package.
|
powerUpStartTime = System.currentTimeMillis();
|
||||||
*/
|
}
|
||||||
@Override
|
|
||||||
public void addObserver(Observer o) {
|
public void powerDown() {
|
||||||
super.addObserver(o);
|
this.powerUp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPowerUpStartTime() {
|
||||||
|
return powerUpStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenType getPowerUp() {
|
||||||
|
return powerUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ import org.w3c.dom.Document;
|
|||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import seng302.gameServer.messages.RoundingSide;
|
import seng302.gameServer.messages.RoundingSide;
|
||||||
import seng302.model.stream.xml.generator.Race;
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.token.Token;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -125,7 +127,10 @@ public class MarkOrder {
|
|||||||
private void loadRaceProperties(){
|
private void loadRaceProperties(){
|
||||||
XMLGenerator generator = new XMLGenerator();
|
XMLGenerator generator = new XMLGenerator();
|
||||||
|
|
||||||
generator.setRace(new Race());
|
// TODO: 29/08/17 wmu16 - This is terrible, having to make a template just to receive constant data
|
||||||
|
generator.setRaceTemplate(new RaceXMLTemplate(
|
||||||
|
new ArrayList<>(),
|
||||||
|
new ArrayList<>()));
|
||||||
|
|
||||||
String raceXML = generator.getRaceAsXml();
|
String raceXML = generator.getRaceAsXml();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+15
-11
@@ -5,28 +5,23 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Race object that can be parsed into XML
|
* A Race object that can be parsed into XML
|
||||||
*/
|
*/
|
||||||
public class Race {
|
public class RaceXMLTemplate {
|
||||||
|
|
||||||
private List<ServerYacht> yachts;
|
private List<ServerYacht> yachts;
|
||||||
private LocalDateTime startTime;
|
private LocalDateTime startTime;
|
||||||
|
private List<Token> tokens;
|
||||||
|
|
||||||
public Race(){
|
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens) {
|
||||||
yachts = new ArrayList<>();
|
this.yachts = yachts;
|
||||||
|
this.tokens = tokens;
|
||||||
startTime = LocalDateTime.now();
|
startTime = LocalDateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a boat to the race
|
|
||||||
* @param yacht The boat to add
|
|
||||||
*/
|
|
||||||
public void addBoat(ServerYacht yacht) {
|
|
||||||
yachts.add(yacht);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of boats in the race
|
* Get a list of boats in the race
|
||||||
* @return A List of boats
|
* @return A List of boats
|
||||||
@@ -35,6 +30,15 @@ public class Race {
|
|||||||
return Collections.unmodifiableList(yachts);
|
return Collections.unmodifiableList(yachts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of tokens in the race
|
||||||
|
*
|
||||||
|
* @return A list of tokens
|
||||||
|
*/
|
||||||
|
public List<Token> getTokens() {
|
||||||
|
return Collections.unmodifiableList(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time until the race starts
|
* Set the time until the race starts
|
||||||
* @param seconds The time in seconds until the race starts
|
* @param seconds The time in seconds until the race starts
|
||||||
+2
-2
@@ -3,7 +3,7 @@ package seng302.model.stream.xml.generator;
|
|||||||
/**
|
/**
|
||||||
* A Race regatta that can be parsed into XML
|
* A Race regatta that can be parsed into XML
|
||||||
*/
|
*/
|
||||||
public class Regatta {
|
public class RegattaXMLTemplate {
|
||||||
private final Double DEFAULT_ALTITUDE = 0d;
|
private final Double DEFAULT_ALTITUDE = 0d;
|
||||||
private final Integer DEFAULT_REGATTA_ID = 0;
|
private final Integer DEFAULT_REGATTA_ID = 0;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public class Regatta {
|
|||||||
private Integer utcOffset;
|
private Integer utcOffset;
|
||||||
private Double magneticVariation;
|
private Double magneticVariation;
|
||||||
|
|
||||||
public Regatta(String name, String courseName, Double latitude, Double longitude) {
|
public RegattaXMLTemplate(String name, String courseName, Double latitude, Double longitude) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.id = DEFAULT_REGATTA_ID;
|
this.id = DEFAULT_REGATTA_ID;
|
||||||
this.courseName = courseName;
|
this.courseName = courseName;
|
||||||
@@ -6,6 +6,7 @@ import java.util.Map;
|
|||||||
import seng302.model.Limit;
|
import seng302.model.Limit;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a Document object containing race data in XML format and stores the data.
|
* Process a Document object containing race data in XML format and stores the data.
|
||||||
@@ -13,13 +14,16 @@ import seng302.model.mark.Corner;
|
|||||||
public class RaceXMLData {
|
public class RaceXMLData {
|
||||||
|
|
||||||
private List<Integer> participants;
|
private List<Integer> participants;
|
||||||
|
private List<Token> tokens;
|
||||||
private Map<Integer, CompoundMark> compoundMarks;
|
private Map<Integer, CompoundMark> compoundMarks;
|
||||||
private List<Corner> markSequence;
|
private List<Corner> markSequence;
|
||||||
private List<Limit> courseLimit;
|
private List<Limit> courseLimit;
|
||||||
|
|
||||||
public RaceXMLData(List<Integer> participants, List<CompoundMark> compoundMarks,
|
public RaceXMLData(List<Integer> participants, List<Token> tokens,
|
||||||
|
List<CompoundMark> compoundMarks,
|
||||||
List<Corner> markSequence, List<Limit> courseLimit) {
|
List<Corner> markSequence, List<Limit> courseLimit) {
|
||||||
this.participants = participants;
|
this.participants = participants;
|
||||||
|
this.tokens = tokens;
|
||||||
this.markSequence = markSequence;
|
this.markSequence = markSequence;
|
||||||
this.courseLimit = courseLimit;
|
this.courseLimit = courseLimit;
|
||||||
this.compoundMarks = new HashMap<>();
|
this.compoundMarks = new HashMap<>();
|
||||||
@@ -32,6 +36,10 @@ public class RaceXMLData {
|
|||||||
return participants;
|
return participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Token> getTokens() {
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, CompoundMark> getCompoundMarks() {
|
public Map<Integer, CompoundMark> getCompoundMarks() {
|
||||||
return compoundMarks;
|
return compoundMarks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package seng302.model.token;
|
||||||
|
|
||||||
|
import seng302.model.GeoPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class describing a game token
|
||||||
|
* Created by wmu16 on 28/08/17.
|
||||||
|
*/
|
||||||
|
public class Token extends GeoPoint {
|
||||||
|
|
||||||
|
private TokenType tokenType;
|
||||||
|
|
||||||
|
public Token(TokenType tokenType, double lat, double lng) {
|
||||||
|
super(lat, lng);
|
||||||
|
this.tokenType = tokenType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenType getTokenType() {
|
||||||
|
return tokenType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package seng302.model.token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum describing the different types of game objects
|
||||||
|
* Created by wmu16 on 28/08/17.
|
||||||
|
*/
|
||||||
|
public enum TokenType {
|
||||||
|
BOOST(0),
|
||||||
|
HANDLING(1);
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
TokenType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenType getToken(int value) {
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
return BOOST;
|
||||||
|
case 1:
|
||||||
|
return HANDLING;
|
||||||
|
default:
|
||||||
|
return BOOST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
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 AudioClip hoverSoundPlayer = new AudioClip(Sounds.class.getClassLoader().getResource("sounds/sound-over.wav").toExternalForm());;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
hoverSoundPlayer.setVolume(2.5);
|
||||||
|
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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import seng302.model.stream.xml.generator.Race;
|
import seng302.model.stream.xml.generator.RaceXMLTemplate;
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,8 +20,8 @@ public class XMLGenerator {
|
|||||||
private static final String BOATS_TEMPLATE_NAME = "boats.ftlh";
|
private static final String BOATS_TEMPLATE_NAME = "boats.ftlh";
|
||||||
private static final String RACE_TEMPLATE_NAME = "race.ftlh";
|
private static final String RACE_TEMPLATE_NAME = "race.ftlh";
|
||||||
private Configuration configuration;
|
private Configuration configuration;
|
||||||
private Regatta regatta;
|
private RegattaXMLTemplate regatta;
|
||||||
private Race race;
|
private RaceXMLTemplate race;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up a configuration instance for Apache Freemake
|
* Set up a configuration instance for Apache Freemake
|
||||||
@@ -48,7 +48,7 @@ public class XMLGenerator {
|
|||||||
* Note: This must be set before a regatta message can be generated
|
* Note: This must be set before a regatta message can be generated
|
||||||
* @param regatta The race regatta
|
* @param regatta The race regatta
|
||||||
*/
|
*/
|
||||||
public void setRegatta(Regatta regatta){
|
public void setRegattaTemplate(RegattaXMLTemplate regatta) {
|
||||||
this.regatta = regatta;
|
this.regatta = regatta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ public class XMLGenerator {
|
|||||||
* Note: This must be set before a boat or race message can be generated
|
* Note: This must be set before a boat or race message can be generated
|
||||||
* @param race The race
|
* @param race The race
|
||||||
*/
|
*/
|
||||||
public void setRace(Race race){
|
public void setRaceTemplate(RaceXMLTemplate race) {
|
||||||
this.race = race;
|
this.race = race;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import seng302.model.mark.Corner;
|
|||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
import seng302.model.stream.xml.parser.RegattaXMLData;
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
import seng302.model.token.TokenType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for parsing XML documents
|
* Utilities for parsing XML documents
|
||||||
@@ -182,12 +184,32 @@ public class XMLParser {
|
|||||||
Element docEle = doc.getDocumentElement();
|
Element docEle = doc.getDocumentElement();
|
||||||
return new RaceXMLData(
|
return new RaceXMLData(
|
||||||
extractParticpantIDs(docEle),
|
extractParticpantIDs(docEle),
|
||||||
|
extractTokens(docEle),
|
||||||
extractCompoundMarks(docEle),
|
extractCompoundMarks(docEle),
|
||||||
extractMarkOrder(docEle),
|
extractMarkOrder(docEle),
|
||||||
extractCourseLimit(docEle)
|
extractCourseLimit(docEle)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts token data
|
||||||
|
*/
|
||||||
|
private static List<Token> extractTokens(Element docEle) {
|
||||||
|
List<Token> tokens = new ArrayList<>();
|
||||||
|
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
|
||||||
|
for (int i = 0; i < tokenList.getLength(); i++) {
|
||||||
|
Node tokenNode = tokenList.item(i);
|
||||||
|
if (tokenNode.getNodeName().equals("Token")) {
|
||||||
|
String tokenType = getNodeAttributeString(tokenNode, "TokenType");
|
||||||
|
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
|
||||||
|
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
|
||||||
|
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts course limit data
|
* Extracts course limit data
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -33,8 +34,6 @@ import seng302.model.stream.packets.StreamPacket;
|
|||||||
*/
|
*/
|
||||||
public class ClientToServerThread implements Runnable {
|
public class ClientToServerThread implements Runnable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional interface for receiving packets from client socket.
|
* Functional interface for receiving packets from client socket.
|
||||||
*/
|
*/
|
||||||
@@ -95,7 +94,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
|
|
||||||
sendRegistrationRequest();
|
sendRegistrationRequest();
|
||||||
|
|
||||||
thread = new Thread(this);
|
thread = new Thread(this, "ClientToServer");
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,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");
|
||||||
@@ -294,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,8 +1,11 @@
|
|||||||
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.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;
|
||||||
@@ -12,12 +15,15 @@ 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 javafx.util.Pair;
|
||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.gameServer.MainServerThread;
|
import seng302.gameServer.MainServerThread;
|
||||||
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;
|
||||||
@@ -28,6 +34,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.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
import seng302.visualiser.controllers.FinishScreenViewController;
|
import seng302.visualiser.controllers.FinishScreenViewController;
|
||||||
@@ -53,6 +60,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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,11 +151,10 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadStartScreen() {
|
private void loadStartScreen() {
|
||||||
|
if (socketThread != null) {
|
||||||
socketThread.setSocketToClose();
|
socketThread.setSocketToClose();
|
||||||
if (server != null) {
|
|
||||||
server.terminate();
|
|
||||||
server = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
getClass().getResource("/views/StartScreenView.fxml"));
|
getClass().getResource("/views/StartScreenView.fxml"));
|
||||||
try {
|
try {
|
||||||
@@ -195,9 +203,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());
|
||||||
@@ -248,6 +266,7 @@ public class GameClient {
|
|||||||
courseData = XMLParser.parseRace(
|
courseData = XMLParser.parseRace(
|
||||||
StreamParser.extractXmlMessage(packet)
|
StreamParser.extractXmlMessage(packet)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (raceView != null) {
|
if (raceView != null) {
|
||||||
raceView.updateRaceData(courseData);
|
raceView.updateRaceData(courseData);
|
||||||
}
|
}
|
||||||
@@ -278,8 +297,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()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +352,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()
|
||||||
);
|
);
|
||||||
@@ -335,6 +366,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +384,7 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (raceFinished) {
|
if (raceFinished) {
|
||||||
|
Sounds.playFinishSound();
|
||||||
close();
|
close();
|
||||||
loadFinishScreenView();
|
loadFinishScreenView();
|
||||||
}
|
}
|
||||||
@@ -373,6 +408,12 @@ public class GameClient {
|
|||||||
* @param e The key event triggering this call
|
* @param e The key event triggering this call
|
||||||
*/
|
*/
|
||||||
private 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;
|
||||||
@@ -381,12 +422,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private 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
|
||||||
@@ -407,13 +452,31 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void formatAndSendChatMessage(String rawChat) {
|
||||||
|
if (rawChat.length() > 0) {
|
||||||
|
socketThread.sendChatterMessage(
|
||||||
|
new SimpleDateFormat("[HH:mm:ss] ").format(new Date()) +
|
||||||
|
allBoatsMap.get(socketThread.getClientId()).getShortName() + ": " + rawChat
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ClientToServerThread getSocketThread() {
|
||||||
|
return socketThread;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ import seng302.model.Limit;
|
|||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Corner;
|
import seng302.model.mark.Corner;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
|
import seng302.model.token.Token;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.fxObjects.AnnotationBox;
|
import seng302.visualiser.fxObjects.AnnotationBox;
|
||||||
import seng302.visualiser.fxObjects.BoatObject;
|
import seng302.visualiser.fxObjects.BoatObject;
|
||||||
import seng302.visualiser.fxObjects.CourseBoundary;
|
import seng302.visualiser.fxObjects.CourseBoundary;
|
||||||
@@ -64,6 +66,8 @@ public class GameView extends Pane {
|
|||||||
private double referencePointX, referencePointY;
|
private double referencePointX, referencePointY;
|
||||||
private double metersPerPixelX, metersPerPixelY;
|
private double metersPerPixelX, metersPerPixelY;
|
||||||
|
|
||||||
|
private boolean isZoom = false;
|
||||||
|
|
||||||
private Text fpsDisplay = new Text();
|
private Text fpsDisplay = new Text();
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
|
|
||||||
@@ -81,6 +85,7 @@ public class GameView extends Pane {
|
|||||||
private Group boatObjectGroup = new Group();
|
private Group boatObjectGroup = new Group();
|
||||||
private Group trails = new Group();
|
private Group trails = new Group();
|
||||||
private Group markers = new Group();
|
private Group markers = new Group();
|
||||||
|
private Group tokens = new Group();
|
||||||
private List<CompoundMark> course = new ArrayList<>();
|
private List<CompoundMark> course = new ArrayList<>();
|
||||||
|
|
||||||
private ImageView mapImage = new ImageView();
|
private ImageView mapImage = new ImageView();
|
||||||
@@ -100,7 +105,7 @@ public class GameView extends Pane {
|
|||||||
|
|
||||||
private void zoomOut() {
|
private void zoomOut() {
|
||||||
scaleFactor = 0.1;
|
scaleFactor = 0.1;
|
||||||
if (this.getScaleX() > 0.5) {
|
if (this.isZoom && this.getScaleX() > 0.5) {
|
||||||
this.setScaleX(this.getScaleX() - scaleFactor);
|
this.setScaleX(this.getScaleX() - scaleFactor);
|
||||||
this.setScaleY(this.getScaleY() - scaleFactor);
|
this.setScaleY(this.getScaleY() - scaleFactor);
|
||||||
}
|
}
|
||||||
@@ -108,7 +113,7 @@ public class GameView extends Pane {
|
|||||||
|
|
||||||
private void zoomIn() {
|
private void zoomIn() {
|
||||||
scaleFactor = 0.1;
|
scaleFactor = 0.1;
|
||||||
if (this.getScaleX() < 2.5) {
|
if (this.isZoom && this.getScaleX() < 2.5) {
|
||||||
this.setScaleX(this.getScaleX() + scaleFactor);
|
this.setScaleX(this.getScaleX() + scaleFactor);
|
||||||
this.setScaleY(this.getScaleY() + scaleFactor);
|
this.setScaleY(this.getScaleY() + scaleFactor);
|
||||||
}
|
}
|
||||||
@@ -140,7 +145,15 @@ public class GameView extends Pane {
|
|||||||
gameObjects.add(mapImage);
|
gameObjects.add(mapImage);
|
||||||
gameObjects.add(raceBorder);
|
gameObjects.add(raceBorder);
|
||||||
gameObjects.add(markers);
|
gameObjects.add(markers);
|
||||||
|
gameObjects.add(tokens);
|
||||||
initializeTimer();
|
initializeTimer();
|
||||||
|
this.sceneProperty().addListener(((observable, oldValue, scene) -> {
|
||||||
|
if (scene != null) {
|
||||||
|
setupZoom();
|
||||||
|
} else {
|
||||||
|
disableZoom();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
this.widthProperty().addListener(new ChangeListener<Number>() {
|
this.widthProperty().addListener(new ChangeListener<Number>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -468,14 +481,33 @@ public class GameView extends Pane {
|
|||||||
raceBorder.getPoints().setAll(boundaryPoints);
|
raceBorder.getPoints().setAll(boundaryPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces all tokens in the course with those passed in
|
||||||
|
*
|
||||||
|
* @param newTokens the tokens to be put on the course.
|
||||||
|
*/
|
||||||
|
public void updateTokens(List<Token> newTokens) {
|
||||||
|
|
||||||
|
List<Marker> mapTokens = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Token token : newTokens) {
|
||||||
|
Point2D location = findScaledXY(token.getLat(), token.getLng());
|
||||||
|
Marker thisMarker = new Marker(Color.YELLOW);
|
||||||
|
thisMarker.setLayoutX(location.getX());
|
||||||
|
thisMarker.setLayoutY(location.getY());
|
||||||
|
mapTokens.add(thisMarker);
|
||||||
|
}
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
tokens.getChildren().clear();
|
||||||
|
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.
|
* Enables zoom. Has to be called after this is added to a scene.
|
||||||
*/
|
*/
|
||||||
public void enableZoom () {
|
private void setupZoom() {
|
||||||
System.out.println("enable zoom");
|
|
||||||
if (this.getScene() != null) {
|
|
||||||
System.out.println("can zoom");
|
|
||||||
this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
|
this.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (event) -> {
|
||||||
if (event.getCode() == KeyCode.Z) {
|
if (event.getCode() == KeyCode.Z) {
|
||||||
zoomIn();
|
zoomIn();
|
||||||
@@ -483,8 +515,17 @@ public class GameView extends Pane {
|
|||||||
zoomOut();
|
zoomOut();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
enableZoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void enableZoom() {
|
||||||
|
isZoom = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disableZoom() {
|
||||||
|
isZoom = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rescales the race to the size of the window.
|
* Rescales the race to the size of the window.
|
||||||
*
|
*
|
||||||
@@ -817,15 +858,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.
|
||||||
if (compoundMark != null) {
|
|
||||||
for (Mark mark : compoundMark.getMarks()) {
|
|
||||||
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();
|
||||||
@@ -839,6 +876,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 {
|
public class CustomizationController {
|
||||||
@@ -34,7 +35,8 @@ public class CustomizationController {
|
|||||||
|
|
||||||
@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,11 @@ public class FinishScreenViewController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void switchToStartScreenView() {
|
public void switchToStartScreenView() {
|
||||||
|
Sounds.playButtonClick();
|
||||||
setContentPane("/views/StartScreenView.fxml");
|
setContentPane("/views/StartScreenView.fxml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
|
Sounds.playHoverSound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
@@ -23,6 +24,7 @@ import seng302.gameServer.GameStages;
|
|||||||
import seng302.gameServer.GameState;
|
import seng302.gameServer.GameState;
|
||||||
import seng302.model.Colors;
|
import seng302.model.Colors;
|
||||||
import seng302.model.RaceState;
|
import seng302.model.RaceState;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.ClientToServerThread;
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +33,10 @@ import seng302.visualiser.ClientToServerThread;
|
|||||||
*/
|
*/
|
||||||
public class LobbyController {
|
public class LobbyController {
|
||||||
|
|
||||||
|
public void playButtonHoverSound(MouseEvent mouseEvent) {
|
||||||
|
Sounds.playHoverSound();
|
||||||
|
}
|
||||||
|
|
||||||
public enum CloseStatus {
|
public enum CloseStatus {
|
||||||
LEAVE,
|
LEAVE,
|
||||||
READY
|
READY
|
||||||
@@ -153,6 +159,7 @@ public class LobbyController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void customize() {
|
public void customize() {
|
||||||
|
Sounds.playButtonClick();
|
||||||
Parent root;
|
Parent root;
|
||||||
try {
|
try {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(LobbyController.class.getResource("/views/customizeView.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(LobbyController.class.getResource("/views/customizeView.fxml"));
|
||||||
@@ -184,6 +191,7 @@ public class LobbyController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void leaveLobbyButtonPressed() {
|
public void leaveLobbyButtonPressed() {
|
||||||
|
Sounds.playButtonClick();
|
||||||
// TODO: 10/07/17 wmu16 - Finish function!
|
// TODO: 10/07/17 wmu16 - Finish function!
|
||||||
GameState.setCurrentStage(GameStages.CANCELLED);
|
GameState.setCurrentStage(GameStages.CANCELLED);
|
||||||
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game
|
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game
|
||||||
@@ -193,6 +201,7 @@ public class LobbyController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void readyButtonPressed() {
|
public void readyButtonPressed() {
|
||||||
|
Sounds.playButtonClick();
|
||||||
GameState.setCurrentStage(GameStages.PRE_RACE);
|
GameState.setCurrentStage(GameStages.PRE_RACE);
|
||||||
// Do countdown logic here
|
// Do countdown logic here
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.TimerTask;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
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.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@@ -25,6 +26,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.control.TextField;
|
||||||
|
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 javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
@@ -41,18 +44,31 @@ import seng302.model.RaceState;
|
|||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.stream.xml.parser.RaceXMLData;
|
import seng302.model.stream.xml.parser.RaceXMLData;
|
||||||
|
import seng302.model.token.Token;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameView;
|
import seng302.visualiser.GameView;
|
||||||
import seng302.visualiser.controllers.annotations.Annotation;
|
import seng302.visualiser.controllers.annotations.Annotation;
|
||||||
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.BoatObject;
|
||||||
|
import seng302.visualiser.fxObjects.ChatHistory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class that manages the display of a race
|
* Controller class that manages the display of a race
|
||||||
*/
|
*/
|
||||||
public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
|
public class RaceViewController extends Thread 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
|
||||||
@@ -85,12 +101,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
private GameView gameView;
|
private GameView 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 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();
|
||||||
|
|
||||||
@@ -101,10 +122,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
raceSparkLine.visibleProperty().setValue(false);
|
raceSparkLine.visibleProperty().setValue(false);
|
||||||
raceSparkLine.getYAxis().setAutoRanging(false);
|
raceSparkLine.getYAxis().setAutoRanging(false);
|
||||||
sparklineYAxis.setTickMarkVisible(false);
|
sparklineYAxis.setTickMarkVisible(false);
|
||||||
|
|
||||||
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
||||||
|
|
||||||
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
|
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);
|
||||||
|
// });
|
||||||
|
contentAnchorPane.setOnMouseClicked((event) ->
|
||||||
|
contentAnchorPane.requestFocus()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRace (
|
public void loadRace (
|
||||||
@@ -116,12 +157,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()) {
|
||||||
@@ -137,10 +172,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView));
|
Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView));
|
||||||
gameView.setBoats(new ArrayList<>(participants.values()));
|
gameView.setBoats(new ArrayList<>(participants.values()));
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
|
gameView.updateTokens(raceData.getTokens());
|
||||||
gameView.updateCourse(
|
gameView.updateCourse(
|
||||||
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
|
||||||
);
|
);
|
||||||
gameView.enableZoom();
|
|
||||||
gameView.setBoatAsPlayer(player);
|
gameView.setBoatAsPlayer(player);
|
||||||
gameView.startRace();
|
gameView.startRace();
|
||||||
|
|
||||||
@@ -155,6 +190,20 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
updateWindDirection(raceState.windDirectionProperty().doubleValue());
|
updateWindDirection(raceState.windDirectionProperty().doubleValue());
|
||||||
updateWindSpeed(raceState.getWindSpeed());
|
updateWindSpeed(raceState.getWindSpeed());
|
||||||
gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
|
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();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -305,13 +354,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()
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -533,10 +575,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
* for the combobox to take action upon selection
|
* for the combobox to take action upon selection
|
||||||
*/
|
*/
|
||||||
private void initialiseBoatSelectionComboBox() {
|
private void initialiseBoatSelectionComboBox() {
|
||||||
yachtSelectionComboBox.setItems(
|
selectionComboBoxList.setAll(participants.values());
|
||||||
FXCollections.observableArrayList(participants.values())
|
yachtSelectionComboBox.setItems(selectionComboBoxList);
|
||||||
);
|
|
||||||
//Null check is if the listener is fired but nothing selected
|
|
||||||
yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
|
||||||
if (selectedBoat != null) {
|
if (selectedBoat != null) {
|
||||||
gameView.selectBoat(selectedBoat);
|
gameView.selectBoat(selectedBoat);
|
||||||
@@ -621,5 +661,26 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
public void updateRaceData (RaceXMLData raceData) {
|
public void updateRaceData (RaceXMLData raceData) {
|
||||||
this.courseData = raceData;
|
this.courseData = raceData;
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
|
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,12 +6,16 @@ import java.net.NetworkInterface;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.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.GameState;
|
import seng302.gameServer.GameState;
|
||||||
|
import seng302.utilities.Sounds;
|
||||||
import seng302.visualiser.GameClient;
|
import seng302.visualiser.GameClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,114 +24,56 @@ import seng302.visualiser.GameClient;
|
|||||||
*/
|
*/
|
||||||
public class StartScreenController implements Initializable {
|
public class StartScreenController implements Initializable {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ToggleButton muteMusicButton;
|
||||||
|
@FXML
|
||||||
|
private ToggleButton muteSoundsButton;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField ipTextField;
|
private TextField ipTextField;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField portTextField;
|
|
||||||
@FXML
|
|
||||||
private GridPane startScreen2;
|
|
||||||
@FXML
|
|
||||||
private AnchorPane holder;
|
private AnchorPane holder;
|
||||||
|
|
||||||
GameClient gameClient;
|
private GameClient gameClient;
|
||||||
|
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
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);
|
// gameClient = new GameClient(holder);
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Loads the fxml content into the parent pane
|
|
||||||
// * @param jfxUrl
|
|
||||||
// * @return the controller of the fxml
|
|
||||||
// */
|
|
||||||
// private Object setContentPane(String jfxUrl) {
|
|
||||||
// try {
|
|
||||||
// AnchorPane contentPane = (AnchorPane) startScreen2.getParent();
|
|
||||||
// contentPane.getChildren().removeAll();
|
|
||||||
// contentPane.getChildren().clear();
|
|
||||||
// contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
|
|
||||||
// FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(jfxUrl));
|
|
||||||
// contentPane.getChildren().addAll((Pane) fxmlLoader.load());
|
|
||||||
//
|
|
||||||
// return fxmlLoader.getController();
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ATTEMPTS TO:
|
* Creates an instance of GameClient and runs it as a host.
|
||||||
* Sets up a new game state with your IP address as designated as the host.
|
|
||||||
* Starts a thread to listen for incoming connections.
|
|
||||||
* Starts a client to server thread and connects to own ip.
|
|
||||||
* Switches to the lobby screen
|
|
||||||
*/
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
public void hostButtonPressed() {
|
public void hostButtonPressed() {
|
||||||
// new GameState(getLocalHostIp());
|
Sounds.playButtonClick();
|
||||||
gameClient = new GameClient(holder);
|
gameClient = new GameClient(holder);
|
||||||
gameClient.runAsHost(getLocalHostIp(), 4942);
|
gameClient.runAsHost(getLocalHostIp(), 4942);
|
||||||
// try {
|
|
||||||
//// String ipAddress = InetAddress.getLocalHost().getHostAddress();
|
|
||||||
//// new GameState(ipAddress);
|
|
||||||
//// new MainServerThread();
|
|
||||||
//// ClientToServerThread clientToServerThread = new ClientToServerThread("localhost", 4950);
|
|
||||||
//// controller.setClientToServerThread(clientToServerThread);
|
|
||||||
// // get the lobby controller so that we can pass the game server thread to it
|
|
||||||
// new GameState(getLocalHostIp());
|
|
||||||
// MainServerThread mainServerThread = new MainServerThread();
|
|
||||||
//// ClientState.setHost(true);
|
|
||||||
// // host will connect and handshake to itself after setting up the server
|
|
||||||
// // TODO: 24/07/17 wmu16 - Make port number some static global type constant?
|
|
||||||
//// ClientToServerThread clientToServerThread = new ClientToServerThread(ClientState.getHostIp(), 4942);
|
|
||||||
//// ClientState.setConnectedToHost(true);
|
|
||||||
//// controller.setClientToServerThread(clientToServerThread);
|
|
||||||
// LobbyController lobbyController = (LobbyController) setContentPane("/views/LobbyView.fxml");
|
|
||||||
// lobbyController.setMainServerThread(mainServerThread);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// Alert alert = new Alert(AlertType.ERROR);
|
|
||||||
// alert.setHeaderText("Cannot host");
|
|
||||||
// alert.setContentText("Oops, failed to host, try to restart.");
|
|
||||||
// alert.showAndWait();
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ATTEMPTS TO:
|
* Creates an instance of GameClient and runs it has a client.
|
||||||
* Connect to an ip address and port using the ip and port specified on start screen.
|
|
||||||
* Starts a Client To Server Thread to maintain connection to host.
|
|
||||||
* Switch view to lobby view.
|
|
||||||
*/
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
public void connectButtonPressed() {
|
public void connectButtonPressed() {
|
||||||
// TODO: 10/07/17 wmu16 - Finish function
|
// TODO: 10/07/17 wmu16 - Finish function
|
||||||
|
Sounds.playButtonClick();
|
||||||
gameClient = new GameClient(holder);
|
gameClient = new GameClient(holder);
|
||||||
gameClient.runAsClient(ipTextField.getText().trim().toLowerCase(), 4942);
|
gameClient.runAsClient(ipTextField.getText().trim().toLowerCase(), 4942);
|
||||||
|
|
||||||
// try {
|
|
||||||
// String ipAddress = ipTextField.getText().trim().toLowerCase();
|
|
||||||
// Integer port = Integer.valueOf(portTextField.getText().trim());
|
|
||||||
//
|
|
||||||
//// ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, port);
|
|
||||||
//// ClientState.setHost(false);
|
|
||||||
//// ClientState.setConnectedToHost(true);
|
|
||||||
//
|
|
||||||
//// controller.setClientToServerThread(clientToServerThread);
|
|
||||||
//// setContentPane("/views/LobbyView.fxml");
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// Alert alert = new Alert(AlertType.ERROR);
|
|
||||||
// alert.setHeaderText("Cannot reach the host");
|
|
||||||
// alert.setContentText("Please check your host IP address.");
|
|
||||||
// alert.showAndWait();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setController(Controller controller) {
|
|
||||||
// this.controller = controller;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the local host ip address and sets this ip to ClientState.
|
* Gets the local host ip address and sets this ip to ClientState.
|
||||||
@@ -162,7 +108,30 @@ public class StartScreenController implements Initializable {
|
|||||||
if (ipAddress == null) {
|
if (ipAddress == null) {
|
||||||
System.out.println("[HOST] Cannot obtain local host ip address.");
|
System.out.println("[HOST] Cannot obtain local host ip address.");
|
||||||
}
|
}
|
||||||
// ClientState.setHostIp(ipAddress);
|
|
||||||
return ipAddress;
|
return ipAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 |
@@ -12,6 +12,8 @@
|
|||||||
<Yacht SourceID="105" />
|
<Yacht SourceID="105" />
|
||||||
<Yacht SourceID="106" />
|
<Yacht SourceID="106" />
|
||||||
</Participants>
|
</Participants>
|
||||||
|
<Tokens>
|
||||||
|
</Tokens>
|
||||||
<Course>
|
<Course>
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330" SourceID="122" />
|
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330" SourceID="122" />
|
||||||
|
|||||||
@@ -4,13 +4,16 @@
|
|||||||
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
<RaceStartTime Start="${raceStartTime}" Postpone="False" />
|
||||||
<RaceID>15082901</RaceID>
|
<RaceID>15082901</RaceID>
|
||||||
<RaceType>Fleet</RaceType>
|
<RaceType>Fleet</RaceType>
|
||||||
|
|
||||||
<Participants>
|
<Participants>
|
||||||
<#list boats as boat>
|
<#list boats as boat>
|
||||||
<Yacht SourceID="${boat.sourceId}"/>
|
<Yacht SourceID="${boat.sourceId}"/>
|
||||||
</#list>
|
</#list>
|
||||||
</Participants>
|
</Participants>
|
||||||
|
<Tokens>
|
||||||
|
<#list tokens as token>
|
||||||
|
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
|
||||||
|
</#list>
|
||||||
|
</Tokens>
|
||||||
<Course>
|
<Course>
|
||||||
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
<CompoundMark CompoundMarkID="1" Name="Mark0">
|
||||||
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.670603" TargetLng="11.828262" SourceID="122" />
|
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.670603" TargetLng="11.828262" SourceID="122" />
|
||||||
|
|||||||
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>
|
||||||
|
|||||||
@@ -37,9 +37,9 @@
|
|||||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<Button fx:id="readyButton" focusTraversable="false" mnemonicParsing="false" onAction="#readyButtonPressed" prefWidth="101.0" text="Ready" GridPane.halignment="CENTER" />
|
<Button fx:id="readyButton" focusTraversable="false" mnemonicParsing="false" onAction="#readyButtonPressed" onMouseEntered="#playButtonHoverSound" prefWidth="101.0" text="Ready" GridPane.halignment="CENTER" />
|
||||||
<Button focusTraversable="false" mnemonicParsing="false" onAction="#leaveLobbyButtonPressed" text="Leave Lobby" GridPane.columnIndex="2" GridPane.halignment="CENTER" />
|
<Button focusTraversable="false" mnemonicParsing="false" onAction="#leaveLobbyButtonPressed" onMouseEntered="#playButtonHoverSound" text="Leave Lobby" GridPane.columnIndex="2" GridPane.halignment="CENTER" />
|
||||||
<Button fx:id="customizeButton" focusTraversable="false" mnemonicParsing="false" onAction="#customize" text="Customization" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
<Button fx:id="customizeButton" focusTraversable="false" mnemonicParsing="false" onAction="#customize" onMouseEntered="#playButtonHoverSound" text="Customization" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
<GridPane GridPane.rowIndex="1">
|
<GridPane GridPane.rowIndex="1">
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
<children>
|
<children>
|
||||||
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
<GridPane fx:id="startScreen2" layoutX="365.0" layoutY="285.0" nodeOrientation="LEFT_TO_RIGHT" prefWidth="800.0" style="-fx-background-color: #2C2c36;">
|
||||||
<children>
|
<children>
|
||||||
<Label alignment="CENTER" text="Welcome to Race Vision" textFill="WHITE" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
|
<Label alignment="CENTER" text="Party Parrots at Sea" textFill="WHITE" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="BOTTOM">
|
||||||
<font>
|
<font>
|
||||||
<Font size="40.0" />
|
<Font size="40.0" />
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</Label>
|
||||||
<Button mnemonicParsing="false" onAction="#hostButtonPressed" prefHeight="25.0" prefWidth="175.0" text="Host" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
|
<Button mnemonicParsing="false" onAction="#hostButtonPressed" onMouseEntered="#playButtonHoverSound" prefHeight="25.0" prefWidth="175.0" text="Host" GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
|
||||||
<Button mnemonicParsing="false" onAction="#connectButtonPressed" prefHeight="25.0" prefWidth="147.0" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
<Button mnemonicParsing="false" onAction="#connectButtonPressed" onMouseEntered="#playButtonHoverSound" prefHeight="25.0" prefWidth="147.0" text="Connect" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets left="5.0" right="5.0" />
|
<Insets left="5.0" right="5.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
@@ -49,6 +49,27 @@
|
|||||||
<Insets left="5.0" right="5.0" />
|
<Insets left="5.0" right="5.0" />
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
<GridPane GridPane.columnSpan="2" GridPane.rowIndex="5">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<ToggleButton fx:id="muteMusicButton" mnemonicParsing="false" onAction="#toggleMusic" onMouseEntered="#playButtonHoverSound" prefWidth="130.0" text="Mute Music" GridPane.halignment="RIGHT">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton fx:id="muteSoundsButton" mnemonicParsing="false" onAction="#toggleSounds" onMouseEntered="#playButtonHoverSound" prefWidth="130.0" text="Mute Sounds" GridPane.columnIndex="1">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</GridPane.margin>
|
||||||
|
</ToggleButton>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="442.0" />
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="442.0" />
|
||||||
|
|||||||
@@ -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