mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge branch 'text_chat' into Story1249_SoundsAndMusic
# Conflicts: # src/main/java/seng302/gameServer/GameState.java # src/main/java/seng302/visualiser/GameClient.java # src/main/java/seng302/visualiser/controllers/StartScreenController.java
This commit is contained in:
@@ -15,6 +15,7 @@ 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;
|
||||||
@@ -41,7 +42,6 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface NewMessageListener {
|
interface NewMessageListener {
|
||||||
|
|
||||||
void notify(Message message);
|
void notify(Message message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +59,7 @@ public class GameState implements Runnable {
|
|||||||
private static Long previousUpdateTime;
|
private static Long previousUpdateTime;
|
||||||
public static Double windDirection;
|
public static Double windDirection;
|
||||||
private static Double windSpeed;
|
private static Double windSpeed;
|
||||||
|
private static Double speedMultiplier = 1d;
|
||||||
|
|
||||||
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
|
||||||
|
|
||||||
@@ -72,19 +73,9 @@ 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<NewMessageListener> messageListeners;
|
||||||
|
|
||||||
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;
|
||||||
@@ -100,7 +91,7 @@ public class GameState implements Runnable {
|
|||||||
//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<>();
|
messageListeners = new ArrayList<>();
|
||||||
|
|
||||||
resetStartTime();
|
resetStartTime();
|
||||||
|
|
||||||
@@ -366,7 +357,7 @@ public class GameState implements Runnable {
|
|||||||
Double velocity = yacht.getCurrentVelocity();
|
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) * 5;
|
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier;
|
||||||
// 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 (velocity < maxBoatSpeed - 500) {
|
||||||
@@ -671,8 +662,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 : messageListeners) {
|
||||||
mpl.notify(message);
|
ml.notify(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,7 +676,7 @@ public class GameState implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
public static void addMarkPassListener(NewMessageListener listener) {
|
public static void addMarkPassListener(NewMessageListener listener) {
|
||||||
markListeners.add(listener);
|
messageListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCustomizationFlag() {
|
public static void setCustomizationFlag() {
|
||||||
@@ -699,4 +690,21 @@ public class GameState implements Runnable {
|
|||||||
public static void resetCustomizationFlag() {
|
public static void resetCustomizationFlag() {
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void broadcastChatter(ChatterMessage chatterMessage) {
|
||||||
|
notifyMessageListeners(chatterMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,20 +44,23 @@ 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(){
|
||||||
Message heartbeat = new Heartbeat(seqNum);
|
try {
|
||||||
for (Player player : GameState.getPlayers()){
|
Message heartbeat = new Heartbeat(seqNum);
|
||||||
if (!player.getSocket().isConnected()) {
|
for (Player player : GameState.getPlayers()) {
|
||||||
playerLostConnection(player);
|
if (!player.getSocket().isConnected()) {
|
||||||
}
|
playerLostConnection(player);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
|
player.getSocket().getOutputStream().write(heartbeat.getBuffer());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
playerLostConnection(player);
|
playerLostConnection(player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
updateDelegate();
|
||||||
|
seqNum++;
|
||||||
|
} catch (NullPointerException ne) {
|
||||||
|
// TODO: 4/09/17 Just ignoring this at the moment. Caused by players getting removed elsewhere.
|
||||||
}
|
}
|
||||||
updateDelegate();
|
|
||||||
seqNum++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -86,17 +86,20 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
|
|
||||||
//FINISHED
|
//FINISHED
|
||||||
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||||
terminate();
|
broadcastMessage(makeRaceStatusMessage());
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000); //Hackish fix to make sure all threads have sent closing RaceStatus
|
||||||
|
terminate();
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
serverLog("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");
|
||||||
}
|
}
|
||||||
@@ -169,6 +172,9 @@ 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);
|
serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0);
|
||||||
|
if (serverToClientThreads.size() == 0) { //Sets first client as host.
|
||||||
|
serverToClientThread.setAsHost();
|
||||||
|
}
|
||||||
serverToClientThreads.add(serverToClientThread);
|
serverToClientThreads.add(serverToClientThread);
|
||||||
serverToClientThread.addConnectionListener(() -> {
|
serverToClientThread.addConnectionListener(() -> {
|
||||||
for (ServerToClientThread thread : serverToClientThreads) {
|
for (ServerToClientThread thread : serverToClientThreads) {
|
||||||
@@ -257,6 +263,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
if (timeTillStart > PREPATORY_TIME) {
|
if (timeTillStart > PREPATORY_TIME) {
|
||||||
raceStatus = RaceStatus.PREPARATORY;
|
raceStatus = RaceStatus.PREPARATORY;
|
||||||
}
|
}
|
||||||
|
} else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||||
|
raceStatus = RaceStatus.TERMINATED;
|
||||||
} else {
|
} else {
|
||||||
raceStatus = RaceStatus.STARTED;
|
raceStatus = RaceStatus.STARTED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,11 @@ 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))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,23 +31,6 @@ 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.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.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.Player;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.packets.PacketType;
|
import seng302.model.stream.packets.PacketType;
|
||||||
@@ -91,6 +75,7 @@ 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 xml;
|
||||||
|
|
||||||
@@ -225,7 +210,12 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
|
|
||||||
completeRegistration(requestedType);
|
completeRegistration(requestedType);
|
||||||
break;
|
break;
|
||||||
|
case CHATTER_TEXT:
|
||||||
|
// GameState.broadcastChatter(
|
||||||
|
// ServerPacketParser.extractChatterText(payload)
|
||||||
|
// );
|
||||||
|
parseChatter(payload);
|
||||||
|
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));
|
||||||
@@ -386,4 +376,40 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseChatter(byte[] chatterPayload) {
|
||||||
|
String chatterText = new String(
|
||||||
|
Arrays.copyOfRange(chatterPayload, 3, 3 + chatterPayload.length)
|
||||||
|
);
|
||||||
|
String[] words = chatterText.split("\\s+");
|
||||||
|
if (words.length > 2 && isHost) {
|
||||||
|
switch (words[2].trim()) {
|
||||||
|
case ">speed":
|
||||||
|
try {
|
||||||
|
GameState.setSpeedMultiplier(Double.valueOf(words[3]));
|
||||||
|
GameState.broadcastChatter(new ChatterMessage(
|
||||||
|
Byte.toUnsignedInt(chatterPayload[1]),
|
||||||
|
"SERVER: Speed modifier set to x" + words[3]
|
||||||
|
));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("cannot parse >speed value");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case ">finish":
|
||||||
|
GameState.broadcastChatter(new ChatterMessage(
|
||||||
|
chatterPayload[1],
|
||||||
|
"SERVER: Game will now finish"
|
||||||
|
));
|
||||||
|
GameState.endRace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameState.broadcastChatter(
|
||||||
|
ServerPacketParser.extractChatterText(chatterPayload)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package seng302.utilities;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javafx.util.Pair;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@@ -62,31 +64,10 @@ public class StreamParser {
|
|||||||
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
long windDir = bytesToLong(Arrays.copyOfRange(payload, 18, 20));
|
||||||
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
long rawWindSpeed = bytesToLong(Arrays.copyOfRange(payload, 20, 22));
|
||||||
|
|
||||||
// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
|
||||||
// currentTime = format.format((new Date(currentTime)))
|
|
||||||
|
|
||||||
RaceStatusData data = new RaceStatusData(
|
RaceStatusData data = new RaceStatusData(
|
||||||
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
windDir, rawWindSpeed, raceStatus, currentTime, expectedStartTime
|
||||||
);
|
);
|
||||||
|
|
||||||
// long timeTillStart =
|
|
||||||
// ((new Date(expectedStartTime)).getTime() - (new Date(currentTime)).getTime()) / 1000;
|
|
||||||
//
|
|
||||||
// if (timeTillStart > 0) {
|
|
||||||
// timeSinceStart = timeTillStart;
|
|
||||||
// } else {
|
|
||||||
// if (raceStatus == 4 || raceStatus == 8) {
|
|
||||||
// raceFinished = true;
|
|
||||||
// raceStarted = false;
|
|
||||||
// } else if (!raceStarted) {
|
|
||||||
// raceStarted = true;
|
|
||||||
// raceFinished = false;
|
|
||||||
// }
|
|
||||||
// timeSinceStart = timeTillStart;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
int noBoats = payload[22];
|
int noBoats = payload[22];
|
||||||
int raceType = payload[23];
|
int raceType = payload[23];
|
||||||
long boatID, estTimeAtNextMark, estTimeAtFinish;
|
long boatID, estTimeAtNextMark, estTimeAtFinish;
|
||||||
@@ -106,24 +87,6 @@ public class StreamParser {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){
|
|
||||||
// Integer placing = 1;
|
|
||||||
// if (leg != updatingBoat.getLegNumber() && (raceStarted || raceFinished)) {
|
|
||||||
// for (Yacht boat : boats.values()) {
|
|
||||||
// if (boat.getLegNumber() != null && leg <= boat.getLegNumber()){
|
|
||||||
// placing += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// updatingBoat.setPlacing(placing.toString());
|
|
||||||
// updatingBoat.setLegNumber(leg);
|
|
||||||
// boatsPos.putIfAbsent(placing, updatingBoat);
|
|
||||||
// boatsPos.replace(placing, updatingBoat);
|
|
||||||
// } else if(updatingBoat.getLegNumber() == null){
|
|
||||||
// updatingBoat.setPlacing("1");
|
|
||||||
// updatingBoat.setLegNumber(leg);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses and returns the text from a StreamPacket containing text data for display.
|
* Parses and returns the text from a StreamPacket containing text data for display.
|
||||||
*
|
*
|
||||||
@@ -255,15 +218,15 @@ public class StreamParser {
|
|||||||
* @return Chatter text message as a string. Returns null if the packet is not of type
|
* @return Chatter text message as a string. Returns null if the packet is not of type
|
||||||
* CHATTER_TEXT.
|
* CHATTER_TEXT.
|
||||||
*/
|
*/
|
||||||
public static String extractChatterText(StreamPacket packet) {
|
public static Pair<Integer, String> extractChatterText(StreamPacket packet) {
|
||||||
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
if (packet.getType() != PacketType.CHATTER_TEXT) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
byte[] payload = packet.getPayload();
|
byte[] payload = packet.getPayload();
|
||||||
int messageVersionNo = payload[0];
|
int messageVersionNo = payload[0];
|
||||||
int messageType = payload[1];
|
int messageType = payload[1];
|
||||||
int length = payload[2];
|
int length = (int) bytesToLong(new byte[]{payload[2]});
|
||||||
return new String(Arrays.copyOfRange(payload, 3, 3 + length));
|
return new Pair<>(messageType, new String(Arrays.copyOfRange(payload, 3, 3 + length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -392,26 +355,6 @@ public class StreamParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void extractBoatAction(StreamPacket packet) {
|
|
||||||
byte[] payload = packet.getPayload();
|
|
||||||
int messageVersionNo = payload[0];
|
|
||||||
long actionType = bytesToLong(Arrays.copyOfRange(payload, 0, 1));
|
|
||||||
if (actionType == 1) {
|
|
||||||
System.out.println("VMG");
|
|
||||||
} else if (actionType == 2) {
|
|
||||||
System.out.println("SAILS IN");
|
|
||||||
} else if (actionType == 3) {
|
|
||||||
System.out.println("SAILS OUT");
|
|
||||||
} else if (actionType == 4) {
|
|
||||||
System.out.println("TACK/GYBE");
|
|
||||||
} else if (actionType == 5) {
|
|
||||||
System.out.println("UPWIND");
|
|
||||||
} else if (actionType == 6) {
|
|
||||||
System.out.println("DOWNWIND");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
* takes an array of up to 7 bytes and returns a positive long constructed from the input bytes
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.BoatAction;
|
||||||
import seng302.gameServer.messages.BoatActionMessage;
|
import seng302.gameServer.messages.BoatActionMessage;
|
||||||
|
import seng302.gameServer.messages.ChatterMessage;
|
||||||
import seng302.gameServer.messages.ClientType;
|
import seng302.gameServer.messages.ClientType;
|
||||||
import seng302.gameServer.messages.CustomizeRequestMessage;
|
import seng302.gameServer.messages.CustomizeRequestMessage;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
import seng302.gameServer.messages.CustomizeRequestType;
|
||||||
@@ -283,9 +284,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 +303,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeSocket() {
|
public void closeSocket() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
socketOpen = false;
|
socketOpen = false;
|
||||||
|
|||||||
@@ -1,9 +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.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;
|
||||||
@@ -13,8 +15,10 @@ 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;
|
||||||
@@ -78,7 +82,6 @@ public class GameClient {
|
|||||||
startClientToServerThread(ipAddress, portNumber);
|
startClientToServerThread(ipAddress, portNumber);
|
||||||
socketThread.addDisconnectionListener((cause) -> {
|
socketThread.addDisconnectionListener((cause) -> {
|
||||||
showConnectionError(cause);
|
showConnectionError(cause);
|
||||||
tearDownConnection();
|
|
||||||
Platform.runLater(this::loadStartScreen);
|
Platform.runLater(this::loadStartScreen);
|
||||||
});
|
});
|
||||||
socketThread.addStreamObserver(this::parsePackets);
|
socketThread.addStreamObserver(this::parsePackets);
|
||||||
@@ -96,10 +99,7 @@ public class GameClient {
|
|||||||
lobbyController.setCourseName("");
|
lobbyController.setCourseName("");
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyController.addCloseListener((exitCause) -> {
|
lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
|
||||||
this.tearDownConnection();
|
|
||||||
this.loadStartScreen();
|
|
||||||
});
|
|
||||||
this.lobbyController = lobbyController;
|
this.lobbyController = lobbyController;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
showConnectionError("Unable to find server");
|
showConnectionError("Unable to find server");
|
||||||
@@ -117,7 +117,6 @@ public class GameClient {
|
|||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, portNumber);
|
startClientToServerThread(ipAddress, portNumber);
|
||||||
socketThread.addDisconnectionListener((cause) -> {
|
socketThread.addDisconnectionListener((cause) -> {
|
||||||
this.tearDownConnection();
|
|
||||||
Platform.runLater(this::loadStartScreen);
|
Platform.runLater(this::loadStartScreen);
|
||||||
});
|
});
|
||||||
LobbyController lobbyController = loadLobby();
|
LobbyController lobbyController = loadLobby();
|
||||||
@@ -138,7 +137,8 @@ public class GameClient {
|
|||||||
lobbyController.disableReadyButton();
|
lobbyController.disableReadyButton();
|
||||||
server.startGame();
|
server.startGame();
|
||||||
} else if (exitCause == CloseStatus.LEAVE) {
|
} else if (exitCause == CloseStatus.LEAVE) {
|
||||||
tearDownConnection();
|
server.terminate();
|
||||||
|
server = null;
|
||||||
loadStartScreen();
|
loadStartScreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -149,21 +149,10 @@ public class GameClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tearDownConnection() {
|
|
||||||
socketThread.setSocketToClose();
|
|
||||||
if (server != null) {
|
|
||||||
server.terminate();
|
|
||||||
server = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadStartScreen() {
|
private void loadStartScreen() {
|
||||||
// socketThread.setSocketToClose();
|
if (socketThread != null) {
|
||||||
// if (server != null) {
|
socketThread.setSocketToClose();
|
||||||
// server.terminate();
|
}
|
||||||
// server = null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Sounds.stopMusic();
|
Sounds.stopMusic();
|
||||||
Sounds.playMenuMusic();
|
Sounds.playMenuMusic();
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
@@ -214,8 +203,15 @@ 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() {
|
||||||
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
|
FXMLLoader fxmlLoader = loadFXMLToHolder("/views/FinishScreenView.fxml");
|
||||||
FinishScreenViewController controller = fxmlLoader.getController();
|
FinishScreenViewController controller = fxmlLoader.getController();
|
||||||
@@ -299,6 +295,14 @@ public class GameClient {
|
|||||||
case YACHT_EVENT_CODE:
|
case YACHT_EVENT_CODE:
|
||||||
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CHATTER_TEXT:
|
||||||
|
Pair<Integer, String> playerIdMessagePair = StreamParser
|
||||||
|
.extractChatterText(packet);
|
||||||
|
raceView.updateChatHistory(
|
||||||
|
allBoatsMap.get(playerIdMessagePair.getKey()).getColour(),
|
||||||
|
playerIdMessagePair.getValue()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,6 +400,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;
|
||||||
@@ -404,12 +414,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
|
||||||
@@ -440,4 +454,19 @@ public class GameClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class GameView extends Pane {
|
|||||||
private double metersPerPixelX, metersPerPixelY;
|
private double metersPerPixelX, metersPerPixelY;
|
||||||
|
|
||||||
final double SCALE_DELTA = 1.1;
|
final double SCALE_DELTA = 1.1;
|
||||||
|
private boolean isZoom = false;
|
||||||
|
|
||||||
private Text fpsDisplay = new Text();
|
private Text fpsDisplay = new Text();
|
||||||
private Polygon raceBorder = new CourseBoundary();
|
private Polygon raceBorder = new CourseBoundary();
|
||||||
@@ -102,7 +103,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);
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ public class GameView extends Pane {
|
|||||||
|
|
||||||
private void zoomIn() {
|
private void zoomIn() {
|
||||||
scaleFactor = 0.10;
|
scaleFactor = 0.10;
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -143,6 +144,13 @@ public class GameView extends Pane {
|
|||||||
gameObjects.add(raceBorder);
|
gameObjects.add(raceBorder);
|
||||||
gameObjects.add(markers);
|
gameObjects.add(markers);
|
||||||
initializeTimer();
|
initializeTimer();
|
||||||
|
this.sceneProperty().addListener(((observable, oldValue, scene) -> {
|
||||||
|
if (scene != null) {
|
||||||
|
setupZoom();
|
||||||
|
} else {
|
||||||
|
disableZoom();
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTimer() {
|
private void initializeTimer() {
|
||||||
@@ -440,17 +448,25 @@ public class GameView extends Pane {
|
|||||||
/**
|
/**
|
||||||
* 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() {
|
||||||
if (this.getScene() != null) {
|
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();
|
} else if (event.getCode() == KeyCode.X) {
|
||||||
} else if (event.getCode() == KeyCode.X) {
|
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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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,7 @@ 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.AnchorPane;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
@@ -48,12 +50,23 @@ 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
|
||||||
@@ -86,6 +99,8 @@ 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<>();
|
||||||
@@ -104,10 +119,27 @@ 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);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRace (
|
public void loadRace (
|
||||||
@@ -119,12 +151,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()) {
|
||||||
@@ -143,7 +169,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
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();
|
||||||
|
|
||||||
@@ -158,6 +183,19 @@ 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initializeUpdateTimer();
|
||||||
|
initialiseFPSCheckBox();
|
||||||
|
initialiseAnnotationSlider();
|
||||||
|
initialiseBoatSelectionComboBox();
|
||||||
|
initialiseSparkLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -539,7 +577,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
yachtSelectionComboBox.setItems(
|
yachtSelectionComboBox.setItems(
|
||||||
FXCollections.observableArrayList(participants.values())
|
FXCollections.observableArrayList(participants.values())
|
||||||
);
|
);
|
||||||
//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);
|
||||||
@@ -625,4 +662,24 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
|
|||||||
this.courseData = raceData;
|
this.courseData = raceData;
|
||||||
gameView.updateBorder(raceData.getCourseLimit());
|
gameView.updateBorder(raceData.getCourseLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -31,15 +31,12 @@ public class StartScreenController implements Initializable {
|
|||||||
@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) {
|
||||||
|
|
||||||
if (Sounds.isMusicMuted()) {
|
if (Sounds.isMusicMuted()) {
|
||||||
muteMusicButton.setText("UnMute Music");
|
muteMusicButton.setText("UnMute Music");
|
||||||
} else {
|
} else {
|
||||||
@@ -53,73 +50,19 @@ public class StartScreenController implements Initializable {
|
|||||||
|
|
||||||
// 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() {
|
||||||
Sounds.playButtonClick();
|
Sounds.playButtonClick();
|
||||||
// new GameState(getLocalHostIp());
|
|
||||||
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() {
|
||||||
@@ -127,28 +70,8 @@ public class StartScreenController implements Initializable {
|
|||||||
Sounds.playButtonClick();
|
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.
|
||||||
@@ -183,7 +106,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package seng302.visualiser.fxObjects;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
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.ALWAYS);
|
||||||
|
this.setHbarPolicy(ScrollBarPolicy.NEVER);
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,50 +6,41 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.shape.*?>
|
<?import javafx.scene.shape.*?>
|
||||||
<?import javafx.scene.text.*?>
|
<?import javafx.scene.text.*?>
|
||||||
<?import javafx.scene.chart.CategoryAxis?>
|
|
||||||
<?import javafx.scene.chart.LineChart?>
|
|
||||||
<?import javafx.scene.chart.NumberAxis?>
|
|
||||||
<?import javafx.scene.control.Button?>
|
|
||||||
<?import javafx.scene.control.CheckBox?>
|
|
||||||
<?import javafx.scene.control.ComboBox?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.control.Slider?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<?import javafx.scene.layout.Pane?>
|
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<?import javafx.scene.shape.Circle?>
|
|
||||||
<?import javafx.scene.text.Font?>
|
|
||||||
<?import javafx.scene.text.Text?>
|
|
||||||
|
|
||||||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="998.0" prefWidth="1530.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.RaceViewController">
|
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="998.0" prefWidth="1530.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.RaceViewController">
|
||||||
<children>
|
<children>
|
||||||
<AnchorPane layoutX="322.0" layoutY="130.0" prefHeight="998.0" prefWidth="1281.0"
|
<AnchorPane fx:id="basePane" layoutX="322.0" layoutY="130.0" prefHeight="998.0" prefWidth="1281.0" style="-fx-background-color: skyblue;" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
style="-fx-background-color: skyblue;" AnchorPane.bottomAnchor="0.0"
|
|
||||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
|
||||||
<children>
|
<children>
|
||||||
<GridPane prefHeight="998.0" prefWidth="1281.0" AnchorPane.bottomAnchor="0.0"
|
<GridPane prefHeight="998.0" prefWidth="1281.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
|
|
||||||
AnchorPane.topAnchor="0.0">
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="630.0" minWidth="10.0"
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="630.0" minWidth="10.0" prefWidth="68.0" />
|
||||||
prefWidth="68.0"/>
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1213.0" minWidth="10.0" prefWidth="1213.0" />
|
||||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1213.0" minWidth="10.0"
|
|
||||||
prefWidth="1213.0"/>
|
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints maxHeight="489.0" minHeight="1.0" prefHeight="24.0"
|
<RowConstraints maxHeight="489.0" minHeight="1.0" prefHeight="24.0" vgrow="SOMETIMES" />
|
||||||
vgrow="SOMETIMES"/>
|
<RowConstraints maxHeight="997.0" minHeight="10.0" prefHeight="974.0" vgrow="SOMETIMES" />
|
||||||
<RowConstraints maxHeight="997.0" minHeight="10.0" prefHeight="974.0"
|
|
||||||
vgrow="SOMETIMES"/>
|
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<AnchorPane fx:id="contentAnchorPane" prefHeight="200.0" prefWidth="200.0"
|
<AnchorPane fx:id="contentAnchorPane" prefHeight="200.0" prefWidth="200.0" GridPane.columnSpan="2" GridPane.rowSpan="2">
|
||||||
GridPane.columnSpan="2" GridPane.rowSpan="2"/>
|
<children>
|
||||||
<Text fx:id="fpsDisplay" strokeType="OUTSIDE" strokeWidth="0.0" text="60 FPS"
|
<AnchorPane layoutX="799.0" layoutY="770.0" prefHeight="214.0" prefWidth="468.0">
|
||||||
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
|
<children>
|
||||||
|
<VBox prefHeight="214.0" prefWidth="468.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<children>
|
||||||
|
<Pane fx:id="chatHistoryHolder" maxHeight="9.9999999999E10" maxWidth="1.7976931348623157E308" prefHeight="9.9999999999E10" />
|
||||||
|
<HBox VBox.vgrow="NEVER">
|
||||||
|
<children>
|
||||||
|
<TextField fx:id="chatInput" focusTraversable="false" prefHeight="25.0" HBox.hgrow="ALWAYS" />
|
||||||
|
<Button fx:id="chatSend" focusTraversable="false" mnemonicParsing="false" text="Send" />
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<Text fx:id="fpsDisplay" strokeType="OUTSIDE" strokeWidth="0.0" text="60 FPS" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
</children>
|
</children>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Feature: SendChat
|
||||||
|
Scenario: User send chat to another client
|
||||||
|
Given The are two games running
|
||||||
|
When the user has pressed sends the message "Hello world" in a text box
|
||||||
|
Then the other client should receive the message "Hello world"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Feature: Sending chatter packets over the web.
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
// @Rule
|
||||||
|
// public Timeout globalTimeout = new Timeout(3, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
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();
|
||||||
|
System.out.println("AY WE DID IT");
|
||||||
|
// host.setSocketToClose();
|
||||||
|
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);
|
||||||
|
System.out.println("the thing " + GameState.getSpeedMultiplier());
|
||||||
|
mst.terminate();
|
||||||
|
// host.setSocketToClose();
|
||||||
|
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();
|
||||||
|
// host.setSocketToClose();
|
||||||
|
Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
|
||||||
|
System.out.println("value " + GameState.getSpeedMultiplier());
|
||||||
|
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);
|
||||||
|
System.out.println("done client and host assigning");
|
||||||
|
} 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();
|
||||||
|
System.out.println("TEST COMPLETE");
|
||||||
|
// client.setSocketToClose();
|
||||||
|
// host.setSocketToClose();
|
||||||
|
Assert.assertTrue(dcSent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
}
|
||||||
|
// 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(200);
|
||||||
|
// } catch (InterruptedException ie) {
|
||||||
|
// ie.printStackTrace();
|
||||||
|
// }
|
||||||
|
//// host.setSocketToClose();
|
||||||
|
// mst.terminate();
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package steps;
|
||||||
|
|
||||||
|
import cucumber.api.java.en.Given;
|
||||||
|
import cucumber.api.java.en.Then;
|
||||||
|
import cucumber.api.java.en.When;
|
||||||
|
import seng302.gameServer.MainServerThread;
|
||||||
|
import seng302.visualiser.GameClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by kre39 on 7/08/17.
|
||||||
|
*/
|
||||||
|
public class SendChatSteps {
|
||||||
|
|
||||||
|
MainServerThread mst;
|
||||||
|
GameClient client1;
|
||||||
|
GameClient client2;
|
||||||
|
|
||||||
|
|
||||||
|
//TODO Need to mock the controller pane in order to run the full game client
|
||||||
|
@Given("^The are two games running$")
|
||||||
|
public void the_are_two_games_running() throws Throwable {
|
||||||
|
// client1 = new GameClient(new Pane());
|
||||||
|
// client1.runAsHost("localhost", 4942);
|
||||||
|
//// client2 = new ClientToServerThread("localhost", 4942);
|
||||||
|
// GameState.setCurrentStage(GameStages.RACING);
|
||||||
|
// Thread.sleep(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@When("^the user has pressed sends the message \"([^\"]*)\" in a text box$")
|
||||||
|
public void the_user_has_pressed_sends_the_message_in_a_text_box(String arg1) throws Throwable {
|
||||||
|
// client1.getSocketThread().sendChatterMessage(arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Then("^the other client should receive the message \"([^\"]*)\"$")
|
||||||
|
public void the_other_client_should_recieve_the_message(String arg1) throws Throwable {
|
||||||
|
// System.out.println(client2.getPacketQueue());
|
||||||
|
// client2.setSocketToClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -49,5 +49,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