Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Michael Rausch
2017-07-27 11:06:00 +12:00
23 changed files with 423 additions and 249 deletions
@@ -59,6 +59,7 @@ public class ClientPacketParser {
*/ */
public ClientPacketParser() { public ClientPacketParser() {
} }
/** /**
* Looks at the type of the packet then sends it to the appropriate parser to extract the * Looks at the type of the packet then sends it to the appropriate parser to extract the
* specific data associated with that packet type * specific data associated with that packet type
@@ -78,7 +79,6 @@ public class ClientPacketParser {
extractDisplayMessage(packet); extractDisplayMessage(packet);
break; break;
case XML_MESSAGE: case XML_MESSAGE:
newRaceXmlReceived = true;
extractXmlMessage(packet); extractXmlMessage(packet);
break; break;
case RACE_START_STATUS: case RACE_START_STATUS:
@@ -108,7 +108,7 @@ public class ClientPacketParser {
} }
} catch (NullPointerException e) { } catch (NullPointerException e) {
System.out.println("Error parsing packet"); System.out.println("Error parsing packet");
e.printStackTrace(); // e.printStackTrace();
} }
} }
@@ -185,7 +185,6 @@ public class ClientPacketParser {
int noBoats = payload[22]; int noBoats = payload[22];
int raceType = payload[23]; int raceType = payload[23];
clientStateBoats = ClientState.getBoats();
for (int i = 0; i < noBoats; i++) { for (int i = 0; i < noBoats; i++) {
long boatStatusSourceID = bytesToLong( long boatStatusSourceID = bytesToLong(
Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20))); Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20)));
@@ -206,7 +205,9 @@ public class ClientPacketParser {
boat.setEstimateTimeAtNextMark(estTimeAtNextMark); boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
boat.setEstimateTimeAtFinish(estTimeAtFinish); boat.setEstimateTimeAtFinish(estTimeAtFinish);
Yacht clientBoat = clientStateBoats.get((int) boatStatusSourceID); // Update Client State boats when receive race status packet.
// Potentially could replace boats in ClientPacketParser.
Yacht clientBoat = ClientState.getBoats().get((int) boatStatusSourceID);
clientBoat.setBoatStatus((boatStatus)); clientBoat.setBoatStatus((boatStatus));
setBoatLegPosition(clientBoat, boatLegNumber); setBoatLegPosition(clientBoat, boatLegNumber);
clientBoat.setPenaltiesAwarded(boatPenaltyAwarded); clientBoat.setPenaltiesAwarded(boatPenaltyAwarded);
@@ -215,26 +216,32 @@ public class ClientPacketParser {
clientBoat.setEstimateTimeAtFinish(estTimeAtFinish); clientBoat.setEstimateTimeAtFinish(estTimeAtFinish);
} }
// 3 is race started // 3 is race started.
// ClientState race started flag will be set to true if race started, else set false.
if (raceStatus == 3) { if (raceStatus == 3) {
ClientState.setRaceStarted(true); ClientState.setRaceStarted(true);
} else {
ClientState.setRaceStarted(false);
} }
} }
private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){ private static void setBoatLegPosition(Yacht updatingBoat, Integer leg){
Integer placing = 1; Integer placing = 1;
if (leg != updatingBoat.getLegNumber() && (raceStarted || raceFinished)) {
if (/* TODO implement when we are getting this data /TODO leg != updatingBoat.getLegNumber() && */(raceStarted || raceFinished)) {
for (Yacht boat : boats.values()) { for (Yacht boat : boats.values()) {
placing = boat.getSourceId();
/* See above to-do
if (boat.getLegNumber() != null && leg <= boat.getLegNumber()){ if (boat.getLegNumber() != null && leg <= boat.getLegNumber()){
placing += 1; placing += 1;
} }*/
} }
updatingBoat.setPosition(placing.toString()); updatingBoat.setPosition(placing.toString());
updatingBoat.setLegNumber(leg); updatingBoat.setLegNumber(leg);
boatsPos.putIfAbsent(placing, updatingBoat); boatsPos.putIfAbsent(placing, updatingBoat);
boatsPos.replace(placing, updatingBoat); boatsPos.replace(placing, updatingBoat);
} else if(updatingBoat.getLegNumber() == null){ } else if(updatingBoat.getLegNumber() == null){
updatingBoat.setPosition("1"); updatingBoat.setPosition("-");
updatingBoat.setLegNumber(leg); updatingBoat.setLegNumber(leg);
} }
} }
@@ -284,10 +291,13 @@ public class ClientPacketParser {
} }
xmlObject.constructXML(doc, messageType); xmlObject.constructXML(doc, messageType);
if (messageType == 7) { //7 is the boat XML if (messageType == 7) { //7 is the boat XML
boats = xmlObject.getBoatXML().getCompetingBoats(); boats = xmlObject.getBoatXML().getCompetingBoats();
// Set/Update the ClientState boats after receiving new boat xml.
// Flag boatsUpdated in ClientState to true.
ClientState.setBoats(xmlObject.getBoatXML().getCompetingBoats()); ClientState.setBoats(xmlObject.getBoatXML().getCompetingBoats());
ClientState.setDirtyState(true); ClientState.setBoatsUpdated(true);
} }
if (messageType == 6) { //6 is race info xml if (messageType == 6) { //6 is race info xml
newRaceXmlReceived = true; newRaceXmlReceived = true;
@@ -1,14 +1,12 @@
package seng302.client; package seng302.client;
import com.sun.org.apache.xpath.internal.operations.Bool;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import seng302.models.Yacht; import seng302.models.Yacht;
/** /**
* Used by the client to store static variables to be used in game. * Used by the client to store static variables, which other threads and classes
* observer so that they can update their status accordingly.
*/ */
public class ClientState { public class ClientState {
@@ -17,7 +15,7 @@ public class ClientState {
private static Boolean raceStarted = false; private static Boolean raceStarted = false;
private static Boolean connectedToHost = false; private static Boolean connectedToHost = false;
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>(); private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
private static Boolean dirtyState = true; private static Boolean boatsUpdated = true;
private static String clientSourceId = ""; private static String clientSourceId = "";
public static String getHostIp() { public static String getHostIp() {
@@ -56,12 +54,12 @@ public class ClientState {
return boats; return boats;
} }
public static Boolean isDirtyState() { public static Boolean isBoatsUpdated() {
return dirtyState; return boatsUpdated;
} }
public static void setDirtyState(Boolean dirtyState) { public static void setBoatsUpdated(Boolean boatsUpdated) {
ClientState.dirtyState = dirtyState; ClientState.boatsUpdated = boatsUpdated;
} }
public static String getClientSourceId() { public static String getClientSourceId() {
@@ -12,6 +12,12 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable
public ClientStateQueryingRunnable() {} public ClientStateQueryingRunnable() {}
/**
* Notifies observers(the lobby controller) that "game started" if ClientState
* raceStarted flag is true and terminates itself. Also, it notifies observers
* to add/remove players if ClientState boatsUpdated flag is true, then resets
* the flag to false;
*/
@Override @Override
public void run() { public void run() {
while(!terminate) { while(!terminate) {
@@ -29,14 +35,19 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable
terminate(); terminate();
} }
if (ClientState.isDirtyState()) { if (ClientState.isBoatsUpdated()) {
setChanged(); setChanged();
notifyObservers("update players"); notifyObservers("update players");
ClientState.setDirtyState(false); ClientState.setBoatsUpdated(false);
} }
} }
} }
/**
* Used to terminate the thread.
*
* Currently called by the main while loop when game started is detected.
*/
public void terminate() { public void terminate() {
terminate = true; terminate = true;
} }
@@ -15,7 +15,8 @@ import seng302.server.messages.BoatActionMessage;
import seng302.server.messages.Message; import seng302.server.messages.Message;
/** /**
* Created by kre39 on 13/07/17. * A class describing a single connection to a Server for the purposes of sending and receiving on
* its own thread.
*/ */
public class ClientToServerThread implements Runnable { public class ClientToServerThread implements Runnable {
@@ -32,6 +33,17 @@ public class ClientToServerThread implements Runnable {
private Boolean updateClient = true; private Boolean updateClient = true;
private ByteArrayOutputStream crcBuffer; private ByteArrayOutputStream crcBuffer;
/**
* Constructor for ClientToServerThread which takes in ipAddress and portNumber and attempts to
* connect to the specified ipAddress and port.
*
* Upon successful socket connection, threeWayHandshake will be preformed and the instance will
* be put on a thread and run immediately.
*
* @param ipAddress a string of ip address to be connected to
* @param portNumber an integer port number
* @throws Exception SocketConnection if fail to connect to ip address and port number combination
*/
public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{ public ClientToServerThread(String ipAddress, Integer portNumber) throws Exception{
socket = new Socket(ipAddress, portNumber); socket = new Socket(ipAddress, portNumber);
is = socket.getInputStream(); is = socket.getInputStream();
@@ -40,7 +52,7 @@ public class ClientToServerThread implements Runnable {
Integer allocatedID = threeWayHandshake(); Integer allocatedID = threeWayHandshake();
if (allocatedID != null) { if (allocatedID != null) {
ourID = allocatedID; ourID = allocatedID;
clientLog("Successful handshake. Allocated ID: " + ourID, 1); clientLog("Successful handshake. Allocated ID: " + ourID, 0);
ClientState.setClientSourceId(String.valueOf(ourID)); ClientState.setClientSourceId(String.valueOf(ourID));
} else { } else {
clientLog("Unsuccessful handshake", 1); clientLog("Unsuccessful handshake", 1);
@@ -50,31 +62,31 @@ public class ClientToServerThread implements Runnable {
thread = new Thread(this); thread = new Thread(this);
thread.start(); thread.start();
} }
/**
* Prints out log messages and the time happened.
* Only perform task if log level is below LOG_LEVEL variable.
*
* @param message a string of message to be printed out
* @param logLevel an int for log level
*/
static void clientLog(String message, int logLevel){ static void clientLog(String message, int logLevel){
if(logLevel <= LOG_LEVEL){ if(logLevel <= LOG_LEVEL){
System.out.println("[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message); System.out.println("[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
} }
} }
/**
* Perform the thread loop. It exits the loop if ClientState connected to host
* variable is false.
*/
public void run() { public void run() {
int sync1; int sync1;
int sync2; int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop // TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while(ClientState.isConnectedToHost()) { while(ClientState.isConnectedToHost()) {
try { try {
//Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) {
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
// try {
// GameState.outputState(os);
// } catch (IOException e) {
// System.out.println("IO error in server thread upon writing to output stream");
// }
updateClient = false;
}
crcBuffer = new ByteArrayOutputStream(); crcBuffer = new ByteArrayOutputStream();
sync1 = readByte(); sync1 = readByte();
sync2 = readByte(); sync2 = readByte();
@@ -93,15 +105,13 @@ public class ClientToServerThread implements Runnable {
if (computedCrc == packetCrc) { if (computedCrc == packetCrc) {
ClientPacketParser ClientPacketParser
.parsePacket(new StreamPacket(type, payloadLength, timeStamp, payload)); .parsePacket(new StreamPacket(type, payloadLength, timeStamp, payload));
// TODO: 17/07/17 wmu16 - Fix this or maybe we dont need to go through the main server at all!?!?
// packetBufferDelegate.addToBuffer(new StreamPacket(type, payloadLength, timeStamp, payload));
} else { } else {
clientLog("Packet has been dropped", 1); clientLog("Packet has been dropped", 1);
} }
} }
} catch (Exception e) { } catch (Exception e) {
closeSocket(); closeSocket();
e.printStackTrace(); clientLog("Disconnected from server", 1);
return; return;
} }
} }
@@ -111,7 +121,7 @@ public class ClientToServerThread implements Runnable {
/** /**
* Listens for an allocated sourceID and returns it to the server if recieved * Listens for an allocated sourceID and returns it to the server
* @return the sourceID allocated to us by the server * @return the sourceID allocated to us by the server
*/ */
private Integer threeWayHandshake() { private Integer threeWayHandshake() {
@@ -120,14 +130,15 @@ public class ClientToServerThread implements Runnable {
try { try {
ourSourceID = is.read(); ourSourceID = is.read();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); clientLog("Three way handshake failed", 1);
} }
if (ourSourceID != null) { if (ourSourceID != null) {
try { try {
os.write(ourSourceID); os.write(ourSourceID);
return ourSourceID; return ourSourceID;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); clientLog("Three way handshake failed", 1);
return null; return null;
} }
} }
@@ -143,8 +154,7 @@ public class ClientToServerThread implements Runnable {
try { try {
os.write(boatActionMessage.getBuffer()); os.write(boatActionMessage.getBuffer());
} catch (IOException e) { } catch (IOException e) {
clientLog("COULD NOT WRITE TO SERVER", 0); clientLog("Could not write to server", 1);
e.printStackTrace();
} }
} }
@@ -153,7 +163,7 @@ public class ClientToServerThread implements Runnable {
try { try {
socket.close(); socket.close();
} catch (IOException e) { } catch (IOException e) {
clientLog("Failed to close the socket", 0); clientLog("Failed to close the socket", 1);
} }
} }
@@ -164,7 +174,7 @@ public class ClientToServerThread implements Runnable {
currentByte = is.read(); currentByte = is.read();
crcBuffer.write(currentByte); crcBuffer.write(currentByte);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); clientLog("Read byte failed", 1);
} }
if (currentByte == -1){ if (currentByte == -1){
throw new Exception(); throw new Exception();
@@ -22,6 +22,7 @@ import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import seng302.client.ClientPacketParser; import seng302.client.ClientPacketParser;
import seng302.client.ClientState;
import seng302.fxObjects.BoatGroup; import seng302.fxObjects.BoatGroup;
import seng302.models.Colors; import seng302.models.Colors;
import seng302.models.Yacht; import seng302.models.Yacht;
@@ -57,8 +58,8 @@ public class CanvasController {
private final int BUFFER_SIZE = 50; private final int BUFFER_SIZE = 50;
private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias. private final int PANEL_WIDTH = 1260; // it should be 1280 but, minors 40 to cancel the bias.
private final int PANEL_HEIGHT = 960; private final int PANEL_HEIGHT = 960;
private final int CANVAS_WIDTH = 720; private final int CANVAS_WIDTH = 1100;
private final int CANVAS_HEIGHT = 720; private final int CANVAS_HEIGHT = 920;
private boolean horizontalInversion = false; private boolean horizontalInversion = false;
private double distanceScaleFactor; private double distanceScaleFactor;
@@ -74,7 +75,7 @@ public class CanvasController {
private List<MarkGroup> markGroups = new ArrayList<>(); private List<MarkGroup> markGroups = new ArrayList<>();
private List<BoatGroup> boatGroups = new ArrayList<>(); private List<BoatGroup> boatGroups = new ArrayList<>();
private Text FPSdisplay = new Text(); private Text FPSDisplay = new Text();
private Polygon raceBorder = new Polygon(); private Polygon raceBorder = new Polygon();
//FRAME RATE //FRAME RATE
@@ -119,10 +120,10 @@ public class CanvasController {
gc.setGlobalAlpha(0.5); gc.setGlobalAlpha(0.5);
fitMarksToCanvas(); fitMarksToCanvas();
drawGoogleMap(); drawGoogleMap();
FPSdisplay.setLayoutX(5); FPSDisplay.setLayoutX(5);
FPSdisplay.setLayoutY(20); FPSDisplay.setLayoutY(20);
FPSdisplay.setStrokeWidth(2); FPSDisplay.setStrokeWidth(2);
group.getChildren().add(FPSdisplay); group.getChildren().add(FPSDisplay);
group.getChildren().add(raceBorder); group.getChildren().add(raceBorder);
initializeMarks(); initializeMarks();
initializeBoats(); initializeBoats();
@@ -249,12 +250,9 @@ public class CanvasController {
// some raceObjects will have multiple ID's (for instance gate marks) // some raceObjects will have multiple ID's (for instance gate marks)
//checking if the current "ID" has any updates associated with it //checking if the current "ID" has any updates associated with it
if (ClientPacketParser.boatLocations.containsKey(boatGroup.getRaceId())) { if (ClientPacketParser.boatLocations.containsKey(boatGroup.getRaceId())) {
if (boatGroup.isStopped()) {
updateBoatGroup(boatGroup); updateBoatGroup(boatGroup);
} }
} }
boatGroup.move();
}
for (MarkGroup markGroup : markGroups) { for (MarkGroup markGroup : markGroups) {
for (Long id : markGroup.getRaceIds()) { for (Long id : markGroup.getRaceIds()) {
if (ClientPacketParser.markLocations.containsKey(id)) { if (ClientPacketParser.markLocations.containsKey(id)) {
@@ -324,10 +322,25 @@ public class CanvasController {
if (participantIDs.contains(boat.getSourceId())) { if (participantIDs.contains(boat.getSourceId())) {
boat.setColour(Colors.getColor()); boat.setColour(Colors.getColor());
BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); BoatGroup boatGroup = new BoatGroup(boat, boat.getColour());
if (boat.getSourceId().equals(Integer.parseInt(ClientState.getClientSourceId()))) {
boatGroup.setAsPlayer();
boatGroups.add(boatGroup); boatGroups.add(boatGroup);
annotations.getChildren().add(boatGroup.getAnnotations());
} else {
//Move annotations and boat to bottom of group keeping player ontop.
if (boatGroups.size() > 0) {
boatGroups.add(0, boatGroup);
} else {
boatGroups.add(boatGroup);
}
if (annotations.getChildren().size() > 0) {
annotations.getChildren().add(0, boatGroup.getAnnotations());
} else {
annotations.getChildren().add(boatGroup.getAnnotations());
}
}
trails.getChildren().add(boatGroup.getTrail()); trails.getChildren().add(boatGroup.getTrail());
wakes.getChildren().add(boatGroup.getWake()); wakes.getChildren().add(boatGroup.getWake());
annotations.getChildren().add(boatGroup.getAnnotations());
} }
} }
group.getChildren().addAll(trails); group.getChildren().addAll(trails);
@@ -391,10 +404,10 @@ public class CanvasController {
private void drawFps(int fps){ private void drawFps(int fps){
if (raceViewController.isDisplayFps()){ if (raceViewController.isDisplayFps()){
FPSdisplay.setVisible(true); FPSDisplay.setVisible(true);
FPSdisplay.setText(String.format("%d FPS", fps)); FPSDisplay.setText(String.format("%d FPS", fps));
} else { } else {
FPSdisplay.setVisible(false); FPSDisplay.setVisible(false);
} }
} }
@@ -112,6 +112,7 @@ public class LobbyController implements Initializable, Observer{
readyButton.setDisable(true); readyButton.setDisable(true);
} }
// put all javafx objects in lists, so we can iterate though conveniently
imageViews = new ArrayList<>(); imageViews = new ArrayList<>();
Collections.addAll(imageViews, firstImageView, secondImageView, thirdImageView, fourthImageView, Collections.addAll(imageViews, firstImageView, secondImageView, thirdImageView, fourthImageView,
fifthImageView, sixthImageView, seventhImageView, eighthImageView); fifthImageView, sixthImageView, seventhImageView, eighthImageView);
@@ -134,6 +135,13 @@ public class LobbyController implements Initializable, Observer{
clientStateQueryingThread.start(); clientStateQueryingThread.start();
} }
/**
* Observers "ClientStateQueryingRunnable".
* When the clients state has been marked to "race start", the querying thread
* will notify this lobby to change the view
* @param o
* @param arg
*/
@Override @Override
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
Platform.runLater(new Runnable() { Platform.runLater(new Runnable() {
@@ -149,6 +157,9 @@ public class LobbyController implements Initializable, Observer{
}); });
} }
/**
* Reset all ListViews and ImageViews according to the current competitors
*/
private void initialiseListView() { private void initialiseListView() {
listViews.forEach(listView -> listView.getItems().clear()); listViews.forEach(listView -> listView.getItems().clear());
imageViews.forEach(gif -> gif.setVisible(false)); imageViews.forEach(gif -> gif.setVisible(false));
@@ -156,12 +167,15 @@ public class LobbyController implements Initializable, Observer{
List<Integer> ids = new ArrayList<>(ClientState.getBoats().keySet()); List<Integer> ids = new ArrayList<>(ClientState.getBoats().keySet());
for (int i = 0; i < ids.size(); i++) { for (int i = 0; i < ids.size(); i++) {
competitors.get(i).add(String.format("Player ID: %d", ids.get(i))); competitors.get(i).add(ClientState.getBoats().get(ids.get(i)).getBoatName());
listViews.get(i).setItems(competitors.get(i)); listViews.get(i).setItems(competitors.get(i));
imageViews.get(i).setVisible(true); imageViews.get(i).setVisible(true);
} }
} }
/**
* Loads preset images into imageViews
*/
private void initialiseImageView() { private void initialiseImageView() {
for (int i = 0; i < MAX_NUM_PLAYERS; i++) { for (int i = 0; i < MAX_NUM_PLAYERS; i++) {
imageViews.get(i).setImage(new Image(getClass().getResourceAsStream("/pics/sail.png"))); imageViews.get(i).setImage(new Image(getClass().getResourceAsStream("/pics/sail.png")));
@@ -195,31 +209,11 @@ public class LobbyController implements Initializable, Observer{
@FXML @FXML
public void readyButtonPressed() { public void readyButtonPressed() {
// setContentPane("/views/RaceView.fxml");
// playTheme();
GameState.setCurrentStage(GameStages.RACING); GameState.setCurrentStage(GameStages.RACING);
mainServerThread.startGame(); mainServerThread.startGame();
} }
// private static MediaPlayer mediaPlayer;
//
// private void playTheme() {
// Random random = new Random(System.currentTimeMillis());
// Integer rand = random.nextInt();
// if(rand == 10) {
// URL file = getClass().getResource("/music/Disturbed - down with the sickness.mp3");
// Media hit = new Media(file.toString());
// mediaPlayer = new MediaPlayer(hit);
// mediaPlayer.play();
// } else if(rand == 9) {
// URL file = getClass().getResource("/music/Owl City - Fireflies.mp3");
// Media hit = new Media(file.toString());
// mediaPlayer = new MediaPlayer(hit);
// mediaPlayer.play();
// }
// }
private void switchToRaceView() { private void switchToRaceView() {
if (!switchedPane) { if (!switchedPane) {
switchedPane = true; switchedPane = true;
@@ -287,6 +287,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
updateWindDirection(); updateWindDirection();
// updateOrder(); // updateOrder();
updateBoatSelectionComboBox(); updateBoatSelectionComboBox();
updateOrder();
}) })
); );
@@ -383,9 +384,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
if (ClientPacketParser.isRaceStarted()) { if (ClientPacketParser.isRaceStarted()) {
/*
for (Yacht boat : ClientPacketParser.getBoatsPos().values()) { for (Yacht boat : ClientPacketParser.getBoatsPos().values()) {
if (participantIDs.contains(boat.getSourceId())) { // check if the boat is racing System.out.println("Hi tjere" + boat.getBoatName());
if (boat.getBoatStatus() == 3) { // 3 is finish status if (participantIDs.contains(boat.getSourceId()) || true
) { // check if the boat is racing
if (boat.getBoatStatus() == 69) { // 3 is finish status
Text textToAdd = new Text(boat.getPosition() + ". " + Text textToAdd = new Text(boat.getPosition() + ". " +
boat.getShortName() + " (Finished)"); boat.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
@@ -397,9 +401,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle(""); textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd); positionVbox.getChildren().add(textToAdd);
System.out.println("Adding " + textToAdd.getText());
} }
} }
} }
*/
for (Yacht boat : ClientPacketParser.getBoats().values()){
Text textToAdd = new Text(boat.getSourceId() + ". " + boat.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle("");
positionVbox.getChildren().add(textToAdd);
}
} else { } else {
for (Yacht boat : ClientPacketParser.getBoats().values()) { for (Yacht boat : ClientPacketParser.getBoats().values()) {
if (participantIDs.contains(boat.getSourceId())) { // check if the boat is racing if (participantIDs.contains(boat.getSourceId())) { // check if the boat is racing
@@ -135,7 +135,11 @@ public class ImportantAnnotationController implements Initializable {
boatEstTimeToNextMarkSelect.isSelected())); boatEstTimeToNextMarkSelect.isSelected()));
boatElapsedTimeSelect.setOnAction( boatElapsedTimeSelect.setOnAction(
event -> setAnnotation(Annotation.LEGTIME, boatElapsedTimeSelect.isSelected())); event -> setAnnotation(Annotation.LEGTIME, boatElapsedTimeSelect.isSelected()));
// TODO: 26/07/17 cir27 - Create a more robust fix for this when the annotation for the game are decided upon.
boatEstTimeToNextMarkSelect.setVisible(false);
boatEstTimeToNextMarkSelect.setDisable(true);
boatElapsedTimeSelect.setVisible(false);
boatElapsedTimeSelect.setDisable(true);
closeButton.setOnAction(event -> stage.close()); closeButton.setOnAction(event -> stage.close());
} }
} }
@@ -33,7 +33,7 @@ public class BoatAnnotations extends Group{
private Text velocityObject; private Text velocityObject;
private Text estTimeToNextMarkObject; private Text estTimeToNextMarkObject;
private Text legTimeObject; private Text legTimeObject;
private boolean isPlayer = false;
private Yacht boat; private Yacht boat;
BoatAnnotations (Yacht boat, Color theme) { BoatAnnotations (Yacht boat, Color theme) {
@@ -56,12 +56,17 @@ public class BoatAnnotations extends Group{
velocityObject = getTextObject("0 m/s", theme); velocityObject = getTextObject("0 m/s", theme);
velocityObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 2); velocityObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 2);
velocityObject.setVisible(false);
estTimeToNextMarkObject = getTextObject("Next mark: ", theme); estTimeToNextMarkObject = getTextObject("Next mark: ", theme);
estTimeToNextMarkObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 3); estTimeToNextMarkObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 3);
estTimeToNextMarkObject.setVisible(false);
legTimeObject = getTextObject("Last mark: -", theme); legTimeObject = getTextObject("Last mark: -", theme);
legTimeObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 4); legTimeObject.relocate(X_OFFSET_TEXT, Y_OFFSET_TEXT_INIT + Y_OFFSET_PER_TEXT * 4);
legTimeObject.setVisible(false);
this.setVisible(true, false, false, false);
super.getChildren().addAll(background, teamNameObject, velocityObject, estTimeToNextMarkObject, legTimeObject); super.getChildren().addAll(background, teamNameObject, velocityObject, estTimeToNextMarkObject, legTimeObject);
} }
@@ -83,6 +88,8 @@ public class BoatAnnotations extends Group{
} }
void update () { void update () {
teamNameObject.setText("Player: " + boat.getShortName());
velocityObject.setText(String.format(String.format("%.2f m/s", boat.getVelocityMMS()))); velocityObject.setText(String.format(String.format("%.2f m/s", boat.getVelocityMMS())));
if (boat.getTimeTillNext() != null) { if (boat.getTimeTillNext() != null) {
@@ -104,13 +111,19 @@ public class BoatAnnotations extends Group{
} }
} }
void setVisibile (boolean nameVisibility, boolean speedVisibility, void setVisible(boolean nameVisibility, boolean speedVisibility,
boolean estTimeVisibility, boolean lastMarkVisibility) { boolean estTimeVisibility, boolean lastMarkVisibility) {
int totalVisible = 0; int totalVisible = 0;
/*
This is a temporary fix until the new annotation group is added along with the visualiser
overhaul.
*/
totalVisible = updateVisibility(nameVisibility, teamNameObject, totalVisible); totalVisible = updateVisibility(nameVisibility, teamNameObject, totalVisible);
if (isPlayer)
totalVisible = updateVisibility(speedVisibility, velocityObject, totalVisible); totalVisible = updateVisibility(speedVisibility, velocityObject, totalVisible);
totalVisible = updateVisibility(estTimeVisibility, estTimeToNextMarkObject, totalVisible); // totalVisible = updateVisibility(estTimeVisibility, estTimeToNextMarkObject, totalVisible);
totalVisible = updateVisibility(lastMarkVisibility, legTimeObject, totalVisible); // totalVisible = updateVisibility(lastMarkVisibility, legTimeObject, totalVisible);
if (totalVisible != 0) { if (totalVisible != 0) {
background.setVisible(true); background.setVisible(true);
background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * totalVisible); background.setHeight(Math.abs(BACKGROUND_X) + TEXT_BUFFER + BACKGROUND_H_PER_TEXT * totalVisible);
@@ -130,4 +143,12 @@ public class BoatAnnotations extends Group{
} }
return totalVisible; return totalVisible;
} }
/**
* Sets these annotations to show more detailed info.
*/
public void setAsPlayer () {
isPlayer = true;
velocityObject.setVisible(true);
}
} }
+50 -53
View File
@@ -6,6 +6,7 @@ import javafx.geometry.Point2D;
import javafx.scene.CacheHint; import javafx.scene.CacheHint;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line; import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
@@ -48,8 +49,9 @@ public class BoatGroup extends Group {
private Point2D lastPoint; private Point2D lastPoint;
private boolean destinationSet; private boolean destinationSet;
private BoatAnnotations boatAnnotations; private BoatAnnotations boatAnnotations;
private Color color;
private Boolean isSelected = true; //All boats are initialised as selected private Boolean isSelected = true; //All boats are initialised as selected\
private boolean isPlayer = false;
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
@@ -88,20 +90,21 @@ public class BoatGroup extends Group {
* polygon. * polygon.
*/ */
private void initChildren(Color color, double... points) { private void initChildren(Color color, double... points) {
this.color = color;
boatPoly = new Polygon(points); boatPoly = new Polygon(points);
boatPoly.setFill(color); boatPoly.setFill(this.color);
boatPoly.setOnMouseEntered(event -> { boatPoly.setOnMouseEntered(event -> {
boatPoly.setFill(Color.FLORALWHITE); boatPoly.setFill(Color.FLORALWHITE);
boatPoly.setStroke(Color.RED); boatPoly.setStroke(Color.RED);
}); });
boatPoly.setOnMouseExited(event -> { boatPoly.setOnMouseExited(event -> {
boatPoly.setFill(color); boatPoly.setFill(this.color);
boatPoly.setStroke(Color.BLACK); boatPoly.setStroke(Color.BLACK);
}); });
boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected)); boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected));
boatPoly.setCache(true); boatPoly.setCache(true);
boatPoly.setCacheHint(CacheHint.SPEED); boatPoly.setCacheHint(CacheHint.SPEED);
boatAnnotations = new BoatAnnotations(boat, color); boatAnnotations = new BoatAnnotations(boat, this.color);
leftLayLine = new Line(); leftLayLine = new Line();
rightLayline = new Line(); rightLayline = new Line();
@@ -160,42 +163,6 @@ public class BoatGroup extends Group {
boatPoly.getTransforms().setAll(new Rotate(rotation)); boatPoly.getTransforms().setAll(new Rotate(rotation));
} }
public void move() {
double dx = xIncrement * framesToMove;
double dy = yIncrement * framesToMove;
distanceTravelled += Math.abs(dx) + Math.abs(dy);
moveGroupBy(xIncrement, yIncrement);
framesToMove = framesToMove - 1;
if (framesToMove <= 0) {
isStopped = true;
}
// if (distanceTravelled > 70) {
// distanceTravelled = 0d;
//
// if (lastPoint != null) {
// Line l = new Line(
// lastPoint.getX(),
// lastPoint.getY(),
// boatPoly.getLayoutX(),
// boatPoly.getLayoutY()
// );
// l.getStrokeDashArray().setAll(3d, 7d);
// l.setStroke(boat.getColour());
// l.setCache(true);
// l.setCacheHint(CacheHint.SPEED);
// lineGroup.getChildren().add(l);
// }
//
// if (destinationSet) {
// lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
// }
// }
wake.updatePosition();
}
/** /**
* Sets the destination of the boat and the headng it should have once it reaches * Sets the destination of the boat and the headng it should have once it reaches
* *
@@ -206,26 +173,42 @@ public class BoatGroup extends Group {
*/ */
public void setDestination(double newXValue, double newYValue, double rotation, public void setDestination(double newXValue, double newYValue, double rotation,
double groundSpeed, long timeValid, double frameRate) { double groundSpeed, long timeValid, double frameRate) {
if (lastTimeValid == 0) {
lastTimeValid = timeValid - 200;
moveTo(newXValue, newYValue, rotation);
}
framesToMove = Math.round((frameRate / (1000.0f / (timeValid - lastTimeValid))));
double dx = newXValue - boatPoly.getLayoutX();
double dy = newYValue - boatPoly.getLayoutY();
xIncrement = dx / framesToMove;
yIncrement = dy / framesToMove;
destinationSet = true; destinationSet = true;
Double dx = Math.abs(boatPoly.getLayoutX() - newXValue);
Double dy = Math.abs(boatPoly.getLayoutY() - newYValue);
moveTo(newXValue, newYValue, rotation);
rotateTo(rotation); rotateTo(rotation);
wake.setRotation(rotation, groundSpeed); wake.setRotation(rotation, groundSpeed);
boat.setVelocity(groundSpeed); boat.setVelocity(groundSpeed);
lastTimeValid = timeValid;
isStopped = false; isStopped = false;
lastRotation = rotation; lastRotation = rotation;
boatAnnotations.update(); boatAnnotations.update();
distanceTravelled += Math.sqrt((dx * dx) + (dy * dy));
if (distanceTravelled > 10 && isPlayer) {
distanceTravelled = 0d;
if (lastPoint != null) {
Line l = new Line(
lastPoint.getX(),
lastPoint.getY(),
boatPoly.getLayoutX(),
boatPoly.getLayoutY()
);
l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(boat.getColour());
l.setCache(true);
l.setCacheHint(CacheHint.SPEED);
lineGroup.getChildren().add(l);
}
if (destinationSet) {
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
}
}
} }
@@ -276,7 +259,7 @@ public class BoatGroup extends Group {
} }
public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime, boolean trail, boolean wake) { public void setVisibility (boolean teamName, boolean velocity, boolean estTime, boolean legTime, boolean trail, boolean wake) {
boatAnnotations.setVisibile(teamName, velocity, estTime, legTime); boatAnnotations.setVisible(teamName, velocity, estTime, legTime);
this.wake.setVisible(wake); this.wake.setVisible(wake);
this.lineGroup.setVisible(trail); this.lineGroup.setVisible(trail);
} }
@@ -349,4 +332,18 @@ public class BoatGroup extends Group {
return boat.toString(); return boat.toString();
} }
/**
* Sets this boat to appear highlighted
*/
public void setAsPlayer() {
boatPoly.getPoints().setAll(
-BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75,
0.0, -BOAT_HEIGHT / 1.75,
BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75
);
boatPoly.setStroke(Color.BLACK);
boatPoly.setStrokeWidth(3);
boatAnnotations.setAsPlayer();
isPlayer = true;
}
} }
+22 -22
View File
@@ -55,29 +55,29 @@ public class Wake extends Group {
} }
void setRotation (double rotation, double velocity) { void setRotation (double rotation, double velocity) {
if (Math.abs(rotations[0] - rotation) > 20) { // if (Math.abs(rotations[0] - rotation) > 20) {
rotate(rotation); rotate(rotation);
} else { // } else {
rotations[0] = rotation; // rotations[0] = rotation;
((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation); // ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
for (int i = 1; i < numWakes; i++) { // for (int i = 1; i < numWakes; i++) {
double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]); // double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
double shortestDistance = Math.atan2( // double shortestDistance = Math.atan2(
Math.sin(wakeSeparationRad), // Math.sin(wakeSeparationRad),
Math.cos(wakeSeparationRad) // Math.cos(wakeSeparationRad)
); // );
double distDeg = Math.toDegrees(shortestDistance); // double distDeg = Math.toDegrees(shortestDistance);
if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) { // if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) {
rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * 2 * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes); // rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * 2 * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
//
} else { // } else {
if (distDeg < (MAX_DIFF / numWakes)) { // if (distDeg < (MAX_DIFF / numWakes)) {
rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes); // rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
} else // } else
rotationalVelocities[i] = rotationalVelocities[i - 1]; // rotationalVelocities[i] = rotationalVelocities[i - 1];
} // }
} // }
} // }
double rad = (14 / numWakes) + velocity; double rad = (14 / numWakes) + velocity;
for (Arc arc : arcs) { for (Arc arc : arcs) {
@@ -1,10 +1,11 @@
package seng302.gameServer; package seng302.gameServer;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import seng302.client.ClientPacketParser; import seng302.client.ClientPacketParser;
import seng302.models.Player; import seng302.models.Player;
import seng302.models.Yacht; import seng302.models.Yacht;
import seng302.server.messages.BoatActionType; import seng302.server.messages.BoatActionType;
@@ -12,7 +13,9 @@ import seng302.server.messages.BoatActionType;
* A Static class to hold information about the current state of the game (model) * A Static class to hold information about the current state of the game (model)
* Created by wmu16 on 10/07/17. * Created by wmu16 on 10/07/17.
*/ */
public class GameState { public class GameState implements Runnable {
private static Integer STATE_UPDATES_PER_SECOND = 60;
private static Long previousUpdateTime; private static Long previousUpdateTime;
public static Double windDirection; public static Double windDirection;
@@ -24,14 +27,17 @@ public class GameState {
private static Boolean isRaceStarted; private static Boolean isRaceStarted;
private static GameStages currentStage; private static GameStages currentStage;
private static long startTime = System.currentTimeMillis();
public GameState(String hostIpAddress) { public GameState(String hostIpAddress) {
windDirection = 170d; windDirection = 180d;
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>(); yachts = new HashMap<>();
players = new ArrayList<>(); players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress; this.hostIpAddress = hostIpAddress;
players = new ArrayList<>(); players = new ArrayList<>();
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
@@ -39,6 +45,9 @@ public class GameState {
//set this when game stage changes to prerace //set this when game stage changes to prerace
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
yachts = new HashMap<>(); yachts = new HashMap<>();
new Thread(this).start();
} }
public static String getHostIpAddress() { public static String getHostIpAddress() {
@@ -74,9 +83,17 @@ public class GameState {
} }
public static void setCurrentStage(GameStages currentStage) { public static void setCurrentStage(GameStages currentStage) {
if (currentStage == GameStages.RACING){
startTime = System.currentTimeMillis();
}
GameState.currentStage = currentStage; GameState.currentStage = currentStage;
} }
public static long getStartTime(){
return startTime;
}
public static Double getWindDirection() { public static Double getWindDirection() {
return windDirection; return windDirection;
} }
@@ -100,7 +117,6 @@ public class GameState {
case VMG: case VMG:
playerYacht.turnToVMG(); playerYacht.turnToVMG();
// System.out.println("Snapping to VMG"); // System.out.println("Snapping to VMG");
// TODO: 22/07/17 wmu16 - Add in the vmg calculation code here
break; break;
case SAILS_IN: case SAILS_IN:
playerYacht.toggleSailIn(); playerYacht.toggleSailIn();
@@ -134,7 +150,6 @@ public class GameState {
} }
public static void update() { public static void update() {
Long timeInterval = System.currentTimeMillis() - previousUpdateTime; Long timeInterval = System.currentTimeMillis() - previousUpdateTime;
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
for (Yacht yacht : yachts.values()) { for (Yacht yacht : yachts.values()) {
@@ -151,4 +166,28 @@ public class GameState {
// TODO: 22/07/17 wmu16 - This may not be robust enough and may have to be improved on. // TODO: 22/07/17 wmu16 - This may not be robust enough and may have to be improved on.
return yachts.size() + 1; return yachts.size() + 1;
} }
/**
* A thread to have the game state update itself at certain intervals
*/
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000 / STATE_UPDATES_PER_SECOND);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (currentStage == GameStages.PRE_RACE) {
update();
}
//RACING
if (currentStage == GameStages.RACING) {
update();
}
}
}
} }
@@ -11,28 +11,26 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
import java.util.logging.Logger;
/** /**
* A class describing the overall server, which creates and collects server threads for each client * A class describing the overall server, which creates and collects server threads for each client
* Created by wmu16 on 13/07/17. * Created by wmu16 on 13/07/17.
*/ */
public class MainServerThread extends Observable implements Runnable, PacketBufferDelegate, ClientConnectionDelegate{ public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer MAX_NUM_PLAYERS = 3; private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
private static final Integer UPDATES_PER_SECOND = 2;
private static final int LOG_LEVEL = 1; private static final int LOG_LEVEL = 1;
private Thread thread; private Thread thread;
private ServerSocket serverSocket = null; private ServerSocket serverSocket = null;
private Socket socket;
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>(); private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
private PriorityBlockingQueue<StreamPacket> packetBuffer;
public MainServerThread() { public MainServerThread() {
try { try {
serverSocket = new ServerSocket(PORT); serverSocket = new ServerSocket(PORT);
@@ -40,8 +38,6 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
serverLog("IO error in server thread handler upon trying to make new server socket", 0); serverLog("IO error in server thread handler upon trying to make new server socket", 0);
} }
packetBuffer = new PriorityBlockingQueue<>();
thread = new Thread(this); thread = new Thread(this);
thread.start(); thread.start();
} }
@@ -57,22 +53,20 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
heartbeatThread.start(); heartbeatThread.start();
serverListenThread.start(); serverListenThread.start();
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app. //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
while (!thread.isInterrupted()) { while (!thread.isInterrupted()) {
try { try {
Thread.sleep(1000 / UPDATES_PER_SECOND); Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
if (GameState.getCurrentStage() == GameStages.PRE_RACE) { if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
GameState.update(); updateClients();
} }
//RACING //RACING
if (GameState.getCurrentStage() == GameStages.RACING) { if (GameState.getCurrentStage() == GameStages.RACING) {
GameState.update();
updateClients(); updateClients();
} }
@@ -81,14 +75,6 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
} }
while (!packetBuffer.isEmpty()){
try {
StreamPacket packet = packetBuffer.take();
ClientPacketParser.parsePacket(packet);
} catch (InterruptedException e) {
continue;
}
}
} }
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients // TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
@@ -113,11 +99,6 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
} }
} }
@Override
public boolean addToBuffer(StreamPacket streamPacket) {
return packetBuffer.add(streamPacket);
}
/** /**
* A client has tried to connect to the server * A client has tried to connect to the server
* @param serverToClientThread The player that connected * @param serverToClientThread The player that connected
@@ -155,8 +136,16 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
} }
public void startGame() { public void startGame() {
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
for (ServerToClientThread serverToClientThread : serverToClientThreads) { for (ServerToClientThread serverToClientThread : serverToClientThreads) {
serverToClientThread.sendRaceStatusMessage(); serverToClientThread.sendRaceStatusMessage();
} }
} }
}, 0, 500);
}
} }
@@ -1,9 +1,12 @@
package seng302.gameServer; package seng302.gameServer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
@@ -12,6 +15,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
@@ -64,17 +70,42 @@ public class ServerToClientThread implements Runnable, Observer {
public ServerToClientThread(Socket socket) { public ServerToClientThread(Socket socket) {
this.socket = socket; this.socket = socket;
BufferedReader fn;
String fName = "";
BufferedReader ln;
String lName = "";
try { try {
is = socket.getInputStream(); is = socket.getInputStream();
os = socket.getOutputStream(); os = socket.getOutputStream();
fn = new BufferedReader(
new InputStreamReader(
ServerToClientThread.class.getResourceAsStream(
"/server_config/CSV_Database_of_First_Names.csv"
)
)
);
List<String> all = fn.lines().collect(Collectors.toList());
fName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
ln = new BufferedReader(
new InputStreamReader(
ServerToClientThread.class.getResourceAsStream(
"/server_config/CSV_Database_of_Last_Names.csv"
)
)
);
all = ln.lines().collect(Collectors.toList());
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
} catch (IOException e) { } catch (IOException e) {
System.out.println("IO error in server thread upon grabbing streams"); System.out.println("IO error in server thread upon grabbing streams");
e.printStackTrace();
} }
//Attempt threeway handshake with connection //Attempt threeway handshake with connection
sourceId = GameState.getUniquePlayerID(); sourceId = GameState.getUniquePlayerID();
if (threeWayHandshake(sourceId)) { if (threeWayHandshake(sourceId)) {
serverLog("Successful handshake. Client allocated id: " + sourceId, 1); serverLog("Successful handshake. Client allocated id: " + sourceId, 1);
Yacht yacht = new Yacht("Yacht", sourceId, sourceId.toString(), "Kapa", "Kappa", "NZ"); Yacht yacht = new Yacht(
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
// Yacht yacht = new Yacht("Kappa", "Kap", new GeoPoint(57.6708220, 11.8321340), 90.0); // Yacht yacht = new Yacht("Kappa", "Kap", new GeoPoint(57.6708220, 11.8321340), 90.0);
GameState.addYacht(sourceId, yacht); GameState.addYacht(sourceId, yacht);
GameState.addPlayer(new Player(socket, yacht)); GameState.addPlayer(new Player(socket, yacht));
@@ -109,11 +140,6 @@ public class ServerToClientThread implements Runnable, Observer {
while (socket.isConnected()) { while (socket.isConnected()) {
try { try {
// if (initialisedRace) {
// sendSetupMessages();
// initialisedRace = false;
// }
//Perform a write if it is time to as delegated by the MainServerThread //Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) { if (updateClient) {
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream // TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
@@ -165,7 +191,6 @@ public class ServerToClientThread implements Runnable, Observer {
return; return;
} }
} }
} }
private void sendSetupMessages() { private void sendSetupMessages() {
@@ -180,7 +205,8 @@ public class ServerToClientThread implements Runnable, Observer {
xml.setRegatta(new Regatta("RaceVision Test Game", 57.6679590, 11.8503233)); xml.setRegatta(new Regatta("RaceVision Test Game", 57.6679590, 11.8503233));
xml.setRace(race); xml.setRace(race);
XMLMessage xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA, XMLMessage xmlMessage;
xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA,
xml.getRegattaAsXml().length()); xml.getRegattaAsXml().length());
sendMessage(xmlMessage); sendMessage(xmlMessage);
@@ -191,7 +217,6 @@ public class ServerToClientThread implements Runnable, Observer {
xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE, xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE,
xml.getRaceAsXml().length()); xml.getRaceAsXml().length());
sendMessage(xmlMessage); sendMessage(xmlMessage);
// System.out.println("Sent xml messages for " + thread.getName());
} }
public void updateClient() { public void updateClient() {
@@ -310,8 +335,7 @@ public class ServerToClientThread implements Runnable, Observer {
public void sendRaceStatusMessage() { public void sendRaceStatusMessage() {
// variables taken from GameServerThread // variables taken from GameServerThread
int TIME_TILL_RACE_START = 20 * 1000;
long startTime = System.currentTimeMillis() + TIME_TILL_RACE_START;
List<BoatSubMessage> boatSubMessages = new ArrayList<>(); List<BoatSubMessage> boatSubMessages = new ArrayList<>();
BoatStatus boatStatus; BoatStatus boatStatus;
@@ -339,7 +363,7 @@ public class ServerToClientThread implements Runnable, Observer {
raceStatus = RaceStatus.WARNING; raceStatus = RaceStatus.WARNING;
} }
sendMessage(new RaceStatusMessage(1, raceStatus, startTime, GameState.getWindDirection(), sendMessage(new RaceStatusMessage(1, raceStatus, GameState.getStartTime(), GameState.getWindDirection(),
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(), GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
RaceType.MATCH_RACE, 1, boatSubMessages)); RaceType.MATCH_RACE, 1, boatSubMessages));
} }
+1 -2
View File
@@ -4,8 +4,6 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
/** /**
@@ -182,4 +180,5 @@ public final class PolarTable {
return closestAngle; return closestAngle;
} }
} }
+63 -13
View File
@@ -4,8 +4,7 @@ import static seng302.utilities.GeoUtility.getGeoCoordinate;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.HashMap;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import seng302.client.ClientPacketParser; import seng302.client.ClientPacketParser;
import seng302.controllers.RaceViewController; import seng302.controllers.RaceViewController;
@@ -119,19 +118,40 @@ public class Yacht {
* @param timeInterval since last update in milliseconds * @param timeInterval since last update in milliseconds
*/ */
public void update(Long timeInterval) { public void update(Long timeInterval) {
if (sailIn) {
Double secondsElapsed = timeInterval / 1000000.0; Double secondsElapsed = timeInterval / 1000000.0;
Double windSpeedKnots = GameState.getWindSpeedKnots(); Double windSpeedKnots = GameState.getWindSpeedKnots();
Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading); Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading);
Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle); Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle);
velocity = boatSpeedInKnots / ClientPacketParser.MS_TO_KNOTS * 1000; Double maxBoatSpeed = boatSpeedInKnots / ClientPacketParser.MS_TO_KNOTS * 1000;
Double metersCovered = velocity * secondsElapsed; if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) {
location = getGeoCoordinate(location, heading, metersCovered);
if (velocity < maxBoatSpeed) {
velocity += maxBoatSpeed / 15; // Acceleration
}
if (velocity > maxBoatSpeed) {
velocity = maxBoatSpeed; // Prevent the boats from exceeding top speed
}
} else { // Deceleration
if (velocity > 0d) {
if (maxBoatSpeed != 0d) {
velocity -= maxBoatSpeed / 600;
} else { } else {
velocity -= velocity / 100;
}
if (velocity < 0) {
velocity = 0d; velocity = 0d;
} }
} }
}
Double metersCovered = velocity * secondsElapsed;
location = getGeoCoordinate(location, heading, metersCovered);
}
public Double getHeading() { public Double getHeading() {
return heading; return heading;
@@ -145,8 +165,7 @@ public class Yacht {
} }
public void tackGybe(Double windDirection) { public void tackGybe(Double windDirection) {
Double normalizedHeading = heading - GameState.windDirection; Double normalizedHeading = normalizeHeading();
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
adjustHeading(-2 * normalizedHeading); adjustHeading(-2 * normalizedHeading);
} }
@@ -155,8 +174,7 @@ public class Yacht {
} }
public void turnUpwind() { public void turnUpwind() {
Double normalizedHeading = heading - GameState.windDirection; Double normalizedHeading = normalizeHeading();
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
if (normalizedHeading == 0) { if (normalizedHeading == 0) {
if (lastHeading < 180) { if (lastHeading < 180) {
adjustHeading(-TURN_STEP); adjustHeading(-TURN_STEP);
@@ -177,8 +195,7 @@ public class Yacht {
} }
public void turnDownwind() { public void turnDownwind() {
Double normalizedHeading = heading - GameState.windDirection; Double normalizedHeading = normalizeHeading();
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
if (normalizedHeading == 0) { if (normalizedHeading == 0) {
if (lastHeading < 180) { if (lastHeading < 180) {
adjustHeading(TURN_STEP); adjustHeading(TURN_STEP);
@@ -199,10 +216,43 @@ public class Yacht {
} }
public void turnToVMG() { public void turnToVMG() {
// TODO: 25/07/17 wmu16 - Fix this so it grabs the optimal value from the optimal Polar Double normalizedHeading = normalizeHeading();
Double optimalHeading;
HashMap<Double, Double> optimalPolarMap;
if (normalizedHeading >= 90 && normalizedHeading <= 270) { // Downwind
optimalPolarMap = PolarTable.getOptimalDownwindVMG(GameState.getWindSpeedKnots());
optimalHeading = optimalPolarMap.keySet().iterator().next();
} else {
optimalPolarMap = PolarTable.getOptimalUpwindVMG(GameState.getWindSpeedKnots());
optimalHeading = optimalPolarMap.keySet().iterator().next();
}
// Take optimal heading and turn into correct
optimalHeading =
optimalHeading + (double) Math.floorMod(GameState.getWindDirection().longValue(), 360L);
turnTowardsHeading(optimalHeading);
} }
private void turnTowardsHeading(Double newHeading) {
System.out.println(newHeading);
if (heading < 90 && newHeading > 270) {
adjustHeading(-TURN_STEP);
} else {
if (heading < newHeading) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
}
}
}
private Double normalizeHeading() {
Double normalizedHeading = heading - GameState.windDirection;
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360L);
return normalizedHeading;
}
public String getBoatType() { public String getBoatType() {
return boatType; return boatType;
+1 -1
View File
@@ -1,4 +1,4 @@
Tws,Twa0,Bsp0,Twa1,Bsp1,UpTwa,UpBsp,Twa2,Bsp2,Twa3,Bsp3,Twa4,Bsp4,Twa5,Bsp5,Twa6,Bsp6,DnTwa,DnBsp,Twa7,Bsp7 Tws,Twa0,Bsp0,Twa1,Bsp1,UpTwa,UpBsp,Twa2,Bsp2,Twa3,Bsp3,Twa4,Bsp4,Twa5,Bsp5,Twa6,Bsp6,DnTwa,DnBsp,Twa7,Bsp7
4,0,0,30,4,45,8,60,9,75,10,90,10,115,10,145,10,155,10,175,4 4,0,0,30,4,45,8,60,9,75,10,90,10,115,10,145,10,155,10,175,4
8,0,0,30,7,43,10,60,11,75,11,90,11,115,12,145,12,153,12,175,10 8,0,0,30,7,43,10,60,11,75,11,90,11,115,12,145,12,153,12,175,10
12,0,0,30,11,43,14.4,60,16,75,20,90,23,115,24,145,23,153,21.6,175,14 12,0,0,30,11,43,14.4,60,16,75,20,90,23,115,24,145,23,153,21.6,175,14
1 Tws Twa0 Bsp0 Twa1 Bsp1 UpTwa UpBsp Twa2 Bsp2 Twa3 Bsp3 Twa4 Bsp4 Twa5 Bsp5 Twa6 Bsp6 DnTwa DnBsp Twa7 Bsp7
2 4 0 0 30 4 45 8 60 9 75 10 90 10 115 10 145 10 155 10 175 4
3 8 0 0 30 7 43 10 60 11 75 11 90 11 115 12 145 12 153 12 175 10
4 12 0 0 30 11 43 14.4 60 16 75 20 90 23 115 24 145 23 153 21.6 175 14
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+10 -10
View File
@@ -20,31 +20,31 @@
<children> <children>
<AnchorPane prefHeight="960.0" prefWidth="250.0" style="-fx-background-color: #2C2c36;" GridPane.rowSpan="3"> <AnchorPane prefHeight="960.0" prefWidth="250.0" style="-fx-background-color: #2C2c36;" GridPane.rowSpan="3">
<children> <children>
<Label layoutX="11.0" layoutY="259.0" text="Team Position" textFill="WHITE" /> <Label layoutX="11.0" layoutY="283.0" text="Team Position" textFill="WHITE" />
<Label layoutX="13.0" layoutY="432.0" text="Settings" textFill="WHITE" /> <Label layoutX="13.0" layoutY="432.0" text="Settings" textFill="WHITE" />
<Label layoutX="11.0" layoutY="14.0" text="Timer" textFill="WHITE" /> <Label layoutX="11.0" layoutY="41.0" text="Timer" textFill="WHITE" />
<Label layoutX="11.0" layoutY="88.0" text="Wind direction" textFill="WHITE" /> <Label layoutX="11.0" layoutY="112.0" text="Wind direction" textFill="WHITE" />
<Circle fx:id="windBackgroundCircle" blendMode="DARKEN" fill="#3dcdc8" layoutX="110.0" layoutY="166.0" radius="35.0" stroke="#d7d7d7" strokeType="INSIDE" strokeWidth="3.0" /> <Circle fx:id="windBackgroundCircle" blendMode="DARKEN" fill="#3dcdc8" layoutX="110.0" layoutY="190.0" radius="35.0" stroke="#d7d7d7" strokeType="INSIDE" strokeWidth="3.0" />
<Text fx:id="windArrowText" fill="#a8a8a8" layoutX="86.0" layoutY="186.0" strokeType="OUTSIDE" strokeWidth="0.0" text="↓"> <Text fx:id="windArrowText" fill="#a8a8a8" layoutX="86.0" layoutY="210.0" strokeType="OUTSIDE" strokeWidth="0.0" text="↓">
<font> <font>
<Font name="AdobeArabic-Regular" size="55.0" /> <Font name="AdobeArabic-Regular" size="55.0" />
</font> </font>
</Text> </Text>
<Text fx:id="windDirectionText" fill="#d3d3d3" layoutX="171.0" layoutY="214.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0°" textAlignment="RIGHT"> <Text fx:id="windDirectionText" fill="#d3d3d3" layoutX="171.0" layoutY="238.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0°" textAlignment="RIGHT">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
</Text> </Text>
<Text fx:id="windSpeedText" fill="#d3d3d3" layoutX="12.0" layoutY="213.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0 Knot" textAlignment="RIGHT"> <Text fx:id="windSpeedText" fill="#d3d3d3" layoutX="12.0" layoutY="237.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0 Knot" textAlignment="RIGHT">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
</Text> </Text>
<CheckBox fx:id="toggleFps" focusTraversable="false" graphicTextGap="0.0" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" styleClass="ui-checkbox" text="Show FPS" textFill="WHITE" /> <CheckBox fx:id="toggleFps" focusTraversable="false" graphicTextGap="0.0" layoutX="21.0" layoutY="453.0" mnemonicParsing="false" prefHeight="18.0" prefWidth="143.0" selected="true" styleClass="ui-checkbox" text="Show FPS" textFill="WHITE" />
<VBox fx:id="positionVbox" layoutX="12.0" layoutY="280.0" prefHeight="140.0" prefWidth="200.0" styleClass="text-white" /> <VBox fx:id="positionVbox" layoutX="12.0" layoutY="304.0" prefHeight="116.0" prefWidth="200.0" styleClass="text-white" />
<Pane layoutX="11.0" layoutY="30.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0"> <Pane layoutX="11.0" layoutY="39.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="193.0">
<children> <children>
<Text fx:id="timerLabel" fill="#f8f8f8" layoutX="-26.0" layoutY="34.0" strokeType="OUTSIDE" strokeWidth="0.0" text="00:00" textAlignment="CENTER" wrappingWidth="246.0"> <Text fx:id="timerLabel" fill="#f8f8f8" layoutX="-26.0" layoutY="51.0" strokeType="OUTSIDE" strokeWidth="0.0" text="00:00" textAlignment="CENTER" wrappingWidth="246.0">
<font> <font>
<Font size="25.0" /> <Font size="25.0" />
</font> </font>
@@ -24,4 +24,5 @@ public class YachtTest {
yachts.add(new Yacht("Yacht 3", "Y3", new GeoPoint(-35.0, -15.5), 20.0)); yachts.add(new Yacht("Yacht 3", "Y3", new GeoPoint(-35.0, -15.5), 20.0));
} }
} }