package seng302.visualiser.controllers; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDialog; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import javafx.application.Platform; import javafx.collections.ListChangeListener; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.geometry.Point3D; import javafx.scene.Group; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.input.MouseEvent; 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.transform.Rotate; import javafx.scene.transform.Scale; import javafx.scene.transform.Translate; import seng302.discoveryServer.DiscoveryServerClient; import seng302.gameServer.GameStages; import seng302.gameServer.GameState; import seng302.model.ClientYacht; import seng302.model.Colors; import seng302.model.Limit; import seng302.model.RaceState; import seng302.model.mark.CompoundMark; import seng302.model.mark.Corner; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.utilities.Sounds; import seng302.visualiser.MapPreview; import seng302.visualiser.controllers.cells.PlayerCell; import seng302.visualiser.controllers.dialogs.BoatCustomizeController; import seng302.visualiser.controllers.dialogs.PopupDialogController; import seng302.visualiser.controllers.dialogs.TokenInfoDialogController; import seng302.visualiser.fxObjects.assets_3D.ModelFactory; import seng302.visualiser.fxObjects.assets_3D.ModelType; public class LobbyController implements Initializable { private final double INITIAL_MAP_HEIGHT = 770d; private final double INITIAL_MAP_WIDTH = 574d; //--------FXML BEGIN--------// @FXML private VBox playerListVBox; @FXML private ScrollPane playerListScrollPane; @FXML private JFXButton customizeButton, leaveLobbyButton, beginRaceButton; @FXML private StackPane serverListMainStackPane; @FXML private Label serverName; @FXML private Label mapName; @FXML private AnchorPane serverMap; @FXML private Label roomLabel; @FXML private Label portNumber; @FXML private Pane speedTokenPane, handlingTokenPane, windWalkerTokenPane, bumperTokenPane, randomTokenPane; //---------FXML END---------// private RaceState raceState; private JFXDialog customizationDialog; private JFXDialog tokenInfoDialog; public Color playersColor; private Map playerBoats; private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT; private MapPreview mapPreview; @Override public void initialize(URL location, ResourceBundle resources) { roomLabel.setText(""); portNumber.setText(""); this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap(); if (this.playersColor == null) { this.playersColor = Colors.getColor(ViewManager.getInstance().getGameClient().getServerThread().getClientId() - 1); } leaveLobbyButton.setOnMouseReleased(event -> leaveLobby()); beginRaceButton.setOnMouseReleased(event -> beginRace()); leaveLobbyButton.setOnMouseReleased(event -> { Sounds.playButtonClick(); leaveLobby(); }); beginRaceButton.setOnMouseReleased(event -> { Sounds.playButtonClick(); beginRace(); }); Platform.runLater(() -> { serverName.setText(ViewManager.getInstance().getProperty("serverName")); mapName.setText(ViewManager.getInstance().getProperty("mapName")); int tries = 0; while (DiscoveryServerClient.getRoomCode() == null && tries <= 10){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } tries ++; } if (DiscoveryServerClient.getRoomCode() != null){ setRoomCode(DiscoveryServerClient.getRoomCode()); } ViewManager.getInstance().getPlayerList().addListener((ListChangeListener) c -> Platform.runLater(this::refreshPlayerList)); ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted()); }); customizeButton.setOnMouseReleased(event -> { customizationDialog = createCustomizeDialog(); Sounds.playButtonClick(); customizationDialog.show(); }); Platform.runLater(() -> { Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId(); playersColor = Colors.getColor(playerId - 1); }); leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound()); customizeButton.setOnMouseEntered(e -> Sounds.playHoverSound()); beginRaceButton.setOnMouseEntered(e -> Sounds.playHoverSound()); initMapPreview(); initTokenPreviews(); } /** * Initialises the tokens in the side panel */ private void initTokenPreviews() { Group speedToken = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets(); Group handlingToken = ModelFactory.importModel(ModelType.HANDLING_PICKUP).getAssets(); Group windWalkerToken = ModelFactory.importModel(ModelType.WIND_WALKER_PICKUP).getAssets(); Group bumperToken = ModelFactory.importModel(ModelType.BUMPER_PICKUP).getAssets(); Group randomToken = ModelFactory.importModel(ModelType.RANDOM_PICKUP).getAssets(); HashMap tokenPanes = new HashMap<>(); tokenPanes.put(speedTokenPane, speedToken); tokenPanes.put(handlingTokenPane, handlingToken); tokenPanes.put(windWalkerTokenPane, windWalkerToken); tokenPanes.put(bumperTokenPane, bumperToken); tokenPanes.put(randomTokenPane, randomToken); Scale hoverScale = new Scale(1.2, 1.2, 1.2); tokenPanes.entrySet().forEach((entry) -> { Pane thisPane = entry.getKey(); Group thisToken = entry.getValue(); thisToken.getTransforms().addAll( new Translate(40, 50, 0), new Scale(13, 13, 13)); thisPane.setOnMouseEntered(event -> { thisToken.getTransforms().add(hoverScale); }); thisPane.setOnMouseExited(event -> { thisToken.getTransforms().remove(hoverScale); }); thisPane.setOnMouseReleased(event -> { tokenInfoDialog = makeTokenDialog(thisPane); tokenInfoDialog.show(); }); thisPane.getChildren().add(thisToken); }); //Hacky rotations for wind and random to level it in the plane windWalkerToken.getTransforms().addAll( new Rotate(-70, new Point3D(1, 0, 0)), new Translate(0, 2,0) ); randomToken.getTransforms().addAll( new Rotate(-90, new Point3D(1, 0, 0)), new Translate(0, 0,1) ); } private JFXDialog makeTokenDialog(Pane inducingPane) { String header = "..."; String body = "Nothing to see here"; ModelType modelType = ModelType.RANDOM_PICKUP; if (inducingPane == speedTokenPane) { header = "Speed Boost"; body = "Increases your max velocity"; modelType = ModelType.VELOCITY_PICKUP; } else if (inducingPane == handlingTokenPane) { header = "Handling Boost"; body = "Increases your turing rate"; modelType = ModelType.HANDLING_PICKUP; } else if (inducingPane == windWalkerTokenPane) { header = "Wind Walker"; body = "The wind now rotates with you, giving you your optimal speed in all directions"; modelType = ModelType.WIND_WALKER_PICKUP; } else if (inducingPane == bumperTokenPane) { header = "Bumper"; body = "While this is active, upon hitting another boat, you will power it down for a short time"; modelType = ModelType.BUMPER_PICKUP; } else if (inducingPane == randomTokenPane) { header = "Random"; body = "A 50% chance of becoming any other token and a 50% chance of slowing your boat for a time"; modelType = ModelType.RANDOM_PICKUP; } FXMLLoader dialog = new FXMLLoader( getClass().getResource("/views/dialogs/TokenInfoDialog.fxml")); JFXDialog tokenInfoDialog = null; try { tokenInfoDialog = new JFXDialog(serverListMainStackPane, dialog.load(), JFXDialog.DialogTransition.CENTER); } catch (IOException e) { e.printStackTrace(); } TokenInfoDialogController controller = dialog.getController(); controller.setParentController(this); controller.setHeader(header); controller.setContent(body); controller.setToken(modelType); return tokenInfoDialog; } private JFXDialog createCustomizeDialog() { FXMLLoader dialog = new FXMLLoader( getClass().getResource("/views/dialogs/BoatCustomizeDialog.fxml")); JFXDialog customizationDialog = null; try { customizationDialog = new JFXDialog(serverListMainStackPane, dialog.load(), JFXDialog.DialogTransition.CENTER); } catch (IOException e) { e.printStackTrace(); } BoatCustomizeController controller = dialog.getController(); controller.setParentController(this); controller.setPlayerColor(this.playersColor); controller.setPlayerName(this.playerBoats .get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatName()); controller.setCurrentBoat(this.playerBoats.get(ViewManager.getInstance().getGameClient().getServerThread().getClientId()) .getBoatType().toString()); return customizationDialog; } /** * Initializes a top down preview of the race course map. */ private void initMapPreview() { RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData(); List border = raceData.getCourseLimit(); List marks = new ArrayList<>(raceData.getCompoundMarks().values()); List corners = raceData.getMarkSequence(); mapPreview = new MapPreview(marks, corners, border); serverMap.getChildren().clear(); serverMap.getChildren().add(mapPreview.getAssets()); mapPreview.setSize(mapWidth, mapHeight); serverMap.widthProperty().addListener((observable, oldValue, newValue) -> { mapWidth = newValue.doubleValue(); mapPreview.setSize(mapWidth, mapHeight); }); // serverMap.heightProperty().addListener((observable, oldValue, newValue) -> { mapHeight = newValue.doubleValue(); mapPreview.setSize(mapWidth, mapHeight); }); } /** * */ private void beginRace() { beginRaceButton.setDisable(true); customizeButton.setDisable(true); GameState.setCurrentStage(GameStages.PRE_RACE); GameState.resetStartTime(); Platform.runLater(()-> ViewManager.getInstance().getGameClient().startGame()); } /** * Refreshes the list of players and their boats, as a series of VBox PlayerCell objects. */ private void refreshPlayerList() { playerListVBox.getChildren().clear(); if (this.playerBoats == null || this.playerBoats.size() == 0) { this.playerBoats = ViewManager.getInstance().getGameClient().getAllBoatsMap(); } // TODO: 12/09/2017 ajm412: Make it so that it only removes players who's details have changed. for (Integer playerId : playerBoats.keySet()) { VBox pane = null; ClientYacht yacht = playerBoats.get(playerId); FXMLLoader loader = new FXMLLoader( getClass().getResource("/views/cells/PlayerCell.fxml")); loader.setController(new PlayerCell(playerId, yacht)); try { pane = loader.load(); } catch (IOException e) { e.printStackTrace(); } playerListVBox.getChildren().add(pane); } } private void leaveLobby() { ViewManager.getInstance().getGameClient().stopGame(); ViewManager.getInstance().goToStartView(); } public void disableReadyButton() { this.beginRaceButton.setDisable(true); this.beginRaceButton.setText("Waiting for host..."); } /** * * @param raceState */ public void updateRaceState(RaceState raceState){ this.raceState = raceState; this.beginRaceButton.setText("Starting in: " + raceState.getRaceTimeStr()); } public void setBoats(Map boats) { this.playerBoats = boats; } public void closeCustomizationDialog() { customizationDialog.close(); } public void closeTokenInfoDialog() { tokenInfoDialog.close(); } public void setRoomCode(String roomCode) { roomLabel.setText("Room: " + roomCode); } public void setPortNumber(String p){ portNumber.setText("Port: " + p); } }