diff --git a/pom.xml b/pom.xml
index aac3b0c7..fca06536 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,8 +69,8 @@
commons-cli
1.4
-
+
diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java
index 3b914350..8c6f85ac 100644
--- a/src/main/java/seng302/App.java
+++ b/src/main/java/seng302/App.java
@@ -67,8 +67,6 @@ public class App extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
- PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
-
Parent root = FXMLLoader.load(getClass().getResource("/views/StartScreenView.fxml"));
primaryStage.setTitle("RaceVision");
Scene scene = new Scene(root, 1530, 960);
diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java
index 1bb968d1..9a54c7d1 100644
--- a/src/main/java/seng302/gameServer/GameState.java
+++ b/src/main/java/seng302/gameServer/GameState.java
@@ -4,9 +4,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import seng302.gameServer.server.messages.BoatAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import seng302.gameServer.server.messages.BoatActionType;
import seng302.model.Player;
import seng302.model.Yacht;
import seng302.model.mark.MarkOrder;
@@ -56,7 +56,6 @@ public class GameState implements Runnable {
players = new ArrayList<>();
currentStage = GameStages.LOBBYING;
isRaceStarted = false;
- yachts = new HashMap<>();
//set this when game stage changes to prerace
previousUpdateTime = System.currentTimeMillis();
yachts = new HashMap<>();
@@ -75,7 +74,8 @@ public class GameState implements Runnable {
public static void addPlayer(Player player) {
players.add(player);
- String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName() + " " + player.getYacht().getCountry();
+ String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
+ + " " + player.getYacht().getCountry();
playerStringMap.put(player, playerText);
}
@@ -132,7 +132,7 @@ public class GameState implements Runnable {
return yachts;
}
- public static void updateBoat(Integer sourceId, BoatActionType actionType) {
+ public static void updateBoat(Integer sourceId, BoatAction actionType) {
Yacht playerYacht = yachts.get(sourceId);
// System.out.println("-----------------------");
switch (actionType) {
diff --git a/src/main/java/seng302/gameServer/HeartbeatThread.java b/src/main/java/seng302/gameServer/HeartbeatThread.java
index f15868c3..b168a197 100644
--- a/src/main/java/seng302/gameServer/HeartbeatThread.java
+++ b/src/main/java/seng302/gameServer/HeartbeatThread.java
@@ -42,7 +42,6 @@ public class HeartbeatThread extends Thread{
*/
private void sendHeartbeatToAllPlayers(){
Message heartbeat = new Heartbeat(seqNum);
-
for (Player player : GameState.getPlayers()){
if (!player.getSocket().isConnected()) {
playerLostConnection(player);
@@ -54,7 +53,6 @@ public class HeartbeatThread extends Thread{
playerLostConnection(player);
}
}
-
updateDelegate();
seqNum++;
}
@@ -71,7 +69,6 @@ public class HeartbeatThread extends Thread{
public void run(){
Timer t = new Timer();
-
t.schedule(new TimerTask() {
@Override
public void run() {
diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java
index 838df5fb..37d693ca 100644
--- a/src/main/java/seng302/gameServer/MainServerThread.java
+++ b/src/main/java/seng302/gameServer/MainServerThread.java
@@ -8,6 +8,7 @@ import java.util.Observable;
import java.util.Timer;
import java.util.TimerTask;
import seng302.model.Player;
+import seng302.model.PolarTable;
/**
* A class describing the overall server, which creates and collects server threads for each client
@@ -32,7 +33,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
} catch (IOException e) {
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
}
-
+ PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
terminated = false;
thread = new Thread(this);
thread.start();
@@ -44,6 +45,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
HeartbeatThread heartbeatThread;
serverListenThread = new ServerListenThread(serverSocket, this);
+
heartbeatThread = new HeartbeatThread(this);
heartbeatThread.start();
@@ -102,9 +104,11 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
public void clientConnected(ServerToClientThread serverToClientThread) {
serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0);
serverToClientThreads.add(serverToClientThread);
- this.addObserver(serverToClientThread);
- setChanged();
- notifyObservers();
+ serverToClientThread.addConnectionListener(() -> {
+ for (ServerToClientThread thread : serverToClientThreads) {
+ thread.sendSetupMessages();
+ }
+ });
}
/**
@@ -121,11 +125,15 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
GameState.removeYacht(player.getYacht().getSourceId());
GameState.removePlayer(player);
+ ServerToClientThread closedConnection = null;
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) {
- this.deleteObserver(serverToClientThread);
+ closedConnection = serverToClientThread;
+ } else {
+ serverToClientThread.sendSetupMessages();
}
}
+ serverToClientThreads.remove(closedConnection);
setChanged();
notifyObservers();
}
diff --git a/src/main/java/seng302/gameServer/ServerPacketParser.java b/src/main/java/seng302/gameServer/ServerPacketParser.java
index 21841f18..84f8fd17 100644
--- a/src/main/java/seng302/gameServer/ServerPacketParser.java
+++ b/src/main/java/seng302/gameServer/ServerPacketParser.java
@@ -5,16 +5,16 @@ import java.util.Arrays;
import seng302.gameServer.server.messages.ClientType;
import seng302.gameServer.server.messages.Message;
import seng302.model.stream.packets.StreamPacket;
-import seng302.gameServer.server.messages.BoatActionType;
+import seng302.gameServer.server.messages.BoatAction;
public class ServerPacketParser {
- public static BoatActionType extractBoatAction(StreamPacket packet) {
+ public static BoatAction extractBoatAction(StreamPacket packet) {
byte[] payload = packet.getPayload();
int messageVersionNo = payload[0];
long actionTypeValue = Message.bytesToLong(Arrays.copyOfRange(payload, 0, 1));
- return BoatActionType.getType((int) actionTypeValue);
+ return BoatAction.getType((int) actionTypeValue);
}
public static ClientType extractClientType(StreamPacket packet){
diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java
index 8ac88848..a3f87e2b 100644
--- a/src/main/java/seng302/gameServer/ServerToClientThread.java
+++ b/src/main/java/seng302/gameServer/ServerToClientThread.java
@@ -1,7 +1,34 @@
package seng302.gameServer;
-import seng302.gameServer.server.messages.*;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.zip.CRC32;
+import java.util.zip.Checksum;
+import seng302.gameServer.server.messages.BoatAction;
+import seng302.gameServer.server.messages.BoatLocationMessage;
+import seng302.gameServer.server.messages.BoatStatus;
+import seng302.gameServer.server.messages.BoatSubMessage;
+import seng302.gameServer.server.messages.ClientType;
+import seng302.gameServer.server.messages.Message;
+import seng302.gameServer.server.messages.RaceStatus;
+import seng302.gameServer.server.messages.RaceStatusMessage;
+import seng302.gameServer.server.messages.RaceType;
+import seng302.gameServer.server.messages.RegistrationResponseMessage;
+import seng302.gameServer.server.messages.RegistrationResponseStatus;
+import seng302.gameServer.server.messages.XMLMessage;
+import seng302.gameServer.server.messages.XMLMessageSubType;
import seng302.model.Player;
import seng302.model.Yacht;
import seng302.model.stream.packets.PacketType;
@@ -10,25 +37,20 @@ import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator;
-import java.io.*;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.Collectors;
-import java.util.zip.CRC32;
-import java.util.zip.Checksum;
-
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
* 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.
*/
-public class ServerToClientThread implements Runnable, Observer {
+public class ServerToClientThread implements Runnable {
+
+ /**
+ * Called to notify listeners when this thread receives a connection correctly.
+ */
+ @FunctionalInterface
+ interface ConnectionListener {
+ void notifyConnection ();
+ }
private static final Integer LOG_LEVEL = 1;
private static final Integer MAX_ID_ATTEMPTS = 10;
@@ -41,9 +63,6 @@ public class ServerToClientThread implements Runnable, Observer {
private ByteArrayOutputStream crcBuffer;
- private Boolean userIdentified = false;
- private Boolean connected = true;
- private Boolean updateClient = true;
// private Boolean initialisedRace = true;
private Integer seqNo;
@@ -54,6 +73,8 @@ public class ServerToClientThread implements Runnable, Observer {
private XMLGenerator xml;
+ private List connectionListeners = new ArrayList<>();
+
public ServerToClientThread(Socket socket) {
this.socket = socket;
seqNo = 0;
@@ -69,7 +90,7 @@ public class ServerToClientThread implements Runnable, Observer {
thread.start();
}
- private void setUpYacht(){
+ private void setUpPlayer(){
BufferedReader fn;
String fName = "";
BufferedReader ln;
@@ -98,7 +119,6 @@ public class ServerToClientThread implements Runnable, Observer {
Yacht yacht = new Yacht(
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
-
GameState.addYacht(sourceId, yacht);
GameState.addPlayer(new Player(socket, yacht));
}
@@ -110,11 +130,6 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
- @Override
- public void update(Observable o, Object arg) {
- sendSetupMessages();
- }
-
private void completeRegistration(ClientType clientType) throws IOException {
// Fail if not a player
if (!clientType.equals(ClientType.PLAYER)){
@@ -134,12 +149,14 @@ public class ServerToClientThread implements Runnable, Observer {
this.clientType = clientType;
this.sourceId = sourceId;
- setUpYacht();
-
isRegistered = true;
os.write(responseMessage.getBuffer());
- sendSetupMessages();
+ setUpPlayer();
+
+ for (ConnectionListener listener : connectionListeners) {
+ listener.notifyConnection();
+ }
}
public void run() {
@@ -151,20 +168,6 @@ public class ServerToClientThread implements Runnable, Observer {
while (socket.isConnected()) {
try {
- //Perform a write if it is time to as delegated by the MainServerThread
- if (updateClient) {
- // TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
-// ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Hello, it's me");
-// sendMessage(chatterMessage);
-// try {
-// GameState.outputState(os);
-// } catch (IOException e) {
-// System.out.println("IO error in server thread upon writing to output stream");
-// }
-// sendBoatLocationPackets();
- updateClient = false;
- }
-
crcBuffer = new ByteArrayOutputStream();
sync1 = readByte();
sync2 = readByte();
@@ -184,7 +187,7 @@ public class ServerToClientThread implements Runnable, Observer {
//System.out.println("RECEIVED A PACKET");
switch (PacketType.assignPacketType(type, payload)) {
case BOAT_ACTION:
- BoatActionType actionType = ServerPacketParser
+ BoatAction actionType = ServerPacketParser
.extractBoatAction(
new StreamPacket(type, payloadLength, timeStamp, payload));
GameState.updateBoat(sourceId, actionType);
@@ -210,7 +213,7 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
- private void sendSetupMessages() {
+ public void sendSetupMessages() {
xml = new XMLGenerator();
Race race = new Race();
@@ -238,23 +241,6 @@ public class ServerToClientThread implements Runnable, Observer {
public void updateClient() {
sendBoatLocationPackets();
- updateClient = true;
- }
-
-
- /**
- * Tries to confirm the connection just accepted.
- * Sends ID, expects that ID echoed for confirmation,
- * if so, sends a confirmation packet back to that connection
- * Creates a player instance with that ID and this thread and adds it to the GameState
- * If not, close the socket and end the threads execution
- *
- * @param id the id to try and assign to the connection
- * @return A boolean indicating if it was a successful handshake
- */
- private Boolean threeWayHandshake(Integer id) {
-
- return true;
}
private void closeSocket() {
@@ -265,7 +251,6 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
-
private int readByte() throws Exception {
int currentByte = -1;
try {
@@ -316,7 +301,6 @@ public class ServerToClientThread implements Runnable, Observer {
private void sendBoatLocationPackets() {
ArrayList yachts = new ArrayList<>(GameState.getYachts().values());
for (Yacht yacht : yachts) {
-// System.out.println("[SERVER] Lat: " + yacht.getLocation().getLat() + " Lon: " + yacht.getLocation().getLng());
BoatLocationMessage boatLocationMessage =
new BoatLocationMessage(
yacht.getSourceId(),
@@ -337,7 +321,6 @@ public class ServerToClientThread implements Runnable, Observer {
public void sendRaceStatusMessage() {
// variables taken from GameServerThread
-
List boatSubMessages = new ArrayList<>();
BoatStatus boatStatus;
RaceStatus raceStatus;
@@ -372,4 +355,12 @@ public class ServerToClientThread implements Runnable, Observer {
public Socket getSocket() {
return socket;
}
+
+ public void addConnectionListener(ConnectionListener listener) {
+ connectionListeners.add(listener);
+ }
+
+ public void removeConnectionListener(ConnectionListener listener) {
+ connectionListeners.remove(listener);
+ }
}
diff --git a/src/main/java/seng302/gameServer/server/messages/BoatActionType.java b/src/main/java/seng302/gameServer/server/messages/BoatAction.java
similarity index 62%
rename from src/main/java/seng302/gameServer/server/messages/BoatActionType.java
rename to src/main/java/seng302/gameServer/server/messages/BoatAction.java
index 53fc6018..cc53668c 100644
--- a/src/main/java/seng302/gameServer/server/messages/BoatActionType.java
+++ b/src/main/java/seng302/gameServer/server/messages/BoatAction.java
@@ -6,29 +6,30 @@ import java.util.Map;
/**
* Created by kre39 on 12/07/17.
*/
-public enum BoatActionType {
+public enum BoatAction {
VMG(1),
SAILS_IN(2),
SAILS_OUT(3),
TACK_GYBE(4),
UPWIND(5),
- DOWNWIND(6);
+ DOWNWIND(6),
+ MAINTAIN_HEADING(7);
private final int type;
- private static final Map intToTypeMap = new HashMap<>();
+ private static final Map intToTypeMap = new HashMap<>();
static {
- for (BoatActionType type : BoatActionType.values()) {
+ for (BoatAction type : BoatAction.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
- BoatActionType(int type){
+ BoatAction(int type){
this.type = type;
}
- public static BoatActionType getType(int value) {
+ public static BoatAction getType(int value) {
return intToTypeMap.get(value);
}
diff --git a/src/main/java/seng302/gameServer/server/messages/BoatActionMessage.java b/src/main/java/seng302/gameServer/server/messages/BoatActionMessage.java
index cfa596f7..2fc084e5 100644
--- a/src/main/java/seng302/gameServer/server/messages/BoatActionMessage.java
+++ b/src/main/java/seng302/gameServer/server/messages/BoatActionMessage.java
@@ -6,9 +6,9 @@ package seng302.gameServer.server.messages;
public class BoatActionMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
private final int MESSAGE_SIZE = 1;
- private BoatActionType actionType;
+ private BoatAction actionType;
- public BoatActionMessage(BoatActionType actionType) {
+ public BoatActionMessage(BoatAction actionType) {
this.actionType = actionType;
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
allocateBuffer();
diff --git a/src/main/java/seng302/model/PolarTable.java b/src/main/java/seng302/model/PolarTable.java
index dee22278..9334cc54 100644
--- a/src/main/java/seng302/model/PolarTable.java
+++ b/src/main/java/seng302/model/PolarTable.java
@@ -71,8 +71,6 @@ public final class PolarTable {
} catch (IOException e) {
System.out.println("[PolarTable] IO exception");
}
-
-
}
@@ -155,7 +153,6 @@ public final class PolarTable {
public static Double getClosestWindSpeedInPolar(Double thisWindSpeed) {
Double smallestDif = Double.POSITIVE_INFINITY;
Double closestWind = 0d;
-
for (Double polarWindSpeed : polarTable.keySet()) {
Double difference = Math.abs(polarWindSpeed - thisWindSpeed);
if (difference < smallestDif) {
diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java
index b95b193f..c47abe38 100644
--- a/src/main/java/seng302/model/Yacht.java
+++ b/src/main/java/seng302/model/Yacht.java
@@ -53,7 +53,7 @@ public class Yacht {
private Integer legNumber = 0;
//SERVER SIDE
- private final Double TURN_STEP = 5.0;
+ public static final Double TURN_STEP = 5.0; //This should be in some utils class somewhere 2bh. Public for tests sake.
private Double lastHeading;
private Boolean sailIn = false;
private GeoPoint location;
@@ -452,9 +452,9 @@ public class Yacht {
private void turnTowardsHeading(Double newHeading) {
Double newVal = heading - newHeading;
if (Math.floorMod(newVal.longValue(), 360L) > 180) {
- adjustHeading(TURN_STEP);
+ adjustHeading(TURN_STEP / 5);
} else {
- adjustHeading(-TURN_STEP);
+ adjustHeading(-TURN_STEP / 5);
}
}
diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java
index 8cb9dd65..9f76d37c 100644
--- a/src/main/java/seng302/visualiser/ClientToServerThread.java
+++ b/src/main/java/seng302/visualiser/ClientToServerThread.java
@@ -10,6 +10,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
@@ -19,7 +21,12 @@ import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import seng302.gameServer.server.messages.*;
+import seng302.gameServer.server.messages.BoatAction;
+import seng302.gameServer.server.messages.BoatActionMessage;
+import seng302.gameServer.server.messages.ClientType;
+import seng302.gameServer.server.messages.Message;
+import seng302.gameServer.server.messages.RegistrationRequestMessage;
+import seng302.gameServer.server.messages.RegistrationResponseStatus;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
@@ -53,9 +60,16 @@ public class ClientToServerThread implements Runnable {
private Socket socket;
private InputStream is;
- private OutputStream os;
+
private Logger logger = LoggerFactory.getLogger(ClientToServerThread.class);
+ //Output stream
+ private OutputStream os;
+ private Timer upWindPacketTimer = new Timer();
+ private Timer downWindPacketTimer = new Timer();
+ private boolean upwindTimerFlag = false, downwindTimerFlag = false;
+ static public final int PACKET_SENDING_INTERVAL_MS = 100;
+
private int clientId = -1;
// private Boolean updateClient = true;
@@ -143,6 +157,7 @@ public class ClientToServerThread implements Runnable {
}
}
} catch (ByteReadException e) {
+ e.printStackTrace();
closeSocket();
Platform.runLater(() -> {
Alert alert = new Alert(AlertType.ERROR);
@@ -153,7 +168,6 @@ public class ClientToServerThread implements Runnable {
clientLog(e.getMessage(), 1);
return;
}
-// System.out.println("streamPackets = " + streamPackets.size());
}
closeSocket();
clientLog("Closed connection to Server", 0);
@@ -207,21 +221,81 @@ public class ClientToServerThread implements Runnable {
});
}
-
/**
- * Send the post-start race course information
- * @param boatActionMessage The message to send
+ * Sends packets for the given boat action. Special cases are: \n
+ * - DOWNWIND = Packets are sent every ClientToServerThread.PACKET_SENDING_INTERVAL_MS
+ * - UPWIND = Packets are sent every ClientToServerThread.PACKET_SENDING_INTERVAL_MS
+ * - MAINTAIN_HEADING = DOWNWIND and UPWIND packets stop being sent.
+ * @param actionType The boat action that will dictate packets sent.
*/
- public void sendBoatActionMessage(BoatActionMessage boatActionMessage) {
- if (clientId == -1) return;
-
- try {
- os.write(boatActionMessage.getBuffer());
- } catch (IOException e) {
- clientLog("Could not write to server", 1);
+ public void sendBoatAction(BoatAction actionType) {
+ switch (actionType) {
+ case MAINTAIN_HEADING:
+ if (upwindTimerFlag) {
+ cancelTimer(upWindPacketTimer);
+ upwindTimerFlag = false;
+ upWindPacketTimer = new Timer();
+ }
+ if (downwindTimerFlag) {
+ cancelTimer(downWindPacketTimer);
+ downwindTimerFlag = false;
+ downWindPacketTimer = new Timer();
+ }
+ break;
+ case DOWNWIND:
+ if (!downwindTimerFlag) {
+ downwindTimerFlag = true;
+ downWindPacketTimer.scheduleAtFixedRate(
+ new TimerTask() {
+ @Override
+ public void run() {
+ sendBoatAction(new BoatActionMessage(BoatAction.DOWNWIND));
+ }
+ }, 0, PACKET_SENDING_INTERVAL_MS
+ );
+ }
+ break;
+ case UPWIND:
+ if (!upwindTimerFlag) {
+ upwindTimerFlag = true;
+ upWindPacketTimer.scheduleAtFixedRate(
+ new TimerTask() {
+ @Override
+ public void run() {
+ sendBoatAction(new BoatActionMessage(BoatAction.UPWIND));
+ }
+ }, 0, PACKET_SENDING_INTERVAL_MS
+ );
+ }
+ break;
+ default:
+ sendBoatAction(new BoatActionMessage(actionType));
+ break;
}
}
+ /**
+ * Cancels a packet sending timer.
+ * @param timer The timer to cancel.
+ */
+ private void cancelTimer (Timer timer) {
+ timer.cancel();
+ timer.purge();
+ }
+
+ /**
+ * Sends a boat action of the given message type.
+ * @param message The given message type.
+ */
+ private void sendBoatAction(BoatActionMessage message) {
+ if (clientId != -1) {
+ try {
+ os.write(message.getBuffer());
+ } catch (IOException e) {
+ clientLog("Could not write to server", 1);
+ }
+ }
+ }
private void closeSocket() {
try {
@@ -275,11 +349,8 @@ public class ClientToServerThread implements Runnable {
}
}
- public Thread getThread() {
- return thread;
- }
-
public int getClientId () {
return clientId;
}
+
}
diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java
index 2af2af93..028ea1e3 100644
--- a/src/main/java/seng302/visualiser/GameClient.java
+++ b/src/main/java/seng302/visualiser/GameClient.java
@@ -13,8 +13,7 @@ import javafx.scene.Node;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import seng302.gameServer.MainServerThread;
-import seng302.gameServer.server.messages.BoatActionMessage;
-import seng302.gameServer.server.messages.BoatActionType;
+import seng302.gameServer.server.messages.BoatAction;
import seng302.model.RaceState;
import seng302.model.Yacht;
import seng302.model.stream.packets.StreamPacket;
@@ -31,7 +30,8 @@ import seng302.visualiser.controllers.LobbyController.CloseStatus;
import seng302.visualiser.controllers.RaceViewController;
/**
- * Created by cir27 on 20/07/17.
+ * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
+ * with a JavaFX Pane to insert itself into.
*/
public class GameClient {
@@ -48,13 +48,20 @@ public class GameClient {
private ObservableList clientLobbyList = FXCollections.observableArrayList();
- private long lastSendingTime;
- private int KEY_STROKE_SENDING_FREQUENCY = 50;
-
+ /**
+ * Create an instance of the game client. Does not do anything until run with runAsClient()
+ * runAsHost().
+ * @param holder The JavaFX Pane that the visual elements for the race will be inserted into.
+ */
public GameClient(Pane holder) {
this.holderPane = holder;
}
+ /**
+ * Connect to a game at the given address and starts the visualiser.
+ * @param ipAddress IP to connect to.
+ * @param portNumber Port to connect to.
+ */
public void runAsClient(String ipAddress, Integer portNumber) {
try {
socketThread = new ClientToServerThread(ipAddress, portNumber);
@@ -71,6 +78,11 @@ public class GameClient {
lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
}
+ /**
+ * Connect to a game as the host at the given address and starts the visualiser.
+ * @param ipAddress IP to connect to.
+ * @param portNumber Port to connect to.
+ */
public void runAsHost(String ipAddress, Integer portNumber) {
server = new MainServerThread();
try {
@@ -94,10 +106,8 @@ public class GameClient {
private void loadStartScreen() {
socketThread.setSocketToClose();
- socketThread = null;
if (server != null) {
- // TODO: 26/07/17 cir27 - handle disconnecting
-// server.shutDown();
+ server.terminate();
server = null;
}
FXMLLoader fxmlLoader = new FXMLLoader(
@@ -179,12 +189,9 @@ public class GameClient {
StreamParser.extractXmlMessage(packet)
);
clientLobbyList.clear();
- allBoatsMap.forEach((id, boat) -> {
- clientLobbyList.add(id + " " + boat.getBoatName());
-// System.out.println(id + " " + boat.getBoatName());
-
- });
-// startRaceIfAllDataReceived();
+ allBoatsMap.forEach((id, boat) ->
+ clientLobbyList.add(id + " " + boat.getBoatName())
+ );
break;
case RACE_START_STATUS:
@@ -281,50 +288,36 @@ public class GameClient {
* Handle the key-pressed event from the text field.
* @param e The key event triggering this call
*/
- public void keyPressed(KeyEvent e) {
- BoatActionMessage boatActionMessage;
- long currentTime = System.currentTimeMillis();
- if (currentTime - lastSendingTime > KEY_STROKE_SENDING_FREQUENCY) {
- lastSendingTime = currentTime;
- switch (e.getCode()) {
- case SPACE: // align with vmg
- boatActionMessage = new BoatActionMessage(BoatActionType.VMG);
- socketThread.sendBoatActionMessage(boatActionMessage);
- break;
- case PAGE_UP: // upwind
- boatActionMessage = new BoatActionMessage(BoatActionType.UPWIND);
- socketThread.sendBoatActionMessage(boatActionMessage);
- break;
- case PAGE_DOWN: // downwind
- boatActionMessage = new BoatActionMessage(BoatActionType.DOWNWIND);
- socketThread.sendBoatActionMessage(boatActionMessage);
- break;
- case ENTER: // tack/gybe
- boatActionMessage = new BoatActionMessage(BoatActionType.TACK_GYBE);
- socketThread.sendBoatActionMessage(boatActionMessage);
- break;
- //TODO Allow a zoom in and zoom out methods
- case Z: // zoom in
- raceView.getGameView().zoomIn();
- System.out.println("Zoom in");
- break;
- case X: // zoom out
- raceView.getGameView().zoomOut();
- System.out.println("Zoom out");
- break;
- }
- }
- }
-
- public void keyReleased(KeyEvent e) {
+ private void keyPressed(KeyEvent e) {
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)
- case SHIFT: // sails in/sails out
- BoatActionMessage boatActionMessage = new BoatActionMessage(
- BoatActionType.SAILS_IN);
- socketThread.sendBoatActionMessage(boatActionMessage);
- raceView.getGameView().getPlayerYacht().toggleClientSail();
+ case SPACE: // align with vmg
+ socketThread.sendBoatAction(BoatAction.VMG); break;
+ case PAGE_UP: // upwind
+ socketThread.sendBoatAction(BoatAction.UPWIND); break;
+ case PAGE_DOWN: // downwind
+ socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
+ case ENTER: // tack/gybe
+ socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
+ //TODO Allow a zoom in and zoom out methods
+ case Z: // zoom in
+ System.out.println("Zoom in");
+ break;
+ case X: // zoom out
+ System.out.println("Zoom out");
break;
}
}
+
+ private void keyReleased(KeyEvent e) {
+ 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)
+ case SHIFT: // sails in/sails out
+ socketThread.sendBoatAction(BoatAction.SAILS_IN);
+ raceView.getGameView().getPlayerYacht().toggleClientSail();
+ break;
+ case PAGE_UP:
+ case PAGE_DOWN:
+ socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
+ }
+ }
}
diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java
index 95e1aed0..15690387 100644
--- a/src/main/java/seng302/visualiser/GameView.java
+++ b/src/main/java/seng302/visualiser/GameView.java
@@ -200,7 +200,7 @@ public class GameView extends Pane {
}
}
// Platform.runLater(() ->
-// boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation())
+ boatObjects.forEach((boat, boatObject) -> boatObject.updateLocation());
// );
}
};
@@ -559,7 +559,6 @@ public class GameView extends Pane {
distanceFromReference = GeoUtility.getDistance(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
);
-// System.out.println("distanceFromReference = " + distanceFromReference);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
@@ -579,8 +578,6 @@ public class GameView extends Pane {
if(horizontalInversion) {
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
}
-// System.out.println("yAxisLocation = " + yAxisLocation + " " + unscaledLat);
-// System.out.println("xAxisLocation = " + xAxisLocation + " " + unscaledLon);
return new Point2D(xAxisLocation, yAxisLocation);
}
diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java
index 1a8b13e3..809bd3b5 100644
--- a/src/main/java/seng302/visualiser/controllers/LobbyController.java
+++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java
@@ -4,15 +4,13 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.application.Platform;
-import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
-import javafx.scene.control.ListView;
+import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
-import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import seng302.gameServer.GameStages;
import seng302.gameServer.GameState;
@@ -33,28 +31,26 @@ public class LobbyController {
void notify(CloseStatus exitCause);
}
- @FXML
- private GridPane lobbyScreen;
@FXML
private Text lobbyIpText;
@FXML
private Button readyButton;
@FXML
- private ListView firstListView;
+ private TextArea playerOneTxt;
@FXML
- private ListView secondListView;
+ private TextArea playerTwoTxt;
@FXML
- private ListView thirdListView;
+ private TextArea playerThreeTxt;
@FXML
- private ListView fourthListView;
+ private TextArea playerFourTxt;
@FXML
- private ListView fifthListView;
+ private TextArea playerFiveTxt;
@FXML
- private ListView sixthListView;
+ private TextArea playerSixTxt;
@FXML
- private ListView seventhListView;
+ private TextArea playerSevenTxt;
@FXML
- private ListView eighthListView;
+ private TextArea playerEightTxt;
@FXML
private ImageView firstImageView;
@FXML
@@ -72,79 +68,67 @@ public class LobbyController {
@FXML
private ImageView eighthImageView;
- private List> competitors = new ArrayList<>();
- private ObservableList firstCompetitor = FXCollections.observableArrayList();
- private ObservableList secondCompetitor = FXCollections.observableArrayList();
- private ObservableList thirdCompetitor = FXCollections.observableArrayList();
- private ObservableList fourthCompetitor = FXCollections.observableArrayList();
- private ObservableList fifthCompetitor = FXCollections.observableArrayList();
- private ObservableList sixthCompetitor = FXCollections.observableArrayList();
- private ObservableList seventhCompetitor = FXCollections.observableArrayList();
- private ObservableList eighthCompetitor = FXCollections.observableArrayList();
-
private List imageViews = new ArrayList<>();
- private List listViews;
+ private List