diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index c4538078..c8ead2e7 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -85,19 +85,19 @@ public class App extends Application { primaryStage.setScene(scene); primaryStage.show(); - primaryStage.setOnCloseRequest(e -> { + primaryStage.setOnCloseRequest(e -> closeAll()); - try { - ServerAdvertiser.getInstance().unregister(); - } catch (IOException e1) { - logger.warn("Could not un-register game"); - } + decorator.setOnCloseButtonAction(this::closeAll); + } - System.exit(0); - }); + private void closeAll(){ + try { + ServerAdvertiser.getInstance().unregister(); + } catch (IOException e1) { + logger.warn("Could not un-register game"); + } -// ClientState.primaryStage = primaryStage; - primaryStage.setOnCloseRequest(e -> System.exit(0)); + System.exit(0); } public static void main(String[] args) { diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index ebe4abbe..e42b2595 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -23,7 +23,6 @@ import java.util.*; * Created by wmu16 on 10/07/17. */ public class GameState implements Runnable { - @FunctionalInterface interface NewMessageListener { @@ -33,7 +32,6 @@ public class GameState implements Runnable { private Logger logger = LoggerFactory.getLogger(GameState.class); private static final Integer STATE_UPDATES_PER_SECOND = 60; - public static Integer MAX_PLAYERS = 8; public static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further public static final Double MARK_COLLISION_DISTANCE = 15d; public static final Double YACHT_COLLISION_DISTANCE = 25.0; @@ -56,6 +54,8 @@ public class GameState implements Runnable { private static long startTime; private static Set marks; private static List courseLimit; + private static Integer maxPlayers = 8; + private static List markListeners; @@ -268,8 +268,6 @@ public class GameState implements Runnable { checkForLegProgression(yacht); raceFinished = false; } - - } if (raceFinished) { @@ -685,10 +683,23 @@ public class GameState implements Runnable { customizationFlag = false; } - public static Integer getSpacesLeft(){ - Integer numberOfPlayers = GameState.getPlayers().size(); - Integer maxPlayers = GameState.MAX_PLAYERS; + public static Integer getNumberOfPlayers(){ + Integer numPlayers = 0; - return maxPlayers - numberOfPlayers - 1; + for(Player p : getPlayers()){ + if(p.getSocket().isConnected()){ + numPlayers++; + } + } + + return numPlayers; + } + + public static Integer getCapacity(){ + return maxPlayers; + } + + public static void setMaxPlayers(Integer newMax){ + maxPlayers = newMax; } } diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 0aa4b3a6..c6384286 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -50,8 +50,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { private ServerSocket serverSocket = null; private ArrayList serverToClientThreads = new ArrayList<>(); private Logger logger = LoggerFactory.getLogger(MainServerThread.class); + private static Integer capacity; - private void startAdvertisingServer(){ + private void startAdvertisingServer() { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; Document doc; @@ -70,16 +71,19 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc); - Integer spacesLeft = GameState.getSpacesLeft(); + + Integer capacity = GameState.getCapacity(); + Integer numPlayers = GameState.getNumberOfPlayers(); + Integer spacesLeft = capacity - numPlayers; // No spaces left on server - if (spacesLeft < 1){ + if (spacesLeft < 1) { return; } // Start advertising server - try{ - ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setSpacesLeft(spacesLeft); + try { + ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setCapacity(capacity).setNumberOfPlayers(numPlayers); ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName()); } catch (IOException e) { logger.warn("Could not register server"); @@ -229,7 +233,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { serverToClientThread.addDisconnectListener(this::clientDisconnected); try { - ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft()); + ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers()); } catch (IOException e) { logger.warn("Couldn't update advertisement"); } @@ -261,7 +265,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { serverToClientThreads.remove(closedConnection); try { - ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft()); + ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers()); } catch (IOException e) { logger.warn("Couldn't update advertisement"); } @@ -273,7 +277,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { try { ServerAdvertiser.getInstance().unregister(); } catch (IOException e) { - logger.warn("Error unregistered server"); + logger.warn("Error unregistering server"); } initialiseBoatPositions(); diff --git a/src/main/java/seng302/gameServer/ServerAdvertiser.java b/src/main/java/seng302/gameServer/ServerAdvertiser.java index 0b69b5a4..3c5929c2 100644 --- a/src/main/java/seng302/gameServer/ServerAdvertiser.java +++ b/src/main/java/seng302/gameServer/ServerAdvertiser.java @@ -41,6 +41,8 @@ public class ServerAdvertiser { props = new Hashtable<>(); props.put("map", ""); props.put("spacesLeft", "0"); + props.put("capacity", "0"); + props.put("players", "0"); } /** @@ -72,12 +74,27 @@ public class ServerAdvertiser { } /** - * Set the spaces left on the server and broadcast an update on the network - * @param spacesLeft The number of spaces left on the server + * Set the number of players on the server and broadcast an update on the network + * @param numPlayers The number of players on the server * @return The current ServerAdvertiser instance */ - public ServerAdvertiser setSpacesLeft(Integer spacesLeft){ - props.replace("spacesLeft", spacesLeft.toString()); + public ServerAdvertiser setNumberOfPlayers(Integer numPlayers){ + props.replace("players", numPlayers.toString()); + + if (serviceInfo != null){ + serviceInfo.setText(props); + } + + return instance; + } + + /** + * Set the max capacity of the server and broadcast an update on the network + * @param capacity The maximum capacity of the server + * @return The current ServerAdvertiser instance + */ + public ServerAdvertiser setCapacity(Integer capacity){ + props.replace("capacity", capacity.toString()); if (serviceInfo != null){ serviceInfo.setText(props); diff --git a/src/main/java/seng302/gameServer/ServerDescription.java b/src/main/java/seng302/gameServer/ServerDescription.java index 02440382..44fc1875 100644 --- a/src/main/java/seng302/gameServer/ServerDescription.java +++ b/src/main/java/seng302/gameServer/ServerDescription.java @@ -1,18 +1,20 @@ package seng302.gameServer; public class ServerDescription { + private Integer capacity; private String address; private Integer portNum; private String serverName; private String mapName; - private Integer spacesLeft; + private Integer numPlayers; - public ServerDescription(String serverName, String mapName, Integer spacesLeft, String address, Integer portNum){ + public ServerDescription(String serverName, String mapName, Integer numPlayers, Integer capacity, String address, Integer portNum){ this.serverName = serverName; this.mapName = mapName; - this.spacesLeft = spacesLeft; + this.numPlayers = numPlayers; this.address = address; this.portNum = portNum; + this.capacity = capacity; } @@ -32,8 +34,12 @@ public class ServerDescription { return address; } - public Integer spacesLeft() { - return spacesLeft; + public Integer getNumPlayers() { + return numPlayers; + } + + public Integer getCapacity(){ + return capacity; } @Override @@ -62,6 +68,10 @@ public class ServerDescription { return false; } + if (!this.getCapacity().equals(other.getCapacity())){ + return false; + } + return true; } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 82e481ce..315a435f 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -132,7 +132,7 @@ public class ServerToClientThread implements Runnable, Observer { return; } - if (GameState.getPlayers().size() >= GameState.MAX_PLAYERS){ + if (GameState.getPlayers().size() >= GameState.getCapacity()){ RegistrationResponseMessage responseMessage = new RegistrationResponseMessage(0, RegistrationResponseStatus.FAILURE_FULL); os.write(responseMessage.getBuffer()); return; diff --git a/src/main/java/seng302/model/stream/xml/generator/Regatta.java b/src/main/java/seng302/model/stream/xml/generator/Regatta.java index fa802e01..ad5180eb 100644 --- a/src/main/java/seng302/model/stream/xml/generator/Regatta.java +++ b/src/main/java/seng302/model/stream/xml/generator/Regatta.java @@ -74,4 +74,12 @@ public class Regatta { public Double getMagneticVariation(){ return magneticVariation; } + + public void setCourseName(String courseName) { + this.courseName = courseName; + } + + public void setRegattaName(String regattaName) { + this.name = regattaName; + } } diff --git a/src/main/java/seng302/utilities/XMLGenerator.java b/src/main/java/seng302/utilities/XMLGenerator.java index 6c478af2..67dd23e8 100644 --- a/src/main/java/seng302/utilities/XMLGenerator.java +++ b/src/main/java/seng302/utilities/XMLGenerator.java @@ -22,11 +22,11 @@ public class XMLGenerator { private static final String BOATS_TEMPLATE_NAME = "boats.ftlh"; private static final String RACE_TEMPLATE_NAME = "race.ftlh"; private Configuration configuration; - private Regatta regatta = null; + private static Regatta regatta = null; private Race race; public static Regatta DEFAULT_REGATTA = new Regatta("Party Parrot Test Server " + new Random().nextInt(100), - "Bermuda Test Course", + "Bermuda", 57.6679590, 11.8503233); @@ -167,4 +167,12 @@ public class XMLGenerator { return result; } + + public static void setDefaultRaceName(String raceName){ + DEFAULT_REGATTA.setRegattaName(raceName); + } + + public static void setDefaultMapName(String mapName){ + DEFAULT_REGATTA.setCourseName(mapName); + } } \ No newline at end of file diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index 57256760..5e8397ee 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -359,7 +359,7 @@ public class ClientToServerThread implements Runnable { } } - int getClientId () { + public int getClientId () { return clientId; } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 03956ae0..b0428b1e 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -3,6 +3,8 @@ package seng302.visualiser; import java.io.IOException; import java.time.ZoneId; import java.time.ZoneOffset; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.TimeZone; import javafx.application.Platform; @@ -30,12 +32,10 @@ import seng302.model.stream.parser.YachtEventData; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.utilities.StreamParser; +import seng302.utilities.XMLGenerator; import seng302.utilities.XMLParser; -import seng302.visualiser.controllers.FinishScreenViewController; -import seng302.visualiser.controllers.LobbyController_old; +import seng302.visualiser.controllers.*; import seng302.visualiser.controllers.LobbyController_old.CloseStatus; -import seng302.visualiser.controllers.RaceViewController; -import seng302.visualiser.controllers.ViewManager; /** * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated @@ -53,7 +53,7 @@ public class GameClient { private RegattaXMLData regattaData; private RaceXMLData courseData; private RaceState raceState = new RaceState(); - private LobbyController_old lobbyController; + private LobbyController lobbyController; private ObservableList clientLobbyList = FXCollections.observableArrayList(); @@ -80,24 +80,23 @@ public class GameClient { // Platform.runLater(this::loadStartScreen); // }); - socketThread.addStreamObserver(this::parsePackets); ViewManager.getInstance().setPlayerList(clientLobbyList); - if (regattaData != null){ - ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName()); - ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName()); - } - else{ - ViewManager.getInstance().setProperty("serverName", ipAddress); - ViewManager.getInstance().setProperty("mapName", ""); + while (regattaData == null){ + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } } + ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName()); + ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName()); // TODO disable ready button; - //LobbyController_old lobbyController = loadLobby(); //lobbyController.setSocketThread(socketThread); //lobbyController.setPlayerID(socketThread.getClientId()); @@ -107,7 +106,8 @@ public class GameClient { // lobbyController.addCloseListener((exitCause) -> this.loadStartScreen()); -// this.lobbyController = lobbyController; + this.lobbyController = ViewManager.getInstance().goToLobby(true); + } catch (IOException ioe) { showConnectionError("Unable to find server"); //Platform.runLater(this::loadStartScreen); @@ -119,7 +119,10 @@ public class GameClient { * @param ipAddress IP to connect to. * @param portNumber Port to connect to. */ - public ServerDescription runAsHost(String ipAddress, Integer portNumber) { + public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers) { + XMLGenerator.setDefaultRaceName(serverName); + GameState.setMaxPlayers(maxPlayers); + server = new MainServerThread(); try { @@ -128,9 +131,6 @@ public class GameClient { showConnectionError("Cannot connect to server as host"); } - String serverName = ""; - String courseName = ""; - while (regattaData == null){ try { Thread.sleep(100); @@ -139,12 +139,10 @@ public class GameClient { } } + this.lobbyController = ViewManager.getInstance().goToLobby(false); + ViewManager.getInstance().setPlayerList(clientLobbyList); - - serverName = regattaData.getRegattaName(); - courseName = regattaData.getCourseName(); - - return new ServerDescription(serverName, courseName, 0, ipAddress, 4942); + return new ServerDescription(serverName, regattaData.getCourseName(), GameState.getNumberOfPlayers(), GameState.getCapacity(), ipAddress, 4942); } private void loadStartScreen() { @@ -232,7 +230,6 @@ public class GameClient { switch (packet.getType()) { case RACE_STATUS: processRaceStatusUpdate(StreamParser.extractRaceStatus(packet)); - if (raceState.getTimeTillStart() <= 5000) { startRaceIfAllDataReceived(); } @@ -273,7 +270,7 @@ public class GameClient { case RACE_START_STATUS: raceState.updateState(StreamParser.extractRaceStartStatus(packet)); - if (lobbyController != null) lobbyController.updateRaceState(raceState); + if (lobbyController != null) Platform.runLater(() -> lobbyController.updateRaceState(raceState)); break; case BOAT_LOCATION: @@ -293,7 +290,10 @@ public class GameClient { private void startRaceIfAllDataReceived() { if (allXMLReceived() && raceView == null) { - loadRaceView(); + raceView = ViewManager.getInstance().loadRaceView(); + + ClientYacht player = allBoatsMap.get(socketThread.getClientId()); + raceView.loadRace(allBoatsMap, courseData, raceState, player); } } @@ -379,7 +379,7 @@ public class GameClient { * Handle the key-pressed event from the text field. * @param e The key event triggering this call */ - private void keyPressed(KeyEvent e) { + public void keyPressed(KeyEvent e) { switch (e.getCode()) { case SPACE: // align with vmg socketThread.sendBoatAction(BoatAction.VMG); break; @@ -393,7 +393,7 @@ public class GameClient { } - private void keyReleased(KeyEvent e) { + 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 @@ -423,4 +423,21 @@ public class GameClient { ); } } + + public void startGame(){ + server.startGame(); + } + + public ClientToServerThread getServerThread() { + return socketThread; + } + + public List getPlayerNames(){ + return Collections.unmodifiableList(clientLobbyList.sorted()); + } + + public void stopGame() { + if (server != null) server.terminate(); + if (socketThread != null) socketThread.setSocketToClose(); + } } diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java index 99a49021..edbed1d3 100644 --- a/src/main/java/seng302/visualiser/GameView.java +++ b/src/main/java/seng302/visualiser/GameView.java @@ -99,6 +99,11 @@ public class GameView extends Pane { double scaleFactor = 1; + public void setRes(Integer x, Integer y){ + this.panelHeight = y; + this.panelWidth = x; + } + private void zoomOut() { scaleFactor = 0.1; if (this.getScaleX() > 0.5) { @@ -550,7 +555,7 @@ public class GameView extends Pane { } private void drawFps(Double fps) { - Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps)))); + //Platform.runLater(() -> fpsDisplay.setText(String.format("%d FPS", Math.round(fps)))); } /** diff --git a/src/main/java/seng302/visualiser/ServerListener.java b/src/main/java/seng302/visualiser/ServerListener.java index 34b76fdb..625d088c 100644 --- a/src/main/java/seng302/visualiser/ServerListener.java +++ b/src/main/java/seng302/visualiser/ServerListener.java @@ -76,14 +76,16 @@ public class ServerListener{ String serverName = event.getInfo().getName(); String mapName = event.getInfo().getPropertyString("map"); - Integer spacesLeft = Integer.parseInt(event.getInfo().getPropertyString("spacesLeft")); - ServerDescription serverDescription = new ServerDescription(serverName, mapName, spacesLeft, address, portNum); + Integer capacity = Integer.parseInt(event.getInfo().getPropertyString("capacity")); + Integer numPlayers = Integer.parseInt(event.getInfo().getPropertyString("players")); + + ServerDescription serverDescription = new ServerDescription(serverName, mapName, numPlayers, capacity, address, portNum); servers.remove(serverDescription); servers.add(serverDescription); - delegate.serverDetected(serverDescription, new ArrayList(servers)); + delegate.serverDetected(serverDescription, new ArrayList<>(servers)); } } @@ -108,6 +110,4 @@ public class ServerListener{ public void setDelegate(ServerListenerDelegate delegate){ this.delegate = delegate; } - - } diff --git a/src/main/java/seng302/visualiser/controllers/BoatCustomizeController.java b/src/main/java/seng302/visualiser/controllers/BoatCustomizeController.java index fdab7cc8..384a2cf6 100644 --- a/src/main/java/seng302/visualiser/controllers/BoatCustomizeController.java +++ b/src/main/java/seng302/visualiser/controllers/BoatCustomizeController.java @@ -1,10 +1,15 @@ package seng302.visualiser.controllers; +import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXColorPicker; +import com.jfoenix.controls.JFXTextField; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.paint.Color; +import javafx.stage.Stage; +import seng302.gameServer.messages.CustomizeRequestType; +import seng302.visualiser.ClientToServerThread; import java.net.URL; import java.util.ResourceBundle; @@ -14,6 +19,19 @@ public class BoatCustomizeController implements Initializable{ @FXML private JFXColorPicker colorPicker; + @FXML + private JFXButton submitBtn; + + @FXML + private JFXTextField boatName; + private ClientToServerThread socketThread; + private LobbyController lobbyController; + + + public BoatCustomizeController(){ + + } + @FXML void colorChanged(ActionEvent event) { Color color = colorPicker.getValue(); @@ -22,5 +40,45 @@ public class BoatCustomizeController implements Initializable{ @Override public void initialize(URL location, ResourceBundle resources) { colorPicker.setValue(Color.BISQUE); + submitBtn.setOnMouseReleased(event -> { + submitCustomization(); + lobbyController.closeCustomizationDialog(); + }); + } + + @FXML + public void submitCustomization() { + socketThread.sendCustomizationRequest(CustomizeRequestType.NAME, boatName.getText().getBytes()); + // TODO: 16/08/17 ajm412: Turn colors into byte array. + Color color = colorPicker.getValue(); + + short red = (short) (color.getRed() * 255); + short green = (short) (color.getGreen() * 255); + short blue = (short) (color.getBlue() * 255); + + byte[] colorArray = new byte[3]; + + colorArray[0] = (byte) red; + colorArray[1] = (byte) green; + colorArray[2] = (byte) blue; + + socketThread.sendCustomizationRequest(CustomizeRequestType.COLOR, colorArray); + lobbyController.closeCustomizationDialog(); + } + + public void setPlayerName(String name) { + this.boatName.setText(name); + } + + public void setPlayerColor(Color playerColor) { + this.colorPicker.setValue(playerColor); + } + + public void setServerThread(ClientToServerThread ctsThread) { + this.socketThread = ctsThread; + } + + public void setParentController(LobbyController lobbyController){ + this.lobbyController = lobbyController; } } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index 45792694..50ee6685 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -19,8 +19,12 @@ import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; import seng302.gameServer.GameStages; import seng302.gameServer.GameState; +import seng302.model.Colors; +import seng302.model.RaceState; +import seng302.visualiser.ServerListener; public class LobbyController implements Initializable { @@ -31,7 +35,7 @@ public class LobbyController implements Initializable { private ScrollPane playerListScrollpane; @FXML - private JFXButton customizeButton, leaveLobbyButton; + private JFXButton customizeButton, leaveLobbyButton, beginRaceButton; @FXML private StackPane serverListMainStackPane; @@ -43,39 +47,44 @@ public class LobbyController implements Initializable { private Label mapName; private List lobbyListeners = new ArrayList<>(); + private RaceState raceState; + private JFXDialog customizationDialog; @Override public void initialize(URL location, ResourceBundle resources) { leaveLobbyButton.setOnMouseReleased(event -> leaveLobby()); + beginRaceButton.setOnMouseReleased(event -> beginRace()); Platform.runLater(() -> { - serverName.setText(ViewManager.getInstance().getProperty("serverName")); mapName.setText(ViewManager.getInstance().getProperty("mapName")); - ViewManager.getInstance().getPlayerList().addListener((ListChangeListener) c -> { - Platform.runLater(this::refreshPlayerList); - }); + ViewManager.getInstance().getPlayerList().addListener((ListChangeListener) c -> Platform.runLater(this::refreshPlayerList)); ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted()); }); Platform.runLater(() -> { - FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( - "/views/dialogs/BoatCustomizeDialog.fxml")); + Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId(); + String name = ViewManager.getInstance().getGameClient().getPlayerNames().get(playerId - 1); - try { - JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), - DialogTransition.CENTER); - customizeButton.setOnAction(action -> dialog.show()); - } catch (IOException e) { - e.printStackTrace(); - } + Color playerColor = Colors.getColor( playerId - 1); + customizationDialog = ViewManager.getInstance().loadCustomizationDialog(serverListMainStackPane, this, playerColor, name); + + customizeButton.setOnMouseReleased(event -> customizationDialog.show()); }); } + private void beginRace() { + beginRaceButton.setDisable(true); + customizeButton.setDisable(true); + GameState.setCurrentStage(GameStages.PRE_RACE); + GameState.resetStartTime(); + Platform.runLater(()-> ViewManager.getInstance().getGameClient().startGame()); + } + private void refreshPlayerList() { playerListVBox.getChildren().clear(); @@ -90,6 +99,7 @@ public class LobbyController implements Initializable { try { pane = loader.load(); } catch (IOException e) { + // TODO replace with logger e.printStackTrace(); } @@ -102,8 +112,21 @@ public class LobbyController implements Initializable { GameState.setCurrentStage(GameStages.CANCELLED); // for (LobbyController_old.LobbyCloseListener readyListener : lobbyListeners) // readyListener.notify(LobbyController_old.CloseStatus.LEAVE); - - //TODO close threads and figure out what the above lines do; + ViewManager.getInstance().getGameClient().stopGame(); ViewManager.getInstance().goToStartView(); } + + public void disableReadyButton() { + this.beginRaceButton.setDisable(true); + this.beginRaceButton.setText("Waiting for host..."); + } + + public void updateRaceState(RaceState raceState){ + this.raceState = raceState; + this.beginRaceButton.setText("Starting in: " + raceState.getRaceTimeStr()); + } + + public void closeCustomizationDialog() { + customizationDialog.close(); + } } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController_old.java b/src/main/java/seng302/visualiser/controllers/LobbyController_old.java index 614f8ba1..20f16801 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController_old.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController_old.java @@ -229,7 +229,7 @@ public class LobbyController_old { this.raceState = raceState; /*if (this.customizeStage != null) { this.customizeStage.close(); - }*/ // TODO: 17/08/17 ajm412: close the customization window if the host starts the game while customizing + }*/ // TODO: 17/08/17 ajm412: close the customization window if the host starts the game while customizing if (!customizeButton.isDisabled()) { customizeButton.setDisable(true); } @@ -241,6 +241,7 @@ public class LobbyController_old { readyButton.setVisible(false); } + //TODO here newui public void setPlayersColor(Color playerColor) { this.playersColor = playerColor; } diff --git a/src/main/java/seng302/visualiser/controllers/RaceViewController.java b/src/main/java/seng302/visualiser/controllers/RaceViewController.java index a7cd9718..e9c5f4f5 100644 --- a/src/main/java/seng302/visualiser/controllers/RaceViewController.java +++ b/src/main/java/seng302/visualiser/controllers/RaceViewController.java @@ -27,6 +27,7 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.Slider; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; @@ -64,7 +65,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel @FXML private Text timerLabel; @FXML - private AnchorPane contentAnchorPane; + private StackPane contentAnchorPane; + @FXML + private AnchorPane rvAnchorPane; @FXML private Text windArrowText, windDirectionText; @FXML @@ -92,19 +95,21 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public void initialize() { // Load a default important annotation state - importantAnnotations = new ImportantAnnotationsState(); + //importantAnnotations = new ImportantAnnotationsState(); //Formatting the y axis of the sparkline // raceSparkLine.getYAxis().setRotate(180); // raceSparkLine.getYAxis().setTickLabelRotation(180); // raceSparkLine.getYAxis().setTranslateX(-5); - raceSparkLine.visibleProperty().setValue(false); - raceSparkLine.getYAxis().setAutoRanging(false); - sparklineYAxis.setTickMarkVisible(false); + //raceSparkLine.visibleProperty().setValue(false); + //raceSparkLine.getYAxis().setAutoRanging(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()); + rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty()); + rvAnchorPane.prefHeightProperty().bind(ViewManager.getInstance().getDecorator().heightProperty()); } public void loadRace ( @@ -133,8 +138,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel updateOrder(raceState.getPlayerPositions()); gameView = new GameView(); - gameView.setFrameRateFXText(fpsDisplay); - Platform.runLater(() -> contentAnchorPane.getChildren().add(0, gameView)); + //gameView.setFrameRateFXText(fpsDisplay); + Platform.runLater(() -> contentAnchorPane.getChildren().add(gameView)); gameView.setBoats(new ArrayList<>(participants.values())); gameView.updateBorder(raceData.getCourseLimit()); gameView.updateCourse( @@ -196,46 +201,46 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } private void initialiseFPSCheckBox() { - toggleFps.selectedProperty().addListener((obs, oldVal, newVal) -> - gameView.setFPSVisibility(toggleFps.isSelected()) - ); +// toggleFps.selectedProperty().addListener((obs, oldVal, newVal) -> +// gameView.setFPSVisibility(toggleFps.isSelected()) +// ); } private void initialiseAnnotationSlider() { - annotationSlider.setLabelFormatter(new StringConverter() { - @Override - public String toString(Double n) { - if (n == 0) { - return "None"; - } - if (n == 1) { - return "Important"; - } - if (n == 2) { - return "All"; - } - return "All"; - } - - @Override - public Double fromString(String s) { - switch (s) { - case "None": - return 0d; - case "Important": - return 1d; - case "All": - return 2d; - - default: - return 2d; - } - } - }); - annotationSlider.setValue(2); - annotationSlider.valueProperty().addListener((obs, oldVal, newVal) -> - setAnnotations((int) annotationSlider.getValue()) - ); +// annotationSlider.setLabelFormatter(new StringConverter() { +// @Override +// public String toString(Double n) { +// if (n == 0) { +// return "None"; +// } +// if (n == 1) { +// return "Important"; +// } +// if (n == 2) { +// return "All"; +// } +// return "All"; +// } +// +// @Override +// public Double fromString(String s) { +// switch (s) { +// case "None": +// return 0d; +// case "Important": +// return 1d; +// case "All": +// return 2d; +// +// default: +// return 2d; +// } +// } +// }); +// annotationSlider.setValue(2); +// annotationSlider.valueProperty().addListener((obs, oldVal, newVal) -> +// setAnnotations((int) annotationSlider.getValue()) +// ); } @@ -243,52 +248,52 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * Used to add any new yachts into the race that may have started late or not have had data received yet */ private void updateSparkLine(){ - // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed. - // Collect the racing yachts that aren't already in the chart - sparkLineData.clear(); - List sparkLineCandidates = new ArrayList<>(participants.values()); - // Create a new data series for new yachts - sparkLineCandidates - .stream() - .filter(yacht -> yacht.getPosition() != null) - .forEach(yacht -> { - Series yachtData = new Series<>(); - yachtData.setName(yacht.getSourceId().toString()); - yachtData.getData().add( - new Data<>( - Integer.toString(yacht.getLegNumber()), - 1.0 + participants.size() - yacht.getPosition() - ) - ); - sparkLineData.add(yachtData); - }); - - // Lambda function to sort the series in order of leg (later legs shown more to the right) - sparkLineData.sort((o1, o2) -> { - Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue()); - Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue()); - if (leg2 < leg1){ - return 1; - } else { - return -1; - } - }); - - // Adds the new data series to the sparkline (and set the colour of the series) - Platform.runLater(() -> { - sparkLineData - .stream() - .filter(spark -> !raceSparkLine.getData().contains(spark)) - .forEach(spark -> { - raceSparkLine.getData().add(spark); - spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName())); - }); - }); +// // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed. +// // Collect the racing yachts that aren't already in the chart +// sparkLineData.clear(); +// List sparkLineCandidates = new ArrayList<>(participants.values()); +// // Create a new data series for new yachts +// sparkLineCandidates +// .stream() +// .filter(yacht -> yacht.getPosition() != null) +// .forEach(yacht -> { +// Series yachtData = new Series<>(); +// yachtData.setName(yacht.getSourceId().toString()); +// yachtData.getData().add( +// new Data<>( +// Integer.toString(yacht.getLegNumber()), +// 1.0 + participants.size() - yacht.getPosition() +// ) +// ); +// sparkLineData.add(yachtData); +// }); +// +// // Lambda function to sort the series in order of leg (later legs shown more to the right) +// sparkLineData.sort((o1, o2) -> { +// Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue()); +// Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue()); +// if (leg2 < leg1){ +// return 1; +// } else { +// return -1; +// } +// }); +// +// // Adds the new data series to the sparkline (and set the colour of the series) +// Platform.runLater(() -> { +// sparkLineData +// .stream() +// .filter(spark -> !raceSparkLine.getData().contains(spark)) +// .forEach(spark -> { +// raceSparkLine.getData().add(spark); +// spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName())); +// }); +// }); } private void initialiseSparkLine() { - sparklineYAxis.setUpperBound(participants.size() + 1); - raceSparkLine.setCreateSymbols(false); +// sparklineYAxis.setUpperBound(participants.size() + 1); +// raceSparkLine.setCreateSymbols(false); } /** @@ -381,8 +386,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * @param direction the from north angle of the wind. */ private void updateWindDirection(double direction) { - windDirectionText.setText(String.format("%.1f°", direction)); - windArrowText.setRotate(direction); +// windDirectionText.setText(String.format("%.1f°", direction)); +// windArrowText.setRotate(direction); } /** @@ -390,7 +395,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * @param windSpeed Windspeed in knots. */ private void updateWindSpeed(double windSpeed) { - windSpeedText.setText("Speed: " + String.format("%.1f", windSpeed) + " Knots"); +// windSpeedText.setText("Speed: " + String.format("%.1f", windSpeed) + " Knots"); } @@ -402,7 +407,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // timerLabel.setFill(Color.RED); // timerLabel.setText("Race Finished!"); // } else { - timerLabel.setText(raceState.getRaceTimeStr()); +// timerLabel.setText(raceState.getRaceTimeStr()); // } } @@ -411,28 +416,28 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * section */ private void updateOrder(ObservableList yachts) { - List vboxEntries = new ArrayList<>(); - - for (int i = 0; i < yachts.size(); i++) { -// System.out.println("yacht == null " + String.valueOf(yacht == null)); - if (yachts.get(i).getBoatStatus() == BoatStatus.FINISHED - .getCode()) { // 3 is finish status - Text textToAdd = new Text(i + 1 + ". " + - yachts.get(i).getShortName() + " (Finished)"); - textToAdd.setFill(Paint.valueOf("#d3d3d3")); - vboxEntries.add(textToAdd); - - } else { - Text textToAdd = new Text(i + 1 + ". " + - yachts.get(i).getShortName() + " "); - textToAdd.setFill(Paint.valueOf("#d3d3d3")); - textToAdd.setStyle(""); - vboxEntries.add(textToAdd); - } - } - Platform.runLater(() -> - positionVbox.getChildren().setAll(vboxEntries) - ); +// List vboxEntries = new ArrayList<>(); +// +// for (int i = 0; i < yachts.size(); i++) { +//// System.out.println("yacht == null " + String.valueOf(yacht == null)); +// if (yachts.get(i).getBoatStatus() == BoatStatus.FINISHED +// .getCode()) { // 3 is finish status +// Text textToAdd = new Text(i + 1 + ". " + +// yachts.get(i).getShortName() + " (Finished)"); +// textToAdd.setFill(Paint.valueOf("#d3d3d3")); +// vboxEntries.add(textToAdd); +// +// } else { +// Text textToAdd = new Text(i + 1 + ". " + +// yachts.get(i).getShortName() + " "); +// textToAdd.setFill(Paint.valueOf("#d3d3d3")); +// textToAdd.setStyle(""); +// vboxEntries.add(textToAdd); +// } +// } +// Platform.runLater(() -> +// positionVbox.getChildren().setAll(vboxEntries) +// ); } @@ -533,15 +538,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * for the combobox to take action upon selection */ private void initialiseBoatSelectionComboBox() { - yachtSelectionComboBox.setItems( - FXCollections.observableArrayList(participants.values()) - ); - //Null check is if the listener is fired but nothing selected - yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> { - if (selectedBoat != null) { - gameView.selectBoat(selectedBoat); - } - }); +// yachtSelectionComboBox.setItems( +// FXCollections.observableArrayList(participants.values()) +// ); +// //Null check is if the listener is fired but nothing selected +// yachtSelectionComboBox.valueProperty().addListener((obs, lastSelection, selectedBoat) -> { +// if (selectedBoat != null) { +// gameView.selectBoat(selectedBoat); +// } +// }); } /** diff --git a/src/main/java/seng302/visualiser/controllers/ServerCell.java b/src/main/java/seng302/visualiser/controllers/ServerCell.java index 7ba0a5d2..c9dced5a 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerCell.java +++ b/src/main/java/seng302/visualiser/controllers/ServerCell.java @@ -16,6 +16,7 @@ import javafx.scene.effect.DropShadow; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; import seng302.gameServer.ServerDescription; +import seng302.visualiser.GameClient; public class ServerCell implements Initializable { @@ -39,7 +40,7 @@ public class ServerCell implements Initializable { private String name; private String mapNameString; - private Integer currPlayerCount; + private String currPlayerCount; private String hostName; private Integer portNumber; @@ -47,7 +48,8 @@ public class ServerCell implements Initializable { public ServerCell(ServerDescription server) { this.name = server.getName(); - this.currPlayerCount = server.spacesLeft(); + + this.currPlayerCount = server.getNumPlayers().toString() + "/" + server.getCapacity().toString(); this.mapNameString = server.getMapName(); this.hostName = server.getAddress(); @@ -57,7 +59,8 @@ public class ServerCell implements Initializable { public void initialize(URL location, ResourceBundle resources) { serverName.setText(name); - serverPlayerCount.setText(Integer.toString(currPlayerCount)); + serverPlayerCount.setText(currPlayerCount); + mapName.setText(mapNameString); serverConnButton.setOnMouseReleased(event -> joinServer()); } @@ -65,12 +68,8 @@ public class ServerCell implements Initializable { public void joinServer() { // TODO: 7/09/17 ajm412: Connect to a server here with the values stored in the hostName/portNumber variables. System.out.println("Connecting to " + serverName.getText()); - try { - Parent root = FXMLLoader.load(StartScreenController.class.getResource("/views/LobbyView.fxml")); - ViewManager.getInstance().setScene(root); - } catch (IOException e) { - e.printStackTrace(); - } + + ViewManager.getInstance().getGameClient().runAsClient(hostName, portNumber); } } diff --git a/src/main/java/seng302/visualiser/controllers/ServerCreationController.java b/src/main/java/seng302/visualiser/controllers/ServerCreationController.java index 5a24f422..c260f947 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerCreationController.java +++ b/src/main/java/seng302/visualiser/controllers/ServerCreationController.java @@ -41,18 +41,11 @@ public class ServerCreationController implements Initializable { } public void createServer() { - try { - ServerDescription serverDescription = ViewManager.getInstance().getGameClient().runAsHost("localhost", 4941); - ViewManager.getInstance().setProperty("serverName", serverDescription.getName()); - ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName()); + ServerDescription serverDescription = ViewManager.getInstance().getGameClient().runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayers.getValue()); - Parent root = FXMLLoader.load(StartScreenController.class.getResource("/views/LobbyView.fxml")); - - ViewManager.getInstance().setScene(root); - } catch (IOException e) { - e.printStackTrace(); - } + ViewManager.getInstance().setProperty("serverName", serverDescription.getName()); + ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName()); } private void updateMaxPlayerLabel() { diff --git a/src/main/java/seng302/visualiser/controllers/ServerListController.java b/src/main/java/seng302/visualiser/controllers/ServerListController.java index 70578076..522b9669 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerListController.java +++ b/src/main/java/seng302/visualiser/controllers/ServerListController.java @@ -18,6 +18,7 @@ import javafx.scene.layout.VBox; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import seng302.gameServer.ServerDescription; +import seng302.visualiser.GameClient; import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListenerDelegate; @@ -55,6 +56,7 @@ public class ServerListController implements Initializable, ServerListenerDelega try { ServerListener.getInstance().setDelegate(this); + System.out.println("Setting DH"); } catch (IOException e) { logger.warn("Could not start Server Listener Delegate"); } @@ -74,9 +76,8 @@ public class ServerListController implements Initializable, ServerListenerDelega } private void goToDirectConnectLobby() { - // TODO: 7/09/17 ajm412: Implement ability to connect to a lobby. - serverHostName.setText("Invalid Host Name or Port Number"); - serverPortNumber.setText(""); + // TODO: 7/09/17 Error handling + ViewManager.getInstance().getGameClient().runAsClient(serverHostName.getText(), Integer.parseInt(serverPortNumber.getText())); } @Override diff --git a/src/main/java/seng302/visualiser/controllers/StartScreenController_old.java b/src/main/java/seng302/visualiser/controllers/StartScreenController_old.java index 417295c3..d6df3491 100644 --- a/src/main/java/seng302/visualiser/controllers/StartScreenController_old.java +++ b/src/main/java/seng302/visualiser/controllers/StartScreenController_old.java @@ -41,7 +41,7 @@ public class StartScreenController_old implements Initializable { @FXML public void hostButtonPressed() { gameClient = new GameClient(holder); - gameClient.runAsHost(getLocalHostIp(), 4942); + //gameClient.runAsHost(getLocalHostIp(), 4942); } /** diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 3f1e49f7..02672af1 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -1,10 +1,17 @@ package seng302.visualiser.controllers; import com.jfoenix.controls.JFXDecorator; +import com.jfoenix.controls.JFXDialog; +import javafx.application.Platform; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.Parent; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import seng302.model.ClientYacht; import seng302.visualiser.GameClient; import java.io.IOException; @@ -17,12 +24,19 @@ public class ViewManager { private JFXDecorator decorator; private HashMap props; //TODO is this the best way to do this?? private ObservableList playerList; + private Logger logger = LoggerFactory.getLogger(ViewManager.class); private ViewManager(){ props = new HashMap<>(); gameClient = new GameClient(decorator); } + private FXMLLoader loadFxml(String fxmlLocation) { + return new FXMLLoader( + getClass().getResource(fxmlLocation) + ); + } + public static ViewManager getInstance(){ if (instance == null){ instance = new ViewManager(); @@ -40,7 +54,7 @@ public class ViewManager { } public void setScene(Node scene){ - decorator.setContent(scene); + Platform.runLater(() -> decorator.setContent(scene)); } public void goToStartView() { @@ -50,7 +64,6 @@ public class ViewManager { } catch (IOException e) { e.printStackTrace(); } - } public GameClient getGameClient(){ @@ -72,4 +85,61 @@ public class ViewManager { public ObservableList getPlayerList(){ return playerList; } + + public LobbyController goToLobby(Boolean disableReadyButton){ + FXMLLoader loader = loadFxml("/views/LobbyView.fxml"); + + try { + setScene(loader.load()); + } catch (IOException e) { + logger.error("Could not load lobby view"); + } + + if (disableReadyButton){ + LobbyController lobbyController = loader.getController(); + lobbyController.disableReadyButton(); + } + + return loader.getController(); + } + + public RaceViewController loadRaceView() { + FXMLLoader loader = loadFxml("/views/RaceView.fxml"); + + try { + setScene(loader.load()); + } catch (IOException e) { + e.printStackTrace(); + } + + decorator.getScene().setOnKeyPressed((ke) -> gameClient.keyPressed(ke)); + decorator.getScene().setOnKeyReleased((ke) -> gameClient.keyReleased(ke)); + + return loader.getController(); + } + + public JFXDialog loadCustomizationDialog(StackPane parent, LobbyController lobbyController, Color playerColor, String name) { + FXMLLoader dialog = loadFxml("/views/dialogs/BoatCustomizeDialog.fxml"); + + JFXDialog customizationDialog = null; + + try { + customizationDialog = new JFXDialog(parent, dialog.load(), + JFXDialog.DialogTransition.CENTER); + + } catch (IOException e) { + e.printStackTrace(); + } + + + BoatCustomizeController controller = dialog.getController(); + + controller.setParentController(lobbyController); + controller.setPlayerColor(playerColor); + controller.setPlayerName(name); + controller.setServerThread(gameClient.getServerThread()); + + + return customizationDialog; + } } diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index d00f0099..2921a2b1 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -1,106 +1,39 @@ + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + -