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;
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));
} }
} }