Merged with develop. Fixed many bugs in Visualiser.

#bugs
This commit is contained in:
Calum
2017-07-26 02:49:31 +12:00
parent acd54dec7a
commit 08e369f1ae
41 changed files with 1693 additions and 1636 deletions
@@ -3,7 +3,7 @@ package seng302.visualiser;
import seng302.model.stream.packets.StreamPacket;
/**
* Created by cir27 on 21/07/17.
* Functional interface for receiving packets from client socket.
*/
@FunctionalInterface
public interface ClientSocketListener {
@@ -9,48 +9,42 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import seng302.model.stream.packets.StreamPacket;
import seng302.models.stream.packets.StreamPacket;
import seng302.server.messages.BoatActionMessage;
import seng302.server.messages.Message;
/**
* Created by kre39 on 13/07/17.
*/
public class ClientToServerThread extends Thread {
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
private List<ClientSocketListener> listeners = new ArrayList<>();
public class ClientToServerThread implements Runnable {
private static final int LOG_LEVEL = 1;
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
private List<ClientSocketListener> listeners = new ArrayList<>();
private Thread thread;
private Integer ourID;
private Socket socket;
private InputStream is;
private OutputStream os;
private int clientId;
private Boolean updateClient = true;
private ByteArrayOutputStream crcBuffer;
public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{
public ClientToServerThread(String ipAddress, Integer portNumber) throws IOException{
socket = new Socket(ipAddress, portNumber);
is = socket.getInputStream();
os = socket.getOutputStream();
Integer allocatedID = threeWayHandshake();
if (allocatedID != null) {
ourID = allocatedID;
clientLog("Successful handshake. Allocated ID: " + ourID, 1);
ClientState.setClientSourceId(String.valueOf(ourID));
clientId = allocatedID;
clientLog("Successful handshake. Allocated ID: " + clientId, 1);
} else {
clientLog("Unsuccessful handshake", 1);
closeSocket();
@@ -59,7 +53,6 @@ public class ClientToServerThread implements Runnable {
thread = new Thread(this);
thread.start();
}
static void clientLog(String message, int logLevel){
@@ -72,7 +65,7 @@ public class ClientToServerThread implements Runnable {
int sync1;
int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while(ClientState.isConnectedToHost()) {
while(true) { /**REMOVED SOMETHING HERE ClientState.isConnectedToHost() */
try {
//Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) {
@@ -113,8 +106,8 @@ public class ClientToServerThread implements Runnable {
return;
}
}
closeSocket();
clientLog("Disconnected from server", 0);
// closeSocket();
// clientLog("Disconnected from server", 0);
}
@@ -0,0 +1,305 @@
package seng302.visualiser;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread;
import seng302.model.Yacht;
import seng302.model.RaceState;
import seng302.model.mark.Mark;
import seng302.model.stream.parser.PositionUpdateData.DeviceType;
import seng302.model.stream.parser.MarkRoundingData;
import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.parser.StreamParser;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.stream.xml.parser.XMLParser;
import seng302.model.stream.parser.PositionUpdateData;
import seng302.model.stream.packets.StreamPacket;
import seng302.visualiser.ClientToServerThread;
import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.LobbyController.CloseStatus;
import seng302.visualiser.controllers.RaceViewController;
/**
* Created by cir27 on 20/07/17.
*/
public class GameClient {
private Pane holderPane;
private ClientToServerThread socketThread;
private MainServerThread server;
private RaceViewController raceView;
private Map<Integer, Yacht> allBoatsMap;
private RegattaXMLData regattaData;
private RaceXMLData courseData;
private RaceState raceState = new RaceState();
private ObservableList<String> lobbyList = FXCollections.observableArrayList();
public GameClient(Pane holder) {
this.holderPane = holder;
}
public void runAsClient (String ipAddress, Integer portNumber) {
try {
socketThread = new ClientToServerThread(ipAddress, portNumber);
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("Unable to connect to host...");
}
LobbyController lobbyController = loadLobby("/views/LobbyView.fxml");
lobbyController.setPlayerListSource(lobbyList);
lobbyController.setTitle("Connected to host - IP : " + ipAddress + " Port : " + portNumber);
lobbyController.addCloseListener((exitCause) -> this.loadStartScreen());
socketThread.addStreamObserver(this::parsePacket);
}
public void runAsHost (String ipAddress, Integer portNumber) {
server = new MainServerThread();
try {
socketThread = new ClientToServerThread(ipAddress, portNumber);
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("Unable to make local connection to host...");
}
LobbyController lobbyController = loadLobby("/views/HostLobbyView.fxml");
lobbyController.setPlayerListSource(GameState.getObservablePlayers());
lobbyController.setTitle("Hosting Lobby - IP : " + ipAddress + " Port : " + portNumber);
lobbyController.addCloseListener(exitCause -> {
if (exitCause == CloseStatus.READY) {
server.startGame();
socketThread.addStreamObserver(this::parsePacket);
} else if (exitCause == CloseStatus.LEAVE) {
loadStartScreen();
}
});
}
private void loadStartScreen () {
socketThread.closeSocket();
socketThread = null;
if (server != null) {
// TODO: 26/07/17 cir27 - handle disconnecting
server.shutDown();
server = null;
}
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/StartScreenView.fxml"));
try {
holderPane.getChildren().clear();
holderPane.getChildren().add(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Loads a view of the lobby into the clients pane
* @param lobbyView fxml file for the desired lobby
* @return the lobby controller.
*/
private LobbyController loadLobby (String lobbyView) {
FXMLLoader fxmlLoader = new FXMLLoader(GameClient.class.getResource(lobbyView));
try {
holderPane.getChildren().clear();
holderPane.getChildren().add(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
return fxmlLoader.getController();
}
private void loadRaceView () {
// allBoatsMap.forEach((id, boat) -> {
// if (courseData.getParticipants().contains(id))
// racingBoats.put(id, boat);
// });
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/RaceView.fxml"));
raceView = fxmlLoader.getController();
try {
holderPane.getChildren().add(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
raceView.loadRace(allBoatsMap, courseData, raceState);
}
private void parsePacket(StreamPacket packet) {
switch (packet.getType()) {
case RACE_STATUS:
processRaceStatusUpdate(StreamParser.extractRaceStatus(packet));
break;
case REGATTA_XML:
System.out.println("REGATTA XML");
regattaData = XMLParser.parseRegatta(
StreamParser.extractXmlMessage(packet)
);
raceState.setTimeZone(
TimeZone.getTimeZone(
ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset()))
)
);
startRaceIfAllDataReceived();
break;
case RACE_XML:
System.out.println("RACE XML");
courseData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet)
);
if (raceView != null) {
raceView.updateRaceData(courseData);
}
startRaceIfAllDataReceived();
break;
case BOAT_XML:
System.out.println("BOAT XML");
allBoatsMap = XMLParser.parseBoats(
StreamParser.extractXmlMessage(packet)
);
lobbyList.clear();
allBoatsMap.forEach((id, boat) -> lobbyList.add(id.toString() + boat.getBoatName()));
startRaceIfAllDataReceived();
break;
case RACE_START_STATUS:
raceState.updateState(StreamParser.extractRaceStartStatus(packet));
break;
case BOAT_LOCATION:
updatePosition(StreamParser.extractBoatLocation(packet));
break;
case MARK_ROUNDING:
updateMarkRounding(StreamParser.extractMarkRounding(packet));
break;
}
}
private void startRaceIfAllDataReceived() {
if (allXMLReceived())
loadRaceView();
}
private boolean allXMLReceived () {
return courseData != null && allBoatsMap != null && regattaData != null;
}
/**
* Updates the position of a boat. Boat and position are given in the provided data.
* @param positionData
*/
private void updatePosition(PositionUpdateData positionData) {
if (positionData.getType() == DeviceType.YACHT_TYPE) {
if (allXMLReceived() && allBoatsMap.containsKey(positionData.getDeviceId())) {
Yacht yacht = allBoatsMap.get(positionData.getDeviceId());
yacht.setVelocityProperty(positionData.getGroundSpeed());
yacht.setLat(positionData.getLat());
yacht.setLon(positionData.getLon());
yacht.setHeading(positionData.getHeading());
}
} else if (positionData.getType() == DeviceType.MARK_TYPE) {
Mark mark = courseData.getCompoundMarks().get(positionData.getDeviceId());
}
}
/**
* Updates the boat as having passed the mark. Boat and mark are given by the ids in the
* provided data.
* @param roundingData Contains data for the rounding of a mark.
*/
private void updateMarkRounding(MarkRoundingData roundingData) {
if (allXMLReceived()) {
Yacht yacht = allBoatsMap.get(roundingData.getBoatId());
yacht.setMarkRoundingTime(roundingData.getTimeStamp());
yacht.updateTimeSinceLastMarkProperty(
raceState.getRaceTime() - roundingData.getTimeStamp());
yacht.setLastMarkRounded(
courseData.getCompoundMarks().get(
roundingData.getMarkId()
)
);
}
}
private void processRaceStatusUpdate (RaceStatusData data) {
if (allXMLReceived()) {
raceState.updateState(data);
for (long[] boatData : data.getBoatData()) {
Yacht yacht = allBoatsMap.get((int) boatData[0]);
yacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
yacht.setEstimateTimeAtFinish(boatData[2]);
int legNumber = (int) boatData[3];
yacht.setLegNumber(legNumber);
if (legNumber != yacht.getLegNumber()) {
int placing = 1;
for (Yacht otherYacht : allBoatsMap.values()) {
if (otherYacht.getSourceId() != boatData[0] &&
yacht.getLegNumber() <= otherYacht.getLegNumber())
placing++;
}
yacht.setPositionInteger(placing);
}
}
}
}
private void close () {
socketThread.closeSocket();
}
// /** Handle the key-pressed event from the text field. */
// public void keyPressed(KeyEvent e) {
// BoatActionMessage boatActionMessage;
// switch (e.getCode()){
// case SPACE: // align with vmg
// boatActionMessage = new BoatActionMessage(BoatActionType.VMG);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case PAGE_UP: // upwind
// boatActionMessage = new BoatActionMessage(BoatActionType.UPWIND);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case PAGE_DOWN: // downwind
// boatActionMessage = new BoatActionMessage(BoatActionType.DOWNWIND);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case ENTER: // tack/gybe
// boatActionMessage = new BoatActionMessage(BoatActionType.TACK_GYBE);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// 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;
// }
// }
// public 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
// BoatActionMessage boatActionMessage = new BoatActionMessage(BoatActionType.SAILS_IN);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// }
// }
//
// onKeyPressed="#keyPressed" onKeyReleased="#keyReleased"
}
+12 -13
View File
@@ -27,14 +27,13 @@ import seng302.visualiser.fxObjects.AnnotationBox;
import seng302.visualiser.fxObjects.BoatObject;
import seng302.visualiser.fxObjects.MarkObject;
import seng302.model.Colors;
import seng302.model.Boat;
import seng302.model.Yacht;
import seng302.model.map.Boundary;
import seng302.model.map.CanvasMap;
import seng302.model.mark.GateMark;
import seng302.model.mark.Mark;
import seng302.model.mark.MarkType;
import seng302.model.mark.SingleMark;
import seng302.model.stream.parsers.StreamParser;
import seng302.utilities.GeoPoint;
import seng302.utilities.GeoUtility;
@@ -65,7 +64,7 @@ public class GameView extends Pane {
private double metersPerPixelY;
private Map<SingleMark, MarkObject> markObjects = new HashMap<>();
private Map<Boat, BoatObject> boatObjects = new HashMap<>();
private Map<Yacht, BoatObject> boatObjects = new HashMap<>();
private List<AnnotationBox> annotations = new ArrayList<>();
private Text fpsDisplay = new Text();
@@ -255,17 +254,17 @@ public class GameView extends Pane {
/**
* Draws all the boats.
*/
public void setBoats(List<Boat> boats) {
public void setBoats(List<Yacht> yachts) {
Group annotationsGroup = new Group();
Group wakesGroup = new Group();
Group boatObjectGroup = new Group();
BoatObject newObject;
for (Boat boat : boats) {
for (Yacht yacht : yachts) {
newObject = new BoatObject();
// newObject.bindBoat(boat);
newObject.setFill(Colors.getColor());
createAnnotationBox(boat);
createAnnotationBox(yacht);
}
// Group wakes = new Group();
@@ -279,19 +278,19 @@ public class GameView extends Pane {
gameObjects.addAll(boatObjects.values());
}
private AnnotationBox createAnnotationBox (Boat boat) {
private AnnotationBox createAnnotationBox (Yacht yacht) {
AnnotationBox newAnnotation;
newAnnotation = new AnnotationBox();
newAnnotation.addAnnotation("name", boat.getShortName());
newAnnotation.addAnnotation("name", yacht.getShortName());
// newAnnotation.addAnnotation("country", boat.getCountry());
newAnnotation.addAnnotation(
"velocity",
boat.getVelocityProperty(),
yacht.getVelocityProperty(),
(velocity) -> String.format("%.2f ms", velocity.doubleValue())
);
newAnnotation.addAnnotation(
"nextMark",
boat.timeTillNextProperty(),
yacht.timeTillNextProperty(),
(time) -> {
DateFormat format = new SimpleDateFormat("mm:ss");
return format.format(time);
@@ -299,7 +298,7 @@ public class GameView extends Pane {
);
newAnnotation.addAnnotation(
"lastMark",
boat.timeTillNextProperty(),
yacht.timeTillNextProperty(),
(time) -> {
DateFormat format = new SimpleDateFormat("mm:ss");
return format.format(time);
@@ -518,9 +517,9 @@ public class GameView extends Pane {
return fpsDisplay.visibleProperty();
}
public void selectBoat (Boat selectedBoat) {
public void selectBoat (Yacht selectedYacht) {
boatObjects.forEach((boat, group) ->
group.setIsSelected(boat == selectedBoat)
group.setIsSelected(boat == selectedYacht)
);
}
@@ -1,8 +1,10 @@
package seng302.controllers;
package seng302.visualiser.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@@ -15,12 +17,8 @@ import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import seng302.client.ClientPacketParser;
import seng302.models.Yacht;
import seng302.models.stream.XMLParser.RaceXMLObject.Participant;
import seng302.model.Boat;
import seng302.model.stream.parsers.StreamParser;
import seng302.model.stream.parsers.xml.XMLParser.RaceXMLObject.Participant;
import seng302.model.Yacht;
import seng302.model.stream.parser.StreamParser;
public class FinishScreenViewController implements Initializable {
@@ -37,6 +35,8 @@ public class FinishScreenViewController implements Initializable {
@FXML
private TableColumn<Yacht, String> countryCol;
ObservableList<Yacht> data = FXCollections.observableArrayList();
@Override
public void initialize(URL location, ResourceBundle resources) {
finishScreenGridPane.getStylesheets()
@@ -44,7 +44,6 @@ public class FinishScreenViewController implements Initializable {
finishOrderTable.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// set up data for table
ObservableList<Yacht> data = FXCollections.observableArrayList();
finishOrderTable.setItems(data);
// setting table col data
@@ -60,24 +59,15 @@ public class FinishScreenViewController implements Initializable {
countryCol.setCellValueFactory(
new PropertyValueFactory<>("country")
);
// check if the boat is racing
ArrayList<Participant> participants = StreamParser.getXmlObject().getRaceXML()
.getParticipants();
ArrayList<Integer> participantIDs = new ArrayList<>();
for (Participant p : participants) {
participantIDs.add(p.getsourceID());
}
// add data to table
for (Yacht boat : StreamParser.getBoatsPos().values()) {
if (participantIDs.contains(boat.getSourceID())) {
data.add(boat);
}
}
finishOrderTable.refresh();
}
public void setFinishers (List<Yacht> participants) {
List<Yacht> sorted = new ArrayList<>(participants);
sorted.sort(Comparator.comparingInt(Yacht::getPositionInteger));
finishOrderTable.getItems().setAll(sorted);
}
private void setContentPane(String jfxUrl) {
try {
// get the main controller anchor pane (FinishView -> MainView)
@@ -1,14 +1,9 @@
package seng302.visualiser.controllers;
import java.io.IOException;
import java.io.InputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.*;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
@@ -24,17 +19,28 @@ import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.text.Text;
import seng302.client.ClientState;
import seng302.client.ClientStateQueryingRunnable;
import seng302.gameServer.GameStages;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread;
/**
* A class describing the actions of the lobby screen
* Created by wmu16 on 10/07/17.
*/
public class LobbyController implements Initializable, Observer{
public class LobbyController implements Initializable {
public enum CloseStatus {
LEAVE,
READY
}
@FunctionalInterface
public interface LobbyCloseListener {
void notify(CloseStatus exitCause);
}
@FXML
private ListView<String> competitorsListView;
@FXML
private GridPane lobbyScreen;
@FXML
@@ -42,7 +48,7 @@ public class LobbyController implements Initializable, Observer{
@FXML
private Button readyButton;
@FXML
private ListView firstListView;
private ListView<String> firstListView;
@FXML
private ListView secondListView;
@FXML
@@ -83,10 +89,11 @@ public class LobbyController implements Initializable, Observer{
private static ObservableList<String> sixthCompetitor = FXCollections.observableArrayList();
private static ObservableList<String> seventhCompetitor = FXCollections.observableArrayList();
private static ObservableList<String> eighthCompetitor = FXCollections.observableArrayList();
private ClientStateQueryingRunnable clientStateQueryingRunnable;
// private ClientStateQueryingRunnable clientStateQueryingRunnable;
private Boolean switchedPane = false;
private MainServerThread mainServerThread;
private List<LobbyCloseListener> lobbyListeners = new ArrayList<>();
private void setContentPane(String jfxUrl) {
try {
@@ -105,51 +112,54 @@ public class LobbyController implements Initializable, Observer{
@Override
public void initialize(URL location, ResourceBundle resources) {
if (ClientState.isHost()) {
lobbyIpText.setText("Lobby Host IP: " + ClientState.getHostIp());
readyButton.setDisable(false);
}
else {
lobbyIpText.setText("Connected to IP: ");
readyButton.setDisable(true);
}
initialiseListView();
// if (ClientState.isHost()) {
// lobbyIpText.setText("Lobby Host IP: " + ClientState.getHostIp());
// readyButton.setDisable(false);
// }
// else {
// lobbyIpText.setText("Connected to IP: ");
// readyButton.setDisable(true);
// readyButton.setVisible(false);
// }
// initialiseListView();
// initialiseLobbyControllerThread();
initialiseImageView(); // parrot gif init
// initialiseImageView(); // parrot gif init
// set up client state query thread, so that when it receives the race-started packet
// it can switch to the race view
ClientStateQueryingRunnable clientStateQueryingRunnable = new ClientStateQueryingRunnable();
clientStateQueryingRunnable.addObserver(this);
Thread clientStateQueryingThread = new Thread(clientStateQueryingRunnable, "Client State querying thread");
clientStateQueryingThread.setDaemon(true);
clientStateQueryingThread.start();
// ClientStateQueryingRunnable clientStateQueryingRunnable = new ClientStateQueryingRunnable();
// clientStateQueryingRunnable.addObserver(this);
// Thread clientStateQueryingThread = new Thread(clientStateQueryingRunnable, "Client State querying thread");
// clientStateQueryingThread.setDaemon(true);
// clientStateQueryingThread.start();
}
@Override
public void update(Observable o, Object arg) {
Platform.runLater(new Runnable() {
@Override
public void run() {
if (arg.equals("game started") && !switchedPane) {
switchToRaceView();
}
if (arg.equals(("update players"))) {
initialiseListView();
}
}
});
}
// @Override
// public void update(Observable o, Object arg) {
// Platform.runLater(new Runnable() {
// @Override
// public void run() {
// if (arg.equals("game started") && !switchedPane) {
// switchToRaceView();
// }
// if (arg.equals(("update players"))) {
// initialiseListView();
// }
// }
// });
// }
private void initialiseListView() {
firstListView.getItems().clear();
secondListView.getItems().clear();
thirdListView.getItems().clear();
fourthListView.getItems().clear();
fifthListView.getItems().clear();
sixthListView.getItems().clear();
seventhListView.getItems().clear();
eighthListView.getItems().clear();
// firstListView.getItems().clear();
// secondListView.getItems().clear();
// thirdListView.getItems().clear();
// fourthListView.getItems().clear();
// fifthListView.getItems().clear();
// sixthListView.getItems().clear();
// seventhListView.getItems().clear();
// eighthListView.getItems().clear();
competitors = new ArrayList<>();
Collections.addAll(competitors, firstCompetitor, secondCompetitor, thirdCompetitor,
@@ -159,19 +169,19 @@ public class LobbyController implements Initializable, Observer{
ol.removeAll();
}
firstCompetitor.add(ClientState.getClientSourceId());
// firstCompetitor.add(ClientState.getClientSourceId());
int competitorIndex = 1;
for (Integer yachtId : ClientState.getBoats().keySet()) {
// break if there are more than 7 competitors
if (competitorIndex >= 8) {
break;
}
if (!yachtId.equals(Integer.parseInt(ClientState.getClientSourceId()))) {
competitors.get(competitorIndex).add(String.valueOf(yachtId));
competitorIndex++;
}
}
// int competitorIndex = 1;
// for (Integer yachtId : ClientState.getBoats().keySet()) {
// // break if there are more than 7 competitors
// if (competitorIndex >= 8) {
// break;
// }
// if (!yachtId.equals(Integer.parseInt(ClientState.getClientSourceId()))) {
// competitors.get(competitorIndex).add(String.valueOf(yachtId));
// competitorIndex++;
// }
// }
firstListView.setItems(firstCompetitor);
secondListView.setItems(secondCompetitor);
@@ -183,20 +193,20 @@ public class LobbyController implements Initializable, Observer{
eighthListView.setItems(eighthCompetitor);
}
private void initialiseLobbyControllerThread() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
}
});
}
});
thread.start();
}
// private void initialiseLobbyControllerThread() {
// Thread thread = new Thread(new Runnable() {
// @Override
// public void run() {
// Platform.runLater(new Runnable() {
// @Override
// public void run() {
//
// }
// });
// }
// });
// thread.start();
// }
private void initialiseImageView() {
Image image1 = new Image(getClass().getResourceAsStream("/ParrotGif/alistair.gif"));
@@ -223,7 +233,7 @@ public class LobbyController implements Initializable, Observer{
setContentPane("/views/StartScreenView.fxml");
GameState.setCurrentStage(GameStages.CANCELLED);
// TODO: 20/07/17 wmu16 - Implement some way of terminating the game
ClientState.setConnectedToHost(false);
// ClientState.setConnectedToHost(false);
}
@FXML
@@ -231,7 +241,8 @@ public class LobbyController implements Initializable, Observer{
// setContentPane("/views/RaceView.fxml");
playTheme();
GameState.setCurrentStage(GameStages.RACING);
mainServerThread.startGame();
for (LobbyCloseListener readyListener : lobbyListeners)
readyListener.notify(CloseStatus.READY);
}
@@ -253,14 +264,27 @@ public class LobbyController implements Initializable, Observer{
}
}
private void switchToRaceView() {
if (!switchedPane) {
switchedPane = true;
setContentPane("/views/RaceView.fxml");
}
// private void switchToRaceView() {
// if (!switchedPane) {
// switchedPane = true;
// setContentPane("/views/RaceView.fxml");
// }
// }
// TODO: 26/07/17 cir27 - Could probably be done in a cleaner way.
public void setTitle (String title) {
lobbyIpText.setText(title);
}
public void setMainServerThread(MainServerThread mainServerThread) {
this.mainServerThread = mainServerThread;
public void addCloseListener(LobbyCloseListener listener) {
lobbyListeners.add(listener);
}
public void setPlayerListSource (ObservableList<String> players) {
if (competitorsListView != null)
competitorsListView.setItems(players);
if (firstListView != null) {
firstListView.setItems(players);
firstImageView.setVisible(false);
}
}
}
@@ -1,12 +1,10 @@
package seng302.visualiser.controllers;
import com.sun.javafx.collections.SortableList;
import java.util.concurrent.TimeUnit;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Point2D;
@@ -33,20 +31,15 @@ import javafx.stage.StageStyle;
import javafx.util.Duration;
import javafx.util.StringConverter;
import seng302.model.Corner;
import seng302.model.stream.parsers.xml.RaceXMLData;
import seng302.utilities.GeoUtility;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.visualiser.GameView;
import seng302.visualiser.controllers.annotations.Annotation;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
import seng302.visualiser.controllers.annotations.ImportantAnnotationDelegate;
import seng302.visualiser.controllers.annotations.ImportantAnnotationsState;
import seng302.visualiser.fxObjects.BoatObject;
import seng302.visualiser.fxObjects.MarkObject;
import seng302.model.*;
import seng302.model.mark.GateMark;
import seng302.model.mark.Mark;
import seng302.model.mark.SingleMark;
import seng302.model.stream.parsers.StreamParser;
import java.io.IOException;
import java.util.*;
@@ -75,10 +68,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
@FXML
private Button selectAnnotationBtn;
@FXML
private ComboBox<Boat> boatSelectionComboBox;
private ComboBox<Yacht> yachtSelectionComboBox;
//Race Data
private Map<Integer, Boat> participants;
private Map<Integer, Yacht> participants;
private Map<Integer, Mark> markers;
private RaceXMLData courseData;
private GameView gameView;
@@ -102,7 +95,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
}
public void loadRace (Map<Integer, Boat> participants, RaceXMLData raceData, RaceState raceState) {
public void loadRace (Map<Integer, Yacht> participants, RaceXMLData raceData, RaceState raceState) {
this.participants = participants;
this.courseData = raceData;
this.markers = raceData.getCompoundMarks();
@@ -205,30 +198,30 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Used to add any new boats into the race that may have started late or not have had data received yet
* Used to add any new yachts into the race that may have started late or not have had data received yet
*/
private void updateSparkLine(){
// Collect the racing boats that aren't already in the chart
List<Boat> sparkLineCandidates = new ArrayList<>();
// participants.forEach((id, boat) ->{
// if (!sparkLineData.containsKey(id) && boat.getPosition() != null && !boat.getPosition().equals("-"))
// sparkLineCandidates.add(boat);
// Collect the racing yachts that aren't already in the chart
List<Yacht> sparkLineCandidates = new ArrayList<>();
// participants.forEach((id, yacht) ->{
// if (!sparkLineData.containsKey(id) && yacht.getPosition() != null && !yacht.getPosition().equals("-"))
// sparkLineCandidates.add(yacht);
// });
participants.forEach((id, boat) -> sparkLineCandidates.add(boat));
participants.forEach((id, yacht) -> sparkLineCandidates.add(yacht));
sparklineYAxis.setUpperBound(participants.size() + 1);
// Create a new data series for new boats
sparkLineCandidates.stream().filter(yacht -> yacht.getPosition() != null).forEach(yacht -> {
// Create a new data series for new yachts
sparkLineCandidates.stream().filter(yacht -> yacht.getPositionInteger() != null).forEach(yacht -> {
Series<String, Double> yachtData = new Series<>();
yachtData.setName(yacht.getSourceID().toString());
yachtData.setName(yacht.getSourceId().toString());
yachtData.getData().add(
new XYChart.Data<>(
Integer.toString(yacht.getLegNumber()),
1.0 + participants.size() - yacht.getPosition()
1.0 + participants.size() - yacht.getPositionInteger()
)
);
sparkLineData.put(yacht.getSourceID(), yachtData);
sparkLineData.put(yacht.getSourceId(), yachtData);
});
// Lambda function to sort the series in order of leg (later legs shown more to the right)
@@ -256,36 +249,36 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Updates the yachts sparkline of the desired boat and using the new leg number
* @param boat The yacht to be updated on the sparkline
* Updates the yachts sparkline of the desired yacht and using the new leg number
* @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to
*/
public void updateYachtPositionSparkline(Boat boat, Integer legNumber){
public void updateYachtPositionSparkline(Yacht yacht, Integer legNumber){
for (XYChart.Series<String, Double> positionData : sparkLineData.values()) {
positionData.getData().add(
new Data<>(
Integer.toString(legNumber),
1.0 + participants.size() - boat.getPosition()
1.0 + participants.size() - yacht.getPositionInteger()
)
);
}
// XYChart.Series<String, Double> positionData = sparkLineData.get(boat.getSourceID());
// XYChart.Series<String, Double> positionData = sparkLineData.get(yacht.getSourceID());
// positionData.getData().add(
// new XYChart.Data<>(
// Integer.toString(legNumber),
// 1.0 + participants.size() - boat.getPosition()
// 1.0 + participants.size() - yacht.getPosition()
// )
// );
}
/**
* gets the rgb string of the boats colour to use for the chart via css
* @param boatId id of boat passed in to get the boats colour
* gets the rgb string of the yachts colour to use for the chart via css
* @param yachtId id of yacht passed in to get the yachts colour
* @return the colour as an rgb string
*/
private String getBoatColorAsRGB(String boatId){
Color color = participants.get(Integer.valueOf(boatId)).getColour();
private String getBoatColorAsRGB(String yachtId){
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
if (color == null){
return String.format("#%02X%02X%02X",255,255,255);
}
@@ -298,7 +291,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Initialises a timer which updates elements of the RaceView such as wind direction, boat
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly.
* Updates of each of these attributes are called ONCE EACH SECOND
*/
@@ -322,28 +315,28 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Iterates over all corners until ones SeqID matches with the boats current leg number.
* Iterates over all corners until ones SeqID matches with the yachts current leg number.
* Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
* Returns null if no next mark found.
* @param bg The BoatGroup to find the next mark of
* @return The next Mark or null if none found
*/
private Mark getNextMark(BoatObject bg) {
Integer legNumber = bg.getBoat().getLegNumber();
List<Corner> markSequence = courseData.getMarkSequence();
if (legNumber == 0) {
return null;
} else if (legNumber == markSequence.size() - 1) {
return null;
}
for (Corner corner : markSequence) {
if (legNumber + 2 == corner.getSeqID()) {
return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
}
}
//
// Integer legNumber = bg.getYacht().getLegNumber();
// List<Corner> markSequence = courseData.getMarkSequence();
//
// if (legNumber == 0) {
// return null;
// } else if (legNumber == markSequence.size() - 1) {
// return null;
// }
//
// for (Corner corner : markSequence) {
// if (legNumber + 2 == corner.getSeqID()) {
// return courseData.getCompoundMarks().get(corner.getCompoundMarkID());
// }
// }
return null;
}
@@ -370,7 +363,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}
/**
* Updates the order of the boats as from the StreamParser and sets them in the boat order
* Updates the order of the yachts as from the StreamParser and sets them in the yacht order
* section
*/
private void updateOrder() {
@@ -378,28 +371,28 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
positionVbox.getChildren().removeAll();
positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// list of racing boat id
List<Boat> sorted = new ArrayList<>(participants.values());
sorted.sort(Comparator.comparingInt(Boat::getPosition));
// list of racing yacht id
List<Yacht> sorted = new ArrayList<>(participants.values());
sorted.sort(Comparator.comparingInt(Yacht::getPositionInteger));
for (Boat boat : sorted) {
if (boat.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)");
for (Yacht yacht : sorted) {
if (yacht.getBoatStatus() == 3) { // 3 is finish status
Text textToAdd = new Text(yacht.getPositionInteger() + ". " +
yacht.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
positionVbox.getChildren().add(textToAdd);
} else {
Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " ");
Text textToAdd = new Text(yacht.getPositionInteger() + ". " +
yacht.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
}
// participants.forEach((id, boat) ->{
// Text textToAdd = new Text(boat.getPosition() + ". " +
// boat.getShortName() + " ");
// participants.forEach((id, yacht) ->{
// Text textToAdd = new Text(yacht.getPosition() + ". " +
// yacht.getShortName() + " ");
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
// textToAdd.setStyle("");
// positionVbox.getChildren().add(textToAdd);
@@ -442,9 +435,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// Double resultingAngle = angleAndSpeed.keySet().iterator().next();
//
//
// Point2D boatCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
// Point2D yachtCurrentPos = new Point2D(bg.getBoatLayoutX(), bg.getBoatLayoutY());
// Point2D gateMidPoint = markPoint1.midpoint(markPoint2);
// Integer lineFuncResult = GeoUtility.lineFunction(boatCurrentPos, gateMidPoint, markPoint2);
// Integer lineFuncResult = GeoUtility.lineFunction(yachtCurrentPos, gateMidPoint, markPoint2);
// Line rightLayline = new Line();
// Line leftLayline = new Line();
// if (lineFuncResult == 1) {
@@ -498,15 +491,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Initialised the combo box with any boats currently in the race and adds the required listener
* Initialised the combo box with any yachts currently in the race and adds the required listener
* for the combobox to take action upon selection
*/
private void initialiseBoatSelectionComboBox() {
boatSelectionComboBox.setItems(
yachtSelectionComboBox.setItems(
FXCollections.observableArrayList(participants.values())
);
//Null check is if the listener is fired but nothing selected
boatSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> {
if (selectedBoat != null) {
gameView.selectBoat(selectedBoat);
}
@@ -514,18 +507,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}
/**
* Grabs the boats currently in the race as from the StreamParser and sets them to be selectable
* in the boat selection combo box
* Grabs the yachts currently in the race as from the StreamParser and sets them to be selectable
* in the yacht selection combo box
*/
private void updateBoatSelectionComboBox() {
ObservableList<Boat> observableBoats = FXCollections.observableArrayList();
observableBoats.addAll(participants.values());
boatSelectionComboBox.setItems(observableBoats);
ObservableList<Yacht> observableYachts = FXCollections.observableArrayList();
observableYachts.addAll(participants.values());
yachtSelectionComboBox.setItems(observableYachts);
}
/**
* Display the list of boats in the order they finished the race
* Display the list of yachts in the order they finished the race
*/
private void loadRaceResultView() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml"));
@@ -580,18 +573,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/**
* Sets all the annotations of the selected boat to be visible and all others to be hidden
* Sets all the annotations of the selected yacht to be visible and all others to be hidden
*
* @param boat The yacht for which we want to view all annotations
* @param yacht The yacht for which we want to view all annotations
*/
private void setSelectedBoat(Boat boat) {
private void setSelectedBoat(Yacht yacht) {
// for (BoatObject bg : gameViewController.getBoatGroups()) {
// //We need to iterate over all race groups to get the matching boat group belonging to this boat if we
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup.
// if (bg.getBoat().getHullID().equals(boat.getHullID())) {
// //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup.
// if (bg.getBoat().getHullID().equals(yacht.getHullID())) {
//// updateLaylines(bg);
// bg.setIsSelected(true);
//// selectedBoat = boat;
//// selectedBoat = yacht;
// } else {
// bg.setIsSelected(false);
// }
@@ -2,9 +2,12 @@ package seng302.visualiser.controllers;
import java.net.Inet4Address;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
@@ -12,20 +15,18 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import seng302.client.ClientState;
import seng302.client.ClientToServerThread;
import seng302.visualiser.ClientToServerThread;
import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import seng302.visualiser.GameClient;
/**
* A Class describing the actions of the start screen controller
* Created by wmu16 on 10/07/17.
*/
public class StartScreenController {
public class StartScreenController implements Initializable {
@FXML
private TextField ipTextField;
@@ -33,27 +34,35 @@ public class StartScreenController {
private TextField portTextField;
@FXML
private GridPane startScreen2;
@FXML
private AnchorPane 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());
GameClient gameClient;
return fxmlLoader.getController();
} catch (IOException e) {
e.printStackTrace();
}
return null;
public void initialize(URL url, ResourceBundle resourceBundle) {
// 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;
// }
/**
@@ -65,33 +74,33 @@ public class StartScreenController {
*/
@FXML
public void hostButtonPressed() {
try {
String ipAddress = InetAddress.getLocalHost().getHostAddress();
new GameState(ipAddress);
new MainServerThread().start();
ClientToServerThread clientToServerThread = new ClientToServerThread("localhost", 4950);
// controller.setClientToServerThread(clientToServerThread);
clientToServerThread.start();
// 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();
}
new GameState(getLocalHostIp());
gameClient = new GameClient(holder);
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();
// }
}
/**
@@ -103,27 +112,30 @@ public class StartScreenController {
@FXML
public void connectButtonPressed() {
// TODO: 10/07/17 wmu16 - Finish function
try {
String ipAddress = ipTextField.getText().trim().toLowerCase();
Integer port = Integer.valueOf(portTextField.getText().trim());
gameClient = new GameClient(holder);
gameClient.runAsClient(ipTextField.getText().trim().toLowerCase(), 4942);
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();
}
// 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;
}
// public void setController(Controller controller) {
// this.controller = controller;
// }
/**
* Gets the local host ip address and sets this ip to ClientState.
@@ -158,7 +170,7 @@ public class StartScreenController {
if (ipAddress == null) {
System.out.println("[HOST] Cannot obtain local host ip address.");
}
ClientState.setHostIp(ipAddress);
// ClientState.setHostIp(ipAddress);
return ipAddress;
}
}
@@ -1,215 +0,0 @@
package seng302.visualiser.controllers.client;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import seng302.model.Boat;
import seng302.model.RaceState;
import seng302.model.mark.Mark;
import seng302.model.stream.parsers.PositionUpdateData.DeviceType;
import seng302.model.stream.parsers.MarkRoundingData;
import seng302.model.stream.parsers.RaceStatusData;
import seng302.model.stream.parsers.xml.RaceXMLData;
import seng302.model.stream.parsers.StreamParser;
import seng302.model.stream.parsers.xml.RegattaXMLData;
import seng302.model.stream.parsers.xml.XMLParser;
import seng302.model.stream.parsers.PositionUpdateData;
import seng302.model.stream.packets.StreamPacket;
import seng302.visualiser.ClientToServerThread;
import seng302.visualiser.controllers.RaceViewController;
/**
* Created by cir27 on 20/07/17.
*/
public class ClientController {
private Pane holderPane;
private ClientToServerThread socketThread;
private RaceViewController raceView;
private Map<Integer, Boat> allBoatsMap;
private Map<Integer, Boat> racingBoats = new HashMap<>();
private RegattaXMLData regattaData;
private RaceXMLData courseData;
private RaceState raceState = new RaceState();
public ClientController (String ipAddress, Pane holder) {
this.holderPane = holder;
socketThread = new ClientToServerThread(ipAddress, 4950);
socketThread.start();
socketThread.addStreamObserver(this::parsePacket);
}
private void loadRaceView () {
allBoatsMap.forEach((id, boat) -> {
if (courseData.getParticipants().contains(id))
racingBoats.put(id, boat);
});
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("RaceView.fxml"));
raceView = fxmlLoader.getController();
try {
holderPane.getChildren().add(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
raceView.loadRace(racingBoats, courseData, raceState);
}
private void parsePacket(StreamPacket packet) {
switch (packet.getType()) {
case RACE_STATUS:
processRaceStatusUpdate(StreamParser.extractRaceStatus(packet));
break;
case REGATTA_XML:
regattaData = XMLParser.parseRegatta(
StreamParser.extractXmlMessage(packet)
);
raceState.setTimeZone(
TimeZone.getTimeZone(
ZoneId.ofOffset("UTC", ZoneOffset.ofHours(regattaData.getUtcOffset()))
)
);
startRaceIfAllDataReceived();
break;
case RACE_XML:
courseData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet)
);
if (raceView != null) {
raceView.updateRaceData(courseData);
}
startRaceIfAllDataReceived();
break;
case BOAT_XML:
allBoatsMap = XMLParser.parseBoats(
StreamParser.extractXmlMessage(packet)
);
startRaceIfAllDataReceived();
break;
case RACE_START_STATUS:
raceState.updateState(StreamParser.extractRaceStartStatus(packet));
break;
case BOAT_LOCATION:
updatePosition(StreamParser.extractBoatLocation(packet));
break;
case MARK_ROUNDING:
updateMarkRounding(StreamParser.extractMarkRounding(packet));
break;
}
}
private void startRaceIfAllDataReceived() {
if (courseData != null && allBoatsMap != null && regattaData != null)
loadRaceView();
}
/**
* Updates the position of a boat. Boat and position are given in the provided data.
* @param positionData
*/
private void updatePosition(PositionUpdateData positionData) {
if (positionData.getType() == DeviceType.YACHT_TYPE) {
Boat boat = racingBoats.get(positionData.getDeviceId());
boat.setVelocity(positionData.getGroundSpeed());
boat.setLat(positionData.getLat());
boat.setLon(positionData.getLon());
boat.setHeading(positionData.getHeading());
} else if (positionData.getType() == DeviceType.MARK_TYPE) {
Mark mark = courseData.getCompoundMarks().get(positionData.getDeviceId());
}
}
/**
* Updates the boat as having passed the mark. Boat and mark are given by the ids in the
* provided data.
* @param roundingData Contains data for the rounding of a mark.
*/
private void updateMarkRounding(MarkRoundingData roundingData) {
Boat boat = racingBoats.get(roundingData.getBoatId());
boat.setMarkRoundingTime(roundingData.getTimeStamp());
boat.setTimeSinceLastMark(raceState.getRaceTime() - roundingData.getTimeStamp());
boat.setLastMarkRounded(
courseData.getCompoundMarks().get(
roundingData.getMarkId()
)
);
}
private void processRaceStatusUpdate (RaceStatusData data) {
raceState.updateState(data);
for (long[] boatData : data.getBoatData()) {
Boat boat = allBoatsMap.get((int) boatData[0]);
boat.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
boat.setEstimateTimeAtFinish(boatData[2]);
int legNumber = (int) boatData[3];
boat.setLegNumber(legNumber);
if (legNumber != boat.getLegNumber()) {
int placing = 1;
for (Boat otherBoat : allBoatsMap.values()) {
if (otherBoat.getSourceID() != boatData[0] &&
boat.getLegNumber() <= otherBoat.getLegNumber())
placing++;
}
boat.setPosition(placing);
}
}
}
private void close () {
socketThread.closeSocket();
}
// /** Handle the key-pressed event from the text field. */
// public void keyPressed(KeyEvent e) {
// BoatActionMessage boatActionMessage;
// switch (e.getCode()){
// case SPACE: // align with vmg
// boatActionMessage = new BoatActionMessage(BoatActionType.VMG);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case PAGE_UP: // upwind
// boatActionMessage = new BoatActionMessage(BoatActionType.UPWIND);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case PAGE_DOWN: // downwind
// boatActionMessage = new BoatActionMessage(BoatActionType.DOWNWIND);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// case ENTER: // tack/gybe
// boatActionMessage = new BoatActionMessage(BoatActionType.TACK_GYBE);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// 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;
// }
// }
// public 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
// BoatActionMessage boatActionMessage = new BoatActionMessage(BoatActionType.SAILS_IN);
// clientToServerThread.sendBoatActionMessage(boatActionMessage);
// break;
// }
// }
//
// onKeyPressed="#keyPressed" onKeyReleased="#keyReleased"
}
@@ -1,13 +0,0 @@
package seng302.visualiser.controllers.host;
import javafx.scene.layout.Pane;
/**
* Created by cir27 on 20/07/17.
*/
public class HostController {
Pane mainHolder;
public HostController (Pane holder) {
this.mainHolder = holder;
}
}
@@ -10,12 +10,7 @@ import javafx.scene.paint.Paint;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import seng302.model.Boat;
import seng302.utilities.GeoUtility;
import seng302.model.mark.GateMark;
import seng302.model.mark.Mark;
import seng302.model.mark.SingleMark;
import seng302.model.stream.parsers.StreamParser;
import seng302.model.Yacht;
/**
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
@@ -38,7 +33,6 @@ public class BoatObject extends Group {
private Double lastRotation = 0.0;
private long framesToMove;
//Graphical objects
private Boat boat;
private Group lineGroup = new Group();
private Polygon boatPoly;
private Wake wake;
@@ -161,7 +155,7 @@ public class BoatObject extends Group {
boatPoly.getLayoutY()
);
l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(boat.getColour());
l.setStroke(colour);
l.setCache(true);
l.setCacheHint(CacheHint.SPEED);
lineGroup.getChildren().add(l);
@@ -199,7 +193,7 @@ public class BoatObject extends Group {
rotateTo(rotation);
wake.setRotation(rotation, groundSpeed);
boat.setVelocity(groundSpeed);
// yacht.setVelocity(groundSpeed);
lastTimeValid = timeValid;
isStopped = false;
lastRotation = rotation;
@@ -278,19 +272,6 @@ public class BoatObject extends Group {
return laylines;
}
public Boat getBoat() {
return boat;
}
/**
* Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat.
*
* @return An array containing all ID's associated with this RaceObject.
*/
public long getRaceId() {
return boat.getSourceID();
}
public Group getWake () {
return wake;
}
@@ -316,9 +297,4 @@ public class BoatObject extends Group {
return isStopped;
}
@Override
public String toString() {
return boat.toString();
}
}