mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -59,6 +59,7 @@ public class ClientPacketParser {
|
||||
*/
|
||||
public ClientPacketParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks at the type of the packet then sends it to the appropriate parser to extract the
|
||||
* specific data associated with that packet type
|
||||
@@ -108,7 +109,7 @@ public class ClientPacketParser {
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
System.out.println("Error parsing packet");
|
||||
e.printStackTrace();
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +186,6 @@ public class ClientPacketParser {
|
||||
|
||||
int noBoats = payload[22];
|
||||
int raceType = payload[23];
|
||||
clientStateBoats = ClientState.getBoats();
|
||||
for (int i = 0; i < noBoats; i++) {
|
||||
long boatStatusSourceID = bytesToLong(
|
||||
Arrays.copyOfRange(payload, 24 + (i * 20), 28 + (i * 20)));
|
||||
@@ -206,7 +206,9 @@ public class ClientPacketParser {
|
||||
boat.setEstimateTimeAtNextMark(estTimeAtNextMark);
|
||||
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));
|
||||
setBoatLegPosition(clientBoat, boatLegNumber);
|
||||
clientBoat.setPenaltiesAwarded(boatPenaltyAwarded);
|
||||
@@ -215,9 +217,12 @@ public class ClientPacketParser {
|
||||
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) {
|
||||
ClientState.setRaceStarted(true);
|
||||
} else {
|
||||
ClientState.setRaceStarted(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +294,10 @@ public class ClientPacketParser {
|
||||
xmlObject.constructXML(doc, messageType);
|
||||
if (messageType == 7) { //7 is the boat XML
|
||||
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.setDirtyState(true);
|
||||
ClientState.setBoatsUpdated(true);
|
||||
}
|
||||
if (messageType == 6) { //6 is race info xml
|
||||
newRaceXmlReceived = true;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
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.concurrent.ConcurrentHashMap;
|
||||
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 {
|
||||
|
||||
@@ -17,7 +15,7 @@ public class ClientState {
|
||||
private static Boolean raceStarted = false;
|
||||
private static Boolean connectedToHost = false;
|
||||
private static Map<Integer, Yacht> boats = new ConcurrentHashMap<>();
|
||||
private static Boolean dirtyState = true;
|
||||
private static Boolean boatsUpdated = true;
|
||||
private static String clientSourceId = "";
|
||||
|
||||
public static String getHostIp() {
|
||||
@@ -56,12 +54,12 @@ public class ClientState {
|
||||
return boats;
|
||||
}
|
||||
|
||||
public static Boolean isDirtyState() {
|
||||
return dirtyState;
|
||||
public static Boolean isBoatsUpdated() {
|
||||
return boatsUpdated;
|
||||
}
|
||||
|
||||
public static void setDirtyState(Boolean dirtyState) {
|
||||
ClientState.dirtyState = dirtyState;
|
||||
public static void setBoatsUpdated(Boolean boatsUpdated) {
|
||||
ClientState.boatsUpdated = boatsUpdated;
|
||||
}
|
||||
|
||||
public static String getClientSourceId() {
|
||||
|
||||
@@ -12,6 +12,12 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable
|
||||
|
||||
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
|
||||
public void run() {
|
||||
while(!terminate) {
|
||||
@@ -29,14 +35,19 @@ public class ClientStateQueryingRunnable extends Observable implements Runnable
|
||||
terminate();
|
||||
}
|
||||
|
||||
if (ClientState.isDirtyState()) {
|
||||
if (ClientState.isBoatsUpdated()) {
|
||||
setChanged();
|
||||
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() {
|
||||
terminate = true;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,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 {
|
||||
|
||||
@@ -30,8 +31,19 @@ public class ClientToServerThread implements Runnable {
|
||||
private OutputStream os;
|
||||
|
||||
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{
|
||||
socket = new Socket(ipAddress, portNumber);
|
||||
is = socket.getInputStream();
|
||||
@@ -40,7 +52,7 @@ public class ClientToServerThread implements Runnable {
|
||||
Integer allocatedID = threeWayHandshake();
|
||||
if (allocatedID != null) {
|
||||
ourID = allocatedID;
|
||||
clientLog("Successful handshake. Allocated ID: " + ourID, 1);
|
||||
clientLog("Successful handshake. Allocated ID: " + ourID, 0);
|
||||
ClientState.setClientSourceId(String.valueOf(ourID));
|
||||
} else {
|
||||
clientLog("Unsuccessful handshake", 1);
|
||||
@@ -50,31 +62,31 @@ public class ClientToServerThread implements Runnable {
|
||||
|
||||
thread = new Thread(this);
|
||||
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){
|
||||
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(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();
|
||||
@@ -93,7 +105,6 @@ public class ClientToServerThread implements Runnable {
|
||||
if (computedCrc == packetCrc) {
|
||||
ClientPacketParser
|
||||
.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 {
|
||||
clientLog("Packet has been dropped", 1);
|
||||
@@ -101,8 +112,7 @@ public class ClientToServerThread implements Runnable {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
closeSocket();
|
||||
System.err.println("SERVER DISCONNECTED");
|
||||
// e.printStackTrace();
|
||||
clientLog("Disconnected from server", 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +122,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
|
||||
*/
|
||||
private Integer threeWayHandshake() {
|
||||
@@ -121,14 +131,15 @@ 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;
|
||||
}
|
||||
}
|
||||
@@ -144,8 +155,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +164,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +175,7 @@ public class ClientToServerThread implements Runnable {
|
||||
currentByte = is.read();
|
||||
crcBuffer.write(currentByte);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
clientLog("Read byte failed", 1);
|
||||
}
|
||||
if (currentByte == -1){
|
||||
throw new Exception();
|
||||
|
||||
@@ -75,7 +75,7 @@ public class CanvasController {
|
||||
|
||||
private List<MarkGroup> markGroups = new ArrayList<>();
|
||||
private List<BoatGroup> boatGroups = new ArrayList<>();
|
||||
private Text FPSdisplay = new Text();
|
||||
private Text FPSDisplay = new Text();
|
||||
private Polygon raceBorder = new Polygon();
|
||||
|
||||
//FRAME RATE
|
||||
@@ -120,10 +120,10 @@ public class CanvasController {
|
||||
gc.setGlobalAlpha(0.5);
|
||||
fitMarksToCanvas();
|
||||
drawGoogleMap();
|
||||
FPSdisplay.setLayoutX(5);
|
||||
FPSdisplay.setLayoutY(20);
|
||||
FPSdisplay.setStrokeWidth(2);
|
||||
group.getChildren().add(FPSdisplay);
|
||||
FPSDisplay.setLayoutX(5);
|
||||
FPSDisplay.setLayoutY(20);
|
||||
FPSDisplay.setStrokeWidth(2);
|
||||
group.getChildren().add(FPSDisplay);
|
||||
group.getChildren().add(raceBorder);
|
||||
initializeMarks();
|
||||
initializeBoats();
|
||||
@@ -404,10 +404,10 @@ public class CanvasController {
|
||||
|
||||
private void drawFps(int fps){
|
||||
if (raceViewController.isDisplayFps()){
|
||||
FPSdisplay.setVisible(true);
|
||||
FPSdisplay.setText(String.format("%d FPS", fps));
|
||||
FPSDisplay.setVisible(true);
|
||||
FPSDisplay.setText(String.format("%d FPS", fps));
|
||||
} else {
|
||||
FPSdisplay.setVisible(false);
|
||||
FPSDisplay.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ public class LobbyController implements Initializable, Observer{
|
||||
readyButton.setDisable(true);
|
||||
}
|
||||
|
||||
// put all javafx objects in lists, so we can iterate though conveniently
|
||||
imageViews = new ArrayList<>();
|
||||
Collections.addAll(imageViews, firstImageView, secondImageView, thirdImageView, fourthImageView,
|
||||
fifthImageView, sixthImageView, seventhImageView, eighthImageView);
|
||||
@@ -134,6 +135,13 @@ public class LobbyController implements Initializable, Observer{
|
||||
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
|
||||
public void update(Observable o, Object arg) {
|
||||
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() {
|
||||
listViews.forEach(listView -> listView.getItems().clear());
|
||||
imageViews.forEach(gif -> gif.setVisible(false));
|
||||
@@ -162,6 +173,9 @@ public class LobbyController implements Initializable, Observer{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads preset images into imageViews
|
||||
*/
|
||||
private void initialiseImageView() {
|
||||
for (int i = 0; i < MAX_NUM_PLAYERS; i++) {
|
||||
imageViews.get(i).setImage(new Image(getClass().getResourceAsStream("/pics/sail.png")));
|
||||
@@ -195,14 +209,11 @@ public class LobbyController implements Initializable, Observer{
|
||||
|
||||
@FXML
|
||||
public void readyButtonPressed() {
|
||||
// setContentPane("/views/RaceView.fxml");
|
||||
GameState.setCurrentStage(GameStages.RACING);
|
||||
mainServerThread.startGame();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void switchToRaceView() {
|
||||
if (!switchedPane) {
|
||||
switchedPane = true;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
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.models.Player;
|
||||
|
||||
import seng302.models.Yacht;
|
||||
import seng302.server.messages.BoatActionType;
|
||||
|
||||
@@ -30,7 +31,7 @@ public class GameState implements Runnable {
|
||||
|
||||
|
||||
public GameState(String hostIpAddress) {
|
||||
windDirection = 170d;
|
||||
windDirection = 180d;
|
||||
windSpeed = 10000d;
|
||||
yachts = new HashMap<>();
|
||||
players = new ArrayList<>();
|
||||
@@ -116,7 +117,6 @@ public class GameState implements Runnable {
|
||||
case VMG:
|
||||
playerYacht.turnToVMG();
|
||||
// System.out.println("Snapping to VMG");
|
||||
// TODO: 22/07/17 wmu16 - Add in the vmg calculation code here
|
||||
break;
|
||||
case SAILS_IN:
|
||||
playerYacht.toggleSailIn();
|
||||
|
||||
@@ -4,8 +4,6 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -182,4 +180,5 @@ public final class PolarTable {
|
||||
return closestAngle;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import static seng302.utilities.GeoUtility.getGeoCoordinate;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import javafx.scene.paint.Color;
|
||||
import seng302.client.ClientPacketParser;
|
||||
import seng302.controllers.RaceViewController;
|
||||
@@ -136,9 +137,9 @@ public class Yacht {
|
||||
|
||||
if (velocity > 0d) {
|
||||
if (maxBoatSpeed != 0d) {
|
||||
velocity -= maxBoatSpeed / 25;
|
||||
velocity -= maxBoatSpeed / 600;
|
||||
} else {
|
||||
velocity -= velocity / 25;
|
||||
velocity -= velocity / 100;
|
||||
}
|
||||
if (velocity < 0) {
|
||||
velocity = 0d;
|
||||
@@ -164,8 +165,7 @@ public class Yacht {
|
||||
}
|
||||
|
||||
public void tackGybe(Double windDirection) {
|
||||
Double normalizedHeading = heading - GameState.windDirection;
|
||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
adjustHeading(-2 * normalizedHeading);
|
||||
}
|
||||
|
||||
@@ -174,8 +174,7 @@ public class Yacht {
|
||||
}
|
||||
|
||||
public void turnUpwind() {
|
||||
Double normalizedHeading = heading - GameState.windDirection;
|
||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
if (normalizedHeading == 0) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(-TURN_STEP);
|
||||
@@ -196,8 +195,7 @@ public class Yacht {
|
||||
}
|
||||
|
||||
public void turnDownwind() {
|
||||
Double normalizedHeading = heading - GameState.windDirection;
|
||||
normalizedHeading = (double) Math.floorMod(normalizedHeading.longValue(), 360);
|
||||
Double normalizedHeading = normalizeHeading();
|
||||
if (normalizedHeading == 0) {
|
||||
if (lastHeading < 180) {
|
||||
adjustHeading(TURN_STEP);
|
||||
@@ -218,10 +216,43 @@ public class Yacht {
|
||||
}
|
||||
|
||||
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() {
|
||||
return boatType;
|
||||
|
||||
Reference in New Issue
Block a user