Merge branch 'new_issue#19' into 'master'

New issue#19



See merge request !31
main
Hamish Ball 9 years ago
commit 27e8cddd94

@ -38,6 +38,8 @@ public class ConnectionAcceptor implements Runnable {
*/ */
private ServerSocket serverSocket; private ServerSocket serverSocket;
private Socket mockSocket = null;
/** /**
* List of client connections. * List of client connections.
@ -97,20 +99,32 @@ public class ConnectionAcceptor implements Runnable {
return serverPort; return serverPort;
} }
public void closeConnection() throws IOException {
this.raceLogic.boolFalse();
if(!this.serverSocket.isClosed()){
this.serverSocket.close();
}
}
/** /**
* Run the Acceptor * Run the Acceptor
*/ */
@Override @Override
public void run() { public void run(){
while(clientConnections.remainingCapacity() > 0) { while(clientConnections.remainingCapacity() > 0) {
try { try {
if(Thread.currentThread().isInterrupted()){
break;
}
Socket mockSocket = serverSocket.accept(); try {
this.mockSocket = serverSocket.accept();
} catch (Exception e){}
Logger.getGlobal().log(Level.INFO, String.format("Client connected. client ip/port = %s. Local ip/port = %s.", mockSocket.getRemoteSocketAddress(), mockSocket.getLocalSocketAddress())); Logger.getGlobal().log(Level.INFO, String.format("Client connected. client ip/port = %s. Local ip/port = %s.", mockSocket.getRemoteSocketAddress(), mockSocket.getLocalSocketAddress()));

@ -64,6 +64,10 @@ public class Event {
*/ */
private SourceIdAllocator sourceIdAllocator; private SourceIdAllocator sourceIdAllocator;
private Thread raceThread;
private Thread connectionThread;
@ -144,7 +148,8 @@ public class Event {
this.latestMessages, this.latestMessages,
this.compositeCommand); this.compositeCommand);
new Thread(newRace, "Event.Start()->RaceLogic thread").start(); this.raceThread = new Thread(newRace, "Event.Start()->RaceLogic thread");
raceThread.start();
//Create connection acceptor. //Create connection acceptor.
@ -157,13 +162,20 @@ public class Event {
} }
new Thread(connectionAcceptor, "Event.Start()->ConnectionAcceptor thread").start(); this.connectionThread = new Thread(connectionAcceptor, "Event.Start()->ConnectionAcceptor thread");
connectionThread.start();
sendXMLs(); sendXMLs();
} }
public void endEvent() throws IOException {
this.connectionThread.interrupt();
this.connectionAcceptor.closeConnection();
this.raceThread.interrupt();
}
/** /**

@ -15,8 +15,6 @@ import java.util.logging.Logger;
*/ */
public class MockOutput implements RunnableWithFramePeriod { public class MockOutput implements RunnableWithFramePeriod {
/** /**
* A queue to send messages to client. * A queue to send messages to client.
*/ */
@ -103,6 +101,8 @@ public class MockOutput implements RunnableWithFramePeriod {
Logger.getGlobal().log(Level.WARNING, "MockOutput.run() interrupted while putting message in queue.", e); Logger.getGlobal().log(Level.WARNING, "MockOutput.run() interrupted while putting message in queue.", e);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;
} catch (Exception e) {
e.printStackTrace();
} }
} }

@ -78,7 +78,7 @@ public class HeartBeatService implements RunnableWithFramePeriod {
* Puts a HeartBeat message on the message queue. * Puts a HeartBeat message on the message queue.
* @throws InterruptedException Thrown if the thread is interrupted. * @throws InterruptedException Thrown if the thread is interrupted.
*/ */
private void sendHeartBeat() throws InterruptedException { private void sendHeartBeat() throws Exception {
HeartBeat heartBeat = createHeartbeatMessage(); HeartBeat heartBeat = createHeartbeatMessage();
@ -92,13 +92,17 @@ public class HeartBeatService implements RunnableWithFramePeriod {
while (!Thread.interrupted()) { while (!Thread.interrupted()) {
long currentFrameTime = System.currentTimeMillis(); long currentFrameTime = System.currentTimeMillis();
try {
waitForFramePeriod(lastHeartbeatTime, currentFrameTime, heartbeatPeriod); waitForFramePeriod(lastHeartbeatTime, currentFrameTime, heartbeatPeriod);
} catch (Exception e) {
e.printStackTrace();
}
lastHeartbeatTime = currentFrameTime; lastHeartbeatTime = currentFrameTime;
try { try {
sendHeartBeat(); sendHeartBeat();
} catch (InterruptedException e) { } catch (Exception e) {
Logger.getGlobal().log(Level.WARNING, "HeartBeatService: " + this + " sendHeartBeat() was interrupted on thread: " + Thread.currentThread(), e); Logger.getGlobal().log(Level.WARNING, "HeartBeatService: " + this + " sendHeartBeat() was interrupted on thread: " + Thread.currentThread(), e);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;

@ -27,6 +27,8 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
private CompositeCommand commands; private CompositeCommand commands;
private boolean loopBool = true;
/** /**
* Initialises race loop with state and server message queue * Initialises race loop with state and server message queue
* @param race state of race to modify * @param race state of race to modify
@ -48,20 +50,32 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
public void run() { public void run() {
race.initialiseBoats(); race.initialiseBoats();
try {
countdown(); countdown();
} catch (Exception e) {
e.printStackTrace();
}
try {
raceLoop(); raceLoop();
} catch (Exception e) {
e.printStackTrace();
}
}
public void boolFalse(){
loopBool = false;
} }
/** /**
* Countdown timer until race starts. * Countdown timer until race starts.
*/ */
private void countdown() { private void countdown() throws Exception {
long previousFrameTime = System.currentTimeMillis(); long previousFrameTime = System.currentTimeMillis();
while (race.getRaceStatusEnum() != RaceStatusEnum.STARTED) { while (race.getRaceStatusEnum() != RaceStatusEnum.STARTED && loopBool) {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
@ -96,11 +110,11 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer {
/** /**
* Timer that runs for the duration of the race, until all boats finish. * Timer that runs for the duration of the race, until all boats finish.
*/ */
private void raceLoop() { private void raceLoop() throws Exception {
long previousFrameTime = System.currentTimeMillis(); long previousFrameTime = System.currentTimeMillis();
while (race.getRaceStatusEnum() != RaceStatusEnum.FINISHED) { while (race.getRaceStatusEnum() != RaceStatusEnum.FINISHED && loopBool) {
//Get the current time. //Get the current time.
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();

@ -93,7 +93,11 @@ public class MessageSerialiser implements RunnableWithFramePeriod {
long currentFrameTime = System.currentTimeMillis(); long currentFrameTime = System.currentTimeMillis();
try {
waitForFramePeriod(previousFrameTime, currentFrameTime, 16); waitForFramePeriod(previousFrameTime, currentFrameTime, 16);
} catch (Exception e) {
e.printStackTrace();
}
previousFrameTime = currentFrameTime; previousFrameTime = currentFrameTime;

@ -20,7 +20,7 @@ public interface RunnableWithFramePeriod extends Runnable {
* @param currentFrameTime The timestamp of the current frame. * @param currentFrameTime The timestamp of the current frame.
* @param minimumFramePeriod The minimum period the frame must be. * @param minimumFramePeriod The minimum period the frame must be.
*/ */
default void waitForFramePeriod(long previousFrameTime, long currentFrameTime, long minimumFramePeriod) { default void waitForFramePeriod(long previousFrameTime, long currentFrameTime, long minimumFramePeriod) throws Exception {
//This is the time elapsed, in milliseconds, since the last server "frame". //This is the time elapsed, in milliseconds, since the last server "frame".
@ -39,10 +39,10 @@ public interface RunnableWithFramePeriod extends Runnable {
} catch (InterruptedException e) { } catch (InterruptedException e) {
//If we get interrupted, exit the function. //If we get interrupted, exit the function.
Logger.getGlobal().log(Level.SEVERE, "RunnableWithFramePeriod.waitForFramePeriod().sleep(framePeriod) was interrupted on thread: " + Thread.currentThread(), e); /*Logger.getGlobal().log(Level.SEVERE, "RunnableWithFramePeriod.waitForFramePeriod().sleep(framePeriod) was interrupted on thread: " + Thread.currentThread(), e);
//Re-set the interrupt flag. //Re-set the interrupt flag.
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;*/
} }

@ -125,7 +125,7 @@ public class ConnectionController extends Controller {
Socket socket = new Socket(connection.getHostname(), connection.getPort()); Socket socket = new Socket(connection.getHostname(), connection.getPort());
socket.setKeepAlive(true); socket.setKeepAlive(true);
connectionWrapper.setVisible(false); connectionWrapper.setVisible(false);
parent.enterLobby(socket); //parent.enterLobby(socket);
} catch (IOException e) { /* Never reached */ } } catch (IOException e) { /* Never reached */ }
} }

@ -35,6 +35,8 @@ public class HostController extends Controller {
@FXML @FXML
AnchorPane hostWrapper; AnchorPane hostWrapper;
private Event game;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
@ -46,7 +48,7 @@ public class HostController extends Controller {
*/ */
public void hostGamePressed() throws IOException{ public void hostGamePressed() throws IOException{
try { try {
Event game = new Event(false); this.game = new Event(false);
game.start(); game.start();
connectSocket("localhost", 4942); connectSocket("localhost", 4942);
} catch (EventConstructionException e) { } catch (EventConstructionException e) {
@ -55,6 +57,10 @@ public class HostController extends Controller {
} }
} }
public void endEvent() throws IOException {
game.endEvent();
}
/** /**
* Connect to a socket * Connect to a socket
* @param address address of the server * @param address address of the server
@ -64,7 +70,7 @@ public class HostController extends Controller {
try{ try{
Socket socket = new Socket(address, port); Socket socket = new Socket(address, port);
hostWrapper.setVisible(false); hostWrapper.setVisible(false);
parent.enterLobby(socket); parent.enterLobby(socket, true);
} catch (IOException e) { /* Never reached */ } } catch (IOException e) { /* Never reached */ }
} }
@ -79,4 +85,9 @@ public class HostController extends Controller {
hostWrapper.setVisible(true); hostWrapper.setVisible(true);
} }
public void menuBtnPressed(){
hostWrapper.setVisible(false);
parent.enterTitle();
}
} }

@ -86,12 +86,17 @@ public class LobbyController extends Controller {
RaceConnection connection = lobbyTable.getSelectionModel().getSelectedItem(); RaceConnection connection = lobbyTable.getSelectionModel().getSelectedItem();
Socket socket = new Socket(connection.getHostname(), connection.getPort()); Socket socket = new Socket(connection.getHostname(), connection.getPort());
lobbyWrapper.setVisible(false); lobbyWrapper.setVisible(false);
parent.enterLobby(socket); parent.enterLobby(socket, false);
} catch (IOException e) { /* Never reached */ } catch (IOException e) { /* Never reached */
e.printStackTrace(); e.printStackTrace();
} }
} }
public void menuBtnPressed(){
lobbyWrapper.setVisible(false);
parent.enterTitle();
}
/** /**
* adds a new connection * adds a new connection
*/ */

@ -3,10 +3,12 @@ package visualiser.Controllers;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import visualiser.app.App;
import visualiser.gameController.ControllerClient; import visualiser.gameController.ControllerClient;
import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserBoat;
import visualiser.model.VisualiserRaceEvent; import visualiser.model.VisualiserRaceEvent;
import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -39,16 +41,19 @@ public class MainController extends Controller {
* @param visualiserRace The object modelling the race. * @param visualiserRace The object modelling the race.
* @param controllerClient Socket Client that manipulates the controller. * @param controllerClient Socket Client that manipulates the controller.
*/ */
public void beginRace(VisualiserRaceEvent visualiserRace, ControllerClient controllerClient) { public void beginRace(VisualiserRaceEvent visualiserRace, ControllerClient controllerClient, Boolean isHost) {
raceController.startRace(visualiserRace, controllerClient); raceController.startRace(visualiserRace, controllerClient, isHost);
} }
public void endEvent() throws IOException { hostController.endEvent(); }
/** /**
* Transitions from the server selection screen to the pre-race lobby for a given server. * Transitions from the server selection screen to the pre-race lobby for a given server.
* @param socket The server to read data from. * @param socket The server to read data from.
* @param isHost is connection a host
*/ */
public void enterLobby(Socket socket) { public void enterLobby(Socket socket, Boolean isHost) {
startController.enterLobby(socket); startController.enterLobby(socket, isHost);
} }
/** /**
@ -62,7 +67,9 @@ public class MainController extends Controller {
/** /**
* Transitions into the title screen * Transitions into the title screen
*/ */
public void enterTitle(){ titleController.enterTitle(); } public void enterTitle() {
titleController.enterTitle();
}
/** /**
* Transitions into lobby screen * Transitions into lobby screen

@ -10,6 +10,8 @@ import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
@ -18,12 +20,15 @@ import javafx.scene.layout.StackPane;
import javafx.util.Callback; import javafx.util.Callback;
import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceStatusEnum;
import shared.model.Leg; import shared.model.Leg;
import visualiser.app.App;
import visualiser.gameController.ControllerClient; import visualiser.gameController.ControllerClient;
import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.ControlKey;
import visualiser.gameController.Keys.KeyFactory; import visualiser.gameController.Keys.KeyFactory;
import visualiser.model.*; import visualiser.model.*;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -48,7 +53,7 @@ public class RaceController extends Controller {
private ControllerClient controllerClient; private ControllerClient controllerClient;
private boolean isHost;
/** /**
* The canvas that draws the race. * The canvas that draws the race.
@ -128,6 +133,35 @@ public class RaceController extends Controller {
Logger.getGlobal().log(Level.WARNING, "RaceController was interrupted on thread: " + Thread.currentThread() + "while sending: " + controlKey, e); Logger.getGlobal().log(Level.WARNING, "RaceController was interrupted on thread: " + Thread.currentThread() + "while sending: " + controlKey, e);
} }
} }
if(event.getCode() == KeyCode.ESCAPE) {
try {
if (isHost) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Exit Race");
alert.setContentText("Do you wish to quit the race? You are the host");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
parent.endEvent();
race.setVisible(false);
App.app.showMainStage(App.getStage());
}
} else {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Exit Race");
alert.setContentText("Do you wish to quit the race?");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
race.setVisible(false);
App.app.showMainStage(App.getStage());
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}); });
} }
@ -366,11 +400,13 @@ public class RaceController extends Controller {
* Displays a specified race. * Displays a specified race.
* @param visualiserRace Object modelling the race. * @param visualiserRace Object modelling the race.
* @param controllerClient Socket Client that manipulates the controller. * @param controllerClient Socket Client that manipulates the controller.
* @param isHost is user a host
*/ */
public void startRace(VisualiserRaceEvent visualiserRace, ControllerClient controllerClient) { public void startRace(VisualiserRaceEvent visualiserRace, ControllerClient controllerClient, Boolean isHost) {
this.visualiserRace = visualiserRace; this.visualiserRace = visualiserRace;
this.controllerClient = controllerClient; this.controllerClient = controllerClient;
this.isHost = isHost;
initialiseRace(); initialiseRace();
@ -434,7 +470,14 @@ public class RaceController extends Controller {
//Return to main screen if we lose connection. //Return to main screen if we lose connection.
if (!visualiserRace.getServerConnection().isAlive()) { if (!visualiserRace.getServerConnection().isAlive()) {
race.setVisible(false); race.setVisible(false);
parent.enterTitle(); //parent.enterTitle();
try {
App.app.showMainStage(App.getStage());
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
//TODO currently this doesn't work correctly - the title screen remains visible after clicking join game //TODO currently this doesn't work correctly - the title screen remains visible after clicking join game
//TODO we should display an error to the user //TODO we should display an error to the user
//TODO also need to "reset" any state (race, connections, etc...). //TODO also need to "reset" any state (race, connections, etc...).

@ -82,7 +82,7 @@ public class StartController extends Controller {
*/ */
private ControllerClient controllerClient; private ControllerClient controllerClient;
private boolean isHost;
@ -238,7 +238,7 @@ public class StartController extends Controller {
startWrapper.setVisible(false); startWrapper.setVisible(false);
//start.setVisible(false);//TODO is this needed? //start.setVisible(false);//TODO is this needed?
parent.beginRace(visualiserRaceEvent, controllerClient); parent.beginRace(visualiserRaceEvent, controllerClient, isHost);
} }
} }
@ -250,10 +250,13 @@ public class StartController extends Controller {
/** /**
* Show starting information for a race given a socket. * Show starting information for a race given a socket.
* @param socket network source of information * @param socket network source of information
* @param isHost is user a host
*/ */
public void enterLobby(Socket socket) { public void enterLobby(Socket socket, Boolean isHost) {
try { try {
this.isHost = isHost;
this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT); this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT);
this.controllerClient = visualiserRaceEvent.getControllerClient(); this.controllerClient = visualiserRaceEvent.getControllerClient();

@ -1,9 +1,14 @@
package visualiser.Controllers; package visualiser.Controllers;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.RadioButton; import javafx.scene.control.RadioButton;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import visualiser.app.App; import visualiser.app.App;
import java.io.IOException; import java.io.IOException;
@ -17,6 +22,7 @@ import java.util.ResourceBundle;
* the game. * the game.
*/ */
public class TitleController extends Controller { public class TitleController extends Controller {
//FXML stuff
@FXML @FXML
Button btnJoin; Button btnJoin;
@FXML @FXML
@ -77,4 +83,26 @@ public class TitleController extends Controller {
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
} }
/**
* Called when control button is pressed. New pop up window displaying controls
*/
public void controlBtnPressed(){
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/visualiser/scenes/controls.fxml"));
Parent layout;
try {
layout = loader.load();
Scene scene = new Scene(layout);
Stage popupStage = new Stage();
popupStage.setResizable(false);
popupStage.setTitle("Game Controls");
popupStage.initModality(Modality.WINDOW_MODAL);
popupStage.setScene(scene);
popupStage.showAndWait();
} catch (Exception e){
e.printStackTrace();
}
}
} }

@ -1,18 +1,48 @@
package visualiser.app; package visualiser.app;
import javafx.animation.FadeTransition;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
import javafx.util.Duration;
import visualiser.Controllers.MainController; import visualiser.Controllers.MainController;
import java.io.IOException;
public class App extends Application { public class App extends Application {
private static Stage stage; private static Stage stage;
private Pane splashLayout;
private ProgressBar loadProgress;
private Label progressText;
private static final int SPLASH_WIDTH = 676;
private static final int SPLASH_HEIGHT = 227;
public static App app;
/** /**
* Entry point for running the programme * Entry point for running the programme
@ -23,19 +53,103 @@ public class App extends Application {
launch(args); launch(args);
} }
@Override
public void init() {
ImageView splash = new ImageView(new Image(
getClass().getClassLoader().getResourceAsStream("images/splashScreen.png")
));
loadProgress = new ProgressBar();
loadProgress.setPrefWidth(SPLASH_WIDTH - 20);
progressText = new Label("Preparing application . . .");
splashLayout = new VBox();
splashLayout.getChildren().addAll(splash, loadProgress, progressText);
progressText.setAlignment(Pos.CENTER);
splashLayout.setStyle(
"-fx-padding: 5; " +
"-fx-background-color: cornsilk; " +
"-fx-border-width:5; " +
"-fx-border-color: " +
"linear-gradient(" +
"to bottom, " +
"chocolate, " +
"derive(chocolate, 50%)" +
");"
);
splashLayout.setEffect(new DropShadow());
}
/** /**
* Method that displays the visualiser, starting with the title screen. * Method that sets up and displays the splash screen
* @param stage the stage to be displayed. * @param initStage the inital stage
* @throws Exception if something wrong with title screen. * @throws Exception if something wrong with title screen.
*/ */
public void start(Stage stage) throws Exception { public void start(Stage initStage) throws Exception {
stage.setOnCloseRequest(new EventHandler<WindowEvent>() { final Task<ObservableList<String>> boatTask = new Task<ObservableList<String>>() {
@Override @Override
public void handle(WindowEvent event) { protected ObservableList<String> call() throws InterruptedException {
Platform.exit(); ObservableList<String> addedFilling =
System.exit(0); FXCollections.<String>observableArrayList();
ObservableList<String> burgerFilling =
FXCollections.observableArrayList(
"Buns", "Patties", "Lettuce", "Onions", "Tomato",
"Sauces"
);
updateMessage("Preparing ingredients . . .");
Thread.sleep(1000);
for (int i = 0; i < burgerFilling.size(); i++) {
Thread.sleep(800);
updateProgress(i + 1, burgerFilling.size());
String nextFilling = burgerFilling.get(i);
addedFilling.add(nextFilling);
updateMessage("Adding the " + nextFilling + " . . .");
} }
}); Thread.sleep(400);
updateMessage("Burger's done!");
return addedFilling;
}
};
showSplash(
initStage,
boatTask,
() -> {
try {
showMainStage(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
);
new Thread(boatTask).start();
}
/**
* Get main stage
* @return main stage
*/
public static Stage getStage() {
return App.stage;
}
/**
* Set main stage
* @param stage stage to set main stage
*/
public static void setStage(Stage stage) {
App.stage = stage;
}
/**
* Show the main stage after the splash screen
* @param stage main stage for application
* @throws Exception Throws an exception on error
*/
public void showMainStage(Stage stage) throws Exception {
App.stage = stage;
App.app = this;
FXMLLoader loader = new FXMLLoader(getClass().getResource("/visualiser/scenes/main.fxml")); FXMLLoader loader = new FXMLLoader(getClass().getResource("/visualiser/scenes/main.fxml"));
Parent root = loader.load(); Parent root = loader.load();
stage.setResizable(false); stage.setResizable(false);
@ -49,13 +163,57 @@ public class App extends Application {
mc.startCss(); mc.startCss();
setStage(stage); setStage(stage);
stage.show(); stage.show();
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
Platform.exit();
System.exit(0);
}
});
} }
public static Stage getStage() { /**
return App.stage; * Show the splash screen
* @param initStage Initial stage
* @param task Task for splash screen
* @param initCompletionHandler initCompletionHandler interface
*/
private void showSplash(
final Stage initStage,
Task<?> task,
InitCompletionHandler initCompletionHandler
) {
progressText.textProperty().bind(task.messageProperty());
loadProgress.progressProperty().bind(task.progressProperty());
task.stateProperty().addListener((observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
loadProgress.progressProperty().unbind();
loadProgress.setProgress(1);
initStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(2), splashLayout);
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(actionEvent -> initStage.hide());
fadeSplash.play();
initCompletionHandler.complete();
} }
});
public static void setStage(Stage stage) { Scene splashScene = new Scene(splashLayout, Color.TRANSPARENT);
App.stage = stage; final Rectangle2D bounds = Screen.getPrimary().getBounds();
initStage.setScene(splashScene);
initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
initStage.initStyle(StageStyle.TRANSPARENT);
initStage.setAlwaysOnTop(true);
initStage.show();
}
/**
* InnitCompletionHandler interface
*/
public interface InitCompletionHandler {
void complete();
} }
} }

@ -69,7 +69,11 @@ public class VisualiserRaceService implements RunnableWithFramePeriod {
long currentFrameTime = System.currentTimeMillis(); long currentFrameTime = System.currentTimeMillis();
try {
waitForFramePeriod(previousFrameTime, currentFrameTime, 16); waitForFramePeriod(previousFrameTime, currentFrameTime, 16);
} catch (Exception e) {
e.printStackTrace();
}
previousFrameTime = currentFrameTime; previousFrameTime = currentFrameTime;

@ -330,7 +330,11 @@ public class ServerConnection implements RunnableWithFramePeriod {
while (!Thread.interrupted()) { while (!Thread.interrupted()) {
long currentFrameTime = System.currentTimeMillis(); long currentFrameTime = System.currentTimeMillis();
try {
waitForFramePeriod(previousFrameTime, currentFrameTime, 100); waitForFramePeriod(previousFrameTime, currentFrameTime, 100);
} catch (Exception e) {
e.printStackTrace();
}
previousFrameTime = currentFrameTime; previousFrameTime = currentFrameTime;

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fitHeight="385.0" fitWidth="600.0" layoutY="-2.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="-1.9456787109375" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-2.0">
<image>
<Image url="@../images/game_controls.png" />
</image>
</ImageView>
</children>
</AnchorPane>

@ -33,6 +33,7 @@
<Font size="17.0" /> <Font size="17.0" />
</font> </font>
</Label> </Label>
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu" GridPane.halignment="CENTER" />
</children> </children>
</GridPane> </GridPane>
</children> </children>

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
@ -12,7 +17,7 @@
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<AnchorPane fx:id="lobbyWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" visible="false" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.LobbyController"> <AnchorPane fx:id="lobbyWrapper" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="780.0" visible="false" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.LobbyController">
<children> <children>
<GridPane fx:id="connection" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <GridPane fx:id="connection" prefHeight="600.0" prefWidth="780.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints> <columnConstraints>
@ -75,8 +80,11 @@
<children> <children>
<TextField fx:id="addressFld" promptText="Address"> <TextField fx:id="addressFld" promptText="Address">
<GridPane.margin> <GridPane.margin>
<Insets left="20.0" right="20.0" /> <Insets left="50.0" right="20.0" />
</GridPane.margin></TextField> </GridPane.margin>
<opaqueInsets>
<Insets />
</opaqueInsets></TextField>
<TextField fx:id="portFld" promptText="Port Number" GridPane.columnIndex="1"> <TextField fx:id="portFld" promptText="Port Number" GridPane.columnIndex="1">
<GridPane.margin> <GridPane.margin>
<Insets left="20.0" right="20.0" /> <Insets left="20.0" right="20.0" />
@ -86,6 +94,11 @@
<Insets /> <Insets />
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
<Button mnemonicParsing="false" onAction="#menuBtnPressed" text="Main Menu">
<GridPane.margin>
<Insets left="50.0" />
</GridPane.margin>
</Button>
</children> </children>
</GridPane> </GridPane>
</children> </children>

@ -37,6 +37,7 @@
</Text> </Text>
<RadioButton fx:id="nightModeRD" layoutX="681.0" layoutY="168.0" mnemonicParsing="false" onAction="#setNightMode" text="Night Mode" /> <RadioButton fx:id="nightModeRD" layoutX="681.0" layoutY="168.0" mnemonicParsing="false" onAction="#setNightMode" text="Night Mode" />
<RadioButton fx:id="dayModeRD" layoutX="574.0" layoutY="168.0" mnemonicParsing="false" onAction="#setDayMode" selected="true" text="Day Mode" /> <RadioButton fx:id="dayModeRD" layoutX="574.0" layoutY="168.0" mnemonicParsing="false" onAction="#setDayMode" selected="true" text="Day Mode" />
<Button layoutX="28.0" layoutY="152.0" mnemonicParsing="false" onAction="#controlBtnPressed" text="Controls" />
</children> </children>
</Pane> </Pane>
<Pane prefHeight="20.0" prefWidth="20.0" style="-fx-background-color: #6be6ff;" GridPane.columnSpan="4" GridPane.rowSpan="4"> <Pane prefHeight="20.0" prefWidth="20.0" style="-fx-background-color: #6be6ff;" GridPane.columnSpan="4" GridPane.rowSpan="4">

Loading…
Cancel
Save