Merge branch 'develop' into story61_player_perspective

# Conflicts:
#	src/main/java/seng302/App.java
#	src/main/java/seng302/client/ClientPacketParser.java
#	src/main/java/seng302/client/ClientState.java
#	src/main/java/seng302/client/ClientStateQueryingRunnable.java
#	src/main/java/seng302/controllers/Controller.java
#	src/main/java/seng302/controllers/LobbyController.java
#	src/main/java/seng302/controllers/RaceViewController.java
#	src/main/java/seng302/controllers/StartScreenController.java
#	src/main/java/seng302/fxObjects/BoatAnnotations.java
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/MainServerThread.java
#	src/main/java/seng302/model/Yacht.java
#	src/main/java/seng302/model/stream/StreamReceiver.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/GameView.java
#	src/main/java/seng302/visualiser/fxObjects/BoatObject.java
#	src/test/java/seng302/model/stream/StreamReceiverTest.java
This commit is contained in:
Calum
2017-07-30 18:07:28 +12:00
30 changed files with 1301 additions and 188 deletions
@@ -18,7 +18,8 @@ import seng302.server.messages.BoatActionMessage;
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 {
private static final int LOG_LEVEL = 1;
@@ -34,9 +35,21 @@ public class ClientToServerThread implements Runnable {
private int clientId;
private Boolean updateClient = true;
private ByteArrayOutputStream crcBuffer;
private ByteArrayOutputStream crcBuffer;
public ClientToServerThread(String ipAddress, Integer portNumber) throws IOException{
/**
* 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 IOException {
socket = new Socket(ipAddress, portNumber);
is = socket.getInputStream();
os = socket.getOutputStream();
@@ -55,33 +68,35 @@ public class ClientToServerThread implements Runnable {
thread.start();
}
static void clientLog(String message, int logLevel){
if(logLevel <= LOG_LEVEL){
System.out.println("[CLIENT " + LocalDateTime.now().toLocalTime().toString() + "] " + message);
/**
* 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) {
if (logLevel <= LOG_LEVEL) {
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() {
int sync1;
int sync2;
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
while(true) { /**REMOVED SOMETHING HERE ClientState.isConnectedToHost() */
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();
sync1 = readByte();
sync2 = readByte();
//checking if it is the start of the packet
if(sync1 == 0x47 && sync2 == 0x83) {
if (sync1 == 0x47 && sync2 == 0x83) {
int type = readByte();
//No. of milliseconds since Jan 1st 1970
long timeStamp = Message.bytesToLong(getBytes(6));
@@ -102,7 +117,16 @@ public class ClientToServerThread implements Runnable {
}
} catch (Exception e) {
closeSocket();
e.printStackTrace();
Platform.runLater(new Runnable() {
@Override
public void run() {
Alert alert = new Alert(AlertType.ERROR);
alert.setHeaderText("Host has disconnected");
alert.setContentText("Cannot find Server");
alert.showAndWait();
}
});
clientLog("Disconnected from server", 1);
return;
}
}
@@ -112,7 +136,8 @@ 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
*/
private Integer threeWayHandshake() {
@@ -121,20 +146,22 @@ public class ClientToServerThread implements Runnable {
try {
ourSourceID = is.read();
} catch (IOException e) {
e.printStackTrace();
clientLog("Three way handshake failed", 1);
}
if (ourSourceID != null) {
try {
os.write(ourSourceID);
return ourSourceID;
} catch (IOException e) {
e.printStackTrace();
clientLog("Three way handshake failed", 1);
return null;
}
}
}
}
/**
* Send the post-start race course information
*/
@@ -142,8 +169,7 @@ public class ClientToServerThread implements Runnable {
try {
os.write(boatActionMessage.getBuffer());
} catch (IOException e) {
clientLog("COULD NOT WRITE TO SERVER", 0);
e.printStackTrace();
clientLog("Could not write to server", 1);
}
}
@@ -152,7 +178,7 @@ public class ClientToServerThread implements Runnable {
try {
socket.close();
} catch (IOException e) {
clientLog("Failed to close the socket", 0);
clientLog("Failed to close the socket", 1);
}
}
@@ -170,24 +196,24 @@ public class ClientToServerThread implements Runnable {
currentByte = is.read();
crcBuffer.write(currentByte);
} catch (IOException e) {
e.printStackTrace();
clientLog("Read byte failed", 1);
}
if (currentByte == -1){
if (currentByte == -1) {
throw new Exception();
}
return currentByte;
}
private byte[] getBytes(int n) throws Exception{
private byte[] getBytes(int n) throws Exception {
byte[] bytes = new byte[n];
for (int i = 0; i < n; i++){
for (int i = 0; i < n; i++) {
bytes[i] = (byte) readByte();
}
return bytes;
}
private void skipBytes(long n) throws Exception{
for (int i=0; i < n; i++){
private void skipBytes(long n) throws Exception {
for (int i = 0; i < n; i++) {
readByte();
}
}
@@ -45,11 +45,11 @@ public class GameView extends Pane {
private ObservableList<Node> gameObjects;
private ImageView mapImage;
private int BUFFER_SIZE = 50;
private int panelWidth = 1260; // it should be 1280 but, minors 40 to cancel the bias.
private int panelHeight = 960;
private double canvasWidth = 720;
private double canvasHeight = 720;
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_HEIGHT = 960;
private final int CANVAS_WIDTH = 1100;
private final int CANVAS_HEIGHT = 920;
private boolean horizontalInversion = false;
private double distanceScaleFactor;
@@ -154,8 +154,10 @@ public class GameView extends Pane {
contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
contentPane.getChildren().addAll(
(Pane) FXMLLoader.load(getClass().getResource("/views/FinishScreenView.fxml")));
} catch (javafx.fxml.LoadException e) {
System.out.println("[Controller] FXML load exception");
} catch (IOException e) {
e.printStackTrace();
System.out.println("[Controller] IO exception");
}
}
@@ -78,9 +78,9 @@ public class FinishScreenViewController implements Initializable {
contentPane.getChildren()
.addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl)));
} catch (javafx.fxml.LoadException e) {
e.printStackTrace();
System.out.println("[Controller] FXML load exception");
} catch (IOException e) {
e.printStackTrace();
System.out.println("[Controller] IO exception");
}
}
@@ -135,7 +135,11 @@ public class ImportantAnnotationController implements Initializable {
boatEstTimeToNextMarkSelect.isSelected()));
boatElapsedTimeSelect.setOnAction(
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());
}
}
@@ -6,7 +6,7 @@ import javafx.geometry.Point2D;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
@@ -64,14 +64,31 @@ public class BoatObject extends Group {
* polygon.
*/
public BoatObject(double... points) {
public BoatGroup(Yacht boat, Color color, double... points) {
destinationSet = false;
this.boat = boat;
initChildren(color, points);
}
/**
* Creates the javafx objects that will be the in the group by default.
*
* @param color The colour of the boat polygon and the trailing line.
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat
* polygon.
*/
private void initChildren(Color color, double... points) {
this.color = color;
boatPoly = new Polygon(points);
boatPoly.setFill(colour);
boatPoly.setFill(this.color);
boatPoly.setOnMouseEntered(event -> {
boatPoly.setFill(Color.FLORALWHITE);
boatPoly.setStroke(Color.RED);
});
boatPoly.setOnMouseExited(event -> {
boatPoly.setFill(colour);
boatPoly.setFill(this.color);
boatPoly.setStroke(Color.BLACK);
});
boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected));
@@ -80,6 +97,7 @@ public class BoatObject extends Group {
annotationBox = new AnnotationBox();
annotationBox.setFill(colour);
boatAnnotations = new BoatAnnotations(boat, this.color);
leftLayLine = new Line();
rightLayline = new Line();
@@ -178,25 +196,44 @@ public class BoatObject extends Group {
*/
public void setDestination(double newXValue, double newYValue, double rotation,
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;
Double dx = Math.abs(boatPoly.getLayoutX() - newXValue);
Double dy = Math.abs(boatPoly.getLayoutY() - newYValue);
moveTo(newXValue, newYValue, rotation);
rotateTo(rotation);
wake.setRotation(rotation, groundSpeed);
// yacht.setVelocity(groundSpeed);
lastTimeValid = timeValid;
boat.setVelocity(groundSpeed);
isStopped = false;
lastRotation = rotation;
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());
}
}
}
@@ -243,6 +280,8 @@ public class BoatObject 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.setVisible(teamName, velocity, estTime, legTime);
this.wake.setVisible(wake);
this.lineGroup.setVisible(trail);
}
@@ -297,4 +336,23 @@ public class BoatObject extends Group {
return isStopped;
}
@Override
public String 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;
}
}
@@ -54,29 +54,29 @@ public class Wake extends Group {
}
void setRotation (double rotation, double velocity) {
if (Math.abs(rotations[0] - rotation) > 20) {
// if (Math.abs(rotations[0] - rotation) > 20) {
rotate(rotation);
} else {
rotations[0] = rotation;
((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
for (int i = 1; i < numWakes; i++) {
double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
double shortestDistance = Math.atan2(
Math.sin(wakeSeparationRad),
Math.cos(wakeSeparationRad)
);
double distDeg = Math.toDegrees(shortestDistance);
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);
} else {
if (distDeg < (MAX_DIFF / numWakes)) {
rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
} else
rotationalVelocities[i] = rotationalVelocities[i - 1];
}
}
}
// } else {
// rotations[0] = rotation;
// ((Rotate) arcs[0].getTransforms().get(0)).setAngle(rotation);
// for (int i = 1; i < numWakes; i++) {
// double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]);
// double shortestDistance = Math.atan2(
// Math.sin(wakeSeparationRad),
// Math.cos(wakeSeparationRad)
// );
// double distDeg = Math.toDegrees(shortestDistance);
// 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);
//
// } else {
// if (distDeg < (MAX_DIFF / numWakes)) {
// rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes);
// } else
// rotationalVelocities[i] = rotationalVelocities[i - 1];
// }
// }
// }
double rad = (14 / numWakes) + velocity;
for (Arc arc : arcs) {