Added empty data sources, to be used by VisualiserRace.

Created FrameRateTracker which can be used to track framerate.
Updated RequestToJoinEnum and JoinAcceptanceEnum to match the agreed connection API.
Added AssignPlayerBoat message, which is used internally on the client to assign the player a source ID once they have connected.
Fixed some race conditions in the MessageRouter.
Updated ConnectionAcceptor.CheckClientConnection to wait slightly longer before removing connection (there was a slight race condition before).
Race no longer has a reference to LatestMessages. LatestMessages no longer has specific messages types in it.
Created RaceState class, which contains the state that is shared between VisualiserRaceState and MockRaceState (currently only used on visualiser).
Split VisualiserRace into VisualiserRaceState and VisualiserRaceService.
Added the VisualiserRace commands (BoatLocatonCommand, RaceStatusCommand, etc...).
Slightly increased the preferred width of race.fxml table columns.
issues #27 #37 #35
#story[1095]
This commit is contained in:
fjc40
2017-08-14 00:53:05 +12:00
parent 89b0aa8b77
commit 7366aba5ec
53 changed files with 2498 additions and 1129 deletions
@@ -9,7 +9,7 @@ import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import mock.model.commandFactory.CompositeCommand;
import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RequestToJoinEnum;
import network.Messages.LatestMessages;
@@ -20,9 +20,10 @@ import shared.exceptions.InvalidRaceDataException;
import shared.exceptions.InvalidRegattaDataException;
import shared.exceptions.XMLReaderException;
import visualiser.gameController.ControllerClient;
import visualiser.model.VisualiserRaceState;
import visualiser.network.ServerConnection;
import visualiser.model.VisualiserBoat;
import visualiser.model.VisualiserRace;
import visualiser.model.VisualiserRaceEvent;
import java.io.IOException;
import java.net.Socket;
@@ -31,10 +32,11 @@ import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Controller to for waiting for the race to start.
*/
public class StartController extends Controller implements Observer {
public class StartController extends Controller {
@FXML private GridPane start;
@FXML private AnchorPane startWrapper;
@@ -70,9 +72,10 @@ public class StartController extends Controller implements Observer {
/**
* Our connection to the server.
* The race + connection to server.
*/
private ServerConnection serverConnection;
private VisualiserRaceEvent visualiserRaceEvent;
/**
* Writes BoatActions to outgoing message queue.
@@ -80,27 +83,9 @@ public class StartController extends Controller implements Observer {
private ControllerClient controllerClient;
/**
* The race object which describes the currently occurring race.
*/
private VisualiserRace visualiserRace;
/**
* An array of colors used to assign colors to each boat - passed in to the VisualiserRace constructor.
*/
private List<Color> colors = new ArrayList<>(Arrays.asList(
Color.BLUEVIOLET,
Color.BLACK,
Color.RED,
Color.ORANGE,
Color.DARKOLIVEGREEN,
Color.LIMEGREEN,
Color.PURPLE,
Color.DARKGRAY,
Color.YELLOW
));
@@ -117,41 +102,17 @@ public class StartController extends Controller implements Observer {
/**
* Starts the race.
* Called once we have received all XML files from the server.
* @param latestMessages The set of latest race messages to use for race.
* @throws XMLReaderException Thrown if XML file cannot be parsed.
* @throws InvalidRaceDataException Thrown if XML file cannot be parsed.
* @throws InvalidBoatDataException Thrown if XML file cannot be parsed.
* @throws InvalidRegattaDataException Thrown if XML file cannot be parsed.
*/
private void startRace(LatestMessages latestMessages) throws XMLReaderException, InvalidRaceDataException, InvalidBoatDataException, InvalidRegattaDataException {
//Create data sources from latest messages for the race.
RaceDataSource raceDataSource = new RaceXMLReader(latestMessages.getRaceXMLMessage().getXmlMessage(), XMLFileType.Contents);
BoatDataSource boatDataSource = new BoatXMLReader(latestMessages.getBoatXMLMessage().getXmlMessage(), XMLFileType.Contents);
RegattaDataSource regattaDataSource = new RegattaXMLReader(latestMessages.getRegattaXMLMessage().getXmlMessage(), XMLFileType.Contents);
//Create race.
this.visualiserRace = new VisualiserRace(boatDataSource, raceDataSource, regattaDataSource, latestMessages, this.colors);
new Thread(this.visualiserRace).start();
//Ugly. TODO refactor
ObservableList<VisualiserBoat> boats = visualiserRace.getBoats();
for (VisualiserBoat boat : boats) {
if (boat.getSourceID() == serverConnection.getAllocatedSourceID()) {
boat.setClientBoat(true);
}
}
private void startRace() {
//Initialise the boat table.
initialiseBoatTable(this.visualiserRace);
initialiseBoatTable(this.visualiserRaceEvent.getVisualiserRaceState());
//Initialise the race name.
initialiseRaceName(this.visualiserRace);
initialiseRaceName(this.visualiserRaceEvent.getVisualiserRaceState());
//Initialises the race clock.
initialiseRaceClock(this.visualiserRace);
initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState());
//Starts the race countdown timer.
countdownTimer();
@@ -169,7 +130,7 @@ public class StartController extends Controller implements Observer {
* Initialises the boat table that is to be shown on the pane.
* @param visualiserRace The race to get data from.
*/
private void initialiseBoatTable(VisualiserRace visualiserRace) {
private void initialiseBoatTable(VisualiserRaceState visualiserRace) {
//Get the boats.
ObservableList<VisualiserBoat> boats = visualiserRace.getBoats();
@@ -184,7 +145,7 @@ public class StartController extends Controller implements Observer {
* Initialises the race name which is shown on the pane.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceName(VisualiserRace visualiserRace) {
private void initialiseRaceName(VisualiserRaceState visualiserRace) {
raceTitleLabel.setText(visualiserRace.getRegattaName());
@@ -194,7 +155,7 @@ public class StartController extends Controller implements Observer {
* Initialises the race clock/timer labels for the start time, current time, and remaining time.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClock(VisualiserRace visualiserRace) {
private void initialiseRaceClock(VisualiserRaceState visualiserRace) {
//Start time.
initialiseRaceClockStartTime(visualiserRace);
@@ -212,7 +173,7 @@ public class StartController extends Controller implements Observer {
* Initialises the race current time label.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClockStartTime(VisualiserRace visualiserRace) {
private void initialiseRaceClockStartTime(VisualiserRaceState visualiserRace) {
raceStartLabel.setText(visualiserRace.getRaceClock().getStartingTimeString());
@@ -229,7 +190,7 @@ public class StartController extends Controller implements Observer {
* Initialises the race current time label.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClockCurrentTime(VisualiserRace visualiserRace) {
private void initialiseRaceClockCurrentTime(VisualiserRaceState visualiserRace) {
visualiserRace.getRaceClock().currentTimeProperty().addListener((observable, oldValue, newValue) -> {
Platform.runLater(() -> {
@@ -243,7 +204,7 @@ public class StartController extends Controller implements Observer {
* Initialises the race duration label.
* @param visualiserRace The race to get data from.
*/
private void initialiseRaceClockDuration(VisualiserRace visualiserRace) {
private void initialiseRaceClockDuration(VisualiserRaceState visualiserRace) {
visualiserRace.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> {
Platform.runLater(() -> {
@@ -261,13 +222,13 @@ public class StartController extends Controller implements Observer {
@Override
public void handle(long arg0) {
//TODO instead of having an AnimationTimer checking the race status, we could provide a Property<RaceStatusEnum>, and connect a listener to that.
//Get the current race status.
RaceStatusEnum raceStatus = visualiserRace.getRaceStatusEnum();
RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum();
//Display it.
raceStatusLabel.setText("Race Status: " + raceStatus.name());
//If the race has reached the preparatory phase, or has started...
if (raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) {
//Stop this timer.
@@ -275,9 +236,10 @@ public class StartController extends Controller implements Observer {
//Hide this, and display the race controller.
startWrapper.setVisible(false);
start.setVisible(false);
//start.setVisible(false);//TODO is this needed?
parent.beginRace(visualiserRaceEvent, controllerClient);
parent.beginRace(visualiserRace, controllerClient, serverConnection);
}
}
}.start();
@@ -285,58 +247,25 @@ public class StartController extends Controller implements Observer {
/**
* Function to handle changes in objects we observe.
* We observe LatestMessages.
* @param o The observed object.
* @param arg The {@link Observable#notifyObservers(Object)} parameter.
*/
@Override
public void update(Observable o, Object arg) {
//Check that we actually have LatestMessages.
if (o instanceof LatestMessages) {
LatestMessages latestMessages = (LatestMessages) o;
//If we've received all of the xml files, start the race. Only start it if it hasn't already been created.
if (latestMessages.hasAllXMLMessages() && this.visualiserRace == null) {
//Need to handle it in the javafx thread.
Platform.runLater(() -> {
try {
this.startRace(latestMessages);
} catch (XMLReaderException | InvalidBoatDataException | InvalidRaceDataException | InvalidRegattaDataException e) {
//We currently don't handle this in meaningful way, as it should never occur.
//If we reach this point it means that malformed XML files were sent.
e.printStackTrace();
}
});
}
}
}
/**
* Show starting information for a race given a socket.
* @param socket network source of information
*/
public void enterLobby(Socket socket) {
startWrapper.setVisible(true);
try {
LatestMessages latestMessages = new LatestMessages();
this.serverConnection = new ServerConnection(socket, latestMessages, RequestToJoinEnum.PARTICIPANT);
this.controllerClient = serverConnection.getControllerClient();
this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT);
this.controllerClient = visualiserRaceEvent.getControllerClient();
//Store a reference to latestMessages so that we can observe it.
latestMessages.addObserver(this);
new Thread(this.serverConnection).start();
startWrapper.setVisible(true);
startRace();
} catch (IOException e) {
Logger.getGlobal().log(Level.WARNING, "Could not connection to server.", e);
//TODO should probably let this propagate, so that we only enter this scene if everything works
Logger.getGlobal().log(Level.WARNING, "Could not connect to server.", e);
}
}