From f544734b4dd49ef22f10e307a1e9314009e69882 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 25 Jul 2017 17:17:36 +1200 Subject: [PATCH] Fixed sending wrong race xml when a player disconnected because xml is getting data from gamestate yacht but the yachts are not updated is player disconnect. Heartbeat packet was sent out at wrong rate which cause the player disconnect detection to be slow. Heartbeat packet is send out every 200ms now. #story[1055] #pair[hyi25, zyt10] --- .../java/seng302/gameServer/GameState.java | 4 + .../seng302/gameServer/HeartbeatThread.java | 2 +- .../seng302/gameServer/MainServerThread.java | 14 +- .../gameServer/ServerToClientThread.java | 173 ++++++------------ 4 files changed, 73 insertions(+), 120 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index b13942c5..43ea0018 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -60,6 +60,10 @@ public class GameState { yachts.put(sourceId, yacht); } + public static void removeYacht(Integer yachtId) { + yachts.remove(yachtId); + } + public static Boolean getIsRaceStarted() { return isRaceStarted; } diff --git a/src/main/java/seng302/gameServer/HeartbeatThread.java b/src/main/java/seng302/gameServer/HeartbeatThread.java index 80c5bb24..0b7ce19a 100644 --- a/src/main/java/seng302/gameServer/HeartbeatThread.java +++ b/src/main/java/seng302/gameServer/HeartbeatThread.java @@ -13,7 +13,7 @@ import java.util.*; * cannot be sent to a player */ public class HeartbeatThread extends Thread{ - private final int HEARTBEAT_PERIOD = 5000; + private final int HEARTBEAT_PERIOD = 200; private ClientConnectionDelegate delegate; private Integer seqNum; private Stack disconnectedPlayers; diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 1d90fbaf..ca3f07ae 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -137,11 +137,21 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff */ @Override public void clientDisconnected(Player player) { - serverLog("Player disconnected", 0); + try { + player.getSocket().close(); + } catch (Exception e) { + serverLog("Cannot disconnect the socket for the disconnected player.", 0); + } + serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0); + GameState.removeYacht(player.getYacht().getSourceId()); GameState.removePlayer(player); + for (ServerToClientThread serverToClientThread : serverToClientThreads) { + if (serverToClientThread.getSocket() == player.getSocket()) { + this.deleteObserver(serverToClientThread); + } + } setChanged(); notifyObservers(); -// sendXml(); } public void startGame() { diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 0ca77b45..0fd3768f 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -43,9 +43,9 @@ import seng302.server.messages.XMLMessageSubType; import seng302.utilities.GeoPoint; /** - * A class describing a single connection to a Client for the purposes of sending and receiving on its own thread. - * 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. + * A class describing a single connection to a Client for the purposes of sending and receiving on + * its own thread. 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 implements Runnable, Observer { @@ -58,12 +58,12 @@ public class ServerToClientThread implements Runnable, Observer { private OutputStream os; private Socket socket; - private ByteArrayOutputStream crcBuffer; + private ByteArrayOutputStream crcBuffer; private Boolean userIdentified = false; private Boolean connected = true; private Boolean updateClient = true; - private Boolean initialisedRace = true; +// private Boolean initialisedRace = true; private Integer seqNo; private Integer sourceId; @@ -97,9 +97,10 @@ public class ServerToClientThread implements Runnable, Observer { thread.start(); } - static void serverLog(String message, int logLevel){ - if(logLevel <= LOG_LEVEL){ - System.out.println("[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message); + static void serverLog(String message, int logLevel) { + if (logLevel <= LOG_LEVEL) { + System.out.println( + "[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message); } } @@ -113,83 +114,13 @@ public class ServerToClientThread implements Runnable, Observer { int sync2; // TODO: 14/07/17 wmu16 - Work out how to fix this while loop - // used by ryan to simulate sending boats.xml -// InputStream inputStream = getClass().getResourceAsStream("/server_config/boats1.xml"); -// StringWriter writer = new StringWriter(); -// try { -// IOUtils.copy(inputStream, writer); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// String xml = writer.toString(); -// Message message = new XMLMessage(xml, XMLMessageSubType.BOAT, 0); -// sendMessage(message); -// System.out.println("[server] send message 1 " + message); -// -// try { -// Thread.sleep(3000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// -// inputStream = getClass().getResourceAsStream("/server_config/boats.xml"); -// writer = new StringWriter(); -// try { -// IOUtils.copy(inputStream, writer); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// xml = writer.toString(); -// message = new XMLMessage(xml, XMLMessageSubType.BOAT, 0); -// sendMessage(message); -// System.out.println("[server] send message 2 " + message); -// -// try { -// Thread.sleep(3000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// -// inputStream = getClass().getResourceAsStream("/server_config/boats2.xml"); -// writer = new StringWriter(); -// try { -// IOUtils.copy(inputStream, writer); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// xml = writer.toString(); -// message = new XMLMessage(xml, XMLMessageSubType.BOAT, 0); -// sendMessage(message); -// System.out.println("[server] send message 3 " + message); -// -// try { -// Thread.sleep(3000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// -// inputStream = getClass().getResourceAsStream("/server_config/boats.xml"); -// writer = new StringWriter(); -// try { -// IOUtils.copy(inputStream, writer); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// xml = writer.toString(); -// message = new XMLMessage(xml, XMLMessageSubType.BOAT, 0); -// sendMessage(message); -// System.out.println("[server] send message 4 " + message); -// sendMessage(getRaceStatusMessage()); -// System.out.println("sent race status"); - //------- - - while(true) { + while (socket.isConnected()) { try { - if (initialisedRace) { - sendSetupMessages(); - initialisedRace = false; - } +// if (initialisedRace) { +// sendSetupMessages(); +// initialisedRace = false; +// } //Perform a write if it is time to as delegated by the MainServerThread if (updateClient) { @@ -209,7 +140,7 @@ public class ServerToClientThread implements Runnable, Observer { 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)); @@ -249,7 +180,7 @@ public class ServerToClientThread implements Runnable, Observer { xml = new XMLGenerator(); Race race = new Race(); - for (Yacht yacht : GameState.getYachts().values()){ + for (Yacht yacht : GameState.getYachts().values()) { race.addBoat(yacht); } @@ -257,16 +188,18 @@ public class ServerToClientThread implements Runnable, Observer { xml.setRegatta(new Regatta("RaceVision Test Game", 57.6679590, 11.8503233)); xml.setRace(race); - XMLMessage xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA, xml.getRegattaAsXml().length()); + XMLMessage xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA, + xml.getRegattaAsXml().length()); sendMessage(xmlMessage); - xmlMessage = new XMLMessage(xml.getBoatsAsXml(), XMLMessageSubType.BOAT, xml.getBoatsAsXml().length()); + xmlMessage = new XMLMessage(xml.getBoatsAsXml(), XMLMessageSubType.BOAT, + xml.getBoatsAsXml().length()); sendMessage(xmlMessage); - xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE, xml.getRaceAsXml().length()); + xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE, + xml.getRaceAsXml().length()); sendMessage(xmlMessage); // System.out.println("Sent xml messages for " + thread.getName()); - } public void updateClient() { @@ -281,6 +214,7 @@ public class ServerToClientThread implements Runnable, Observer { * 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 */ @@ -300,7 +234,7 @@ public class ServerToClientThread implements Runnable, Observer { } else if (identificationAttempt > MAX_ID_ATTEMPTS) { //No response. not a client. tidy up and go home. return false; } - identificationAttempt++; + identificationAttempt++; } return true; @@ -315,7 +249,6 @@ public class ServerToClientThread implements Runnable, Observer { } - private int readByte() throws Exception { int currentByte = -1; try { @@ -325,54 +258,55 @@ public class ServerToClientThread implements Runnable, Observer { } catch (IOException e) { e.printStackTrace(); } - 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(); } } - public void sendMessage(Message message){ + public void sendMessage(Message message) { try { os.write(message.getBuffer()); } catch (SocketException e) { - serverLog("Player " + sourceId + " " + e.getMessage(), 0); + //serverLog("Player " + sourceId + " side socket disconnected", 0); + return; } catch (IOException e) { e.printStackTrace(); } } - private int getSeqNo(){ + private int getSeqNo() { seqNo++; return seqNo; } - private void sendBoatLocationPackets(){ + private void sendBoatLocationPackets() { ArrayList yachts = new ArrayList<>(GameState.getYachts().values()); - for (Yacht yacht: yachts){ + for (Yacht yacht : yachts) { // System.out.println("[SERVER] Lat: " + yacht.getLocation().getLat() + " Lon: " + yacht.getLocation().getLng()); BoatLocationMessage boatLocationMessage = - new BoatLocationMessage( - yacht.getSourceId(), - getSeqNo(), - yacht.getLocation().getLat(), - yacht.getLocation().getLng(), - yacht.getHeading(), - (long) yacht.getVelocity()); + new BoatLocationMessage( + yacht.getSourceId(), + getSeqNo(), + yacht.getLocation().getLat(), + yacht.getLocation().getLng(), + yacht.getHeading(), + (long) yacht.getVelocity()); sendMessage(boatLocationMessage); } @@ -382,38 +316,43 @@ public class ServerToClientThread implements Runnable, Observer { return thread; } - public void sendRaceStatusMessage(){ + public void sendRaceStatusMessage() { // variables taken from GameServerThread - int TIME_TILL_RACE_START = 20*1000; + int TIME_TILL_RACE_START = 20 * 1000; long startTime = System.currentTimeMillis() + TIME_TILL_RACE_START; List boatSubMessages = new ArrayList<>(); BoatStatus boatStatus; RaceStatus raceStatus; - for (Player player : GameState.getPlayers()){ + for (Player player : GameState.getPlayers()) { Yacht y = player.getYacht(); - if (GameState.getCurrentStage() == GameStages.PRE_RACE){ + if (GameState.getCurrentStage() == GameStages.PRE_RACE) { boatStatus = BoatStatus.PRESTART; - } - else if(GameState.getCurrentStage() == GameStages.RACING){ + } else if (GameState.getCurrentStage() == GameStages.RACING) { boatStatus = BoatStatus.RACING; } else { boatStatus = BoatStatus.UNDEFINED; } - BoatSubMessage m = new BoatSubMessage(y.getSourceId(), boatStatus, 0, 0, 0, 1234l, 1234l); + BoatSubMessage m = new BoatSubMessage(y.getSourceId(), boatStatus, 0, 0, 0, 1234l, + 1234l); boatSubMessages.add(m); } - if (GameState.getCurrentStage() == GameStages.RACING){ + if (GameState.getCurrentStage() == GameStages.RACING) { raceStatus = RaceStatus.STARTED; } else { raceStatus = RaceStatus.WARNING; } sendMessage(new RaceStatusMessage(1, raceStatus, startTime, GameState.getWindDirection(), - GameState.getWindSpeed().longValue(), GameState.getPlayers().size(), RaceType.MATCH_RACE, 1, boatSubMessages)); + GameState.getWindSpeed().longValue(), GameState.getPlayers().size(), + RaceType.MATCH_RACE, 1, boatSubMessages)); + } + + public Socket getSocket() { + return socket; } }