From 913e5fee7b6c07fd7ade8da1d19c1b29660574c8 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Fri, 21 Jul 2017 16:50:09 +1200 Subject: [PATCH 1/4] Hooked up key press actions to the GameState, applying the relevant maths to update headings etc. tags: #story[989] #pair[ptg19, wmu16] --- .../java/seng302/gameServer/GameState.java | 16 +- src/main/java/seng302/models/Yacht.java | 222 ++++-------------- 2 files changed, 60 insertions(+), 178 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 20aaaf4f..f6ff2bb7 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -15,9 +15,11 @@ import seng302.server.messages.BoatActionType; */ public class GameState { + private static final Integer HEADING_STEP = 3; + private static Long previousUpdateTime; - private static Double windDirection = 0d; - private static Double windSpeed = 0d; + public static Double windDirection; + private static Double windSpeed; private static String hostIpAddress; private static List players; @@ -26,6 +28,10 @@ public class GameState { private static GameStages currentStage; public GameState(String hostIpAddress) { + windDirection = 170d; + windSpeed = 0d; + + GameState.hostIpAddress = hostIpAddress; players = new ArrayList<>(); currentStage = GameStages.LOBBYING; @@ -75,18 +81,24 @@ public class GameState { } public static void updateBoat(Integer sourceId, BoatActionType actionType) { + Yacht playerYacht = yachts.get(sourceId); switch (actionType) { case VMG: break; case SAILS_IN: + playerYacht.toggleSailIn(); break; case SAILS_OUT: + playerYacht.toggleSailIn(); break; case TACK_GYBE: + playerYacht.tackGybe(windDirection); break; case UPWIND: + playerYacht.turnUpwind(); break; case DOWNWIND: + playerYacht.turnDownwind(); break; } } diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 7e45549d..02bae325 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -7,6 +7,7 @@ import java.text.SimpleDateFormat; import java.util.Map; import javafx.scene.paint.Color; import seng302.controllers.RaceViewController; +import seng302.gameServer.GameState; import seng302.models.mark.Mark; import seng302.utilities.GeoPoint; @@ -18,82 +19,37 @@ import seng302.utilities.GeoPoint; */ public class Yacht { - // Used in boat group - private Color colour; + private final Double TURN_STEP = 3.0; - private String boatType; private Integer sourceID; - private String hullID; //matches HullNum in the XML spec. - private String shortName; - private String boatName; - private String country; - - // Situational data - - - // Boat status - private Integer boatStatus; - private Integer legNumber; - private Integer penaltiesAwarded; - private Integer penaltiesServed; - private Long estimateTimeAtFinish; - private String position; private GeoPoint location; private Double heading; + private Double lastHeading; private Double velocity; - private Long timeTillNext; - private Long markRoundTime; - // Mark rounding - private Mark lastMarkRounded; - private Mark nextMark; + private Boolean sailIn; /** - * Used in EventTest and RaceTest. - * - * @param boatName Create a yacht object with name. + * @param location latlon location of the boat stored in a geopoint + * @param heading heading of the boat in degrees from 0 to 365 with 0 being north */ - public Yacht(String boatName, String shortName, GeoPoint location, Double heading) { - this.boatName = boatName; - this.shortName = shortName; + public Yacht(GeoPoint location, Double heading) { this.location = location; this.heading = heading; this.velocity = 0.0; - } - - /** - * Used in BoatGroupTest. - * - * @param boatName The name of the team sailing the boat - * @param boatVelocity The speed of the boat in meters/second - * @param shortName A shorter version of the teams name - */ - public Yacht(String boatName, double boatVelocity, String shortName, int id) { - this.boatName = boatName; - this.velocity = boatVelocity; - this.shortName = shortName; - this.sourceID = id; - } - - public Yacht(String boatType, Integer sourceID, String hullID, String shortName, - String boatName, String country) { - this.boatType = boatType; - this.sourceID = sourceID; - this.hullID = hullID; - this.shortName = shortName; - this.boatName = boatName; - this.country = country; - this.position = "-"; + this.sailIn = false; } /** * @param timeInterval since last update in milliseconds */ public void update(Long timeInterval) { - Double secondsElapsed = timeInterval / 1000000.0; - Double metersCovered = velocity * secondsElapsed; - location = getGeoCoordinate(location, heading, metersCovered); + if (sailIn) { + Double secondsElapsed = timeInterval / 1000000.0; + Double metersCovered = velocity * secondsElapsed; + location = getGeoCoordinate(location, heading, metersCovered); + } } /** @@ -121,135 +77,49 @@ public class Yacht { velocity = polarsFromClosestSpd.get(closest_key); } - - public String getBoatType() { - return boatType; + public Double getHeading() { + return heading; } - public Integer getSourceID() { - return sourceID; + public void adjustHeading(Double amount) { + lastHeading = heading; + heading = (heading + amount) % 360.0; } - public String getHullID() { - return hullID; + public void tackGybe(Double windDirection) { + adjustHeading(-2 * ((heading - windDirection) % 360)); } - public String getShortName() { - return shortName; + public void toggleSailIn() { + sailIn = !sailIn; } - public String getBoatName() { - return boatName; - } - - public String getCountry() { - return country; - } - - public Integer getBoatStatus() { - return boatStatus; - } - - public void setBoatStatus(Integer boatStatus) { - this.boatStatus = boatStatus; - } - - public Integer getLegNumber() { - return legNumber; - } - - public void setLegNumber(Integer legNumber) { - if (colour != null && position != "-" && legNumber != this.legNumber&& RaceViewController.sparkLineStatus(sourceID)) { - RaceViewController.updateYachtPositionSparkline(this, legNumber); + public void turnUpwind() { + Double normalizedHeading = (heading - GameState.windDirection) % 360; + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } + } else if (normalizedHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); } - this.legNumber = legNumber; } - public Integer getPenaltiesAwarded() { - return penaltiesAwarded; + public void turnDownwind() { + if ((heading - GameState.windDirection) % 360 < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } } - - public void setPenaltiesAwarded(Integer penaltiesAwarded) { - this.penaltiesAwarded = penaltiesAwarded; - } - - public Integer getPenaltiesServed() { - return penaltiesServed; - } - - public void setPenaltiesServed(Integer penaltiesServed) { - this.penaltiesServed = penaltiesServed; - } - - public void setEstimateTimeAtNextMark(Long estimateTimeAtNextMark) { - timeTillNext = estimateTimeAtNextMark; - } - - public String getEstimateTimeAtFinish() { - DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); - return format.format(estimateTimeAtFinish); - } - - public void setEstimateTimeAtFinish(Long estimateTimeAtFinish) { - this.estimateTimeAtFinish = estimateTimeAtFinish; - } - - public String getPosition() { - return position; - } - - public void setPosition(String position) { - this.position = position; - } - - public Color getColour() { - return colour; - } - - public void setColour(Color colour) { - this.colour = colour; - } - - public void setVelocity(double velocity) { - this.velocity = velocity; - } - - - public void setMarkRoundingTime(Long markRoundingTime) { - this.markRoundTime = markRoundingTime; - } - - public double getVelocity() { - return velocity; - } - - public Long getTimeTillNext() { - return timeTillNext; - } - - public Long getMarkRoundTime() { - return markRoundTime; - } - - public Mark getLastMarkRounded() { - return lastMarkRounded; - } - - public void setLastMarkRounded(Mark lastMarkRounded) { - this.lastMarkRounded = lastMarkRounded; - } - - public void setNextMark(Mark nextMark) { - this.nextMark = nextMark; - } - - public Mark getNextMark(){ - return nextMark; - } - - @Override - public String toString() { - return boatName; - } - } From a0005064ac5ab6b78ca5b66addd4b83c8bdfe46e Mon Sep 17 00:00:00 2001 From: William Muir Date: Sat, 22 Jul 2017 16:32:05 +1200 Subject: [PATCH 2/4] Fixed the Yacht clas so it now works. Lists and Maps are instantiated as they should be in GameState which were creating NullPointers Introduced ServerLog to server to client threads for bug reporting Introduced some print statements to test the game state updating upon receiving key presses tags: #story[989] #refactor #fix --- .../seng302/client/ClientToServerThread.java | 6 +- .../java/seng302/gameServer/GameState.java | 27 ++- .../gameServer/ServerToClientThread.java | 11 +- src/main/java/seng302/models/Yacht.java | 207 +++++++++++++++++- 4 files changed, 237 insertions(+), 14 deletions(-) diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index a2f23419..bdf0710b 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -19,7 +19,6 @@ public class ClientToServerThread extends Thread { private Socket socket; private InputStream is; private OutputStream os; - private final int PORT_NUMBER = 0; private static final int LOG_LEVEL = 1; private Boolean updateClient = true; @@ -36,9 +35,9 @@ public class ClientToServerThread extends Thread { } - static void serverLog(String message, int logLevel){ + static void clientLog(String message, int logLevel){ if(logLevel <= LOG_LEVEL){ - System.out.println("[SERVER] " + message); + System.out.println("[CLIENT] " + message); } } @@ -98,6 +97,7 @@ public class ClientToServerThread extends Thread { try { os.write(boatActionMessage.getBuffer()); } catch (IOException e) { + clientLog("COULD NOT WRITE TO SERVER", 0); e.printStackTrace(); } } diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index f6ff2bb7..879fc8e9 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,11 +1,9 @@ package seng302.gameServer; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; + import seng302.models.Player; -import java.util.ArrayList; import seng302.models.Yacht; import seng302.server.messages.BoatActionType; @@ -15,8 +13,6 @@ import seng302.server.messages.BoatActionType; */ public class GameState { - private static final Integer HEADING_STEP = 3; - private static Long previousUpdateTime; public static Double windDirection; private static Double windSpeed; @@ -30,6 +26,8 @@ public class GameState { public GameState(String hostIpAddress) { windDirection = 170d; windSpeed = 0d; + yachts = new HashMap<>(); + players = new ArrayList<>(); GameState.hostIpAddress = hostIpAddress; @@ -56,8 +54,8 @@ public class GameState { players.remove(player); } - public static void addYacht(Integer sourceId, Yacht yatch) { - yachts.put(sourceId, yatch); + public static void addYacht(Integer sourceId, Yacht yacht) { + yachts.put(sourceId, yacht); } public static Boolean getIsRaceStarted() { @@ -82,25 +80,38 @@ public class GameState { public static void updateBoat(Integer sourceId, BoatActionType actionType) { Yacht playerYacht = yachts.get(sourceId); + System.out.println("-----------------------"); switch (actionType) { case VMG: + System.out.println("Snapping to VMG"); + // TODO: 22/07/17 wmu16 - Add in the vmg calculation code here break; case SAILS_IN: playerYacht.toggleSailIn(); + System.out.println("Toggling Sails"); break; case SAILS_OUT: playerYacht.toggleSailIn(); + System.out.println("Toggling Sails"); break; case TACK_GYBE: playerYacht.tackGybe(windDirection); + System.out.println("Tack/Gybe"); break; case UPWIND: playerYacht.turnUpwind(); + System.out.println("Moving upwind"); break; case DOWNWIND: playerYacht.turnDownwind(); + System.out.println("Moving downwind"); break; } + + System.out.println("-----------------------"); + System.out.println("Heading: " + playerYacht.getHeading()); + System.out.println("Sails are in: " + playerYacht.getSailIn()); + System.out.println("-----------------------\n"); } public static void update() { diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 9a7d8786..69851682 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -2,7 +2,6 @@ package seng302.gameServer; import java.util.Random; -import seng302.client.ClientPacketParser; import seng302.models.Player; import seng302.models.Yacht; import seng302.models.stream.packets.PacketType; @@ -22,6 +21,8 @@ import seng302.utilities.GeoPoint; * Created by wmu16 on 13/07/17. */ public class ServerToClientThread extends Thread { + + private static final Integer LOG_LEVEL = 1; private static final Integer MAX_ID_ATTEMPTS = 10; private InputStream is; @@ -51,6 +52,13 @@ public class ServerToClientThread extends Thread { GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); } + + static void serverLog(String message, int logLevel){ + if(logLevel <= LOG_LEVEL){ + System.out.println("[SERVER] " + message); + } + } + public void run() { int sync1; int sync2; @@ -100,6 +108,7 @@ public class ServerToClientThread extends Thread { } } } catch (Exception e) { + serverLog("ERROR OCCURED, CLOSING SERVER CONNETION: " + socket.getRemoteSocketAddress().toString(), 1); closeSocket(); return; } diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 02bae325..fb8a86b0 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -21,13 +21,39 @@ public class Yacht { private final Double TURN_STEP = 3.0; + private Double lastHeading; + private Boolean sailIn; + + + // Used in boat group + private Color colour; + + private String boatType; private Integer sourceID; + private String hullID; //matches HullNum in the XML spec. + private String shortName; + private String boatName; + private String country; + + // Situational data + + + // Boat status + private Integer boatStatus; + private Integer legNumber; + private Integer penaltiesAwarded; + private Integer penaltiesServed; + private Long estimateTimeAtFinish; + private String position; private GeoPoint location; private Double heading; - private Double lastHeading; private Double velocity; + private Long timeTillNext; + private Long markRoundTime; - private Boolean sailIn; + // Mark rounding + private Mark lastMarkRounded; + private Mark nextMark; /** @@ -41,6 +67,48 @@ public class Yacht { this.sailIn = false; } + + /** + * Used in EventTest and RaceTest. + * + * @param boatName Create a yacht object with name. + */ + public Yacht(String boatName, String shortName, GeoPoint location, Double heading) { + this.boatName = boatName; + this.shortName = shortName; + this.location = location; + this.heading = heading; + this.velocity = 0.0; + this.sailIn = false; + } + + /** + * Used in BoatGroupTest. + * + * @param boatName The name of the team sailing the boat + * @param boatVelocity The speed of the boat in meters/second + * @param shortName A shorter version of the teams name + */ + public Yacht(String boatName, double boatVelocity, String shortName, int id) { + this.boatName = boatName; + this.velocity = boatVelocity; + this.shortName = shortName; + this.sourceID = id; + this.sailIn = false; + } + + public Yacht(String boatType, Integer sourceID, String hullID, String shortName, + String boatName, String country) { + this.boatType = boatType; + this.sourceID = sourceID; + this.hullID = hullID; + this.shortName = shortName; + this.boatName = boatName; + this.country = country; + this.position = "-"; + this.sailIn = false; + } + /** * @param timeInterval since last update in milliseconds */ @@ -122,4 +190,139 @@ public class Yacht { adjustHeading(-TURN_STEP); } } + + + public String getBoatType() { + return boatType; + } + + public Integer getSourceID() { + return sourceID; + } + + public String getHullID() { + return hullID; + } + + public String getShortName() { + return shortName; + } + + public String getBoatName() { + return boatName; + } + + public String getCountry() { + return country; + } + + public Integer getBoatStatus() { + return boatStatus; + } + + public void setBoatStatus(Integer boatStatus) { + this.boatStatus = boatStatus; + } + + public Integer getLegNumber() { + return legNumber; + } + + public void setLegNumber(Integer legNumber) { + if (colour != null && position != "-" && legNumber != this.legNumber&& RaceViewController.sparkLineStatus(sourceID)) { + RaceViewController.updateYachtPositionSparkline(this, legNumber); + } + this.legNumber = legNumber; + } + + public Integer getPenaltiesAwarded() { + return penaltiesAwarded; + } + + public void setPenaltiesAwarded(Integer penaltiesAwarded) { + this.penaltiesAwarded = penaltiesAwarded; + } + + public Integer getPenaltiesServed() { + return penaltiesServed; + } + + public void setPenaltiesServed(Integer penaltiesServed) { + this.penaltiesServed = penaltiesServed; + } + + public void setEstimateTimeAtNextMark(Long estimateTimeAtNextMark) { + timeTillNext = estimateTimeAtNextMark; + } + + public String getEstimateTimeAtFinish() { + DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); + return format.format(estimateTimeAtFinish); + } + + public void setEstimateTimeAtFinish(Long estimateTimeAtFinish) { + this.estimateTimeAtFinish = estimateTimeAtFinish; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public Color getColour() { + return colour; + } + + public void setColour(Color colour) { + this.colour = colour; + } + + public void setVelocity(double velocity) { + this.velocity = velocity; + } + + + public void setMarkRoundingTime(Long markRoundingTime) { + this.markRoundTime = markRoundingTime; + } + + public double getVelocity() { + return velocity; + } + + public Long getTimeTillNext() { + return timeTillNext; + } + + public Long getMarkRoundTime() { + return markRoundTime; + } + + public Mark getLastMarkRounded() { + return lastMarkRounded; + } + + public void setLastMarkRounded(Mark lastMarkRounded) { + this.lastMarkRounded = lastMarkRounded; + } + + public void setNextMark(Mark nextMark) { + this.nextMark = nextMark; + } + + public Mark getNextMark(){ + return nextMark; + } + + public Boolean getSailIn() { + return sailIn; + } + + @Override + public String toString() { + return boatName; + } } From 3ec930491fcf69d191767fbd8eebf5245f1b73c8 Mon Sep 17 00:00:00 2001 From: William Muir Date: Sat, 22 Jul 2017 16:45:24 +1200 Subject: [PATCH 3/4] Minor refactor, threads now start themselves tags: #story[989] #refactor --- .../java/seng302/client/ClientToServerThread.java | 14 ++++++++++++-- .../seng302/controllers/StartScreenController.java | 5 ++--- .../java/seng302/gameServer/MainServerThread.java | 11 ++++++++--- .../seng302/gameServer/ServerListenThread.java | 1 - .../seng302/gameServer/ServerToClientThread.java | 12 +++++++++++- 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index bdf0710b..79d2de3f 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -15,7 +15,10 @@ import seng302.server.messages.Message; /** * Created by kre39 on 13/07/17. */ -public class ClientToServerThread extends Thread { +public class ClientToServerThread implements Runnable { + + private Thread thread; + private Socket socket; private InputStream is; private OutputStream os; @@ -33,6 +36,9 @@ public class ClientToServerThread extends Thread { e.printStackTrace(); } + thread = new Thread(this); + thread.start(); + } static void clientLog(String message, int logLevel){ @@ -139,4 +145,8 @@ public class ClientToServerThread extends Thread { readByte(); } } - } + + public Thread getThread() { + return thread; + } +} diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index eb5990f0..42a282e7 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -62,10 +62,9 @@ public class StartScreenController { try { String ipAddress = InetAddress.getLocalHost().getHostAddress(); new GameState(ipAddress); - new MainServerThread().start(); + new MainServerThread(); // get the lobby controller so that we can pass the game server thread to it setContentPane("/views/LobbyView.fxml"); - } catch (UnknownHostException e) { System.err.println("COULD NOT FIND YOUR IP ADDRESS!"); e.printStackTrace(); @@ -79,9 +78,9 @@ public class StartScreenController { // TODO: 10/07/17 wmu16 - Finish function String ipAddress = ipTextField.getText().trim().toLowerCase(); try { + // TODO: 22/07/17 wmu 16 - make this port number some static constant somewhere perhaps a config file? ClientToServerThread clientToServerThread = new ClientToServerThread(ipAddress, 4950); controller.setClientToServerThread(clientToServerThread); - clientToServerThread.start(); setContentPane("/views/LobbyView.fxml"); } catch (Exception e){ e.printStackTrace(); diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index b28dce91..aae020da 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -15,12 +15,14 @@ import java.util.concurrent.PriorityBlockingQueue; * A class describing the overall server, which creates and collects server threads for each client * Created by wmu16 on 13/07/17. */ -public class MainServerThread extends Thread implements PacketBufferDelegate, ClientConnectionDelegate{ +public class MainServerThread implements Runnable, PacketBufferDelegate, ClientConnectionDelegate{ private static final int PORT = 4950; private static final Integer MAX_NUM_PLAYERS = 3; private static final int LOG_LEVEL = 1; + private Thread thread; + private ServerSocket serverSocket = null; private Socket socket; private ArrayList serverToClientThreads = new ArrayList<>(); @@ -36,6 +38,9 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl } packetBuffer = new PriorityBlockingQueue<>(); + + thread = new Thread(this); + thread.start(); } @@ -50,7 +55,7 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl serverListenThread.start(); //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app. - while (!isInterrupted()) { + while (!thread.isInterrupted()) { try { Thread.sleep(1000 / 60); //60 times per second we should calculate the game state } catch (InterruptedException e) { @@ -122,7 +127,7 @@ public class MainServerThread extends Thread implements PacketBufferDelegate, Cl */ @Override public void clientConnected(ServerToClientThread serverToClientThread) { - serverLog("Player Connected From " + serverToClientThread.getName(), 0); + serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0); serverToClientThreads.add(serverToClientThread); } diff --git a/src/main/java/seng302/gameServer/ServerListenThread.java b/src/main/java/seng302/gameServer/ServerListenThread.java index b734ab8c..f36d08df 100644 --- a/src/main/java/seng302/gameServer/ServerListenThread.java +++ b/src/main/java/seng302/gameServer/ServerListenThread.java @@ -29,7 +29,6 @@ public class ServerListenThread extends Thread{ Socket thisClient = serverSocket.accept(); if (thisClient != null){ ServerToClientThread thisConnection = new ServerToClientThread(thisClient); - thisConnection.start(); delegate.clientConnected(thisConnection); } } catch (IOException e) { diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 69851682..72dbd53a 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -20,11 +20,13 @@ import seng302.utilities.GeoPoint; * All server threads created and owned by the server thread handler which can trigger client updates on its threads * Created by wmu16 on 13/07/17. */ -public class ServerToClientThread extends Thread { +public class ServerToClientThread implements Runnable { private static final Integer LOG_LEVEL = 1; private static final Integer MAX_ID_ATTEMPTS = 10; + private Thread thread; + private InputStream is; private OutputStream os; private Socket socket; @@ -50,6 +52,9 @@ public class ServerToClientThread extends Thread { Random rand = new Random(); sourceId = rand.nextInt(100000); GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); + + thread = new Thread(this); + thread.start(); } @@ -185,4 +190,9 @@ public class ServerToClientThread extends Thread { readByte(); } } + + + public Thread getThread() { + return thread; + } } From 2869d139a36273f74155a731fcc78f902406ba05 Mon Sep 17 00:00:00 2001 From: William Muir Date: Sat, 22 Jul 2017 17:44:37 +1200 Subject: [PATCH 4/4] Three way handshake implemented client and server side and functioning Server generates a new Id for connections (Size of connections + 1) Client now stores an id allocated to it by the server The id is currently being saved in the clientToServer thread client side tags: #story[987] #implement --- .../seng302/client/ClientToServerThread.java | 42 ++++++++++++- .../java/seng302/gameServer/GameState.java | 10 +++ .../gameServer/ServerToClientThread.java | 62 +++++++++++-------- 3 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/main/java/seng302/client/ClientToServerThread.java b/src/main/java/seng302/client/ClientToServerThread.java index 79d2de3f..7c4bfea4 100644 --- a/src/main/java/seng302/client/ClientToServerThread.java +++ b/src/main/java/seng302/client/ClientToServerThread.java @@ -17,12 +17,15 @@ import seng302.server.messages.Message; */ public class ClientToServerThread implements Runnable { + private static final int LOG_LEVEL = 1; + private Thread thread; + private Integer ourID; + private Socket socket; private InputStream is; private OutputStream os; - private static final int LOG_LEVEL = 1; private Boolean updateClient = true; private ByteArrayOutputStream crcBuffer; @@ -36,6 +39,16 @@ public class ClientToServerThread implements Runnable { e.printStackTrace(); } + Integer allocatedID = threeWayHandshake(); + if (allocatedID != null) { + ourID = allocatedID; + clientLog("Successful handshake. Allocated ID: " + ourID, 1); + } else { + clientLog("Unsuccessful handhsake", 1); + closeSocket(); + return; + } + thread = new Thread(this); thread.start(); @@ -96,6 +109,33 @@ public class ClientToServerThread implements Runnable { } + + /** + * Listens for an allocated sourceID and returns it to the server if recieved + * @return the sourceID allocated to us by the server + */ + private Integer threeWayHandshake() { + Integer ourSourceID = null; + while (true) { + try { + ourSourceID = is.read(); + } catch (IOException e) { + e.printStackTrace(); + } + if (ourSourceID != null) { + try { + os.write(ourSourceID); + return ourSourceID; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + } + } + + + /** * Send the post-start race course information */ diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 879fc8e9..e9b1bfc7 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -121,4 +121,14 @@ public class GameState { yacht.update(timeInterval); } } + + + /** + * Generates a new ID based off the size of current players + 1 + * @return a playerID to be allocated to a new connetion + */ + public static Integer getUniquePlayerID() { + // TODO: 22/07/17 wmu16 - This may not be robust enough and may have to be improved on. + return yachts.size() + 1; + } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 72dbd53a..9b7f15fd 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -47,11 +47,19 @@ public class ServerToClientThread implements Runnable { } catch (IOException e) { System.out.println("IO error in server thread upon grabbing streams"); } -// threeWayHandshake(); - GameState.addPlayer(new Player(socket)); - Random rand = new Random(); - sourceId = rand.nextInt(100000); - GameState.addYacht(sourceId, new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); + + //Attempt threeway handshake with connection + sourceId = GameState.getUniquePlayerID(); + if (threeWayHandshake(sourceId)) { + serverLog("Successful handshake. Client allocated id: " + sourceId, 1); + GameState.addYacht(sourceId, + new Yacht("Kappa", "Kap", new GeoPoint(0.0, 0.0), 0.0)); + GameState.addPlayer(new Player(socket)); //Is this neccesary??? + } else { + serverLog("Unsuccessful handshake. Connection rejected", 1); + closeSocket(); + return; + } thread = new Thread(this); thread.start(); @@ -113,7 +121,7 @@ public class ServerToClientThread implements Runnable { } } } catch (Exception e) { - serverLog("ERROR OCCURED, CLOSING SERVER CONNETION: " + socket.getRemoteSocketAddress().toString(), 1); + serverLog("ERROR OCCURRED, CLOSING SERVER CONNECTION: " + socket.getRemoteSocketAddress().toString(), 1); closeSocket(); return; } @@ -132,28 +140,32 @@ public class ServerToClientThread implements Runnable { * if so, sends a confirmation packet back to that connection * Creates a player instance with that ID and this thread and adds it to the GameState * If not, close the socket and end the threads execution + * @param id the id to try and assign to the connection + * @return A boolean indicating if it was a successful handshake */ - private void threeWayHandshake() { -// // TODO: 13/07/17 Finish using AC35 -// Integer playerID = GameState.getUniquePlayerID(); -// Integer confirmationID = null; -// Integer identificationAttempt = 0 -// while (!userIdentified) { -// os.write(playerID); //Send out new ID looking for echo -// confirmationID = is.read(); -// if (playerID == idConfirmation) { //ID is echoed back. Connection is a client -// os.write( some determined confirmation message ); //Confirm to client -// GameState.addPlayer(new Player(playerID, this)); //Create a player in game state for client -// userIdentified = true; -// } else if (identificationAttempt > MAX_ID_ATTEMPTS) { //No response. not a client. tidy up and go home. -// closeSocket(); -// return; -// } -// identificationAttempt++; -// } + private Boolean threeWayHandshake(Integer id) { + Integer confirmationID = null; + Integer identificationAttempt = 0; + while (!userIdentified) { + try { + os.write(id); //Send out new ID looking for echo + confirmationID = is.read(); + } catch (IOException e) { + e.printStackTrace(); + } + + if (id.equals(confirmationID)) { //ID is echoed back. Connection is a client + return true; + } else if (identificationAttempt > MAX_ID_ATTEMPTS) { //No response. not a client. tidy up and go home. + return false; + } + identificationAttempt++; + } + + return true; } - public void closeSocket() { + private void closeSocket() { try { socket.close(); } catch (IOException e) {